@topy-ai/maggie 0.7.37 → 0.7.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/README-zh-TW.md +65 -7
  2. package/README.md +80 -11
  3. package/bin/maggie.js +10 -2
  4. package/bundled-contracts/maggie-design/css-utility-evidence-v1.schema.json +10 -0
  5. package/bundled-contracts/maggie-design/dashboard-surface-v1.schema.json +11 -0
  6. package/bundled-contracts/maggie-design/progressive-enhancement-v1.schema.json +12 -0
  7. package/bundled-contracts/maggie-design/sample-surface-v1.schema.json +13 -0
  8. package/bundled-contracts/maggie-seo/privacy-origin-evidence-v1.schema.json +11 -0
  9. package/bundled-contracts/maggiedash/README.md +1 -1
  10. package/bundled-contracts/maggiedash/booking-access-v1.json +5 -4
  11. package/bundled-contracts/maggiedash/booking-customer-surface-v1.json +12 -1
  12. package/bundled-contracts/maggiedash/booking-email-templates-v1.json +2 -0
  13. package/bundled-contracts/maggiedash/booking-host-adapter-v1.json +16 -2
  14. package/bundled-contracts/maggiedash/booking-runtime.v1.json +41 -0
  15. package/bundled-contracts/maggiedash/execution-board.json +529 -28
  16. package/bundled-contracts/maggiedash/host-capabilities-v1.schema.json +10 -0
  17. package/bundled-contracts/maggiedash/site-structure-v1.schema.json +13 -0
  18. package/bundled-references/maggiedash-booking/ARCHITECTURE.md +218 -0
  19. package/bundled-references/maggiedash-booking/CURRENT-STATE.md +92 -0
  20. package/bundled-references/maggiedash-booking/DATA-FLOW.md +143 -0
  21. package/bundled-references/maggiedash-booking/DATA-MODEL.md +367 -0
  22. package/bundled-references/maggiedash-booking/DECISIONS.md +94 -0
  23. package/bundled-references/maggiedash-booking/EXECUTION-BOARD.json +2387 -0
  24. package/bundled-references/maggiedash-booking/HOST-ADAPTER.md +314 -0
  25. package/bundled-references/maggiedash-booking/ORAWELLNESS-INTEGRATION-AUDIT.md +227 -0
  26. package/bundled-references/maggiedash-booking/PAYMENT-GATEWAY.md +267 -0
  27. package/bundled-references/maggiedash-booking/PRD.md +228 -0
  28. package/bundled-references/maggiedash-booking/PROGRESS.md +2434 -0
  29. package/bundled-references/maggiedash-booking/QA-TEST-PLAN.md +235 -0
  30. package/bundled-references/maggiedash-booking/README.md +271 -0
  31. package/bundled-references/maggiedash-booking/RUNTIME-OPERATIONS.md +152 -0
  32. package/bundled-references/maggiedash-booking/SECURITY-COMPLIANCE.md +158 -0
  33. package/bundled-references/maggiedash-booking/SKILLS-AND-CLI.md +542 -0
  34. package/bundled-references/maggiedash-booking/STRIPE-INTEGRATION.md +129 -0
  35. package/bundled-references/maggiedash-booking/TASK-RUNBOOK.md +107 -0
  36. package/bundled-references/maggiedash-booking/TASKS.md +137 -0
  37. package/bundled-references/maggiedash-booking/USER-JOURNEYS.md +224 -0
  38. package/bundled-references/maggiedash-booking/diagrams/booking-dfd.excalidraw +1 -0
  39. package/bundled-references/maggiedash-booking/diagrams/booking-dfd.mmd +16 -0
  40. package/bundled-references/maggiedash-booking/diagrams/booking-dfd.png +0 -0
  41. package/bundled-references/maggiedash-booking/diagrams/booking-dfd.svg +1 -0
  42. package/bundled-references/maggiedash-booking/diagrams/booking-state-machine.mmd +19 -0
  43. package/bundled-references/maggiedash-booking/diagrams/booking-state-machine.png +0 -0
  44. package/bundled-references/maggiedash-booking/diagrams/booking-state-machine.svg +1 -0
  45. package/bundled-references/maggiedash-booking/diagrams/manager-journey.excalidraw +1 -0
  46. package/bundled-references/maggiedash-booking/diagrams/manager-journey.mmd +11 -0
  47. package/bundled-references/maggiedash-booking/diagrams/manager-journey.png +0 -0
  48. package/bundled-references/maggiedash-booking/diagrams/manager-journey.svg +1 -0
  49. package/bundled-references/maggiedash-booking/diagrams/payment-sequence.mmd +20 -0
  50. package/bundled-references/maggiedash-booking/diagrams/payment-sequence.png +0 -0
  51. package/bundled-references/maggiedash-booking/diagrams/payment-sequence.svg +1 -0
  52. package/bundled-references/maggiedash-booking/diagrams/system-context.excalidraw +1 -0
  53. package/bundled-references/maggiedash-booking/diagrams/system-context.mmd +10 -0
  54. package/bundled-references/maggiedash-booking/diagrams/system-context.png +0 -0
  55. package/bundled-references/maggiedash-booking/diagrams/system-context.svg +1 -0
  56. package/bundled-skills/maggie-blog-bootstrap/SKILL.md +16 -0
  57. package/bundled-skills/maggie-booking/SKILL.md +103 -22
  58. package/bundled-skills/maggie-design/SKILL.md +35 -0
  59. package/bundled-skills/maggie-seo-geo/SKILL.md +12 -0
  60. package/bundled-skills/maggie-service-booking/SKILL.md +14 -0
  61. package/bundled-tools/clis/maggie_booking.py +231 -31
  62. package/bundled-tools/clis/maggie_contracts.py +282 -0
  63. package/bundled-tools/clis/maggie_dash.py +28 -6
  64. package/bundled-tools/clis/maggie_design.py +29 -12
  65. package/bundled-tools/clis/maggie_service_booking.py +50 -1
  66. package/bundled-tools/clis/site_audit.py +49 -0
  67. package/package.json +1 -1
