Seraya Psikologi — Documentation

Booking and payment MVP · Implementation baseline · 96 ADR

Seraya Psikologi — Implementation Guide

Status

Implementation Baseline — boleh dipakai sebagai pegangan implementasi.

Source baseline:

Dokumen ini sengaja tidak menunggu semua jawaban pada dua PRD form. Keputusan yang sudah confirmed menjadi aturan implementasi. Hal yang belum diputuskan ditulis sebagai TBC dan harus diisolasi di configuration/adapter/policy seam, bukan ditebak sebagai keputusan bisnis.

1. Cara membaca dokumen ini

1.1 Authority order

Jika terjadi perbedaan:

  1. Accepted ADR terbaru;
  2. bagian canonical pada Technical PRD revision 168;
  3. dokumen ini;
  4. catatan/open question lama.

Jika konflik belum terselesaikan, jangan memilih diam-diam. Buat TBC atau blocker ticket dan minta keputusan owner.

1.2 Label

1.3 Prinsip utama

2. Launch scope

2.1 In scope — CONFIRMED

2.2 Out of scope — DEFERRED

3. Actors and authorization

3.1 Active roles — CONFIRMED

Role Scope
Visitor Public pages, catalog, program content, published availability
Client/Guest Own verified Booking/PackagePurchase melalui scoped ClientAccess
Psychologist Own profile/availability input, assigned operational appointments, initial completed/no_show
Admin Operational owner: catalog, availability override, booking, payment/refund, cancellation, privacy, staff, audit
Editor DEFERRED; jangan aktifkan di launch

3.2 Staff authentication — CONFIRMED

3.3 ClientAccess — CONFIRMED baseline

TBC-ACCESS-01: rate limit detail, recovery flow, re-authentication, session revocation, dan abuse response. Isolasi di ClientAccessPolicy/SessionPolicy; jangan campur dengan domain Booking.

4. Domain model minimum

Implementasi awal harus memiliki boundary/module untuk entity berikut. Nama tabel boleh berbeda, tetapi vocabulary domain harus dipertahankan.

4.1 Catalog and capacity

4.2 Transaction and service delivery

4.3 Financial and policy records

4.4 Access, content, and notifications

5. Module seams

Implementasi boleh berupa satu Worker/modular monolith. Jangan membocorkan detail provider atau SQL ke semua caller. Gunakan module interface yang dalam dan kecil.

5.1 Required modules

5.2 Minimum command interface

Transport route dan exact payload shape adalah TBC-API-01. Command semantics berikut sudah confirmed:

Setiap command harus menerima atau menghasilkan:

6. State machines and invariants

6.1 Booking and Appointment — CONFIRMED

Create Booking
  → pending_payment + SlotHold(active)
  → confirmed hanya setelah verified PaymentEvent(success)

Payment/hold failure
  → expired | failed

Hold expiry + later verified success
  → Payment=paid_late/reconciliation-required
  → reacquire original slot atomically jika masih free
  → jika tidak free: no automatic alternate Appointment

Invariants:

6.1.1 Appointment state machine — CONFIRMED (ADR 0092)

confirmed
  → (auto, T+15m, no client_arrived) → no_show        [entitlement consumed, checkpoint locked]
  → (client_arrived ≤ T+15m) → in_progress              [auto-checkpoint cancelled]
  → (client_arrived > T+15m) → in_progress              [auto-checkpoint already locked; outcome_final = no_show_late]
  → (CancellationDecision approve) → cancelled          [entitlement restored jika valid]

in_progress
  → (session_ended ≥ 60m attended) → completed          [entitlement consumed]
  → (session_ended 1–59m attended) → completed_partial  [entitlement consumed; compensation token eligible]
  → (CancellationDecision approve) → cancelled          [entitlement restored jika valid]

Final outcome enum (lima nilai):

Outcome Trigger Entitlement Notification
completed psikolog/Admin, end-of-session, attended ≥60m consumed email outcome_finalized
completed_partial psikolog/Admin, end-of-session, attended 1–59m consumed email outcome_finalized
no_show system auto T+15m, atau psikolog/Admin override consumed email no_show_recorded + admin alert
no_show_late psikolog/Admin, client_arrived > T+15m dan sesi berjalan ≥1m consumed email outcome_finalized
cancelled CancellationDecision approve restored jika valid sesuai cancellation flow

6.1.2 Late-arrival handling — CONFIRMED (ADR 0092)

