{"generatedAt":"2026-10-03T18:48:54.444Z","product":{"slug":"capture-feedback","name":"Capture & Feedback","summary":"On-demand location capture, camera evidence, map feedback, and update workflows.","stateModel":"hybrid","platforms":["Android","iOS"],"auth":{"type":"SDK entitlement and user consent","guidance":"Request the minimum device permission needed, retain evidence only for the declared purpose, and make capture policy visible to the user. The repository snapshot documents entitled SDK operations; direct REST access remains selection-required until an authoritative HTTP contract is supplied."}},"ownership":{"classification":"hybrid-provider-application","boundary":"Capture & Feedback combines request/response capabilities with durable sessions, workspaces, releases, reviews, or agent runs. Persist the business journey independently from any one provider response.","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":"capture-feedback","name":"Capture & Feedback","stateModel":"hybrid","ownership":"hybrid-provider-application","accent":"#1c9c62","journeyCount":3,"boundary":"Capture & Feedback combines request/response capabilities with durable sessions, workspaces, releases, reviews, or agent runs. Persist the business journey independently from any one provider response.","aggregates":["feedback report","location capture attempt","place contribution"],"journeySlugs":["ios-feedback-report-review","location-capture-evidence","place-contribution-publication"],"sampleSlugs":["place-contribution-desk","address-verifier"],"tutorialSlugs":["reverse-geocode-check-in","workmate-proof-review","flutter-production-lifecycle","ios-sdk-production-readiness","react-native-native-parity","widget-host-production"],"useCaseSlugs":["last-mile-delivery","field-service","energy-grid-resilience","banking-address-risk","insurance-claims","hospital-care-logistics","aviation-ground-operations","agriculture-field-ops","mining-haulage-safety","telecom-network-care"],"contractSlugs":["core-location-get-api-places-search-json-autosuggest-api","core-location-get-apis-o2o-entity-eloc-place-detail-api"],"sourceGuideSlugs":["mappls-feedback-kit-ios-distribution","mappls-feedback-kit-ios-distribution-base","mappls-feedback-uikit-ios-distribution","mappls-feedback-uikit-ios-distribution-base","mappls-location-capture-android-sdk","mappls-location-capture-ios-sdk","mappls-location-capture-sdk-ios-distribution","mappls-app-widgets","mappls-rest-apis"],"totals":{"states":24,"transitions":26,"failurePlans":14,"durableRecords":12,"operationalSignals":23}},"controlLayers":[{"id":"identity","title":"Identity and aggregate boundary","question":"What durable thing is being operated?","implementation":"Use stable business and provider identifiers for feedback report, location capture attempt, place contribution; 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: Contributor, Host application, Mappls Feedback Kit, Provider adapter, Operations reviewer, Application user, Platform adapter, Evidence reviewer, Mappls Location Capture SDK, Mappls hosted widget and search. 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: Feedback report, Submission revision, Provider attempt, Review decision, Capture attempt, Normalized location evidence, Audit and outbox, Contribution aggregate, Widget attempt, Publication evidence. 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":"ios-feedback-report-review","title":"iOS feedback report and review","eyebrow":"Mappls Feedback Kit · evidence before resolution","productSlug":"capture-feedback","stateModel":"hybrid","summary":"Open one feedback UI generation, normalize a bounded report candidate, commit an application submission, reconcile provider acknowledgement separately, review evidence, and close only with an attributable resolution.","aggregate":"feedback report","actors":["Contributor","Host application","Mappls Feedback Kit","Provider adapter","Operations reviewer"],"sourceGuideSlugs":["mappls-feedback-kit-ios-distribution","mappls-feedback-kit-ios-distribution-base","mappls-feedback-uikit-ios-distribution","mappls-feedback-uikit-ios-distribution-base"],"contractSlugs":[],"sampleSlug":"place-contribution-desk","states":[{"id":"draft","label":"Draft","meaning":"The host owns purpose, category intent, reporter consent, location context, and retention policy before opening provider UI.","recovery":"Restore only bounded host fields; never serialize a view controller, delegate, credential, attachment body, or opaque provider object."},{"id":"capturing","label":"Capturing","meaning":"One presented feedback generation owns UI, focus, permission prompts, callbacks, cancellation, and cleanup.","recovery":"Dismiss and dispose once; a later attempt receives a new generation and cannot accept callbacks from the old one."},{"id":"candidate","label":"Candidate","meaning":"The adapter copied allow-listed category, bounded description, normalized location identity, and attachment references into application state.","recovery":"Reject malformed, oversized, stale, unexpected, or late output without retaining an opaque payload."},{"id":"submitted","label":"Submitted","meaning":"The contributor deliberately committed one immutable application report with idempotency, expected version, audit, and outbox evidence.","recovery":"Submission proves only the application's accepted record; provider receipt and publication or resolution remain separate facts."},{"id":"provider_pending","label":"Provider pending","meaning":"A separately selected adapter has an acknowledged or unknown provider submission outcome that requires reconciliation.","recovery":"Query or reconcile using the original application and provider identity; never blind-retry with a new command key."},{"id":"review_pending","label":"Review pending","meaning":"Submission evidence and any provider acknowledgement await an attributable quality, privacy, duplication, or policy decision.","recovery":"Request rework as a new immutable attempt or reject with a bounded reason; never overwrite the submitted evidence."},{"id":"resolved","label":"Resolved","meaning":"An authorized reviewer recorded the disposition and exact supporting evidence, with provider resolution only when independently proven.","recovery":"Corrections append a linked decision revision rather than mutating the terminal record.","terminal":true},{"id":"rejected","label":"Rejected","meaning":"Review found the report invalid, duplicate, out of scope, or unsupported and preserved the reason plus evidence lineage.","recovery":"A contributor may create a linked retry with a new attempt identity.","terminal":true},{"id":"cancelled","label":"Cancelled","meaning":"The contributor ended the active attempt before application submission and every UI resource was disposed.","recovery":"Renewed intent creates a new report aggregate or explicitly linked attempt.","terminal":true}],"transitions":[{"command":"create_report","actor":"Host application","from":[],"to":"draft","event":"feedback_report.created","idempotency":"One external case and purpose maps to one draft aggregate across retries."},{"command":"open_feedback_ui","actor":"Contributor","from":["draft"],"to":"capturing","event":"feedback_report.ui_opened","idempotency":"One command creates one active presentation generation and ownership record."},{"command":"receive_candidate","actor":"Mappls Feedback Kit","from":["capturing"],"to":"candidate","event":"feedback_report.candidate_received","idempotency":"Accept one terminal allow-listed result for the active generation and normalized content hash."},{"command":"commit_submission","actor":"Contributor","from":["candidate"],"to":"submitted","event":"feedback_report.submitted","idempotency":"Commit report, processed command, audit event, and outbox atomically under expected version."},{"command":"request_provider_submission","actor":"Provider adapter","from":["submitted"],"to":"provider_pending","event":"feedback_report.provider_requested","idempotency":"Persist application command and provider request identities before attempting the separately approved contract."},{"command":"queue_review","actor":"Host application","from":["submitted","provider_pending"],"to":"review_pending","event":"feedback_report.review_queued","idempotency":"One immutable submission revision creates at most one active review case."},{"command":"resolve_report","actor":"Operations reviewer","from":["review_pending"],"to":"resolved","event":"feedback_report.resolved","idempotency":"Bind actor, disposition, exact evidence revision, audit, and notification outbox in one commit."},{"command":"reject_report","actor":"Operations reviewer","from":["review_pending"],"to":"rejected","event":"feedback_report.rejected","idempotency":"One reviewer decision applies once to one immutable report revision."},{"command":"cancel_report","actor":"Contributor","from":["draft","capturing","candidate"],"to":"cancelled","event":"feedback_report.cancelled","idempotency":"Repeated cancellation returns the terminal result while cleanup remains exactly-once-in-effect."}],"invariants":["A UI callback creates only a candidate; it cannot prove application submission, provider receipt, publication, or resolution.","One presentation generation produces at most one accepted terminal result and all late callbacks are ignored.","Every submission revision is immutable and content-hashed; rework creates a new linked attempt.","Provider acknowledgement and reviewer disposition are separate attributable records.","Credentials, view controllers, delegates, attachment bodies, and opaque provider payloads never enter durable state.","Idempotency, optimistic concurrency, audit, outbox, privacy purpose, retention, and redaction apply to every committed transition."],"records":[{"name":"Feedback report","purpose":"Host-owned intent, lifecycle state, current immutable submission, and optimistic version.","keyFields":["reportId","externalId","purpose","state","submissionRevision","version"]},{"name":"Submission revision","purpose":"Allow-listed category, description, normalized location, consent, attachment references, and content identity.","keyFields":["submissionId","reportId","contentHash","locationIdentity","consentVersion","submittedAt"]},{"name":"Provider attempt","purpose":"Separately selected contract request, acknowledgement, unknown outcome, and reconciliation evidence.","keyFields":["attemptId","submissionId","providerRequestId","status","receiptReference","lastCheckedAt"]},{"name":"Review decision","purpose":"Attributable disposition against one exact submission and provider-evidence revision.","keyFields":["reviewId","submissionId","reviewer","decision","reason","decidedAt"]}],"failures":[{"trigger":"UI is denied, blocked, dismissed, or times out","detection":"The active generation ends without a valid allow-listed candidate.","recovery":"Dispose, restore focus, retain the draft, record a safe reason, and offer a purpose-appropriate manual fallback."},{"trigger":"A callback arrives after replacement or disposal","detection":"Its presentation generation differs from the report's active generation.","recovery":"Ignore it, release its resources, and keep current report state unchanged."},{"trigger":"Provider submission response is lost","detection":"The application has a durable request identity but no authoritative acknowledgement.","recovery":"Remain provider pending and reconcile under the same identity before any retry."},{"trigger":"Review rejects or requests corrected evidence","detection":"Policy, privacy, duplication, location, or content validation fails for the immutable revision.","recovery":"Preserve the decision and original revision; create a new linked attempt rather than editing history."}],"observability":["UI open, activation, cancellation, candidate, and terminal outcome by released component version","Schema, size, stale-generation, duplicate, and late-callback rejection","Draft-to-candidate and candidate-to-submit conversion","Provider pending age, acknowledgement, unknown outcome, and reconciliation","Review queue age, disposition, rework, and duplicate rate","Idempotency replay, version conflict, audit, and outbox health","Privacy retention and redaction completion without attachment-body logging"],"website":"/journeys/ios-feedback-report-review"},{"slug":"location-capture-evidence","title":"Consent-bound location capture evidence","eyebrow":"Location Capture SDK · application-owned evidence","productSlug":"capture-feedback","stateModel":"hybrid","summary":"Initialize and configure an entitled Location Capture SDK, acquire a bounded single or subscribed fix, preserve accuracy and timing as evidence, review weak results, and stop every native resource deterministically.","aggregate":"location capture attempt","actors":["Application user","Host application","Platform adapter","Evidence reviewer","Mappls Location Capture SDK"],"sourceGuideSlugs":["mappls-location-capture-android-sdk","mappls-location-capture-ios-sdk","mappls-location-capture-sdk-ios-distribution"],"contractSlugs":[],"sampleSlug":"address-verifier","states":[{"id":"draft","label":"Draft","meaning":"The host owns a business purpose, subject or case identity, capture policy, and retention class before requesting device access.","recovery":"Restore only host-owned intent; never persist a location manager, callback, permission prompt, or opaque SDK object."},{"id":"permission_pending","label":"Permission pending","meaning":"The user is deciding the minimum native permission for the declared purpose and visible capture behavior.","recovery":"Represent denial, restriction, and interruption separately; offer a purpose-appropriate manual path without repeatedly prompting."},{"id":"ready","label":"Ready","meaning":"SDK initialization, entitlement, permission, policy validation, and one launch generation have succeeded.","recovery":"If configuration changes or the app backgrounds, invalidate the generation before starting another acquisition."},{"id":"acquiring","label":"Acquiring","meaning":"Exactly one single-shot request or bounded subscription owns timeout, accuracy, distance, packet-size, callback, and cleanup responsibility.","recovery":"Stop the active request once on timeout, cancellation, owner disposal, or replacement; late callbacks cannot mutate the aggregate."},{"id":"candidate","label":"Candidate","meaning":"A returned event has normalized coordinates, horizontal accuracy, event time, receipt time, policy result, and source generation, but is not yet accepted evidence.","recovery":"Reject malformed, stale, impossible, duplicated, or superseded events and retain a safe reason without an opaque payload."},{"id":"review_pending","label":"Review pending","meaning":"The candidate is usable only with human review because accuracy, freshness, or policy confidence is below the automatic threshold.","recovery":"A reviewer may accept with an attributable reason, request a new immutable attempt, or choose an approved alternate evidence source."},{"id":"accepted","label":"Accepted","meaning":"An actor accepted one immutable normalized fix for the declared purpose and policy version, with an audit event and retention deadline.","recovery":"Corrections create a linked evidence revision or new attempt rather than changing the accepted observation.","terminal":true},{"id":"cancelled","label":"Cancelled","meaning":"The user or host ended the attempt and every active SDK resource was stopped or unsubscribed.","recovery":"Renewed intent creates a new attempt and permission decision where required; do not revive an old callback generation.","terminal":true}],"transitions":[{"command":"create_attempt","actor":"Host application","from":[],"to":"draft","event":"location_capture.attempt_created","idempotency":"Map one external case and capture-purpose identity to one attempt across retries."},{"command":"request_permission","actor":"Application user","from":["draft"],"to":"permission_pending","event":"location_capture.permission_requested","idempotency":"Record one visible request per policy decision and current native authorization state."},{"command":"prepare_sdk","actor":"Platform adapter","from":["permission_pending"],"to":"ready","event":"location_capture.sdk_ready","idempotency":"Bind initialization and validated configuration to one launch generation without persisting credentials or SDK instances."},{"command":"start_acquisition","actor":"Application user","from":["ready","review_pending"],"to":"acquiring","event":"location_capture.acquisition_started","idempotency":"A command key starts at most one single-shot request or subscription generation."},{"command":"receive_location","actor":"Platform adapter","from":["acquiring"],"to":"candidate","event":"location_capture.candidate_received","idempotency":"Normalize and hash one qualifying terminal event per single-shot generation, or deduplicate subscribed events by bounded source identity."},{"command":"queue_review","actor":"Host application","from":["candidate"],"to":"review_pending","event":"location_capture.review_queued","idempotency":"The evidence hash and policy version create at most one review case."},{"command":"accept_evidence","actor":"Application user","from":["candidate"],"to":"accepted","event":"location_capture.evidence_accepted","idempotency":"Commit evidence, policy result, processed command, audit event, and outbox record atomically."},{"command":"approve_weak_evidence","actor":"Evidence reviewer","from":["review_pending"],"to":"accepted","event":"location_capture.weak_evidence_approved","idempotency":"Bind the reviewer identity and bounded justification to the immutable candidate hash."},{"command":"cancel_attempt","actor":"Application user","from":["draft","permission_pending","ready","acquiring","candidate","review_pending"],"to":"cancelled","event":"location_capture.attempt_cancelled","idempotency":"Repeated cancellation returns the terminal record while stop and unsubscribe cleanup remain exactly-once-in-effect."}],"invariants":["A permission grant is not consent for every purpose; purpose, policy, and retention are recorded separately.","One acquisition generation owns one callback family, timeout, stop, and unsubscribe lifecycle.","Accuracy, event time, receipt time, and policy result remain attached to the normalized coordinates.","A callback creates a candidate, never an accepted business decision.","Weak or stale evidence cannot pass an automatic acceptance threshold by omitting quality fields.","Credentials, native manager instances, full opaque payloads, and callback closures never enter durable storage."],"records":[{"name":"Capture attempt","purpose":"Current host-owned purpose, policy, lifecycle state, generation, and optimistic version.","keyFields":["attemptId","externalId","purpose","policyVersion","state","generation","version"]},{"name":"Normalized location evidence","purpose":"Immutable accuracy-bearing observation independent of the SDK object's lifetime.","keyFields":["evidenceId","latitude","longitude","horizontalAccuracy","eventTime","receivedTime","sourceGeneration","contentHash"]},{"name":"Review decision","purpose":"Attributable disposition of evidence that cannot be accepted automatically.","keyFields":["reviewId","evidenceId","reviewer","decision","reason","decidedAt"]},{"name":"Audit and outbox","purpose":"Append-only transitions and exactly-once-in-effect downstream notification.","keyFields":["eventId","aggregateVersion","actor","idempotencyKey","outboxStatus"]}],"failures":[{"trigger":"Permission is denied or restricted","detection":"The native authorization result cannot satisfy the declared capture mode.","recovery":"Explain the affected outcome, offer settings or a manual fallback where appropriate, and keep the attempt non-acquiring."},{"trigger":"Initialization or entitlement fails","detection":"The documented initialize operation returns failure before the generation becomes ready.","recovery":"Expose a safe configuration or entitlement error, retain no credential value, and require a deliberate retry after correction."},{"trigger":"Acquisition times out or misses the accuracy budget","detection":"The configured deadline expires or every event remains outside policy.","recovery":"Stop or unsubscribe once, preserve the quality reason, and route to review, retry, or fallback rather than fabricating a precise fix."},{"trigger":"A callback arrives after cancellation or screen disposal","detection":"The owner is inactive or callback generation differs from the current attempt generation.","recovery":"Ignore the event, perform idempotent cleanup, and do not change the terminal or newer attempt."},{"trigger":"The app restarts during review","detection":"The immutable candidate exists but the review command lacks acknowledgement.","recovery":"Reload the attempt and replay the same command key; never reacquire or duplicate evidence merely to recover workflow state."}],"observability":["Initialization and configuration outcomes by SDK platform and released version","Permission denied, restricted, and settings-return rate","Time to first event and time to policy-acceptable event","Accuracy and freshness distributions without high-cardinality coordinate labels","Single-shot, subscription, timeout, stop, unsubscribe, and late-callback counts","Automatic acceptance, review, retry, fallback, and cancellation rate","Idempotency replay and optimistic version conflict rate","Outbox backlog, retry, and dead-letter age"],"website":"/journeys/location-capture-evidence"},{"slug":"place-contribution-publication","title":"Governed place contribution and publication","eyebrow":"App Widgets · contribution reconciliation","productSlug":"capture-feedback","stateModel":"stateful","summary":"Embed the credential-free Add a Place surface, record what the user reports, reconcile independently, and call a place published only when durable provider-backed evidence exists.","aggregate":"place contribution","actors":["Contributor","Host application","Operations reviewer","Mappls hosted widget and search"],"sourceGuideSlugs":["mappls-app-widgets","mappls-rest-apis"],"contractSlugs":["core-location-get-api-places-search-json-autosuggest-api","core-location-get-apis-o2o-entity-eloc-place-detail-api"],"sampleSlug":"place-contribution-desk","states":[{"id":"draft","label":"Draft","meaning":"The host owns a bounded contribution intent, business purpose, and external identity before any provider surface opens.","recovery":"Restore only host-owned fields and version; never persist the iframe DOM, browser session, or undocumented provider payload."},{"id":"widget_open","label":"Widget open","meaning":"The Mappls-hosted form is visible for one recorded attempt, while provider UI and submission remain outside the host contract.","recovery":"Let the contributor reopen or abandon the attempt; never infer success from frame navigation or inaccessible DOM state."},{"id":"submission_reported","label":"Submission reported","meaning":"The contributor says the hosted form showed success, which is useful testimony but not a receipt or publication result.","recovery":"Preserve actor, attempt, and report time, then queue an independent reconciliation check."},{"id":"publication_pending","label":"Publication pending","meaning":"An operations process is checking supported Mappls search or an approved provider receipt for a stable published identity.","recovery":"Retry under a bounded schedule and keep the case visibly pending when no result exists; do not manufacture a Mappls Pin."},{"id":"published","label":"Published","meaning":"A supported provider surface returned a six-character Mappls Pin with attributable observation evidence.","recovery":"Treat publication evidence as immutable; later corrections create a linked case or evidence revision.","terminal":true},{"id":"rejected","label":"Rejected","meaning":"A reviewer found a duplicate, invalid, unsafe, or otherwise non-publishable contribution and recorded why.","recovery":"Retain the failed attempt and allow an explicit retry that opens a new attempt rather than rewriting history."},{"id":"withdrawn","label":"Withdrawn","meaning":"The host stopped its own follow-up workflow at the contributor's request without claiming that the provider submission was deleted.","recovery":"Treat withdrawal as terminal application state; use a separately documented provider channel for any provider-side request.","terminal":true}],"transitions":[{"command":"create_contribution","actor":"Host application","from":[],"to":"draft","event":"place_contribution.created","idempotency":"Map one bounded external case identity to one aggregate across network retries."},{"command":"open_widget","actor":"Contributor","from":["draft"],"to":"widget_open","event":"place_contribution.widget_opened","idempotency":"Create at most one immutable attempt per command key and aggregate version."},{"command":"report_submission","actor":"Contributor","from":["widget_open"],"to":"submission_reported","event":"place_contribution.submission_reported","idempotency":"Record one acknowledgement for the active attempt without inventing a provider receipt."},{"command":"queue_reconciliation","actor":"Host application","from":["submission_reported"],"to":"publication_pending","event":"place_contribution.reconciliation_queued","idempotency":"The same scheduling key creates at most one pending transition and outbox event."},{"command":"confirm_publication","actor":"Operations reviewer","from":["submission_reported","publication_pending"],"to":"published","event":"place_contribution.published","idempotency":"Hash the supported evidence source, Mappls Pin, observation time, and source fingerprint before committing."},{"command":"reject","actor":"Operations reviewer","from":["submission_reported","publication_pending"],"to":"rejected","event":"place_contribution.rejected","idempotency":"Preserve the review decision, reason, and attempt version under the reviewer command key."},{"command":"retry","actor":"Contributor","from":["rejected"],"to":"widget_open","event":"place_contribution.retried","idempotency":"Create a new immutable attempt once while retaining the rejected attempt and decision in audit history."},{"command":"withdraw","actor":"Contributor","from":["draft","widget_open","submission_reported","publication_pending"],"to":"withdrawn","event":"place_contribution.withdrawn","idempotency":"Stop host follow-up once without representing this as provider-side deletion."}],"invariants":["A hosted success screen or contributor report never proves publication.","No callback, browser message, receipt, moderation status, or withdrawal capability is invented when the public source does not document it.","Only provider-backed evidence containing a valid Mappls Pin can close the aggregate as published.","Every widget attempt is immutable and linked to the aggregate version that opened it.","Commands are idempotent, compare expected version, and commit audit plus outbox atomically.","Contribution text, actor identity, and precise location follow declared purpose, access, and retention boundaries."],"records":[{"name":"Contribution aggregate","purpose":"Current host-owned state, business identity, purpose, ownership, and optimistic version.","keyFields":["contributionId","externalId","state","version","purpose","owner"]},{"name":"Widget attempt","purpose":"Immutable record of each frame launch and contributor-reported outcome without provider-internal data.","keyFields":["attemptId","aggregateVersion","openedAt","reportedAt","documentedSourceUrl"]},{"name":"Publication evidence","purpose":"Attributable supported-source proof that a stable Mappls identity is observable.","keyFields":["mapplsPin","evidenceSource","observedAt","sourceFingerprint","reviewer"]},{"name":"Audit and outbox","purpose":"Append-only transitions and exactly-once-in-effect downstream notifications.","keyFields":["eventId","aggregateVersion","actor","idempotencyKey","outboxStatus"]}],"failures":[{"trigger":"Hosted frame is blocked or unavailable","detection":"The host cannot load the established HTTPS source within its timeout and CSP boundary.","recovery":"Keep the contribution in draft, explain the boundary, and offer an external open or later retry without claiming a submission."},{"trigger":"User loses the success acknowledgement","detection":"No provider receipt exists and the contributor cannot confirm what the hosted surface showed.","recovery":"Leave the attempt unresolved and allow a deliberate new attempt; never infer completion from iframe navigation."},{"trigger":"Reconciliation finds an existing duplicate","detection":"Supported search resolves the same place identity or a reviewer establishes duplicate ownership.","recovery":"Reject with duplicate reason and link the known Mappls Pin as context, not as evidence that this attempt created it."},{"trigger":"No public result appears within the operating window","detection":"Every bounded supported-source check returns no qualifying Mappls identity before the stated review deadline.","recovery":"Keep pending or reject according to published host policy and expose the last check time without promising a provider SLA."},{"trigger":"Application restarts during review","detection":"An in-flight command lacks acknowledgement while aggregate, command key, and outbox state are durable.","recovery":"Reload the aggregate and replay the same command key; do not duplicate an attempt, decision, or notification."}],"observability":["Widget opens, contributor reports, and abandonment by attempt","Time from report to first reconciliation and terminal decision","Pending age and last supported-source check","Publication evidence source and Mappls Pin validity","Duplicate and rejection reasons without opaque provider payloads","Withdrawal count explicitly separated from provider-side deletion","Idempotency replay and optimistic version conflict rate","Outbox backlog, retry, and dead-letter age"],"website":"/journeys/place-contribution-publication"}],"evidence":{"contracts":[{"slug":"core-location-get-api-places-search-json-autosuggest-api","method":"GET","path":"/api/places/search/json","summary":"AutoSuggest API","contractStatus":"legacy-source","stateModel":"stateless","journeyRole":"request-response","website":"/api-reference/core-location-get-api-places-search-json-autosuggest-api"},{"slug":"core-location-get-apis-o2o-entity-eloc-place-detail-api","method":"GET","path":"/apis/O2O/entity/{eLoc}","summary":"Place Detail API","contractStatus":"legacy-source","stateModel":"stateless","journeyRole":"request-response","website":"/api-reference/core-location-get-apis-o2o-entity-eloc-place-detail-api"}],"guides":[{"slug":"mappls-feedback-kit-ios-distribution","title":"MapplsFeedbackKit for iOS","summary":"Mappls Feedback Kit Native for iOS distributed via the SPM (Swift Package Manager).","kind":"Distribution","maturity":"distribution","platforms":["iOS"],"website":"/reference/mappls-feedback-kit-ios-distribution"},{"slug":"mappls-feedback-kit-ios-distribution-base","title":"MapplsFeedbackKit for iOS","summary":"A versioned iOS distribution package used to integrate search places, tracking telematics, widgets deep links, offline automotive, capture feedback, identity platform into an application.","kind":"Distribution","maturity":"distribution","platforms":["iOS"],"website":"/reference/mappls-feedback-kit-ios-distribution-base"},{"slug":"mappls-feedback-uikit-ios-distribution","title":"MapplsFeedbackUIKit for iOS","summary":"Mappls Feedback UI Kit Native for iOS distributed via the SPM (Swift Package Manager).","kind":"Distribution","maturity":"distribution","platforms":["iOS"],"website":"/reference/mappls-feedback-uikit-ios-distribution"},{"slug":"mappls-feedback-uikit-ios-distribution-base","title":"MapplsFeedbackUIKit for iOS","summary":"A versioned iOS distribution package used to integrate maps, routes navigation, tracking telematics, widgets deep links, capture feedback, identity platform into an application.","kind":"Distribution","maturity":"distribution","platforms":["iOS"],"website":"/reference/mappls-feedback-uikit-ios-distribution-base"},{"slug":"mappls-location-capture-android-sdk","title":"Mappls Location Capture SDK","summary":"A lightweight, on-demand location capture SDK for Android that enables applications to fetch a user’s current location efficiently with accuracy limits, timeout control, and minimal battery usage. The SDK supports single-shot and subscribed location fetching without continuous tracking.","kind":"SDK","maturity":"current","platforms":["Android"],"website":"/reference/mappls-location-capture-android-sdk"},{"slug":"mappls-location-capture-ios-sdk","title":"Mappls Location Capture IOS SDK","summary":"A Mappls sdk for capture feedback across iOS.","kind":"SDK","maturity":"current","platforms":["iOS"],"website":"/reference/mappls-location-capture-ios-sdk"},{"slug":"mappls-location-capture-sdk-ios-distribution","title":"Mappls Location Capture SDK (iOS)","summary":"A versioned iOS distribution package used to integrate tracking telematics, workforce, capture feedback into an application.","kind":"Distribution","maturity":"distribution","platforms":["iOS"],"website":"/reference/mappls-location-capture-sdk-ios-distribution"},{"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-rest-apis","title":"Mappls Map APIs (REST) !","summary":"Building Blocks to Add Powerful Location Intelligence & Mapping Functionality to your Apps","kind":"REST API","maturity":"current","platforms":["REST"],"website":"/reference/mappls-rest-apis"}],"samples":[{"slug":"place-contribution-desk","name":"Place Contribution Desk","description":"Embed the public Add a Place form, preserve contributor-reported submission as testimony, reconcile independently, and close only with attributable publication evidence.","stack":["Node.js","Responsive operations UI","Add a Place iframe","Reconciliation evidence ledger"],"implementation":"full-stack-reference","verifiedTestCount":8,"downloadPath":"/downloads/place-contribution-desk.zip","website":"/samples/place-contribution-desk"},{"slug":"address-verifier","name":"Address Verifier","description":"Normalize an address, govern consented device evidence, apply versioned policy, and retain an attributable decision.","stack":["Node.js","Browser trust studio","Search adapter","Evidence ledger"],"implementation":"full-stack-reference","verifiedTestCount":8,"downloadPath":"/downloads/address-verifier.zip","website":"/samples/address-verifier"}],"tutorials":[{"slug":"reverse-geocode-check-in","title":"Turn a device fix into a trustworthy check-in","outcome":"A privacy-aware check-in that retains both raw evidence and human-readable context.","level":"Beginner","duration":"30 min","website":"/tutorials/reverse-geocode-check-in"},{"slug":"workmate-proof-review","title":"Build proof review and rework for field jobs","outcome":"An auditable proof workflow that cannot silently overwrite rejected evidence.","level":"Advanced","duration":"90 min","website":"/tutorials/workmate-proof-review"},{"slug":"flutter-production-lifecycle","title":"Production-harden a Flutter location feature","outcome":"A cross-platform feature with stable identity, bounded bridge traffic, and deterministic disposal.","level":"Advanced","duration":"90 min","website":"/tutorials/flutter-production-lifecycle"},{"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":"react-native-native-parity","title":"Qualify React Native native parity","outcome":"One JavaScript contract backed by independently qualified Android and iOS behavior.","level":"Advanced","duration":"100 min","website":"/tutorials/react-native-native-parity"},{"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":"last-mile-delivery","title":"A delivery promise customers can trust","industry":"Logistics","outcome":"Fewer failed deliveries and a live, explainable ETA from checkout to doorstep.","website":"/use-cases/last-mile-delivery"},{"slug":"field-service","title":"Dispatch the right technician, with the right proof","industry":"Utilities","outcome":"Higher first-time-fix rates and auditable work from dispatch through customer sign-off.","website":"/use-cases/field-service"},{"slug":"energy-grid-resilience","title":"Restore the grid from alarm to verified service","industry":"Energy","outcome":"Faster, safer restoration with an explainable view of affected assets, customers, crews, and residual risk.","website":"/use-cases/energy-grid-resilience"},{"slug":"banking-address-risk","title":"Make address risk explainable","industry":"Financial services","outcome":"More straight-through approvals with a clear audit trail for ambiguous or high-risk addresses.","website":"/use-cases/banking-address-risk"},{"slug":"insurance-claims","title":"Evidence-led claims from incident to settlement","industry":"Insurance","outcome":"Faster, more consistent claims decisions with tamper-aware spatial evidence.","website":"/use-cases/insurance-claims"},{"slug":"hospital-care-logistics","title":"Coordinate time-critical care without losing custody","industry":"Healthcare","outcome":"Shorter transfer and specimen journeys with fewer missed hand-offs and a complete chain of operational custody.","website":"/use-cases/hospital-care-logistics"},{"slug":"aviation-ground-operations","title":"Run a safe, punctual airport turnaround","industry":"Aviation","outcome":"More predictable departures with safer vehicle movement and attributable hand-offs across airport and airline teams.","website":"/use-cases/aviation-ground-operations"},{"slug":"agriculture-field-ops","title":"Coordinate field operations across every plot","industry":"Agriculture","outcome":"Less travel and better traceability for inspection, inputs, harvest, and compliance.","website":"/use-cases/agriculture-field-ops"},{"slug":"mining-haulage-safety","title":"Move material safely across a changing mine","industry":"Mining","outcome":"Higher productive haulage with fewer route conflicts, stale-map movements, and unexplained cycle losses.","website":"/use-cases/mining-haulage-safety"},{"slug":"telecom-network-care","title":"Operate the network from tower to doorstep","industry":"Telecommunications","outcome":"Faster restoration with better prioritization and fewer repeat dispatches.","website":"/use-cases/telecom-network-care"}]},"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=capture-feedback","api":"https://developer.mappls.com/api/stateful-plan?product=capture-feedback","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."}