@@ -0,0 +1,107 @@
1
+ # Booking task execution runbook
2
+
3
+ This is the operating procedure for the Booking delivery board. The board is
4
+ machine-readable in [`EXECUTION-BOARD.json`](./EXECUTION-BOARD.json), while
5
+ this document defines what each status means.
6
+
7
+ ## Task loop
8
+
9
+ Every task follows the same six checkpoints:
10
+
11
+ 1. **Task** — select one task whose dependencies are passed; record the task ID
12
+ and current evidence in `PROGRESS.md`.
13
+ 2. **Plan** — inspect the linked contracts and write the smallest complete
14
+ implementation slice in the task's `plan` field or a linked design note.
15
+ 3. **Implement** — change only the owning repository and preserve the host
16
+ boundary; add fixtures before external integration where possible.
17
+ 4. **Test** — run the task's listed commands and add a regression test for each
18
+ defect found. A green source scan is not runtime evidence.
19
+ 5. **Update docs** — update the contract, README, runbook, and affected
20
+ product/data-flow documents in the same change.
21
+ 6. **Record progress** — append commands, evidence paths, result, and remaining
22
+ host dependencies to `PROGRESS.md`; only then change the board status.
23
+
24
+ ## Status rules
25
+
26
+ | Status | Meaning |
27
+ |---|---|
28
+ | `planned` | Dependencies are not all passed or implementation has not started |
29
+ | `in_progress` | The current task has a recorded plan and an active implementation change |
30
+ | `needs-evidence` | Code and local tests pass, but the required host/runtime evidence is missing |
31
+ | `blocked` | The same external dependency has prevented progress for three consecutive delivery turns |
32
+ | `passed` | Implementation, tests, docs, and acceptance evidence all pass |
33
+
34
+ Never mark a task `passed` because files exist or a static validator finds a
35
+ marker. Host authentication, PostgreSQL transactions, provider events, and
36
+ browser evidence need evidence from the corresponding boundary.
37
+
38
+ ## Stable commands
39
+
40
+ From `ai-cmo-skills`:
41
+
42
+ ```bash
43
+ maggie booking tasks validate
44
+ maggie booking tasks list
45
+ maggie booking tasks show BK-019
46
+ ```
47
+
48
+ From `MaggieDash`:
49
+
50
+ ```bash
51
+ npm test
52
+ npm run booking:worker -- --job all --now 2026-09-20T10:00:00Z
53
+ npm run booking:stripe:validate
54
+ npm run booking:runtime:evidence:test
55
+ npm run booking:runtime:plan:test
56
+ npm run booking:ops:evidence:test
57
+ npm run booking:ops:evidence:regression:test
58
+ npm run booking:customer-flow:test
59
+ ```
60
+
61
+ After a host is wired:
62
+
63
+ ```bash
64
+ npm run booking:runtime:plan:test
65
+ npm run booking:runtime:evidence -- \
66
+ --base-url https://booking-staging.example.test \
67
+ --plan .secrets/booking-runtime-plan.json \
68
+ --storage-state .secrets/booking-storage-state.json \
69
+ --output .maggie/booking/runtime/evidence.json \
70
+ --confirm
71
+ node scripts/validate-booking-runtime-evidence.mjs \
72
+ .maggie/booking/runtime/evidence.json
73
+ maggie booking ops-validate --evidence .maggie/booking/ops-evidence.json
74
+ maggie booking inspect --project .
75
+ maggie booking runtime-validate --project . --evidence .maggie/booking/runtime-evidence.json
76
+ maggie booking release-gate --project . --require-runtime \
77
+ --evidence .maggie/booking/runtime-evidence.json \
78
+ --require-browser --browser-evidence .maggie/booking/browser/evidence.json \
79
+ --require-ops --ops-evidence .maggie/booking/ops-evidence.json
80
+ ```
81
+
82
+ `--require-browser` applies the same 15-screen × 3-viewport checks as the
83
+ browser evidence validator, including safe screenshot paths, ready state,
84
+ empty console errors, and empty failed-request reports.
85
+
86
+ For a final delivery decision, also require the machine-readable board to be
87
+ complete:
88
+
89
+ ```bash
90
+ maggie booking release-gate --project . --require-runtime \
91
+ --evidence .maggie/booking/runtime-evidence.json \
92
+ --require-browser --browser-evidence .maggie/booking/browser/evidence.json \
93
+ --require-ops --ops-evidence .maggie/booking/ops-evidence.json \
94
+ --require-board
95
+ ```
96
+
97
+ `--require-board` reads `docs/maggiedash-booking/EXECUTION-BOARD.json` (or the
98
+ path supplied with `--board`) and fails closed while any task is `planned`,
99
+ `in_progress`, `needs-evidence`, or `blocked`. `--board` without
100
+ `--require-board` reports the board status without making it a release blocker.
101
+
102
+ ## Evidence naming
103
+
104
+ Use `.maggie/booking/` for local evidence. Evidence must contain schema
105
+ versions, counts, statuses, timestamps, safe errors, and source revisions. It
106
+ must not contain cookies, tokens, card/payment credentials, raw provider
107
+ payloads, database URLs, or unredacted customer exports.
@@ -0,0 +1,137 @@
1
+ # MaggieDash Booking task board
2
+
3
+ This is the executable work breakdown for the first-party `/_maggie/booking`
4
+ workspace. Each task has one repository owner, a concrete output, and a test
5
+ or evidence gate. The detailed leaf-task board is
6
+ [`EXECUTION-BOARD.json`](./EXECUTION-BOARD.json); the required task loop is in
7
+ [`TASK-RUNBOOK.md`](./TASK-RUNBOOK.md). Status is updated in
8
+ [`PROGRESS.md`](./PROGRESS.md).
9
+
10
+ ## Task sequence
11
+
12
+ | ID | Task | Repository | Depends on | Output | Gate | Status |
13
+ |---|---|---|---|---|---|---|
14
+ | BK-001 | Freeze the implementation contract | both | docs baseline | versioned booking UI, host adapter, auth, payment and error boundaries | JSON contract validation | done |
15
+ | BK-002 | Add the Booking workspace distribution target | MaggieDash | BK-001 | manifest workspace mapping and install-safe source tree | manifest/install validator | done |
16
+ | BK-003 | Add the provider-neutral booking schema | MaggieDash | BK-001 | idempotent PostgreSQL migration with tenancy, lifecycle, overlap, payment, audit and outbox records | schema static gate + migration preflight notes | starter done; host pending |
17
+ | BK-004 | Add Booking host adapter contracts | MaggieDash | BK-001 | endpoint/capability/error contract and TypeScript types | contract validator | done |
18
+ | BK-005 | Build the Booking manager workspace | MaggieDash | BK-002, BK-004 | overview, calendar, bookings, customers, catalogue, staff, resources, payments, settings and audit screens | source gate + browser-ready route contract | UI done; runtime pending |
19
+ | BK-006 | Add stable ai-cmo booking commands | ai-cmo-skills | BK-004 | `maggie booking inspect`, contract validation and release gate | CLI tests | done |
20
+ | BK-007 | Add Maggie booking skill integration | ai-cmo-skills | BK-006 | install/configure/verify workflow with provider and payment boundaries | skill validation | done |
21
+ | BK-008 | Add installer and host integration documentation | both | BK-002..BK-007 | README, Astro adapter guide, host route example and migration instructions | link/checklist validation | done |
22
+ | BK-009 | Run unit/static/contract tests and fix regressions | both | BK-002..BK-008 | repeatable green test commands and sanitized evidence | all repository gates | done (repository gates; host browser/runtime pending) |
23
+ | BK-010 | Record delivery and remaining production work | both | BK-009 | progress log, known limits, release checklist and next phase | docs cross-links | done |
24
+ | BK-011 | Add provider-neutral runtime domain services | MaggieDash | BK-003, BK-004 | availability slot calculator, hold expiry, payment event reconciliation, notification retry rules | deterministic runtime fixture tests | done |
25
+ | BK-012 | Add executable host worker runner | MaggieDash | BK-011 | dry-run/fixture-safe job runner for availability, holds, payments, and notifications | CLI job matrix and redacted reports | done |
26
+ | BK-013 | Add production scheduling templates | MaggieDash | BK-012 | systemd service/timer, cron fallback, environment and locking runbook | template safety validator | done; host wiring pending |
27
+ | BK-014 | Add production browser evidence workflow | MaggieDash | BK-005, BK-012 | Playwright capture contract, validator, protected manual workflow and artifact retention | fixture + workflow YAML validation | workflow done; host evidence pending |
28
+ | BK-015 | Document host wiring and release operations | both | BK-011..BK-014 | adapter module shape, deploy order, rollback, alerts, and incident recovery | docs/link/release checklist | done |
29
+ | BK-016 | Audit Stripe booking and operations surface | both | BK-004, BK-011 | versioned API/event capability matrix, Stripe normalizer, ecosystem boundary, and stale-audit gate | Stripe contract + runtime tests | done; host adapter pending |
30
+ | BK-017 | Create executable Booking delivery board | both | BK-010 | machine-readable leaf tasks and task inspection CLI | board validator and list/show commands | passed |
31
+ | BK-018 | Reconcile host adapter routes with UI and host documentation | MaggieDash | BK-017 | 47-route canonical contract, independent fixture, installed route projection, and validator | `npm test` / host contract validator | passed |
32
+ | BK-019 | Build deterministic reference host adapter | MaggieDash | BK-018 | 47-route fixture host, local server, auth/scope/idempotency checks | reference-host validator, self-test, HTTP smoke | passed |
33
+ | BK-020 | Harden PostgreSQL migration and evidence | MaggieDash | BK-018 | v2 migration, compatibility backfill, schema validator, repeatable migration and overlap evidence | schema validator + PostgreSQL 14 disposable DB | passed |
34
+ | BK-021 | Complete availability, timezone, hold, and booking lifecycle rules | MaggieDash | BK-019, BK-020 | IANA/DST utilities, command layer, multi-segment conflict and idempotent hold/lifecycle operations | domain validator + runtime suite | passed |
35
+ | BK-022 | Implement host adapter service boundaries and safe DTOs | MaggieDash | BK-019, BK-021 | request validation, canonical DTOs, safe errors, canonical list-object handling, transaction-injected service, and reusable 47-route dispatcher | service + route-handler validators + full suite | passed |
36
+ | BK-023 | Implement catalog, staff, resource, schedule, and policy configuration | MaggieDash | BK-020, BK-022 | configuration contract, validation/update layer, readiness and audit | configuration validator + full suite | passed |
37
+ | BK-024 | Implement provider-neutral payment orchestration and fake gateway | MaggieDash | BK-021, BK-022 | payment port, fake modes, reconciliation/refund boundaries and capability checks | payment gateway validator + full suite | passed |
38
+ | BK-025 | Implement host-owned Stripe adapter against the current contract | host-owned with MaggieDash contract | BK-024 | injected official SDK factory, pinned API version, PaymentIntent/Checkout/SetupIntent/Refund/webhook seam | Stripe adapter conformance + full suite | passed |
39
+ | BK-026 | Complete outbox notifications and recovery | both | BK-021, BK-022 | allowlisted templates, recipient hashing, lease/retry/dead-letter/replay and adapter contract | notifications validator + full suite | passed |
40
+ | BK-027 | Finish Booking UI data loading, navigation, forms, and action feedback | MaggieDash | BK-018, BK-022, BK-023 | typed route loading, pagination, dialogs, forms, feedback | UI source gate + esbuild + reference-host Chrome smoke | passed |
41
+ | BK-028 | Finish manager daily operations journeys | MaggieDash | BK-021, BK-023, BK-027 | calendar modes, lifecycle/reschedule, payment operations, audit views | UI source gate + reference-host Chrome interaction smoke | passed |
42
+ | BK-029 | Verify authentication, tenancy, roles, and privacy boundaries | both | BK-019, BK-022, BK-027 | session/role/project checks, staff lifecycle-only mutations, payment/customer denial, and redaction scan | security validator + contract gate | passed |
43
+ | BK-030 | Wire the production worker and operational controls | both | BK-020, BK-021, BK-024, BK-026 | injected PostgreSQL worker repository/adapter, tenant lock, correlation/health report, dead-letter policy, ops evidence contract, production fixture guard, executable backup/restore rehearsal, and reviewed systemd/cron schedule generation | adapter/repository/health/ops evidence tests + `maggie booking worker-schedule` + real disposable worker cycle/schema/lock + `npm run booking:postgres-backup-restore:integration -- --source-database-url <source> --restore-database-url <empty-target> --pg-bin-dir <matching-postgres-bin-dir> --confirm`; host connection/alert routing/backup/recovery evidence pending | needs-evidence |
44
+ | BK-031 | Capture real host conformance and browser evidence | both | BK-019, BK-022, BK-028, BK-029, BK-030 | 47-manager-endpoint runtime plan/evidence and 15-screen Playwright evidence with concrete route/query validation, console/request/layout overflow checks | `npm run booking:runtime:plan:test` + protected runtime/browser workflows | needs-evidence |
45
+ | BK-032 | Run release gate, canary, documentation, and feedback closure | both | BK-025, BK-030, BK-031, BK-033, BK-034, BK-035, BK-036, BK-037, BK-038 | final release report, browser artifact parity/layout rejection, and docs | `maggie booking release-gate --require-runtime --require-browser --require-ops --require-board` | needs-evidence |
46
+ | BK-033 | Freeze and validate the public customer booking boundary | both | BK-021, BK-024, BK-026 | public-noindex catalog/availability/hold/checkout/payment-return/cancel contract, redacted DTOs, notification intents, and host safety boundary | `npm run booking:customer-flow:test` + `npm test` | passed |
47
+ | BK-034 | Ship the public customer booking page and pending-payment recovery UI | MaggieDash | BK-033 | installable customer page source, Astro route starter, catalog/availability/hold/checkout/pending-return UI, and noindex/public request checks | `npm run booking:customer-ui:test` + manifest/install validation | passed |
48
+ | BK-035 | Exercise the public customer flow against the reference host | MaggieDash | BK-034 | deterministic public catalog/availability/hold/checkout/payment-return/cancel host and installable validator | `npm run booking:customer-reference-host:test` + `npm test` | passed |
49
+ | BK-036 | Harden customer input validation and mutation replay | both | BK-035 | validated email/consent boundary, stable errors, customer-scoped checkout/cancel replay, and regressions | `npm run booking:customer-flow:test` + `npm run booking:customer-reference-host:test` + `npm test` | passed |
50
+ | BK-037 | Reject public idempotency-key payload mismatches | MaggieDash | BK-036 | normalized request hash, safe 409 conflict, and hold/checkout/cancel mismatch regressions | `npm run booking:customer-reference-host:test` + `npm test` | passed |
51
+ | BK-038 | Run all public customer gates in the runtime workflow | MaggieDash | BK-037 | source/install CI checks for customer flow, reference host, UI, and backend syntax | `npm test` + workflow marker validation | passed |
52
+ | BK-039 | Freeze the complete manager and customer service adapter surface | MaggieDash | BK-022, BK-033, BK-038 | typed repository/service/customer methods, endpoint mappings, and installable drift validator | `npm run booking:service-contract:test` + `npm test` | passed |
53
+ | BK-040 | Expose the service contract through the Booking CLI gates | ai-cmo-skills | BK-039 | compact contract mapping, install inspection, release-gate checks, and regression test | `python3 -m unittest tools.tests.test_maggie_booking -v` + `maggie booking inspect` | passed |
54
+ | BK-041 | Complete the public customer cancellation journey | MaggieDash | BK-035, BK-040 | token-bound cancellation action, idempotent request, bounded UI states, and installable validator coverage | `npm run booking:customer-ui:test` + `npm test` | passed |
55
+ | BK-042 | Implement the tenant-scoped PostgreSQL manager core repository | MaggieDash | BK-020, BK-021, BK-022, BK-039 | parameterized core reads, lifecycle writes, idempotency/event/audit persistence, schema/host seam, and real disposable-DB cycle | `npm run booking:postgres-core-repository:test` + disposable PostgreSQL integration + `npm test` | passed |
56
+ | BK-043 | Complete PostgreSQL manager configuration and operational reads | MaggieDash | BK-042 | tenant-scoped catalog, staff, resource, schedule, closure, settings, health, and payment reads/writes with provider boundary gate | `npm run booking:postgres-manager-methods:test` + disposable PostgreSQL integration + `npm test` | passed |
57
+ | BK-044 | Persist provider-injected payment operations through PostgreSQL | MaggieDash | BK-024, BK-025, BK-043 | payment start/reconcile/refund adapter, outside-transaction provider calls, normalized payment truth, and real integration evidence | `npm run booking:postgres-payment-adapter:test` + service gate + disposable PostgreSQL integration + `npm test` | passed |
58
+ | BK-045 | Persist the public customer Booking journey | MaggieDash | BK-033, BK-034, BK-041, BK-044 | customer token hash/sealed storage, public hold/checkout/payment-return/cancel adapter, mutation idempotency replay, manager transaction seam, and public DTO boundary | `npm run booking:postgres-customer-adapter:test` + customer gates + disposable PostgreSQL hold/checkout/cancel replay + `npm test` | passed |
59
+ | BK-046 | Recover customer checkout after provider failure | MaggieDash | BK-044, BK-045 | replay-safe hold conversion, reusable sealed token, provider idempotency, and retry from pending payment without a duplicate booking | `npm run booking:postgres-customer-adapter:test` + disposable PostgreSQL integration + `npm test` | passed |
60
+ | BK-047 | Fail closed on a non-empty backup restore target | MaggieDash | BK-030 | empty-public-schema preflight before `pg_restore`, refusal without target mutation, matching PostgreSQL client selection, and successful empty-target parity | disposable backup/restore integration with matching `--pg-bin-dir` plus non-empty-target refusal + `npm test` | passed |
61
+ | BK-048 | Add tenant-scoped manager reporting | both | BK-043, BK-027 | period totals and day/service/staff/location breakdowns with permissions, route contract, and dashboard screen | report repository validator + route/reference-host/UI gates | passed |
62
+ | BK-049 | Automate 24-hour booking reminders | both | BK-026 | idempotent reminder enqueue job, Resend outbox persistence, worker contract, and host dispatcher compatibility | runtime/reminder replay tests + worker repository gate + host build | passed |
63
+ | BK-050 | Implement payment policies, deposits, and outstanding balances | both | BK-024, BK-044, BK-045, BK-049 | full/deposit/pay-later/no-payment service policies, payment purposes, captured/refunded projection, checkout due amount, and manager payment controls | gateway/runtime/postgres adapter/reference-host/UI gates + `npm test` + host build | passed locally; host staging pending |
64
+ | BK-051 | Add manager customer history workspace | both | BK-039, BK-045 | searchable customer directory, consent summary, selected customer details, and appointment history backed by the existing customer-detail route | UI source gate + `npm test` + host build | passed locally; host staging pending |
65
+ | BK-052 | Complete schedule rule management without destructive UI writes | both | BK-023, BK-027 | working hours, staff shifts, time off, and location closures with full-snapshot preservation and safe validation | UI validator + `npm test` + host build | passed locally; host staging pending |
66
+ | BK-053 | Merge Maggie rewrites into existing Astro middleware during install | ai-cmo-skills + MaggieDash | BK-006, BK-008 | idempotent middleware merge, unsupported-shape warning, install state evidence, and inspect gate | CLI regression + install projection + inspect | passed |
67
+ | BK-054 | Add editable service and treatment catalogue management | both | BK-023, BK-027 | selectable catalogue rows, stable service/variant edits, payment policy changes, and safe active/inactive control | UI validator + configuration regression + `npm test` + host build | passed locally; host staging pending |
68
+ | BK-055 | Add editable staff and resource management | both | BK-023, BK-027 | selectable staff/resource rows, stable profile edits, assignment updates, bookable state, capacity, and safe active/inactive control | UI validator + configuration regression + `npm test` + host build | passed locally; host staging pending |
69
+ | BK-056 | Add editable schedule-rule management | both | BK-023, BK-027, BK-052 | selectable working-hours, shift, time-off, and closure rows with stable IDs and full-snapshot writes | UI validator + schedule regression + `npm test` + host build | passed locally; host staging pending |
70
+ | BK-057 | Make manager booking creation use live configuration | both | BK-023, BK-027, BK-028 | catalogue, location, staff, and resource selectors with required staff/resource allocation | UI validator + reference-host regression + `npm test` + host build | passed locally; host staging pending |
71
+ | BK-058 | Add safe first-run Booking setup checklist | ai-cmo-skills | BK-006, BK-008 | `maggie booking setup` reports install, middleware, env-key presence, owner/schema/worker next steps without exposing secrets or mutating the host | CLI regression + secret-redaction test + inspect/setup check | passed |
72
+ | BK-059 | Add explicit one-command host bootstrap | ai-cmo-skills | BK-058 | `maggie booking install --confirm --bootstrap` installs the host scaffold and runs the host-provided idempotent schema command only when explicitly requested | CLI bootstrap regression + package smoke + docs/whitespace checks | passed |
73
+ | BK-060 | Add token-bound customer self-service rescheduling | MaggieDash + ai-cmo-skills | BK-033, BK-041, BK-059 | Public customers can choose a future available slot from the payment-return page; the server enforces token, tenant, status, conflict, and idempotency boundaries and queues the existing Resend rescheduled notification | customer-flow + reference-host + PostgreSQL adapter + UI + full suite | passed |
74
+ | BK-061 | Add Resend customer-manage links with separate token lifetimes | MaggieDash + ai-cmo-skills | BK-026, BK-033, BK-060 | Short-lived payment token plus 30-day sealed manage token, idempotent schema migration, and Resend worker link for confirmed/rescheduled/cancelled/reminder emails | adapter/schema validators + full suite + ORA build | passed |
75
+ | BK-062 | Add tenant-scoped waitlist and Resend availability notification | MaggieDash + ai-cmo-skills | BK-033, BK-043, BK-054, BK-061 | Public noindex waitlist join, manager queue/actions, tenant/staff scope, audit/outbox records, and Resend availability notification | full suite + customer/schema/UI/host validators + ORA build | passed |
76
+ | BK-063 | Make waitlist conversion create and link a real booking | MaggieDash + ai-cmo-skills | BK-062 | Transactional booking/segment/allocation creation, converted-booking link, server-side conflict checks, manager conversion form, and confirmation email hand-off | core repository + reference host + ORA host/build gates | passed |
77
+ | BK-064 | Expose first-run payment readiness in the Booking overview | MaggieDash + ai-cmo-skills | BK-058, BK-059, BK-063 | Stripe status/mode, copyable webhook URL, secret-safe setup guidance, explicit API verification, and ORA mirror | full suite + Booking UI validator + ORA build | passed |
78
+ | BK-065 | Fail the Booking setup checklist on invalid secrets | ai-cmo-skills | BK-058, BK-064 | Minimum token length validation, paired Stripe-key detection, secret-safe error state, and regression tests | Python CLI tests + task-board validation | passed |
79
+ | BK-066 | Make installed Booking UI validators resolve the installed workspace | MaggieDash + ORA host | BK-064, BK-065 | Source/installed workspace detection, bounded missing-workspace diagnostic, and host validator regression coverage | central npm test + central UI validator + ORA UI/customer validators | passed |
80
+ | BK-067 | Automatically match newly available slots to the waitlist | MaggieDash + ORA host | BK-062, BK-063, BK-066 | Priority/FIFO matching with service/location/staff/time filters, idempotent Resend outbox notification, offered-slot persistence, and no automatic booking reservation | central npm test + ORA worker/runtime/UI validators | passed |
81
+ | BK-068 | Add customer self-service booking history | MaggieDash + ORA host | BK-061, BK-066 | New token-bound public manage endpoint, tenant/customer-scoped redacted history DTO, customer page history panel, and reference/Postgres regression coverage | central and ORA customer-flow/reference-host/Postgres/UI validators + build | passed |
82
+ | BK-069 | Make reviewed Booking bootstrap provision its implementation secret | ai-cmo-skills | BK-058, BK-059, BK-065 | Generate a cryptographically random `BOOKING_TOKEN_SECRET` only during explicit `--bootstrap`, preserve valid existing values, reject short values, and never print the secret | Python CLI regression + secret-redaction + whitespace checks | passed |
83
+ | BK-070 | Add transactional Booking schema dry-run | MaggieDash + ORA host | BK-059, BK-069 | Validate every additive schema file and PostgreSQL extension permission in one transaction, roll it back, and keep `--apply --confirm` as the only committing path | central/ORA syntax checks + live ORA dry-run + whitespace checks | passed |
84
+ | BK-071 | Accept the existing Resend sender-key convention in the generic host | MaggieDash + ORA host | BK-026, BK-058 | Resolve `EMAIL_FROM` or `RESEND_FROM_EMAIL` consistently in account invitations, worker delivery, and readiness summaries | host bootstrap validator + ORA build + syntax/whitespace checks | passed |
85
+ | BK-072 | Add multi-treatment manager appointments | MaggieDash + ORA host | BK-021, BK-027, BK-057, BK-071 | Create up to 12 service segments with per-segment time, price, staff/resource allocation, same-location/currency validation, transactional persistence, reference-host coverage, and manager UI controls | central/ORA reference-host regression + `npm test` + ORA build + UI markers + `git diff --check` | passed |
86
+ | BK-073 | Add public multi-treatment booking | MaggieDash + ORA host | BK-033, BK-034, BK-045, BK-072 | Let customers choose multiple treatments, see combined availability, hold every segment, and checkout one summed booking while preserving single-treatment compatibility | central/ORA customer-flow/reference-host/Postgres/UI validators + `npm test` + ORA build + schema gate | passed |
87
+ | BK-074 | Make multi-treatment rescheduling segment-safe | MaggieDash + ORA host | BK-072, BK-073 | Preserve segment/allocation identity, shift every segment by one delta, validate per-segment conflicts, and keep single-treatment rescheduling compatible | central/ORA customer reference-host + PostgreSQL repository validators + ORA build | passed |
88
+ | BK-075 | Remove install-time hardcoded Booking IDs | MaggieDash + ORA host | BK-054, BK-055, BK-056, BK-057 | Read tenant locations and live services from catalog/schedule responses, default new forms from bootstrap data, persist resource service assignments, and reject regression to `location-1`/`service-1` UI fallbacks | central/ORA UI validators + reference-host/core tests + ORA build + `git diff --check` | passed |
89
+ | BK-076 | Add install-time location management | MaggieDash + ORA host | BK-023, BK-054, BK-055, BK-075 | Let a blank project create and edit its first tenant location with timezone, locale, address, active state, and online-booking controls before configuring services, staff, resources, and schedules | central/ORA configuration, service, route, reference-host, UI validators + ORA build + `git diff --check` | passed |
90
+ | BK-077 | Synchronize the install-time Booking contract | ai-cmo-skills + MaggieDash | BK-076 | Keep the public ai-cmo-skills contract, detailed MaggieDash contract, CLI count, service-method map, and location endpoints identical | `maggie booking contract` + Python Booking tests + MaggieDash `booking:contract:validate` + task-board validation | passed |
91
+ | BK-078 | Verify and release the public MaggieDash install source | MaggieDash + release owner | BK-077 | Release the manifest host bootstrap, 47-route Booking source, schema, worker, and Astro host scaffold that the default ai-cmo-skills installer fetches | default `maggie booking install --project <disposable> --host astro --dry-run` from GitHub, local-source projection parity, host bootstrap validator, and release tag/commit evidence | passed |
92
+ | BK-079 | Fix npm CLI Booking contract paths | ai-cmo-skills | BK-077 | Make packaged Booking CLI commands resolve bundled contracts and the execution board while preserving source-checkout paths | packaged `maggie booking contract`, `stripe-audit`, `tasks validate`, `setup`, syntax, and whitespace checks | passed |
93
+ | BK-080 | Add tenant-scoped notification delivery management | both | BK-026, BK-077 | Expose redacted Resend delivery state in the manager workspace and allow owner/manager dead-letter replay with required reason, idempotency, tenant scope, event, and audit evidence | MaggieDash `npm test` + ai-cmo CLI contract/test gates + ORA validators/build | passed |
94
+ | BK-081 | Harden first-owner registration | both | BK-058, BK-071 | Serialize first-owner registration, verify existing passwords, and prevent password overwrite or disabled-account reactivation | MaggieDash bootstrap validator + `npm test` + ORA `contract:check`/build + `git diff --check` | passed |
95
+ | BK-082 | Harden Booking access defaults and disabled-account boundary | both | BK-026, BK-081 | Give invited staff/finance accounts safe role defaults, preserve granular permissions, and reject disabled accounts instead of re-enabling them | MaggieDash bootstrap validator + `npm test` + ORA `contract:check`/build + `git diff --check` | passed |
96
+ | BK-083 | Add worker migration preflight | both | BK-030, BK-070 | Check core, Booking, and access tables before worker lock/repository reads and return bounded `needs-migration` JSON without writes or stack traces | worker `node --check` + Astro bootstrap validator + unmigrated ORA worker run + `git diff --check` | passed |
97
+ | BK-084 | Synchronize browser evidence with the complete manager workspace | both | BK-080, BK-083 | Cover all 15 manager routes at mobile, tablet, and desktop viewports and keep installed UI markers aligned with the evidence contract | MaggieDash `npm test` + ORA contract/build + ai-cmo Booking tests + packaged task validation + `git diff --check` | passed |
98
+ | BK-085 | Make cancellation and refund policy tenant-configurable and booking-scoped | both | BK-064, BK-084 | Configure cutoff/refund/no-show policy, snapshot it on every booking creation path, and enforce customer cancellation cutoff without pretending provider refunds are automatic | MaggieDash `npm test` + ORA contract/build + policy validators + `git diff --check` | passed |
99
+ | BK-086 | Make calendar day and week views honor their requested venue-local range | both | BK-084, BK-085 | Filter Day/Week queries by the correct venue-local range, keep staff scope, and align reference host/UI behavior with the PostgreSQL contract | MaggieDash `npm test` + calendar/repository validators + ORA contract/build + `git diff --check` | passed |
100
+ | BK-087 | Execute cancellation refunds through the provider boundary and Resend outbox | both | BK-080, BK-085, BK-086 | Allocate policy-safe refunds across captured attempts, call the injected provider after cancellation, expose bounded settlement status, queue payment.refunded only for accepted/pending refunds, and keep generic/ORA Resend workers behaviorally aligned | MaggieDash `npm test` + cancellation/customer settlement validators + Astro bootstrap validator + ORA contract/build + `git diff --check` | passed |
101
+ | BK-088 | Expose no-show fee review without automatic charging | both | BK-087 | Return a policy-derived review_required settlement, never call the refund provider, and show the bounded fee review in manager Booking detail | no-show review validator + reference-host regression + MaggieDash `npm test` + ORA contract/build + `git diff --check` | passed |
102
+ | BK-089 | Make Booking team access an installable and verifiable contract | both | BK-082, BK-084 | Add a versioned access contract, distribution manifest gate, CLI check, and route/UI/schema validator for administrator-managed email/password staff access | `npm run booking:access:test` + MaggieDash `npm test` + `maggie booking access-contract` + packaged checks | passed |
103
+ | BK-090 | Make the reference host exercise Team access CRUD and role denial | MaggieDash | BK-089 | Add owner-only deterministic access CRUD, invitation intent, audit, and staff denial to the reference host | reference-host validator + MaggieDash `npm test` + secret/PII scan | passed |
104
+ | BK-091 | Make fresh Astro Booking installation dependency-complete | ai-cmo-skills | BK-078, BK-089 | Add explicit npm/pnpm/yarn/bun dependency completion that installs only missing Booking host packages, supplies a blank-host SSR adapter/config, preserves existing deployment adapters, and remains read-only-safe | Python Booking CLI tests + public-source fresh `astro build` + packaged task validation + `git diff --check` | passed |
105
+ | BK-092 | Add tenant-scoped Booking email template management | both | BK-080, BK-091 | Add versioned event templates, allowlisted rendering, owner/manager preview-publish-rollback, and Resend-worker resolution while preserving outbox safety | template contract/renderer/permission/worker tests + reference-host and ORA build | passed |
106
+ | BK-093 | Expose complete Booking defaults in manager Settings | both | BK-023, BK-092 | Let an owner/manager edit venue timezone/currency, pause new booking writes, and select automatic/manual payment capture policy through the existing audited settings boundary | central/ORA UI validators, MaggieDash `npm test`, ORA contract/build, and whitespace checks | passed |
107
+ | BK-094 | Add tenant-scoped treatment package catalogue | both | BK-023, BK-093 | Add prepaid treatment package metadata, included variant quantities, price/currency/expiry, active state, manager CRUD, tenant scope, idempotency, audit, and reference/install parity | central/ORA schema, service, route, reference-host, UI, contract, and build gates plus ai-cmo CLI tests | passed |
108
+ | BK-095 | Add customer package balances and redemption | both | BK-094, BK-087 | Add manager-granted customer package entitlements, per-variant balances, expiry enforcement, an auditable redemption ledger, and transactional manager-booking redemption while keeping Stripe purchase/refund provider work separate | central/ORA schema, service, route, reference-host, UI, contract, build gates, and package regression tests | passed |
109
+
110
+ | BK-096 | Add customer package checkout and refund settlement | both | BK-095, BK-087 | Add a separate package purchase/refund aggregate, public package checkout/payment return, Stripe metadata/webhook/reconciliation fulfillment, manager purchase listing, and redemption-safe refunds | central/ORA schema, payment/service/route/reference-host/UI/contract gates, ai-cmo tests, and ORA build | passed |
111
+ | BK-097 | Add package lifecycle Resend notifications | both | BK-096, BK-092 | Queue idempotent package confirmation/refund emails from verified Stripe state, link notifications to package purchases, and deliver them through the generic/ORA Resend workers without booking-only manage links | central npm test, email-template/notification/worker validators, ORA contract/build, schema mirror, and `git diff --check` | passed |
112
+ | BK-098 | Add public customer package redemption | both | BK-095, BK-096 | Carry a customer-bound package entitlement from the confirmed package return into public hold/checkout, redeem matching treatment credits atomically with booking creation, and expose a safe package summary in the customer response | central/ORA public reference-host regression, PostgreSQL adapter/core syntax and contract gates, UI validator, ORA build, and `git diff --check` | passed |
113
+ | BK-099 | Restore package credits on cancellation | both | BK-095, BK-098 | Reverse active package redemption ledger rows exactly once when a manager or eligible customer cancellation succeeds, restore per-variant balances transactionally, keep no-show/completed visits consumed, and expose an auditable reversal result | central npm/reference-host/customer-flow/schema gates, disposable PostgreSQL integration, ORA contract/build, ai-cmo task validation, and `git diff --check` | passed |
114
+ | BK-100 | Allow secure dashboard-managed Stripe connection | both | BK-064, BK-065 | Owner/manager-only Stripe key-pair form, API verification before persistence, AES-256-GCM ciphertext at rest, deployment-secret precedence, and synchronized generic/ORA/CLI/docs behavior | MaggieDash npm/host/schema gates, ORA contract/build, ai-cmo Booking tests/packaged setup, and `git diff --check` | passed |
115
+ | BK-101 | Complete server-enforced Booking capability permissions | both | BK-089, BK-100 | Reconcile every route capability with the administrator registry, enforce safe role defaults for legacy rows, honor explicitly granted staff reads, and synchronize generic/ORA/reference-host/CLI contracts | MaggieDash npm/access/route-handler gates, ORA contract/build, ai-cmo Booking tests, and `git diff --check` | passed |
116
+ | BK-102 | Persist provider customer identity for real Stripe payments | both | BK-025, BK-100 | Resolve local tenant customer UUIDs to idempotent Stripe Customer objects, persist only the provider reference, and use it for Checkout/PaymentIntent/SetupIntent without leaking credentials or cross-tenant data | Stripe adapter conformance with customer resolver, central/ORA schema validators, ORA contract/build, MaggieDash `npm test`, and `git diff --check` | passed |
117
+ | BK-103 | Add consented Stripe no-show fee charging | both | BK-088, BK-102 | Add an explicit manager/finance action that charges only a policy-derived no-show fee when the customer consented, a saved payment method is available, and Stripe off-session capability is verified; persist adjustment payment/audit state and queue the Resend payment notification | Stripe adapter, payment adapter, route/reference-host, email, UI, central `npm test`, ORA contract/build, and `git diff --check` | passed |
118
+
119
+ ## Execution rule
120
+
121
+ For each leaf task: select it with `maggie booking tasks`, write the plan and
122
+ acceptance checks, implement the smallest complete slice, run its gate, update
123
+ the relevant docs, then append a dated entry to [`PROGRESS.md`](./PROGRESS.md).
124
+ A task is not `passed` because files exist; its gate and documentation must
125
+ pass. Host/runtime tasks additionally require evidence from the real host
126
+ boundary.
127
+
128
+ ## Scope boundary
129
+
130
+ This delivery implements the MaggieDash manager workspace, the public customer
131
+ boundary contract, tenant-scoped manager and customer persistence for
132
+ configuration, lifecycle, checkout, and token-bound cancellation operations,
133
+ and provider-neutral host-facing runtime primitives. It does not silently
134
+ invent a production provider integration, notification transport, or live
135
+ database migration runner. Those remain explicit Phase 2–6 host work in
136
+ [`CURRENT-STATE.md`](./CURRENT-STATE.md) and are represented by contracts and
137
+ readiness states where the host must own the runtime behavior.
@@ -0,0 +1,224 @@
1
+ # Booking user journeys
2
+
3
+ The journeys below describe the intended end-to-end behavior. A journey is not
4
+ complete when the happy-path screen renders; it includes authorization, retries,
5
+ provider delay, timezones, and the final user-visible outcome.
6
+
7
+ ![Manager setup and daily operations](./diagrams/manager-journey.svg)
8
+
9
+ [Open Mermaid source](./diagrams/manager-journey.mmd) · [PNG](./diagrams/manager-journey.png) · [Editable scene](./diagrams/manager-journey.excalidraw)
10
+
11
+ ## 1. Owner configures a location
12
+
13
+ ```text
14
+ Owner signs in
15
+ -> opens Booking
16
+ -> creates location and timezone
17
+ -> adds service and variant
18
+ -> adds staff and service eligibility
19
+ -> defines working hours and closure exceptions
20
+ -> runs configuration check
21
+ -> sees "ready for booking" or named missing dependencies
22
+ ```
23
+
24
+ | Step | System behavior | Failure behavior |
25
+ |---|---|---|
26
+ | Create location | Validates tenant scope, timezone, currency, and unique slug | Inline validation; no partial location |
27
+ | Create service | Saves draft until required factual fields are present | Draft is visible but not bookable |
28
+ | Add staff | Stores profile and active/bookable flags | Email invite is separate from bookability |
29
+ | Assign eligibility | Links staff, service, location, and optional override | Duplicate assignment is idempotent |
30
+ | Set hours | Stores recurring rules in venue timezone | Invalid DST rule is rejected |
31
+ | Check readiness | Evaluates catalog, schedule, staff, resource, and payment policy | Returns a checklist, not a generic 500 |
32
+
33
+ Acceptance: the owner can explain why a service is or is not bookable without
34
+ reading server logs.
35
+
36
+ ## 2. Customer makes a paid booking
37
+
38
+ ```text
39
+ Customer selects service/location
40
+ -> availability query
41
+ -> selects slot
42
+ -> creates hold
43
+ -> starts payment attempt
44
+ -> completes gateway action
45
+ -> verified event reconciles payment
46
+ -> hold becomes confirmed booking
47
+ -> confirmation notification is queued
48
+ ```
49
+
50
+ The public steps use the separate `booking-customer-surface-v1` boundary and
51
+ `customer-route-handler.mjs`. It is public/noindex rather than manager-session
52
+ authenticated, but the host still binds every request to one tenant and applies
53
+ origin/CSRF, rate-limit, bot, and opaque continuation-token controls. The
54
+ customer DTO never exposes project IDs, internal allocations, provider object
55
+ references, or credentials.
56
+
57
+ Important details:
58
+
59
+ - The hold is created before payment starts.
60
+ - The hold expiry is visible to the customer.
61
+ - The success redirect only displays a pending state until reconciliation.
62
+ - The confirmation contains the local booking ID and safe next actions.
63
+ - The payment-return page offers token-bound cancellation with an idempotent
64
+ request and explicit success/error feedback; it never asks for manager login.
65
+ - A confirmation or reminder email carries a separate 30-day manage link. The
66
+ manage page can show the current and historical appointments for that
67
+ customer, but returns no email, customer ID, project ID, or bearer token.
68
+ - If the hold expires before payment confirmation, the system does not silently
69
+ allocate the slot. It starts a recovery/manual-review path.
70
+
71
+ Acceptance: a refresh, double-click, browser close, or delayed webhook cannot
72
+ create a second booking or second payment attempt under the same idempotency key.
73
+
74
+ ## 2a. Customer books with a prepaid package
75
+
76
+ ```text
77
+ Customer completes package payment
78
+ -> verified provider state fulfills the entitlement
79
+ -> package return shows the available entitlement
80
+ -> customer opens the public booking page
81
+ -> selects only treatments covered by the package
82
+ -> creates a customer-bound hold
83
+ -> checkout locks the entitlement and converts the hold
84
+ -> balance and redemption ledger update with the booking transaction
85
+ -> zero-price booking is confirmed without a second payment
86
+ ```
87
+
88
+ The entitlement identifier is only a continuation hint. The server binds it to
89
+ the tenant customer resolved from the submitted email, checks active status,
90
+ expiry, currency, and every selected treatment's remaining quantity, then
91
+ locks the entitlement and item rows before decrementing them. A browser cannot
92
+ choose another customer's package, redeem an expired balance, or partially
93
+ consume a package when the selected multi-treatment booking is not fully
94
+ covered.
95
+
96
+ Acceptance: a confirmed package purchase can reach a real public booking, a
97
+ successful redemption creates one zero-price booking and one ledger entry per
98
+ treatment, an eligible cancellation restores the credit with a reversed ledger
99
+ row, and retrying the same hold, checkout, or cancellation key does not consume
100
+ or restore another credit.
101
+
102
+ ## 3. Manager creates an unpaid booking
103
+
104
+ The manager selects a customer, service, staff/resource, and slot. The system
105
+ applies the same allocation constraints as a customer booking. The manager must
106
+ choose a reason when bypassing payment or changing the standard policy.
107
+
108
+ The booking can be `confirmed` with `paymentStatus = not_required` or
109
+ `paymentStatus = requires_payment`; these are not the same as `paid`.
110
+
111
+ Acceptance: a manager cannot create an unpaid booking that bypasses a required
112
+ policy unless their role has the explicit permission and the audit record has a
113
+ reason.
114
+
115
+ ## 4. Manager runs the day
116
+
117
+ ```text
118
+ Open calendar
119
+ -> filter location/staff
120
+ -> open next booking
121
+ -> check in
122
+ -> mark in progress
123
+ -> take balance payment or record no payment required
124
+ -> complete
125
+ ```
126
+
127
+ The calendar is a read model over bookings and allocations. It is not a second
128
+ booking database. Status buttons call lifecycle commands, show pending state,
129
+ and refresh the canonical record after the server responds.
130
+
131
+ Acceptance: the manager can identify deposit paid, balance due, payment action
132
+ required, refund pending, and no-show without opening Stripe.
133
+
134
+ ## 4a. Manager reviews and charges a consented no-show fee
135
+
136
+ ```text
137
+ Manager/finance marks the visit no-show
138
+ -> Booking shows a review-only policy amount
139
+ -> authorized operator confirms the separate fee action
140
+ -> server checks customer consent, saved payment method, Stripe capability, and idempotency
141
+ -> Stripe off-session PaymentIntent is attempted
142
+ -> adjustment/audit state is persisted; success queues Resend notification
143
+ ```
144
+
145
+ The no-show transition itself never charges. A missing consent, saved method,
146
+ webhook capability, or provider confirmation returns a bounded operator state;
147
+ it does not create a false success.
148
+
149
+ ## 5. Customer payment requires action
150
+
151
+ The gateway reports that the customer must authenticate or use another action.
152
+ The local payment attempt becomes `action_required`; the booking remains held
153
+ until the configured timeout.
154
+
155
+ The customer can resume the same attempt using a safe continuation token. The
156
+ server rechecks tenant, booking, hold, and payment-attempt ownership. It never
157
+ trusts a client-supplied provider object ID without local association.
158
+
159
+ Acceptance: the UI never calls this state “failed” until the provider confirms a
160
+ terminal failure or the hold expires.
161
+
162
+ ## 6. Payment succeeds but webhook is late
163
+
164
+ The redirect returns the customer to a pending confirmation page. A background
165
+ reconciliation worker reads the provider status using the local external ID.
166
+ When the read or verified webhook confirms success, the worker atomically writes
167
+ the payment transaction, converts the hold, appends events, and queues the
168
+ confirmation.
169
+
170
+ Acceptance: the redirect is safe to repeat and the reconciliation job is safe to
171
+ repeat.
172
+
173
+ ## 7. Manager reschedules a booking
174
+
175
+ The manager opens an existing booking, requests a new slot, and sees a preview
176
+ of the allocation conflicts and policy impact. On confirm, the server releases
177
+ the old allocation and creates the new allocation in one transaction, or keeps
178
+ the original booking unchanged if the new allocation cannot be acquired.
179
+
180
+ The event history records old time, new time, actor, reason, policy version,
181
+ notification outcome, and any payment/refund effect.
182
+
183
+ Acceptance: a failed reschedule cannot leave the booking with neither slot.
184
+
185
+ ## 8. Manager cancels and refunds
186
+
187
+ The manager selects a cancellation reason. The server evaluates the booking's
188
+ stored cancellation policy, calculates the allowed refund or fee, and starts a
189
+ refund operation through the payment gateway. The booking cancellation and
190
+ refund status are independent until the provider confirms the refund.
191
+
192
+ Acceptance: the manager sees `refund_pending` when the gateway is delayed and
193
+ cannot issue a second refund that exceeds the captured total.
194
+
195
+ ## 9. Staff sees assigned work
196
+
197
+ An editor/staff role sees only permitted locations and assigned services or
198
+ bookings. Staff can check in, mark in progress, complete, or record a no-show
199
+ when allowed. They cannot change payment provider configuration, access
200
+ payment/customer directories, or view unrelated customer data.
201
+
202
+ Acceptance: authorization is enforced on the server for list, detail, and
203
+ mutation endpoints; hiding a button is not the permission boundary.
204
+
205
+ ## 10. Provider is unavailable
206
+
207
+ If Stripe or another provider health check fails, configuration and bookings
208
+ remain readable. Actions requiring the provider are disabled with a reason and a
209
+ retry/reconciliation path. An existing confirmed booking is not changed to
210
+ failed because a health check is temporarily down.
211
+
212
+ Acceptance: an external provider outage is visible, bounded, and does not cause
213
+ data loss or duplicate retries.
214
+
215
+ ## 11. Support investigates a disputed booking
216
+
217
+ Support searches by local booking ID, customer email, provider object ID, or
218
+ correlation ID. The detail view shows booking transitions, payment attempts,
219
+ transactions, webhook events, refunds, notifications, and audit events with
220
+ secret values redacted.
221
+
222
+ Acceptance: support can answer what happened, when, who acted, and whether the
223
+ provider confirmed the money without reading raw logs or querying production
224
+ tables manually.
@@ -0,0 +1 @@
1
+ {"type":"excalidraw","version":2,"source":"gstack-diagram-render","elements":[{"id":"OfpI-O84eYLDOPXjqNsdl","type":"rectangle","x":28.5,"y":75.5,"width":123.375,"height":44,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"a0","roundness":null,"seed":751327251,"version":3,"versionNonce":2050630525,"isDeleted":false,"boundElements":[{"type":"text","id":"5ryl4OCE81RwtqpzuuLSt"},{"id":"ZBMZvf5BP3n7v7f7xxyCD","type":"arrow"}],"updated":1789908597316,"link":null,"locked":false},{"id":"KaBBooCAwVY38BlHryTY0","type":"rectangle","x":276.953125,"y":75.5,"width":137.296875,"height":44,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"a1","roundness":null,"seed":613885597,"version":4,"versionNonce":907148541,"isDeleted":false,"boundElements":[{"type":"text","id":"H0gTMRLXi0f9DTu797B9a"},{"id":"ZBMZvf5BP3n7v7f7xxyCD","type":"arrow"},{"id":"GteZFCazJxGcSz_lfM8BI","type":"arrow"}],"updated":1789908597317,"link":null,"locked":false},{"id":"85PYpE8zBTKyBV51-vTk8","type":"rectangle","x":0,"y":169.5,"width":180.375,"height":44,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"a2","roundness":null,"seed":1892277683,"version":3,"versionNonce":2069571645,"isDeleted":false,"boundElements":[{"type":"text","id":"vqNeqLqjj2LIp2eNX1dJy"},{"id":"g_Qh43ylNzo5MMTpNBqI0","type":"arrow"}],"updated":1789908597316,"link":null,"locked":false},{"id":"Hrd_K3sQRcifZm2gQ3h4s","type":"rectangle","x":230.375,"y":169.5,"width":230.453125,"height":44,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"a3","roundness":null,"seed":1066552061,"version":4,"versionNonce":2066391485,"isDeleted":false,"boundElements":[{"type":"text","id":"Lrw8pn3-58j01L4iBSz2_"},{"id":"g_Qh43ylNzo5MMTpNBqI0","type":"arrow"},{"id":"nOf-tgCXvGKz0RjOpVytA","type":"arrow"}],"updated":1789908597317,"link":null,"locked":false},{"id":"hgbqtrPjeKpQz-YdIJDDt","type":"rectangle","x":510.828125,"y":122.5,"width":151.21875,"height":44,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"a4","roundness":null,"seed":1909043027,"version":7,"versionNonce":709167485,"isDeleted":false,"boundElements":[{"type":"text","id":"8xQy-PVIhN0rq2bhk3EOW"},{"id":"GteZFCazJxGcSz_lfM8BI","type":"arrow"},{"id":"nOf-tgCXvGKz0RjOpVytA","type":"arrow"},{"id":"-8qMUbx_QyYSz38YrmFsN","type":"arrow"},{"id":"qKoV_fP_CNaXvc9bN3YVX","type":"arrow"},{"id":"VWkAnLC2FY45nI710IwUC","type":"arrow"}],"updated":1789908597318,"link":null,"locked":false},{"id":"0aK8YRdi2EIFZLRG_Q_s4","type":"rectangle","x":736.5859375,"y":0,"width":214.671875,"height":44,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"a5","roundness":null,"seed":745136989,"version":4,"versionNonce":1488018237,"isDeleted":false,"boundElements":[{"type":"text","id":"w-bu7AqotHQRP64uLfGW0"},{"id":"-8qMUbx_QyYSz38YrmFsN","type":"arrow"},{"id":"QA77Nsz0KCb_Q-p0zdsMA","type":"arrow"}],"updated":1789908597317,"link":null,"locked":false},{"id":"45d-LLNXj9lgaV3XhvzzL","type":"rectangle","x":1025.796875,"y":0,"width":333.25,"height":44,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"a6","roundness":null,"seed":303975667,"version":3,"versionNonce":666692509,"isDeleted":false,"boundElements":[{"type":"text","id":"O5taB5oYsr4_i0ENhFWjS"},{"id":"QA77Nsz0KCb_Q-p0zdsMA","type":"arrow"}],"updated":1789908597317,"link":null,"locked":false},{"id":"1tY23PRQkjM2qDc8WPc9m","type":"rectangle","x":730.09375,"y":226.5,"width":227.65625,"height":44,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"a7","roundness":null,"seed":1601138621,"version":4,"versionNonce":1582257341,"isDeleted":false,"boundElements":[{"type":"text","id":"3EBQ4aNueqA5jmlrfQpOG"},{"id":"qKoV_fP_CNaXvc9bN3YVX","type":"arrow"},{"id":"KKr1CJBaYcO-gO14OeUSg","type":"arrow"}],"updated":1789908597318,"link":null,"locked":false},{"id":"ik50w5Nc1poOGuPV_iwE-","type":"rectangle","x":1084.8359375,"y":226.5,"width":215.171875,"height":44,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"a8","roundness":null,"seed":625882771,"version":4,"versionNonce":1119222909,"isDeleted":false,"boundElements":[{"type":"text","id":"Wt392N_h1FuYv_JFIfzOI"},{"id":"KKr1CJBaYcO-gO14OeUSg","type":"arrow"},{"id":"q8T0ahNfOIJQitvVRyQme","type":"arrow"}],"updated":1789908597319,"link":null,"locked":false},{"id":"_Ar6kM0PJuLCp9vjbkshD","type":"rectangle","x":712.046875,"y":122.5,"width":263.75,"height":44,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"a9","roundness":null,"seed":1187278877,"version":5,"versionNonce":1119029277,"isDeleted":false,"boundElements":[{"type":"text","id":"tb2gyJnuudCbTcGaZWsoN"},{"id":"VWkAnLC2FY45nI710IwUC","type":"arrow"},{"id":"W3hzHZBYu2qcxyFB3dcQz","type":"arrow"},{"id":"cLCsLC8qUL9tZrX8btoaB","type":"arrow"}],"updated":1789908597319,"link":null,"locked":false},{"id":"HD0tkz6QdpBYmoJAJuLNM","type":"rectangle","x":1106.3984375,"y":94,"width":172.046875,"height":44,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"aA","roundness":null,"seed":1242557491,"version":4,"versionNonce":242868989,"isDeleted":false,"boundElements":[{"type":"text","id":"U_2LPEjxE0izDoPYDrLPq"},{"id":"W3hzHZBYu2qcxyFB3dcQz","type":"arrow"},{"id":"cJR9ta689el8xgJBJB-EC","type":"arrow"}],"updated":1789908597319,"link":null,"locked":false},{"id":"vP_BtboPj4h6oKD8IEoK0","type":"rectangle","x":1409.046875,"y":122.5,"width":205.40625,"height":44,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"aB","roundness":null,"seed":274359421,"version":4,"versionNonce":458295229,"isDeleted":false,"boundElements":[{"type":"text","id":"DNWKdqy03ldwI0XpL7SsR"},{"id":"cJR9ta689el8xgJBJB-EC","type":"arrow"},{"id":"cLCsLC8qUL9tZrX8btoaB","type":"arrow"}],"updated":1789908597319,"link":null,"locked":false},{"id":"EjGqulH_Xm6_hesp5pRBi","type":"rectangle","x":1431.28125,"y":226.5,"width":160.9375,"height":44,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"aC","roundness":null,"seed":71953875,"version":5,"versionNonce":1767462397,"isDeleted":false,"boundElements":[{"type":"text","id":"UJmJutK7PtwzWgQ3KWcAw"},{"id":"q8T0ahNfOIJQitvVRyQme","type":"arrow"},{"id":"OQvBLkk_2Gyx8uBJhko3x","type":"arrow"},{"id":"AclEh4vURbCTAtaLvGooF","type":"arrow"}],"updated":1789908597320,"link":null,"locked":false},{"id":"HRS68EvITzjuzu8OnE0O2","type":"rectangle","x":1695.046875,"y":179.5,"width":151.171875,"height":44,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"aD","roundness":null,"seed":804441309,"version":3,"versionNonce":623088029,"isDeleted":false,"boundElements":[{"type":"text","id":"hiqDeUjF-NmD0vj2U2oVr"},{"id":"OQvBLkk_2Gyx8uBJhko3x","type":"arrow"}],"updated":1789908597319,"link":null,"locked":false},{"id":"En3AKGnoCMngtTxb5jbAI","type":"rectangle","x":1664.453125,"y":273.5,"width":212.359375,"height":44,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"aE","roundness":null,"seed":387103603,"version":3,"versionNonce":1058508381,"isDeleted":false,"boundElements":[{"type":"text","id":"03nSqc1BPfda7OX1bs0Pu"},{"id":"AclEh4vURbCTAtaLvGooF","type":"arrow"}],"updated":1789908597320,"link":null,"locked":false},{"id":"ZBMZvf5BP3n7v7f7xxyCD","type":"arrow","x":151.875,"y":97.5,"width":119.77800000000002,"height":0,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"aF","roundness":{"type":2},"seed":622799165,"version":4,"versionNonce":2022285011,"isDeleted":false,"boundElements":null,"updated":1789908597316,"link":null,"locked":false,"points":[[0.5,0],[53.5,0],[119.27800000000002,0]],"lastCommittedPoint":null,"startBinding":{"elementId":"OfpI-O84eYLDOPXjqNsdl","focus":0,"gap":1},"endBinding":{"elementId":"KaBBooCAwVY38BlHryTY0","focus":0,"gap":5.30012499999998},"startArrowhead":null,"endArrowhead":"arrow","elbowed":false},{"id":"g_Qh43ylNzo5MMTpNBqI0","type":"arrow","x":180.375,"y":191.5,"width":44.69999999999999,"height":0,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"aG","roundness":{"type":2},"seed":514905363,"version":4,"versionNonce":1501054483,"isDeleted":false,"boundElements":null,"updated":1789908597317,"link":null,"locked":false,"points":[[0.5,0],[44.19999999999999,0]],"lastCommittedPoint":null,"startBinding":{"elementId":"85PYpE8zBTKyBV51-vTk8","focus":0,"gap":1},"endBinding":{"elementId":"Hrd_K3sQRcifZm2gQ3h4s","focus":0,"gap":5.300000000000011},"startArrowhead":null,"endArrowhead":"arrow","elbowed":false},{"id":"GteZFCazJxGcSz_lfM8BI","type":"arrow","x":414.25,"y":97.5,"width":120.29200000000003,"height":22.757000000000005,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"aH","roundness":{"type":2},"seed":21035421,"version":4,"versionNonce":1775639891,"isDeleted":false,"boundElements":null,"updated":1789908597317,"link":null,"locked":false,"points":[[0.5,0.5],[71.57799999999997,0],[119.79200000000003,22.257000000000005]],"lastCommittedPoint":null,"startBinding":{"elementId":"KaBBooCAwVY38BlHryTY0","focus":0,"gap":1},"endBinding":{"elementId":"hgbqtrPjeKpQz-YdIJDDt","focus":-0.0000044376591660668065,"gap":2.242999999999995},"startArrowhead":null,"endArrowhead":"arrow","elbowed":false},{"id":"nOf-tgCXvGKz0RjOpVytA","type":"arrow","x":460.828,"y":191.5,"width":73.71400000000006,"height":22.757000000000005,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"aI","roundness":{"type":2},"seed":1788525235,"version":4,"versionNonce":462890131,"isDeleted":false,"boundElements":null,"updated":1789908597317,"link":null,"locked":false,"points":[[0.5,-0.5],[25,0],[73.21400000000006,-22.257000000000005]],"lastCommittedPoint":null,"startBinding":{"elementId":"Hrd_K3sQRcifZm2gQ3h4s","focus":0,"gap":1},"endBinding":{"elementId":"hgbqtrPjeKpQz-YdIJDDt","focus":0.00000443765916755389,"gap":2.242999999999995},"startArrowhead":null,"endArrowhead":"arrow","elbowed":false},{"id":"-8qMUbx_QyYSz38YrmFsN","type":"arrow","x":604.506,"y":122.5,"width":126.77999999999997,"height":100.5,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"aJ","roundness":{"type":2},"seed":764001789,"version":4,"versionNonce":1940872147,"isDeleted":false,"boundElements":null,"updated":1789908597317,"link":null,"locked":false,"points":[[0.5,0],[82.54100000000005,-100.5],[126.27999999999997,-100.5]],"lastCommittedPoint":null,"startBinding":{"elementId":"hgbqtrPjeKpQz-YdIJDDt","focus":-0.0000018853606859282727,"gap":1},"endBinding":{"elementId":"0aK8YRdi2EIFZLRG_Q_s4","focus":0,"gap":5.2999375000000555},"startArrowhead":null,"endArrowhead":"arrow","elbowed":false},{"id":"QA77Nsz0KCb_Q-p0zdsMA","type":"arrow","x":951.258,"y":22,"width":69.23899999999992,"height":0,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"aK","roundness":{"type":2},"seed":393669715,"version":4,"versionNonce":1242743571,"isDeleted":false,"boundElements":null,"updated":1789908597317,"link":null,"locked":false,"points":[[0.5,0],[68.73899999999992,0]],"lastCommittedPoint":null,"startBinding":{"elementId":"0aK8YRdi2EIFZLRG_Q_s4","focus":0,"gap":1},"endBinding":{"elementId":"45d-LLNXj9lgaV3XhvzzL","focus":0,"gap":5.299875000000043},"startArrowhead":null,"endArrowhead":"arrow","elbowed":false},{"id":"qKoV_fP_CNaXvc9bN3YVX","type":"arrow","x":607.72,"y":166.5,"width":117.07399999999996,"height":82,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"aL","roundness":{"type":2},"seed":1895495261,"version":4,"versionNonce":162880083,"isDeleted":false,"boundElements":null,"updated":1789908597318,"link":null,"locked":false,"points":[[0.5,0],[79.327,82],[116.57399999999996,82]],"lastCommittedPoint":null,"startBinding":{"elementId":"hgbqtrPjeKpQz-YdIJDDt","focus":0.0000036500196283968767,"gap":1},"endBinding":{"elementId":"1tY23PRQkjM2qDc8WPc9m","focus":0,"gap":5.299750000000017},"startArrowhead":null,"endArrowhead":"arrow","elbowed":false},{"id":"KKr1CJBaYcO-gO14OeUSg","type":"arrow","x":957.75,"y":248.5,"width":121.78600000000006,"height":0,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"aM","roundness":{"type":2},"seed":1763437043,"version":4,"versionNonce":1888166291,"isDeleted":false,"boundElements":null,"updated":1789908597318,"link":null,"locked":false,"points":[[0.5,0],[43.047000000000025,0],[121.28600000000006,0]],"lastCommittedPoint":null,"startBinding":{"elementId":"1tY23PRQkjM2qDc8WPc9m","focus":0,"gap":1},"endBinding":{"elementId":"ik50w5Nc1poOGuPV_iwE-","focus":0,"gap":5.299937499999942},"startArrowhead":null,"endArrowhead":"arrow","elbowed":false},{"id":"VWkAnLC2FY45nI710IwUC","type":"arrow","x":662.047,"y":144.5,"width":44.69999999999993,"height":0,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"aN","roundness":{"type":2},"seed":912663229,"version":4,"versionNonce":1334319315,"isDeleted":false,"boundElements":null,"updated":1789908597318,"link":null,"locked":false,"points":[[0.5,0],[44.19999999999993,0]],"lastCommittedPoint":null,"startBinding":{"elementId":"hgbqtrPjeKpQz-YdIJDDt","focus":0,"gap":1},"endBinding":{"elementId":"_Ar6kM0PJuLCp9vjbkshD","focus":0,"gap":5.299875000000043},"startArrowhead":null,"endArrowhead":"arrow","elbowed":false},{"id":"W3hzHZBYu2qcxyFB3dcQz","type":"arrow","x":965.018,"y":122.5,"width":136.07999999999993,"height":6.5,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"aO","roundness":{"type":2},"seed":1687171987,"version":4,"versionNonce":1252016147,"isDeleted":false,"boundElements":null,"updated":1789908597318,"link":null,"locked":false,"points":[[0.5,0],[35.778999999999996,-6.5],[135.57999999999993,-6.5]],"lastCommittedPoint":null,"startBinding":{"elementId":"_Ar6kM0PJuLCp9vjbkshD","focus":-0.000008020005770944968,"gap":1},"endBinding":{"elementId":"HD0tkz6QdpBYmoJAJuLNM","focus":0,"gap":5.300437500000044},"startArrowhead":null,"endArrowhead":"arrow","elbowed":false},{"id":"cJR9ta689el8xgJBJB-EC","type":"arrow","x":1278.445,"y":116,"width":129.5540000000001,"height":5.346000000000004,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"aP","roundness":{"type":2},"seed":309117725,"version":4,"versionNonce":415733587,"isDeleted":false,"boundElements":null,"updated":1789908597319,"link":null,"locked":false,"points":[[0.5,0.5],[105.60200000000009,0],[129.0540000000001,4.846000000000004]],"lastCommittedPoint":null,"startBinding":{"elementId":"HD0tkz6QdpBYmoJAJuLNM","focus":0,"gap":1},"endBinding":{"elementId":"vP_BtboPj4h6oKD8IEoK0","focus":-0.0000634185158362069,"gap":1.5587681083551017},"startArrowhead":null,"endArrowhead":"arrow","elbowed":false},{"id":"cLCsLC8qUL9tZrX8btoaB","type":"arrow","x":1413.172,"y":166.5,"width":442.9390000000001,"height":6.5,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"aQ","roundness":{"type":2},"seed":705317171,"version":4,"versionNonce":1139941011,"isDeleted":false,"boundElements":null,"updated":1789908597319,"link":null,"locked":false,"points":[[-0.5,-0.5],[-29.125,6.5],[-220.75,6.5],[-412.375,6.5],[-442.4390000000001,1.4470000000000027]],"lastCommittedPoint":null,"startBinding":{"elementId":"vP_BtboPj4h6oKD8IEoK0","focus":0.000005350371718996201,"gap":1},"endBinding":{"elementId":"_Ar6kM0PJuLCp9vjbkshD","focus":-0.000038135365851219884,"gap":1},"startArrowhead":null,"endArrowhead":"arrow","elbowed":false},{"id":"q8T0ahNfOIJQitvVRyQme","type":"arrow","x":1300.008,"y":248.5,"width":125.97299999999996,"height":0,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"aR","roundness":{"type":2},"seed":159405949,"version":4,"versionNonce":1762907603,"isDeleted":false,"boundElements":null,"updated":1789908597319,"link":null,"locked":false,"points":[[0.5,0],[84.03899999999999,0],[125.47299999999996,0]],"lastCommittedPoint":null,"startBinding":{"elementId":"ik50w5Nc1poOGuPV_iwE-","focus":0,"gap":1},"endBinding":{"elementId":"EjGqulH_Xm6_hesp5pRBi","focus":0,"gap":5.3002500000000055},"startArrowhead":null,"endArrowhead":"arrow","elbowed":false},{"id":"OQvBLkk_2Gyx8uBJhko3x","type":"arrow","x":1571.526,"y":226.5,"width":118.221,"height":25,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"aS","roundness":{"type":2},"seed":250653395,"version":4,"versionNonce":2015411475,"isDeleted":false,"boundElements":null,"updated":1789908597319,"link":null,"locked":false,"points":[[0.5,0],[67.92699999999991,-25],[117.721,-25]],"lastCommittedPoint":null,"startBinding":{"elementId":"EjGqulH_Xm6_hesp5pRBi","focus":0.0000017112969375320896,"gap":1},"endBinding":{"elementId":"HRS68EvITzjuzu8OnE0O2","focus":0,"gap":5.299874999999929},"startArrowhead":null,"endArrowhead":"arrow","elbowed":false},{"id":"AclEh4vURbCTAtaLvGooF","type":"arrow","x":1571.526,"y":270.5,"width":87.62699999999995,"height":25,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"aT","roundness":{"type":2},"seed":367157213,"version":4,"versionNonce":1946997843,"isDeleted":false,"boundElements":null,"updated":1789908597320,"link":null,"locked":false,"points":[[0.5,0],[67.92699999999991,25],[87.12699999999995,25]],"lastCommittedPoint":null,"startBinding":{"elementId":"EjGqulH_Xm6_hesp5pRBi","focus":-0.0000017112969349029908,"gap":1},"endBinding":{"elementId":"En3AKGnoCMngtTxb5jbAI","focus":0,"gap":5.30012499999998},"startArrowhead":null,"endArrowhead":"arrow","elbowed":false},{"id":"5ryl4OCE81RwtqpzuuLSt","type":"text","x":51.30078125,"y":85,"width":77.7734375,"height":25,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"aU","roundness":null,"seed":811017427,"version":3,"versionNonce":179622387,"isDeleted":false,"boundElements":null,"updated":1789908597320,"link":null,"locked":false,"text":"Customer","fontSize":20,"fontFamily":5,"textAlign":"center","verticalAlign":"middle","containerId":"OfpI-O84eYLDOPXjqNsdl","originalText":"Customer","autoResize":true,"lineHeight":1.25},{"id":"H0gTMRLXi0f9DTu797B9a","type":"text","x":298.1015625,"y":85,"width":95,"height":25,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"aV","roundness":null,"seed":1516311155,"version":3,"versionNonce":1160755901,"isDeleted":false,"boundElements":null,"updated":1789908597320,"link":null,"locked":false,"text":"Booking UI","fontSize":20,"fontFamily":5,"textAlign":"center","verticalAlign":"middle","containerId":"KaBBooCAwVY38BlHryTY0","originalText":"Booking UI","autoResize":true,"lineHeight":1.25},{"id":"vqNeqLqjj2LIp2eNX1dJy","type":"text","x":32.1552734375,"y":179,"width":116.064453125,"height":25,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"aW","roundness":null,"seed":874269715,"version":3,"versionNonce":852237203,"isDeleted":false,"boundElements":null,"updated":1789908597320,"link":null,"locked":false,"text":"Store manager","fontSize":20,"fontFamily":5,"textAlign":"center","verticalAlign":"middle","containerId":"85PYpE8zBTKyBV51-vTk8","originalText":"Store manager","autoResize":true,"lineHeight":1.25},{"id":"Lrw8pn3-58j01L4iBSz2_","type":"text","x":267.5546875,"y":179,"width":156.09375,"height":25,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"aX","roundness":null,"seed":1367298483,"version":3,"versionNonce":1145264925,"isDeleted":false,"boundElements":null,"updated":1789908597320,"link":null,"locked":false,"text":"Booking dashboard","fontSize":20,"fontFamily":5,"textAlign":"center","verticalAlign":"middle","containerId":"Hrd_K3sQRcifZm2gQ3h4s","originalText":"Booking dashboard","autoResize":true,"lineHeight":1.25},{"id":"8xQy-PVIhN0rq2bhk3EOW","type":"text","x":533.3759765625,"y":132,"width":106.123046875,"height":25,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"aY","roundness":null,"seed":61907795,"version":3,"versionNonce":411644211,"isDeleted":false,"boundElements":null,"updated":1789908597320,"link":null,"locked":false,"text":"Booking API","fontSize":20,"fontFamily":5,"textAlign":"center","verticalAlign":"middle","containerId":"hgbqtrPjeKpQz-YdIJDDt","originalText":"Booking API","autoResize":true,"lineHeight":1.25},{"id":"w-bu7AqotHQRP64uLfGW0","type":"text","x":767.740234375,"y":9.5,"width":152.36328125,"height":25,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"aZ","roundness":null,"seed":856080627,"version":3,"versionNonce":1958997885,"isDeleted":false,"boundElements":null,"updated":1789908597320,"link":null,"locked":false,"text":"Availability engine","fontSize":20,"fontFamily":5,"textAlign":"center","verticalAlign":"middle","containerId":"0aK8YRdi2EIFZLRG_Q_s4","originalText":"Availability engine","autoResize":true,"lineHeight":1.25},{"id":"O5taB5oYsr4_i0ENhFWjS","type":"text","x":1080.5224609375,"y":9.5,"width":223.798828125,"height":25,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"aa","roundness":null,"seed":2030578323,"version":3,"versionNonce":491950803,"isDeleted":false,"boundElements":null,"updated":1789908597320,"link":null,"locked":false,"text":"Schedule and resource rules","fontSize":20,"fontFamily":5,"textAlign":"center","verticalAlign":"middle","containerId":"45d-LLNXj9lgaV3XhvzzL","originalText":"Schedule and resource rules","autoResize":true,"lineHeight":1.25},{"id":"3EBQ4aNueqA5jmlrfQpOG","type":"text","x":765.0546875,"y":236,"width":157.734375,"height":25,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"ab","roundness":null,"seed":2053857331,"version":3,"versionNonce":83032029,"isDeleted":false,"boundElements":null,"updated":1789908597320,"link":null,"locked":false,"text":"Hold and allocation","fontSize":20,"fontFamily":5,"textAlign":"center","verticalAlign":"middle","containerId":"1tY23PRQkjM2qDc8WPc9m","originalText":"Hold and allocation","autoResize":true,"lineHeight":1.25},{"id":"Wt392N_h1FuYv_JFIfzOI","type":"text","x":1121.0498046875,"y":236,"width":142.744140625,"height":25,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"ac","roundness":null,"seed":18276819,"version":3,"versionNonce":834584691,"isDeleted":false,"boundElements":null,"updated":1789908597320,"link":null,"locked":false,"text":"Booking database","fontSize":20,"fontFamily":5,"textAlign":"center","verticalAlign":"middle","containerId":"ik50w5Nc1poOGuPV_iwE-","originalText":"Booking database","autoResize":true,"lineHeight":1.25},{"id":"tb2gyJnuudCbTcGaZWsoN","type":"text","x":754.5029296875,"y":132,"width":178.837890625,"height":25,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"ad","roundness":null,"seed":1445015411,"version":3,"versionNonce":1591866429,"isDeleted":false,"boundElements":null,"updated":1789908597320,"link":null,"locked":false,"text":"Payment gateway port","fontSize":20,"fontFamily":5,"textAlign":"center","verticalAlign":"middle","containerId":"_Ar6kM0PJuLCp9vjbkshD","originalText":"Payment gateway port","autoResize":true,"lineHeight":1.25},{"id":"U_2LPEjxE0izDoPYDrLPq","type":"text","x":1136.611328125,"y":103.5,"width":111.62109375,"height":25,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"ae","roundness":null,"seed":1540409619,"version":3,"versionNonce":1871985171,"isDeleted":false,"boundElements":null,"updated":1789908597320,"link":null,"locked":false,"text":"Stripe adapter","fontSize":20,"fontFamily":5,"textAlign":"center","verticalAlign":"middle","containerId":"HD0tkz6QdpBYmoJAJuLNM","originalText":"Stripe adapter","autoResize":true,"lineHeight":1.25},{"id":"DNWKdqy03ldwI0XpL7SsR","type":"text","x":1440.3828125,"y":132,"width":142.734375,"height":25,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"af","roundness":null,"seed":1738288819,"version":3,"versionNonce":779248797,"isDeleted":false,"boundElements":null,"updated":1789908597320,"link":null,"locked":false,"text":"Verified webhook","fontSize":20,"fontFamily":5,"textAlign":"center","verticalAlign":"middle","containerId":"vP_BtboPj4h6oKD8IEoK0","originalText":"Verified webhook","autoResize":true,"lineHeight":1.25},{"id":"UJmJutK7PtwzWgQ3KWcAw","type":"text","x":1458.146484375,"y":236,"width":107.20703125,"height":25,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"ag","roundness":null,"seed":1546248275,"version":3,"versionNonce":1942585267,"isDeleted":false,"boundElements":null,"updated":1789908597320,"link":null,"locked":false,"text":"Event outbox","fontSize":20,"fontFamily":5,"textAlign":"center","verticalAlign":"middle","containerId":"EjGqulH_Xm6_hesp5pRBi","originalText":"Event outbox","autoResize":true,"lineHeight":1.25},{"id":"hiqDeUjF-NmD0vj2U2oVr","type":"text","x":1718.4208984375,"y":189,"width":104.423828125,"height":25,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"ah","roundness":null,"seed":55598579,"version":3,"versionNonce":659933437,"isDeleted":false,"boundElements":null,"updated":1789908597320,"link":null,"locked":false,"text":"Notifications","fontSize":20,"fontFamily":5,"textAlign":"center","verticalAlign":"middle","containerId":"HRS68EvITzjuzu8OnE0O2","originalText":"Notifications","autoResize":true,"lineHeight":1.25},{"id":"03nSqc1BPfda7OX1bs0Pu","type":"text","x":1700.0908203125,"y":283,"width":141.083984375,"height":25,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"ai","roundness":null,"seed":672540563,"version":3,"versionNonce":2021986643,"isDeleted":false,"boundElements":null,"updated":1789908597320,"link":null,"locked":false,"text":"Reports and audit","fontSize":20,"fontFamily":5,"textAlign":"center","verticalAlign":"middle","containerId":"En3AKGnoCMngtTxb5jbAI","originalText":"Reports and audit","autoResize":true,"lineHeight":1.25}],"appState":{"viewBackgroundColor":"#ffffff"},"files":{}}