6.1.3 Outcome correction — CONFIRMED (ADR 0092, ADR 0054)

6.1.4 Notification templates untuk outcome events

6.2 Package and entitlement — CONFIRMED (ADR 0092, ADR 0095)

TBC-PACKAGE-01: exact package validity/expiry calendar semantics, reminder offset, dan package availability resolution SLA. Simpan policy sebagai snapshot pada PackagePurchase; jangan membaca ulang catalog saat entitlement lama diproses.

6.3 Cancellation — CONFIRMED

Canonical matrix lives in ADR 0095-package-cancellation-matrix.md. Ringkasan operasional:

Admin WhatsApp (public channel)
  → CancellationRequest (at most one open per target; ADR 0095 §1.2)
  → state: open
  → race resolution per ADR 0095 §2:
      R1: outcome completed lands first  → request auto_resolved
      R2: outcome no_show lands first     → request auto_resolved
      R3: approval lands first            → outcome marking blocked afterwards
      R4: RescheduleAction lands          → request rebinds to replacement
  → Admin approve | deny (DecideCancellation)

approve atomically (per target; see ADR 0095 §3):
  target = appointment:
    Appointment → cancelled
    CapacityReservation → cancelled (release_reason = appointment_cancelled)
    linked SessionEntitlement → restored if valid, else closed
    eligible future slot → available

  target = package_purchase (single transaction):
    all future non-terminal Appointments → cancelled
    all CapacityReservations for those Appointments → cancelled
    all unused SessionEntitlements with valid_until >= now → closed_restored_by_cancellation
    all other unused SessionEntitlements → closed_cancelled_with_package
    PackagePurchase.state → closed_by_cancellation (terminal, no re-open)
    PackageValidity.valid_until unchanged
    consumed/expired entitlements untouched (refund is separate)

  target = booking (single-session single-Appointment):
    identical to target = appointment

den y:
  no mutation to Booking/Appointment/slot/entitlement/Payment

correction (repeat rule, ADR 0095 §4):
  new CancellationRequest with correction_of = previous_decision_id
  new Decision applies §3 effects afresh (idempotent on already-cancelled)
  original Decision marked superseded_by, remains immutable history

6.4 Refund — CONFIRMED

6.5 Availability — CONFIRMED

7. Payment implementation

7.1 Adapter interface — CONFIRMED seam

Gunakan interface provider-neutral seperti:

interface PaymentGatewayAdapter {
  createCheckout(input: CreateCheckoutInput): Promise<CheckoutCreated>;
  verifyNotification(input: unknown): Promise<VerifiedPaymentEvent>;
  requestFullRefund(input: FullRefundInput): Promise<RefundProviderResult>;
}

Nama type boleh berubah, tetapi adapter wajib menyembunyikan:

7.2 Midtrans launch

TBC-PAY-01 / PRODUCTION GATE: exact Midtrans method codes, merchant onboarding, fees, limits, expiry behavior, refund coverage, signature/API verification evidence, retry/dead-letter policy, dan reconciliation cadence.

Implementasikan PaymentGatewayAdapter dengan fake/in-memory adapter untuk unit/domain tests. Jangan membuat domain code bergantung langsung pada Midtrans SDK.

7.3 Settlement uniqueness invariants — CONFIRMED

Diperlukan oleh ADR 0093-payment-settlement-uniqueness.md. Berlaku untuk semua PaymentGatewayAdapter, bukan hanya Midtrans:

7.4 Midtrans adapter contract — CONFIRMED

PaymentGatewayAdapter interface (provider-neutral, type names dapat berubah):

interface PaymentGatewayAdapter {
  createCheckout(input: CreateCheckoutInput): Promise<CheckoutCreated>;
  verifyNotification(input: unknown): Promise<VerifiedPaymentEvent>;
  requestFullRefund(input: FullRefundInput): Promise<RefundProviderResult>;
}

interface CreateCheckoutInput {
  bookingId: string;            // = order_id, matches Booking.id
  amountCents: number;          // snapshot from OfferSnapshot.amount_cents
  currency: 'IDR';              // launch only IDR
  clientName: string;
  clientEmail: string;
  enabledMethods: ('qris' | 'va')[];  // launch subset; no e-wallet/card/OTC/BNPL
  expiresAtSeconds: number;     // matches SlotHold TTL (default 600 = 10 min)
  metadata: Record<string, string>;
}

