Documentation navigation

Wayfarer

Protected Place deletion

BD2-12 (#853) requires a current content preview and explicit confirmation for every Place, including a Place with no dependents. Both adapters use one lifecycle transaction.

Authority Preview POST Confirmed POST
Active incoming bearer, no cookie fallback /api/trips/{tripId}/conditional/places/{placeId}/deletion-preview /api/trips/{tripId}/conditional/places/{placeId}/deletion
Cookie with User role and ownership /api/trips/{tripId}/editor/places/{placeId}/deletion-preview /api/trips/{tripId}/editor/places/{placeId}/deletion

Both cookie POSTs require RequestVerificationToken. Both adapters return Cache-Control: no-store and check the complete owned scope before parsing. Preview accepts exactly {}. Confirmation accepts only confirmationToken; unknown or duplicate fields, non-string tokens and malformed JSON reject.

Mobile request examples

Obtain the current consequences without mutation:

POST /api/trips/{tripId}/conditional/places/{placeId}/deletion-preview
Authorization: Bearer <incoming-token>
Content-Type: application/json

{}

Preview returns contractVersion: 1, tripId, placeId, regionId, placeName, deletedSegments, updatedSegments, detachedWaypoints, unlinkedVisits, deletedCandidates, placeOrderIds, segmentOrderIds, and confirmation: {token, expiresAt}. Effect groups contain {count, ids, hasMore}; Place deletion publishes complete effect identities (hasMore: false). Waypoint identities are {segmentId, placeId}. Place ordering lists the surviving siblings in their resulting order. Segment ordering is null unless endpoint Segments will be deleted, in which case it lists all resulting surviving Segments. The opaque token expires after ten minutes. It is consent, never authority or a receipt. No private route/profile/provenance content is published by preview.

After the user reviews these exact consequences and explicitly confirms:

POST /api/trips/{tripId}/conditional/places/{placeId}/deletion
Authorization: Bearer <incoming-token>
Content-Type: application/json

{"confirmationToken":"<token-from-that-preview>"}

Success is the same EditorMutationResult<PlaceDeletionResultDto> envelope for both authorities: {success, data, affected, deletedIds, warnings}. data contains tripId, placeId, regionId, complete updatedSegmentIds and detachedWaypointAssociations. Deleted IDs contain the target Place and exact endpoint-dependent Segments; Region/Area/Tag deletion arrays are empty. Affected slices contain all reordered sibling Places and their complete order, updated/reordered surviving Segments with fresh route/aggregate tokens, applicable Segment order, current Trip metadata/freshness and visit progress. Unrelated Region/Area/Tag/options slices remain empty/null. Projection happens before commit; success is sent only after confirmed commit.

Approval binds server protection keys, owner, Trip, typed target, expiry, full mapped target and parent contents, source membership/stored nullable orders, endpoint-dependent and waypoint-only Segments, full route/measurement/provenance contents, waypoint positions/indices, anchor coordinates and parent identities, linked profile contents, relevant complete Segment ordering, and visit/candidate identities. Same-ID edits cannot be replaced by identity-only approval.

The transaction locks profiles → Segments → Places → Regions → Trip, with sorted IDs in each class, then the active account and incoming bearer credential where applicable. It rediscovers persisted inputs after all waits. Changed contents, new dependencies, missing required earlier-class locks or expired approval reject before writes. Place/Segment/Region/Trip parent barriers also fence new membership. There is no automatic destructive retry.

The established lifecycle deletes endpoint Segments once (including loops), detaches deleted saved-Place waypoints from surviving Segments, retains anonymous custom vertices, reconciles fallback routes/measurements and invalidates affected route provenance without provider calls. It normalizes only source Place order and, when endpoint Segments are deleted, Trip Segment order. Database FK behavior retains visit snapshots with PlaceId = null and cascades ephemeral visit candidates. These changes and property-only, nondecreasing current Trip freshness commit together. Caller pending work is isolated; failed transactions restore caller state or retire an incoherent context using existing lifecycle recovery.

Rejections and uncertain outcomes

Status/code Meaning
400 place-deletion-request-invalid Invalid request or tampered/cross-purpose token
401/403 Invalid/currently revoked authority or forbidden role
Concealed 404 Target/Trip unavailable in the owned scope; no dependency disclosure
409 place-deletion-confirmation-required Review preview and explicitly confirm, including an empty footprint
409 place-deletion-preview-stale Expiry or material/dependency/order drift; obtain fresh preview and explicitly confirm again
409 mutation-dependency-stale Malformed affected ownership/graph; review current state
409 mutation-confirmation-required Unconditional DELETE adapter rejects without mutation

The participating Web/bearer Place and Region DELETE adapters cannot execute identity-only or unconditional deletion. Region deletion continues to use the existing four-way preview/confirmed POST contract. Canonical Region deletion stays forbidden. No client falls back to DELETE.

Definite precommit rejections leave the graph unchanged. A lost response, 5xx, connection failure or ambiguous commit does not prove rollback. The editor retains its immutable attempt in the existing Place draft hold owner, blocks replay and validates exact response scope before adoption. Cancel before dispatch preserves drafts; a successful response clears only the same unchanged target draft. Newer intent, superseding sessions and unrelated drafts survive. Reset, refresh, absence of the target and leaving without saving cannot prove noncommit or undo a request. Place holds are scoped to the mounted workspace; there is no cross-reload recovery promise, durable receipt or automatic recovery API. Mobile must retain its own unknown intent under MD03/MD05 rather than replay destruction.

BD2-13 integration evidence boundary

The delivered #848 four-way Place/Area matrix, conservative kept-child fingerprint, canonical destination/append rules and transaction recovery are reused. The integration adds final active-account/bearer checks, nondecreasing freshness, closed unconditional adapters and checked client acknowledgements/newer-draft retention. Focused routed tests cover prepared Place moves, source/destination Place ordering and Region ordering against deletion in both save orders, plus revocation during a physical Region wait. Global C1/C2 reconciliation and independent C5 final acceptance remain separate; #853 stays open.

Back to top