{"generatedAt":"2026-10-03T18:50:33.160Z","product":{"slug":"app-widgets-deep-links","name":"App Widgets & Deep Links","summary":"Embeddable Mappls experiences for places, directions, 3D views, RealView, and app hand-off.","stateModel":"stateless","platforms":["Widgets","Deep links","Web","Android","iOS"],"auth":{"type":"Often credential-free","guidance":"Use an API key only when the selected widget explicitly requires one; validate and encode all user-provided URL parameters."}},"ownership":{"classification":"application-stateful","boundary":"App Widgets & Deep Links is stateless at the product boundary for this catalog, while the published consent, selection, inspection, or publication journeys are application-owned state machines. Do not attribute those states to Mappls.","applicationRule":"The application owns business identity, expected version, command idempotency, evidence receipts, audit, reconciliation, and downstream side effects even when Mappls owns provider resource state."},"coverage":{"slug":"app-widgets-deep-links","name":"App Widgets & Deep Links","stateModel":"stateless","ownership":"application-stateful","accent":"#ff4f64","journeyCount":2,"boundary":"App Widgets & Deep Links is stateless at the product boundary for this catalog, while the published consent, selection, inspection, or publication journeys are application-owned state machines. Do not attribute those states to Mappls.","aggregates":["widget selection session","remote visual inspection"],"journeySlugs":["widget-selection-session","realview-remote-inspection"],"sampleSlugs":["widget-journey-host","realview-inspection-desk"],"tutorialSlugs":["deep-link-campaign","web-widget-place-picker","navigation-deep-link","deep-link-attribution-resilience","ios-sdk-production-readiness","ios-direction-geofence-handoffs","widget-host-production"],"useCaseSlugs":["travel-discovery"],"contractSlugs":[],"sourceGuideSlugs":["mappls-app-widgets","mappls-android-sdk","mappls-ui-widget-ios-distribution","mappls-ui-widget-ios-distribution-base","mappls-flutter-sdk","mappls-react-native-sdk","mappls-web-maps-js"],"totals":{"states":17,"transitions":19,"failurePlans":11,"durableRecords":9,"operationalSignals":16}},"controlLayers":[{"id":"identity","title":"Identity and aggregate boundary","question":"What durable thing is being operated?","implementation":"Use stable business and provider identifiers for widget selection session, remote visual inspection; never infer identity from display text or the latest coordinates.","proof":"Duplicate creation, resource rebinding, tenant isolation, and retirement tests."},{"id":"authority","title":"Actor authority","question":"Who may advance each transition?","implementation":"Authorize every command against the named journey actors: Application user, Host application, Platform adapter, Mappls widget, Inspector, Inspection reviewer, Platform administrator, Mappls RealView widget. Persist the attributable actor, tenant, purpose, and policy decision.","proof":"Role, resource, tenant, purpose, and human-approval denial tests."},{"id":"commands","title":"Commands and concurrency","question":"How are retries and races made safe?","implementation":"Require a command idempotency key and expected aggregate version. Cache the canonical result, reject key reuse with different intent, and reconcile ambiguous timeouts before retry.","proof":"Exact replay, stale-version rejection, concurrent-writer, timeout, and restart tests."},{"id":"evidence","title":"Evidence and durable records","question":"What proves each state?","implementation":"Persist immutable receipts and revisions around these catalog records: Selection session, Normalized selection, Audit event, Transactional outbox, Inspection aggregate, Entitlement reference, Viewer attempt, Observation and review, Audit and outbox. Keep event time, receipt time, source identity, hashes, and retention policy separate.","proof":"Missing, malformed, late, duplicate, conflicting, and redacted-evidence tests."},{"id":"events","title":"Events and side effects","question":"How do downstream systems learn what committed?","implementation":"Commit aggregate state, audit, and a transactional outbox together. Sign deliveries, bound retries, dead-letter exhaustions, and preserve delivery attempts without changing business history.","proof":"Atomic commit, signature, retry, lease fencing, dead-letter, replay, and ordering tests."},{"id":"recovery","title":"Recovery and reconciliation","question":"What happens when systems disagree?","implementation":"Treat timeouts as unknown outcomes, poll or consume authoritative evidence, compare versions, append a reconciliation decision, and use compensation instead of destructive history edits.","proof":"Provider timeout, callback-before-response, delayed event, outage, restart, and manual-recovery drills."},{"id":"privacy","title":"Privacy and human control","question":"Which data and decisions are sensitive?","implementation":"Minimize precise location and media, scope retention, redact derived data deliberately, and require attributable approval for dispatch, publication, access, closure, and destructive change where consequential.","proof":"Least-privilege, consent expiry, separation-of-duties, retention, export, revocation, and redaction tests."},{"id":"operations","title":"Operations and release","question":"Can operators see and recover the journey?","implementation":"Expose state age, source freshness, stuck commands, retries, reconciliation lag, outbox depth, terminal outcomes, and per-aggregate audit. Roll out behind explicit acceptance gates.","proof":"SLO alerts, support lookup, bulk reconciliation, rollback, backup restore, regional failover, and incident drills."}],"journeys":[{"slug":"widget-selection-session","title":"Application-owned widget selection","eyebrow":"Widgets · host-owned candidate lifecycle","productSlug":"app-widgets-deep-links","stateModel":"hybrid","summary":"Launch a Mappls widget, recover through a useful fallback, validate a narrow candidate, commit it deliberately, invalidate stale selection, and submit one durable business record.","aggregate":"widget selection session","actors":["Application user","Host application","Platform adapter","Mappls widget"],"sourceGuideSlugs":["mappls-app-widgets","mappls-android-sdk","mappls-ui-widget-ios-distribution","mappls-ui-widget-ios-distribution-base","mappls-flutter-sdk","mappls-react-native-sdk"],"contractSlugs":[],"sampleSlug":"widget-journey-host","states":[{"id":"draft","label":"Draft","meaning":"Host-owned address or place intent exists without an active provider surface or committed Mappls identity.","recovery":"Restore only the host draft; never serialize a widget view, controller, listener, Promise, or opaque provider result."},{"id":"widget_open","label":"Widget open","meaning":"One launch generation owns the provider surface, lifecycle callbacks, focus, cancellation, and timeout.","recovery":"Dispose the generation exactly once and either retry explicitly or activate the host-owned fallback."},{"id":"fallback_active","label":"Fallback active","meaning":"The provider surface is unavailable and a bounded manual or search-assisted host path remains operable.","recovery":"Preserve the same session identity and record why fallback was selected before returning a candidate."},{"id":"candidate_received","label":"Candidate received","meaning":"An exact-origin or native-adapter result passed schema validation but is not yet a business selection.","recovery":"Discard malformed, late, duplicated, or superseded candidates; retain only the narrow normalized value."},{"id":"selected","label":"Selected","meaning":"The user deliberately committed a normalized Mappls Pin and label against the current host draft version.","recovery":"Any material host edit clears selection and returns the aggregate to draft."},{"id":"submitted","label":"Submitted","meaning":"Host text and committed selection form one immutable, attributable business record with an outbox event.","recovery":"Treat submission as terminal; corrections create a new version or linked replacement rather than changing history.","terminal":true},{"id":"cancelled","label":"Cancelled","meaning":"A named actor ended the journey without submission and with a recorded reason.","recovery":"Start a new session for renewed intent; do not silently resurrect a cancelled provider generation.","terminal":true}],"transitions":[{"command":"create_session","actor":"Host application","from":[],"to":"draft","event":"host.session_created","idempotency":"The external checkout/form identity maps to one aggregate across retries."},{"command":"open_widget","actor":"Application user","from":["draft","fallback_active"],"to":"widget_open","event":"widget.opened","idempotency":"Persist one launch generation and ignore every callback belonging to an older generation."},{"command":"activate_fallback","actor":"Platform adapter","from":["widget_open"],"to":"fallback_active","event":"widget.fallback_activated","idempotency":"One failed generation produces at most one fallback transition and focus restoration."},{"command":"receive_candidate","actor":"Platform adapter","from":["widget_open","fallback_active"],"to":"candidate_received","event":"location.candidate_received","idempotency":"Deduplicate the terminal adapter result and bind it to session and launch generation."},{"command":"accept_selection","actor":"Application user","from":["candidate_received"],"to":"selected","event":"location.selected","idempotency":"Compare aggregate version and hash the normalized candidate before committing."},{"command":"edit_host_text","actor":"Application user","from":["draft","widget_open","fallback_active","candidate_received","selected"],"to":"draft","event":"host.text_edited","idempotency":"The edit command version determines whether candidate and selection invalidation already occurred."},{"command":"submit","actor":"Application user","from":["selected"],"to":"submitted","event":"host.submitted","idempotency":"Commit the record, audit event, processed command, and outbox entry atomically."},{"command":"cancel","actor":"Application user","from":["draft","widget_open","fallback_active","candidate_received","selected"],"to":"cancelled","event":"host.cancelled","idempotency":"Repeated cancellation returns the terminal record without rerunning cleanup side effects."}],"invariants":["A provider callback or browser message creates only a candidate, never a submitted business record.","Every browser message matches the exact reviewed origin and a versioned allow-listed schema.","Only a six-character alphanumeric Mappls Pin and bounded printable label enter durable selection state.","A host-text edit invalidates every candidate and committed selection from the previous draft version.","One launch generation produces at most one terminal adapter outcome; late callbacks are ignored.","Credentials, provider controllers, native views, bridge objects, and opaque response payloads are never persisted."],"records":[{"name":"Selection session","purpose":"Current host draft, lifecycle state, launch generation, candidate, selection, and optimistic version.","keyFields":["sessionId","externalId","state","version","launchGeneration","hostText"]},{"name":"Normalized selection","purpose":"Application-owned portable place identity independent of provider UI lifetime.","keyFields":["schemaVersion","mapplsPin","label","source","selectedAt","selectedBy"]},{"name":"Audit event","purpose":"Attributable state transition and recovery history.","keyFields":["eventId","aggregateVersion","type","actor","idempotencyKey","occurredAt"]},{"name":"Transactional outbox","purpose":"Exactly-once-in-effect notification and downstream form processing.","keyFields":["outboxId","eventId","status","attempts","nextAttemptAt"]}],"failures":[{"trigger":"Widget fails, is denied, or times out","detection":"The active generation reaches a typed failure without a valid terminal candidate.","recovery":"Dispose it, restore focus, record the reason, and activate a useful host-owned fallback."},{"trigger":"Message arrives from a wrong origin or with unknown fields","detection":"Exact origin or narrow schema validation fails before domain processing.","recovery":"Reject without changing aggregate state and emit a safe rejection metric without storing opaque content."},{"trigger":"Callback arrives after screen disposal or a newer launch","detection":"Owner is inactive or result generation differs from the current session generation.","recovery":"Ignore the late result and clean up its provider resources without committing state."},{"trigger":"User edits the address after selecting a place","detection":"Host draft version changes while a candidate or selection exists.","recovery":"Clear both values, return to draft, and require a new selection before submission."},{"trigger":"Submit response is lost","detection":"Client lacks acknowledgement but retains session and idempotency identity.","recovery":"Repeat the same command key or read the session; never create a second business record."}],"observability":["Widget launch, time-to-active, and terminal outcome by platform and component version","Origin and schema rejection counts without raw payload retention","Fallback activation, completion, and abandonment rate","Candidate-to-selection and selection-to-submit conversion","Stale selection invalidation after host edits","Duplicate, late, and superseded callback count","Idempotency replay and optimistic version conflict rate","Outbox backlog, retry, and dead-letter age"],"website":"/journeys/widget-selection-session"},{"slug":"realview-remote-inspection","title":"Entitled RealView remote inspection","eyebrow":"RealView · human observation and review","productSlug":"app-widgets-deep-links","stateModel":"stateful","summary":"Qualify paid RealView entitlement, open one browser-visible-token viewer attempt, handle the documented no-imagery signal safely, and turn human observations into a reviewed business record without inventing panorama metadata.","aggregate":"remote visual inspection","actors":["Inspector","Inspection reviewer","Platform administrator","Host application","Mappls RealView widget"],"sourceGuideSlugs":["mappls-app-widgets","mappls-web-maps-js"],"contractSlugs":[],"sampleSlug":"realview-inspection-desk","states":[{"id":"draft","label":"Draft","meaning":"The host owns an inspection purpose, external asset/site identity, Mappls Pin or coordinate, classification, and policy version.","recovery":"Restore only host-owned data; never persist a token, complete iframe URL, provider DOM, controller, or opaque imagery payload."},{"id":"entitlement_pending","label":"Entitlement pending","meaning":"Paid product access, exact host generation, browser credential class, restrictions, expiry, quota, and permitted use are being approved.","recovery":"Keep the case pending until an administrator records a current entitlement reference; do not substitute another Mappls credential."},{"id":"ready","label":"Ready","meaning":"The approved entitlement reference and bounded viewer configuration are current enough to open an attempt.","recovery":"If the entitlement expires or configuration changes, invalidate readiness before a browser-visible token is requested."},{"id":"viewing","label":"Viewing","meaning":"One browser lifecycle owns the iframe, exact origin, location/radius configuration, ephemeral token-handle reference, listener, timeout, and disposal.","recovery":"Dispose exactly once and ignore every message from a superseded attempt; return to entitlement pending on token expiry."},{"id":"coverage_unavailable","label":"Coverage unavailable","meaning":"The exact Auth2 origin emitted the documented schema-valid status 204 for this attempt and configuration.","recovery":"Adjust only a justified location/radius or choose field evidence; never generalize one 204 into permanent area-wide absence."},{"id":"observation_recorded","label":"Observation recorded","meaning":"An inspector saved a bounded human checklist and notes linked to the viewer attempt, without claiming provider metadata or copying imagery.","recovery":"Corrections create a linked observation revision; the source attempt and original observation remain immutable."},{"id":"review_pending","label":"Review pending","meaning":"An immutable observation set awaits a separately authorized reviewer under the declared purpose and policy.","recovery":"Reassign review explicitly and keep its SLA independent from provider availability."},{"id":"accepted","label":"Accepted","meaning":"A named reviewer accepted the observation set for the exact business decision and policy version.","recovery":"Later evidence creates a new inspection or linked revision rather than rewriting acceptance.","terminal":true},{"id":"rework_required","label":"Rework required","meaning":"Review retained the prior observation and reason while requiring a new viewer attempt or alternate field evidence.","recovery":"Open a new immutable attempt after requalifying entitlement and configuration."},{"id":"cancelled","label":"Cancelled","meaning":"An authorized actor ended the inspection with a bounded reason while preserving prior attempts and observations.","recovery":"Renewed business intent creates a new linked inspection.","terminal":true}],"transitions":[{"command":"create_inspection","actor":"Host application","from":[],"to":"draft","event":"realview_inspection.created","idempotency":"One external inspection identity maps to one aggregate across retries."},{"command":"request_entitlement","actor":"Inspector","from":["draft"],"to":"entitlement_pending","event":"realview_inspection.entitlement_requested","idempotency":"The product, environment, and account request identity is stable and contains no credential value."},{"command":"confirm_entitlement","actor":"Platform administrator","from":["entitlement_pending"],"to":"ready","event":"realview_inspection.entitlement_confirmed","idempotency":"Commit only entitlement reference, exact host, restrictions, and expiry metadata—not the issued token."},{"command":"open_viewer","actor":"Inspector","from":["ready","coverage_unavailable","rework_required"],"to":"viewing","event":"realview_inspection.viewer_opened","idempotency":"One command creates one immutable attempt and one ephemeral token-handle reference."},{"command":"record_no_coverage","actor":"Host application","from":["viewing"],"to":"coverage_unavailable","event":"realview_inspection.coverage_unavailable","idempotency":"Accept one exact-origin, one-field status 204 result for the active attempt only."},{"command":"record_observation","actor":"Inspector","from":["viewing"],"to":"observation_recorded","event":"realview_inspection.observation_recorded","idempotency":"Hash the bounded checklist, notes, attempt, actor, and observation time."},{"command":"submit_review","actor":"Inspector","from":["observation_recorded"],"to":"review_pending","event":"realview_inspection.review_requested","idempotency":"Freeze one observation set and enqueue review atomically."},{"command":"accept","actor":"Inspection reviewer","from":["review_pending"],"to":"accepted","event":"realview_inspection.accepted","idempotency":"Bind reviewer, reason, policy version, observation IDs, and command identity."},{"command":"request_rework","actor":"Inspection reviewer","from":["review_pending"],"to":"rework_required","event":"realview_inspection.rework_requested","idempotency":"Retain the reviewed evidence and create one attributable rework decision."},{"command":"record_entitlement_expired","actor":"Host application","from":["ready","viewing"],"to":"entitlement_pending","event":"realview_inspection.entitlement_expired","idempotency":"Invalidate the active attempt once and discard only its ephemeral token handle."},{"command":"cancel","actor":"Inspector","from":["draft","entitlement_pending","ready","viewing","coverage_unavailable","observation_recorded","review_pending","rework_required"],"to":"cancelled","event":"realview_inspection.cancelled","idempotency":"Commit actor, reason, cleanup, audit, and outbox exactly once."}],"invariants":["No server secret, browser token value, or complete token-bearing iframe URL is persisted, logged, analyzed, exported, or sent to a model.","The exact selected origin and narrow documented schema are checked before any browser message reaches domain state.","Status 204 proves only no imagery for one attempt and configuration; HTTP 200 and frame load prove only a delivered shell.","Human observation is distinct from provider imagery, panorama metadata, measurement, currentness, and inspection acceptance.","Imagery is not copied, screenshotted, exported, or retained without an explicit licensed product contract and purpose-specific policy.","Every command is idempotent, compares expected version, and commits snapshot, audit, receipt, and outbox atomically.","Reviewer acceptance is attributable and cannot be performed by the same automated actor that created the observation."],"records":[{"name":"Inspection aggregate","purpose":"Current purpose, asset/site and location identity, ownership, policy, state, and optimistic version.","keyFields":["inspectionId","externalId","assetId","mapplsPinOrCoordinate","purpose","state","version"]},{"name":"Entitlement reference","purpose":"Non-secret proof of the approved product generation and credential policy.","keyFields":["entitlementRef","product","host","environment","credentialClass","expiresAt","restrictionFingerprint"]},{"name":"Viewer attempt","purpose":"Immutable browser lifecycle and documented no-imagery outcome.","keyFields":["attemptId","configFingerprint","tokenHandleRef","openedAt","disposedAt","coverageStatus"]},{"name":"Observation and review","purpose":"Human-authored evidence and separately authorized decision without copied imagery.","keyFields":["observationId","attemptId","checklist","notes","observedAt","reviewer","decision","policyVersion"]},{"name":"Audit and outbox","purpose":"Append-only transitions and exactly-once-in-effect downstream delivery.","keyFields":["eventId","aggregateVersion","actor","idempotencyKey","outboxStatus"]}],"failures":[{"trigger":"Iframe returns a shell but no usable imagery","detection":"HTTP/frame load occurred without entitled viewing or the documented 204 signal.","recovery":"Keep viewing unresolved until a bounded timeout, then record a host technical outcome rather than coverage or completion."},{"trigger":"Message uses a lookalike origin or malformed payload","detection":"Exact origin, object shape, field count, or integer status validation fails.","recovery":"Reject before domain processing, retain only a safe rejection metric, and never store the opaque payload."},{"trigger":"Entitlement expires during viewing","detection":"The entitlement reference is expired/revoked or the account-approved broker reports token expiry.","recovery":"Dispose the viewer, remove the ephemeral handle, return to entitlement pending, and retain the incomplete attempt."},{"trigger":"Imagery is unavailable for the selected radius","detection":"The active attempt receives the documented exact-origin status 204 message.","recovery":"Record configuration-specific no coverage and offer justified radius/location retry or alternate field evidence."},{"trigger":"Reviewer cannot rely on the observation","detection":"Checklist is incomplete, limitations are missing, purpose changed, or stronger field evidence is required.","recovery":"Request rework without overwriting the observation or prior viewer attempt."},{"trigger":"Application restarts after an unknown command outcome","detection":"Client lacks acknowledgement while aggregate, command key, and outbox state are durable.","recovery":"Reload and replay the same command key; never create another attempt or review decision to recover transport uncertainty."}],"observability":["Entitlement request age, confirmation, expiry, revocation, and renewal without token values","Viewer open, time-to-first-useful-state, timeout, disposal, and superseded-attempt count","Exact-origin/schema rejection counts without raw payload retention","Status 204 rate by bounded configuration fingerprint, not generalized geography","Observation completeness, limitation flags, and review duration","Rework reason and new-attempt conversion","Credential-bearing URL log/screenshot/model-context prevention checks","Idempotency replay, optimistic conflict, audit, outbox backlog, retry, and dead-letter age"],"website":"/journeys/realview-remote-inspection"}],"evidence":{"contracts":[],"guides":[{"slug":"mappls-app-widgets","title":"Mappls App Widgets","summary":"Using Mappls App Widgets, you can embed latest features of Mappls app in a universal, cross-platform mechanism and perform visualization of a place, get immersive 3D metaverse visuals, and display Realviews - panoramic images. You don't need a Mappls API credential to use most of these Mappls App widgets.","kind":"Deep link","maturity":"current","platforms":["Widgets/Deep links"],"website":"/reference/mappls-app-widgets"},{"slug":"mappls-android-sdk","title":"Mappls Android SDK","summary":"A collection of Mappls's Map and others SDKs for Native android Development.","kind":"SDK","maturity":"current","platforms":["Android"],"website":"/reference/mappls-android-sdk"},{"slug":"mappls-ui-widget-ios-distribution","title":"MapplsUIWidgets - UI Components SDK for iOS","summary":"Mappls UI Widget Native for iOS distributed via the SPM (Swift Package Manager).","kind":"Distribution","maturity":"distribution","platforms":["iOS"],"website":"/reference/mappls-ui-widget-ios-distribution"},{"slug":"mappls-ui-widget-ios-distribution-base","title":"MapplsUIWidgets - UI Components SDK for iOS","summary":"A versioned iOS distribution package used to integrate maps, search places, routes navigation, tracking telematics, widgets deep links, capture feedback, identity platform into an application.","kind":"Distribution","maturity":"distribution","platforms":["iOS"],"website":"/reference/mappls-ui-widget-ios-distribution-base"},{"slug":"mappls-flutter-sdk","title":"Mappls Flutter SDK","summary":"This SDK is wrapper for Flutter on Native Map SDK to support on Android and iOS.","kind":"SDK","maturity":"current","platforms":["Flutter"],"website":"/reference/mappls-flutter-sdk"},{"slug":"mappls-react-native-sdk","title":"Mappls React Native SDK","summary":"A Mappls sdk for maps, search places, routes navigation, tracking telematics, gis analytics, widgets deep links, capture feedback, identity platform across React Native.","kind":"SDK","maturity":"current","platforms":["React Native"],"website":"/reference/mappls-react-native-sdk"},{"slug":"mappls-web-maps-js","title":"Mappls Web Maps JS","summary":"Mappls's Latest Vector Maps Web SDK for rendering beautifully interactive, fluid maps that are powered by browser based WebGL.","kind":"Guide","maturity":"current","platforms":["Web"],"website":"/reference/mappls-web-maps-js"}],"samples":[{"slug":"widget-journey-host","name":"Widget Journey Host","description":"Own a complete place-selection journey around a Mappls widget: launch, recover through fallback, normalize a candidate, commit deliberately, invalidate stale selection, and submit exactly once in effect.","stack":["Node.js","Responsive host form UI","Widget message adapter","Durable evidence store"],"implementation":"full-stack-reference","verifiedTestCount":8,"downloadPath":"/downloads/widget-journey-host.zip","website":"/samples/widget-journey-host"},{"slug":"realview-inspection-desk","name":"RealView Inspection Desk","description":"Qualify paid RealView access, open bounded viewer attempts, validate the documented no-imagery signal, record human observations, and require separate review without persisting tokens or imagery.","stack":["Node.js","Responsive inspection UI","RealView Auth2 adapter","Human evidence and review ledger"],"implementation":"full-stack-reference","verifiedTestCount":10,"downloadPath":"/downloads/realview-inspection-desk.zip","website":"/samples/realview-inspection-desk"}],"tutorials":[{"slug":"deep-link-campaign","title":"Create a zero-SDK location campaign","outcome":"A campaign that opens a useful Mappls experience everywhere.","level":"Beginner","duration":"15 min","website":"/tutorials/deep-link-campaign"},{"slug":"web-widget-place-picker","title":"Embed a place picker widget","outcome":"An accessible embedded place picker with explicit host-page ownership.","level":"Beginner","duration":"25 min","website":"/tutorials/web-widget-place-picker"},{"slug":"navigation-deep-link","title":"Hand off to navigation with a resilient deep link","outcome":"A tested app-to-navigation hand-off across installed and uninstalled states.","level":"Beginner","duration":"20 min","website":"/tutorials/navigation-deep-link"},{"slug":"deep-link-attribution-resilience","title":"Operate deep links across every hand-off","outcome":"A measurable zero-SDK journey that never confuses a click with arrival.","level":"Advanced","duration":"70 min","website":"/tutorials/deep-link-attribution-resilience"},{"slug":"ios-sdk-production-readiness","title":"Qualify an iOS Mappls release","outcome":"A clean-device iOS qualification record spanning SDK, widget, tracking, and distribution boundaries.","level":"Advanced","duration":"2 hr","website":"/tutorials/ios-sdk-production-readiness"},{"slug":"ios-direction-geofence-handoffs","title":"Build restart-safe iOS direction and geofence handoffs","outcome":"Two tested, durable iOS handoff journeys with explicit provider and application evidence boundaries.","level":"Advanced","duration":"95 min","website":"/tutorials/ios-direction-geofence-handoffs"},{"slug":"widget-host-production","title":"Operate widgets as untrusted lifecycle surfaces","outcome":"A restart-safe host journey with exact-origin validation and a complete non-widget fallback.","level":"Advanced","duration":"85 min","website":"/tutorials/widget-host-production"}],"useCases":[{"slug":"travel-discovery","title":"Turn inspiration into an itinerary","industry":"Travel","outcome":"More confident trip planning and higher conversion from discovery to booking.","website":"/use-cases/travel-discovery"}]},"releaseGates":["Every command has tenant, actor, purpose, idempotency, expected-version, and authorization evidence.","Every state transition has an objective evidence rule and an explicit recovery path.","Provider and business identities remain distinct, versioned, and reconcilable.","Timeout, retry, duplicate, late, out-of-order, conflict, restart, and outage paths are tested.","Sensitive location, media, identity, and operational evidence has consent, access, retention, and redaction policy.","Audit and outbox commit atomically; signing, delivery, dead-letter, replay, and lease fencing are verified.","Operators can find one aggregate, explain its state, repair safely, and prove who acted.","Live Mappls entitlement, quota, regional behavior, callbacks, and exact provider contracts are validated before production."],"handoffs":{"website":"https://developer.mappls.com/tools/stateful?product=app-widgets-deep-links","api":"https://developer.mappls.com/api/stateful-plan?product=app-widgets-deep-links","console":"https://developer.mappls.com/console/apps","resource":"mappls://catalog/stateful","tool":"mappls_plan_stateful_integration"},"credentialRule":"The planner accepts no credential, token, secret, precise location, media, or provider resource identifier."}