interface CheckoutCreated {
  provider: 'midtrans';
  providerIntentId: string;     // Midtrans transaction_id
  snapToken: string;
  snapRedirectUrl: string;      // informational only, never settlement source
  expiresAt: string;            // ISO timestamp; client countdown mirrors SlotHold TTL
}

interface VerifiedPaymentEvent {
  providerEventId: string;       // Midtrans notification id; idempotency key
  paymentIntentId: string;      // = providerIntentId; FK to Payment
  bookingId: string;             // = order_id; must match Booking.id
  eventType:
    | 'capture' | 'settlement'
    | 'pending'
    | 'deny' | 'cancel' | 'expire' | 'failure'
    | 'refund' | 'partial_refund' | 'chargeback'
    | 'challenge';
  grossAmountCents: number;     // must match OfferSnapshot.amount_cents
  currency: 'IDR';
  merchantId: string;           // must match configured merchant
  verifiedAt: string;           // ISO timestamp
  payloadHash: string;          // sha256 hex of canonical JSON payload
  rawPayloadRedacted: Record<string, unknown>;
}

interface FullRefundInput {
  paymentProviderId: string;    // Midtrans transaction_id
  amountCents: number;          // = captured amount for full_refund
  reasonCode: string;           // policy/version reference
  idempotencyKey: string;
}

interface RefundProviderResult {
  provider: 'midtrans';
  providerRefundId: string;
  status: 'completed' | 'pending' | 'failed';
  rawResult: Record<string, unknown>;
}

Adapter wajib:

Adapter tidak wajib:

7.5 paid_late package effects — CONFIRMED

Mengikuti ADR 0093 §5. Pada verified webhook untuk late payment (hold sudah expired):

Invariant: PackagePurchase dan SessionEntitlement rows dibuat tepat pada saat webhook verified, bukan ditunda. Financial truth terjaga. Admin resolution tidak pernah otomatis — selalu eksplisit Admin decision (konsisten dengan ADR 0076 no auto-cutoff).

7.6 Duplicate webhook integration test (acceptance criteria #1)

Didefinisikan di ADR 0093 §1.2. Skenario test wajib:

  1. Buat Booking dengan Booking.id = X, hold aktif.
  2. Trigger Midtrans Snap checkout → Payment row status = 'pending' di-insert.
  3. Kirim dua webhook capture event berbeda provider_event_id (event_a, event_b) untuk order_id = X secara berurutan (atau concurrent).
  4. Assertion:
    - Hanya satu Payment row dengan status = 'paid' (verified by unique partial index).
    - event_a di-apply sebagai state transition.
    - event_b adalah idempotency no-op (new PaymentEvent row inserted, Payment unchanged, no duplicate email).
  5. State akhir: Booking confirmed, Payment.settled_at di-set sekali (tidak di-update kedua kali).

7.7 Paid-late package integration test (acceptance criteria #2)

Didefinisikan di ADR 0093 §5. Skenario test wajib:

  1. Buat Booking package (couple atau individual) dengan Booking.id = Y, hold aktif untuk slot S1.
  2. SlotHold expire (released).
  3. Midtrans Snap checkout expired (atau skip; trigger verified webhook langsung setelah expiry).
  4. Kirim verified webhook capture event untuk order_id = Y.
  5. Place CapacityReservation baru untuk slot lain (hold oleh Booking berbeda) untuk mensimulasikan overlap → reacquire attempt gagal.
  6. Assertion:
    - Payment.status = 'paid_late_first_session_pending', settled_at di-set.
    - PackagePurchase.status = 'paid_late', requires_first_session_scheduling = true.
    - SessionEntitlement #1.state = 'pending_schedule'.
    - SessionEntitlement #2..N.state = 'available'.
    - PackageValidity.validity_start = now() (bukan original checkout time).
    - Booking original tidak confirmed (status paid_late_slot_unavailable); original slot reference di-keep untuk audit.
  7. Admin resolution action: ScheduleNextEntitlement untuk slot S2 (different slot).
  8. Assertion post-resolution:
    - SessionEntitlement #1.state = 'scheduled', linked ke Appointment di S2.
    - PackagePurchase.requires_first_session_scheduling = false.
    - Booking original tetap paid_late_slot_unavailable (historical); new Booking mungkin tercipta untuk reschedule per IMPLEMENTATION-GUIDE.md §6.1 rules.

TBC-PAY-SETTLEMENT-01 closed by ADR 0093-payment-settlement-uniqueness.md; patch section §6.3 dan §6.4 cross-reference.

8. Persistence and data rules

8.1 General

8.2 Concurrency

Minimal concurrency protections:

9. Privacy and retention

9.1 Data boundary — CONFIRMED

Allowed:

Forbidden in MVP:

9.2 Retention — CONFIRMED baseline + TBC policy values

TBC-PRIVACY-01 / PRODUCTION GATE: exact policy-controlled duration, definition/event trigger untuk last active service, exception precedence, policy owner evidence, dan execution cadence.

Saat Client/contact eligible:

  1. redact direct identifier/contact fields;
  2. pertahankan non-reversible pseudonymous reference hanya jika minimum transactional/audit integrity membutuhkan;
  3. catat policy/version/action/result di audit;
  4. jangan cascade-delete Payment/Refund/Audit integrity.

10. Notifications and manual support

10.1 Automated email — CONFIRMED

Email dipakai untuk:

Delivery failure tidak me-roll back domain truth.

TBC-NOTIFY-01: provider email, sender/domain verification, copy/template, localization, bounce handling, dan package reminder offset.

10.2 WhatsApp — CONFIRMED boundary

11. Admin workspace and audit

Admin workspace minimal harus bisa:

TBC-ADMIN-01: exact form fields, table columns, filter, bulk action, visibility matrix detail, notification copy, dan exception UX. Default: least privilege; jika field tidak diperlukan untuk command, jangan tampilkan.

Audit record minimal:

12. Suggested implementation sequence

Slice 0 — Foundation

Slice 1 — Catalog and public availability

Slice 2 — Guest booking and SlotHold

Slice 3 — Payment adapter

Slice 4 — Package entitlement

Slice 5 — Staff and ClientAccess

Slice 6 — Cancellation/refund

Slice 7 — Notifications and support

Slice 8 — Privacy/retention

Slice 9 — CMS/admin hardening and UAT

13. Test requirements

13.1 Domain/module tests

13.2 Integration tests

13.3 Browser/UAT tests

14. TBC register

ID Topic Current implementation instruction Owner / gate
TBC-ACCESS-01 ClientAccess rate limit/recovery/revocation Isolate in AccessPolicy; use conservative configurable defaults Technical; before production
TBC-API-01 Exact API routes/payloads Define transport after command interfaces and UAT cases Technical
TBC-PACKAGE-01 Exact validity calendar semantics/reminders Store snapshot policy; do not read current catalog for old purchase Business + technical
TBC-PAY-01 Midtrans onboarding/method codes/fees/limits/refund Adapter/config; fake provider for development Business/ops; production gate
TBC-PRIVACY-01 Policy duration/trigger/exception/evidence Implement RetentionPolicy, no destructive production action yet Clinical/ethics + technical/data; production gate
TBC-NOTIFY-01 Email provider/copy/bounce/package offsets Domain events first; provider behind NotificationAdapter Business + technical
TBC-ADMIN-01 Admin forms/visibility/copy Least privilege and command-driven UI Technical + operations
TBC-SCHEDULE-01 Fuja recurring schedule/offline venue Placeholder only; no live slot publication Operations; production gate
TBC-POLICY-01 Package unavailability SLA/credit/transfer workflow Same-offering resolution first; explicit client consent for transfer Business + clinical/ethics
TBC-REC-01 Retry/dead-letter/reconciliation cadence Persist reconciliation-required; never silently resolve Operations/finance; production gate
TBC-CONSENT-01 Final consent wording/publication evidence Version ConsentRecord and block publish where required Clinical/ethics; production gate
TBC-LIVE-PRD-01 Reconcile live form readback with canonical closure baseline Do not treat missing summary fields as new business decisions; reconcile against ADR/domain model before using live form as authority Technical; before implementation handoff
TBC-PACKAGE-CANCEL-01 Package-wide cancellation matrix and pending-versus-outcome race Closed by ADR 0095-package-cancellation-matrix.md: targets, open-request invariant, R1–R4 race resolution, atomic package-wide effects, partial-package 1-of-N, repeat/correction, couple override, RescheduleAction table Owner: clinical/ethics + operations + technical; closed 2026-08-31
TBC-NO-SHOW-01 No-show early checkpoint vs terminal outcome/late-arrival correction Closed by ADR 0092-appointment-outcome-timing.md: no_show early checkpoint T+15m, completed_partial 1–59m, no_show_late late arrival with session held, OutcomeCorrection window 7×24 jam Owner: clinical/ethics + operations; closed 2026-08-31
TBC-RESCHEDULE-01 Allowed RescheduleAction lifecycle states/cutoff/repeat handling Closed by ADR 0095-package-cancellation-matrix.md §5: forbidden transitions enumerated, replacement capacity overlap enforced, couple-package rules via BookingParticipant, cancellation-request rebound (R4) Owner: operations + technical; closed 2026-08-31
TBC-PAY-SETTLEMENT-01 At-most-one successful settlement and package paid_late effects Verify amount/currency uniqueness per intent; document paid_late PackagePurchase/Entitlement creation rules Business/ops + technical; before Slice 3 production
TBC-EXTENSION-01 Explicit Admin extension state for entitlement/correction past windows Add extension_request / extension_grant audited commands; matrix update to ADR 0092 §6.1.3 and ADR 0095 §3 Operations; before production

15. Definition of implementation-ready

A slice is implementation-ready when:

The MVP is implementation-ready for core slices when:

16. Production launch gate

PRD/design handoff can proceed now using this document and explicit placeholders (see §16.1). Production launch requires passing every gate in §16.2 with named-role owner sign-off and concrete acceptance evidence attached (no narrative-only "TBD"). No cell in §16.2 may be left as TBD or TBC; every blocked gate must close the related TBC first per §16.3.

Canonical checklist: docs/adr/0096-launch-gate-checklist.md (this section is the executable mirror). Gate numbering G-1..G-14 and source ADRs match ADR 0096 §3.

16.1 PRD/design handoff checklist (allowed now)

These items are not gates for PRD/design handoff. Handoff may proceed now using this guide, DOMAIN-MODEL.md, ADR 0001–0095, and explicit placeholders per ADR 0088.

# Item Handoff assumption Placeholder / explicit marker
H-1 Domain model vocabulary DOMAIN-MODEL.md + ADR 0089–0095 none
H-2 Aggregate ownership ADR 0095 §3 (Booking/Appointment/PackagePurchase/SessionEntitlement) none
H-3 Catalog/pricing (individual only) IMPLEMENTATION-GUIDE.md §2.1 + ADR 0074 couple: see §16.2 G-6
H-4 Catalog/pricing (couple) shown in catalog with badge coming soon per PRD-GUIDELINE-REVIEW.md Round 2 R2-07 recommendation explicit not_purchasable until G-6 evidence
H-5 Identity/auth model ADR 0080 Google SSO + ADR 0081 two-Admin bootstrap staff-session TBC carries forward
H-6 State machines Booking/Payment/Appointment/Package/Entitlement/Cancellation/Refund per ADR 0095 + ADR 0093 + ADR 0092 none
H-7 Module seams IMPLEMENTATION-GUIDE.md §5 TBC-API-01 routes/payload
H-8 Test seams IMPLEMENTATION-GUIDE.md §13 none

16.2 Production-launch checklist (Matrix §7, executable)

Blocking stage legend:

Gate Title Owner (named role) Blocking stage Acceptance evidence (artifact) Source ADR / TBC
G-1 Profile asset, service presentation, placeholder venue/schedule clearly marked fixture-only, NOT paid at launch business owner + technical before UAT (a) PsychologistProfile.publish_status for non-Fuja slots = not_published (D1 query returns empty); (b) catalog screenshot showing coming soon badge on couple; (c) Fuja profile fields complete per ADR 0075; (d) business owner sign-off note confirming "no live paid booking except SERAYA PULANG individual counseling". ADR 0075, Ticket 06 06.6, PRD-GUIDELINE-REVIEW.md Round 2 R2-08
G-2 Real availability + online joining instructions + offline venue operations + psychologist (Fuja) + technical before UAT (a) AvailabilityRule rows populated for Fuja's recurring schedule; (b) AvailabilityException for blackouts; (c) no row with location_label = 'anytime' in published slots (D1 query returns empty); (d) online join instructions at docs/operations/online-join-instructions.md; (e) offline venue at docs/operations/offline-venue.md; (f) psychologist sign-off confirming schedule is current. ADR 0075, ADR 0088:17, TBC-SCHEDULE-01
G-3 Approved consent, privacy notice, cancellation/refund policy, crisis/referral information clinical/ethics + business owner production only (a) Consent copy final versioned at docs/consent/consent-v1.md (8 sections matching JSON consents); (b) clinical/ethics sign-off note in frontmatter; (c) privacy notice published page URL + 12-month retention per ADR 0083; (d) cancellation/refund public copy "Cancellation and refund are handled by Admin via WhatsApp; review is case-by-case." published on /booking + in confirmation email; (e) crisis boundary text in every public page footer per ADR 0082; (f) referrals populated with ≥3 named services; TBC-CONSENT-01 + TBC-CANCELLATION-PUBLIC-01 must be closed. ADR 00820086, ADR 0076/0077, Round 3
G-4 Verified payment integration and reconciliation behavior technical + finance + operations production only (a) Midtrans sandbox test pass log (CI run-id) — capture/settlement/expire/refund all green; (b) production merchant activation evidence (dashboard screenshot or signed letter) — QRIS + VA enabled; (c) ≥1 successful sandbox test refund with disbursement; (d) reconciliation runbook at docs/operations/payment-reconciliation.md (daily cadence, retry policy, dead-letter escalation); (e) paid_late integration test pass (run-id, §7.7); (f) duplicate webhook integration test pass (run-id, §7.6); (g) finance sign-off on QRIS/VA account mapping; (h) TBC-PAY-01 + TBC-PAY-EXPIRY-01 must be closed. ADR 0088:13-14, ADR 0093, §7.3–§7.7
G-5 Booking confirmation/reminder flow and operational owner operations + technical before UAT (a) Email templates final: docs/templates/email/{booking-confirmation,payment-confirmation,reminder-24h,reminder-2h,outcome-finalized,no-show-recorded}.md; (b) UAT §13.3 reminder scenarios pass with delivery log; (c) Admin WhatsApp number in /contact footer + confirmation email; (d) on-call runbook docs/operations/admin-on-call.md with primary + backup Admin + response SLA; (e) TBC-NOTIFY-01 must be closed. ADR 0052, ADR 0088:19, Round 3
G-6 Couple-participant/consent decisions if couple counselling is bookable business owner + clinical/ethics + technical production only If couple launch-deferred (recommended per PRD-GUIDELINE-REVIEW.md Round 2 R2-07): business owner sign-off note + catalog badge coming soon verified in §13.3 UAT. If couple launch-ready: (a) BookingParticipant/AppointmentParticipant migration applied (migration-id); (b) couple_consent + participant_consent_a + participant_consent_b + joint_session_consent finalized and signed by clinical/ethics; (c) notification routing test pass; (d) visibility matrix test pass; (e) couple-package cancellation test per ADR 0095 §6. ADR 0090, ADR 0095 §6, PRD-GUIDELINE-REVIEW.md Round 2 R2-07/R2-11
G-7 Architecture / persistence stack ratified technical before slice 0 ADR 0089-architecture-worker-d1.md accepted; migrations/0001_init.sql applied to D1 binding; backup/restore runbook at docs/operations/d1-backup-restore.md; D1 binding in wrangler.toml (committed). ADR 0089, PRD-GUIDELINE-REVIEW.md Round 1 P0-01
G-8 Booking intake, minor (16–17) guardian route, eligibility boundary, cutoff business owner + clinical/ethics + technical before slice 2 ADR 0094-intake-eligibility-cutoff.md accepted; intake schema applied (D1 migration-id); JSON booking_intake updated to match ADR 0094 field list; 1 hour before scheduled_start cutoff enforced in CreateBooking precondition (integration test run-id). ADR 0094, PRD-GUIDELINE-REVIEW.md Round 1 P0-04, Ticket 09
G-9 No-show timing, late-arrival correction window clinical/ethics + operations + technical before UAT ADR 0092-appointment-outcome-timing.md accepted; T+15m auto-checkpoint cron handler deployed to Worker; OutcomeCorrection 7×24h window enforced (integration test run-id covering in-window vs out-of-window). ADR 0092, PRD-GUIDELINE-REVIEW.md Round 1 P1-12
G-10 Package-wide cancellation matrix + outcome race operations + technical before UAT ADR 0095-package-cancellation-matrix.md accepted; D1/Postgres triggers applied (migration-id); 15 acceptance criteria tests pass (run-id); couple-package target resolution per ADR 0095 §6 test pass. ADR 0095, PRD-GUIDELINE-REVIEW.md Round 1 P1-13, Ticket 10
G-11 Payment settlement uniqueness + paid_late package technical + finance production only (paired with G-4) Unique partial index payment(booking_id) WHERE status = 'paid' AND settled_at IS NOT NULL applied (migration-id); paid_late test pass (§7.7 run-id); duplicate webhook test pass (§7.6 run-id); finance sign-off confirming reconciliation report uses Payment.settled_at as canonical truth. ADR 0093, PRD-GUIDELINE-REVIEW.md Round 1 P1-10
G-12 Two-Admin bootstrap + last-active-Admin guard business owner + operations + technical before UAT (a) StaffMembership rows for both bootstrap Admins with RoleAssignment.role = 'admin' and is_active = true (D1 query result); (b) last-active-Admin guard implementation (cannot revoke the only remaining active Admin without another Admin present — integration test run-id); (c) Google SSO configured per ADR 0080 (OAuth client_id/secret in secret store, redirect URIs registered). ADR 0080, ADR 0081, PRD-GUIDELINE-REVIEW.md Round 1 P1-11
G-13 UAT pass for recorded critical scenarios operations + technical + business owner production only (a) UAT §13.3 scenarios recorded as pass with screenshots + run-ids (four program pillars; counseling catalog + pricing; guest booking + hold expiry; payment success/failure/late webhook; package next-session scheduling; Admin cancellation approve/deny + separate refund; staff role visibility; mobile keyboard/focus/contrast/error; privacy/no-clinical-data); (b) accessibility/perf/SEO checks (Lighthouse scores committed); (c) business owner walkthrough sign-off. §13.3, ADR 0088:12, PRD-GUIDELINE-REVIEW.md Round 1 P1-06
G-14 Operational sign-off (consolidated) business owner + operations + clinical/ethics + finance + technical production only Consolidated sign-off at docs/launch/release-sign-off-v1.md listing G-1..G-13 status (pass / blocked / waived) with each owner's signature (typed name + role + date) and attached evidence links. No TBD cells. Waivers require explicit business owner acknowledgement. this section + ADR 0096 §3

16.3 Gate-to-TBC dependency map

Every TBC that still blocks one or more gates is listed below. Closing each TBC is the prerequisite for collecting the related evidence; the TBC is not closed until the evidence artifact exists.

TBC Blocks gate Closure action
TBC-CONSENT-01 G-3 Clinical/ethics sign-off on consent copy final; commit ConsentRecord.version.
TBC-PRIVACY-01 G-3 Retention policy values decided; execution cadence documented; test fixtures redacted.
TBC-PAY-01 G-4 Method codes, fees, limits, refund capability documented; adapter config committed.
TBC-PAY-EXPIRY-01 G-4 Provider expiry vs SlotHold TTL invariant decided; integration test pass.
TBC-NOTIFY-01 G-5 Email provider + sender/domain verification + bounce handling + reminder offsets committed.
TBC-REC-01 G-4, G-11 Reconciliation cadence and dead-letter policy committed.
TBC-ADMIN-01 G-12, G-5 Admin workspace fields/visibility matrix committed; last-active-Admin guard tested.
TBC-ACCESS-01 G-12 ClientAccess rate limit/recovery/revocation decided; conservative defaults applied.
TBC-STAFF-SESSION-01 G-12 OAuth state/nonce/session/cookie/CSRF/re-auth/revocation/recovery behavior committed.
TBC-COUPLE-LAUNCH-01 G-6 Business owner decides couple launch-deferred (default) vs launch-ready.
TBC-SCHEDULE-01 G-2 Fuja recurring schedule + offline venue confirmed; AvailabilityRule populated.
TBC-API-01 G-13 Transport routes/payloads defined; UAT scenarios reference real endpoints.
TBC-LIVE-PRD-01 G-13, G-14 Live form reconciled with closure baseline; missing canonical keys restored or removed.
TBC-EXTENSION-01 G-9, G-10 extension_request / extension_grant audited commands added to ADR 0092 §6.1.3 and ADR 0095 §3.

16.4 Release sign-off template

Live launch can only proceed after G-14 consolidated sign-off is signed and every G-1..G-13 gate is pass or explicitly waived by the business owner.

Required signatures on docs/launch/release-sign-off-v1.md:

Until G-14 is signed, development may use fixtures and sandbox behavior, but production must not infer or silently invent the missing business decisions.