@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.
- package/README-zh-TW.md +65 -7
- package/README.md +80 -11
- package/bin/maggie.js +10 -2
- package/bundled-contracts/maggie-design/css-utility-evidence-v1.schema.json +10 -0
- package/bundled-contracts/maggie-design/dashboard-surface-v1.schema.json +11 -0
- package/bundled-contracts/maggie-design/progressive-enhancement-v1.schema.json +12 -0
- package/bundled-contracts/maggie-design/sample-surface-v1.schema.json +13 -0
- package/bundled-contracts/maggie-seo/privacy-origin-evidence-v1.schema.json +11 -0
- package/bundled-contracts/maggiedash/README.md +1 -1
- package/bundled-contracts/maggiedash/booking-access-v1.json +5 -4
- package/bundled-contracts/maggiedash/booking-customer-surface-v1.json +12 -1
- package/bundled-contracts/maggiedash/booking-email-templates-v1.json +2 -0
- package/bundled-contracts/maggiedash/booking-host-adapter-v1.json +16 -2
- package/bundled-contracts/maggiedash/booking-runtime.v1.json +41 -0
- package/bundled-contracts/maggiedash/execution-board.json +529 -28
- package/bundled-contracts/maggiedash/host-capabilities-v1.schema.json +10 -0
- package/bundled-contracts/maggiedash/site-structure-v1.schema.json +13 -0
- package/bundled-references/maggiedash-booking/ARCHITECTURE.md +218 -0
- package/bundled-references/maggiedash-booking/CURRENT-STATE.md +92 -0
- package/bundled-references/maggiedash-booking/DATA-FLOW.md +143 -0
- package/bundled-references/maggiedash-booking/DATA-MODEL.md +367 -0
- package/bundled-references/maggiedash-booking/DECISIONS.md +94 -0
- package/bundled-references/maggiedash-booking/EXECUTION-BOARD.json +2387 -0
- package/bundled-references/maggiedash-booking/HOST-ADAPTER.md +314 -0
- package/bundled-references/maggiedash-booking/ORAWELLNESS-INTEGRATION-AUDIT.md +227 -0
- package/bundled-references/maggiedash-booking/PAYMENT-GATEWAY.md +267 -0
- package/bundled-references/maggiedash-booking/PRD.md +228 -0
- package/bundled-references/maggiedash-booking/PROGRESS.md +2434 -0
- package/bundled-references/maggiedash-booking/QA-TEST-PLAN.md +235 -0
- package/bundled-references/maggiedash-booking/README.md +271 -0
- package/bundled-references/maggiedash-booking/RUNTIME-OPERATIONS.md +152 -0
- package/bundled-references/maggiedash-booking/SECURITY-COMPLIANCE.md +158 -0
- package/bundled-references/maggiedash-booking/SKILLS-AND-CLI.md +542 -0
- package/bundled-references/maggiedash-booking/STRIPE-INTEGRATION.md +129 -0
- package/bundled-references/maggiedash-booking/TASK-RUNBOOK.md +107 -0
- package/bundled-references/maggiedash-booking/TASKS.md +137 -0
- package/bundled-references/maggiedash-booking/USER-JOURNEYS.md +224 -0
- package/bundled-references/maggiedash-booking/diagrams/booking-dfd.excalidraw +1 -0
- package/bundled-references/maggiedash-booking/diagrams/booking-dfd.mmd +16 -0
- package/bundled-references/maggiedash-booking/diagrams/booking-dfd.png +0 -0
- package/bundled-references/maggiedash-booking/diagrams/booking-dfd.svg +1 -0
- package/bundled-references/maggiedash-booking/diagrams/booking-state-machine.mmd +19 -0
- package/bundled-references/maggiedash-booking/diagrams/booking-state-machine.png +0 -0
- package/bundled-references/maggiedash-booking/diagrams/booking-state-machine.svg +1 -0
- package/bundled-references/maggiedash-booking/diagrams/manager-journey.excalidraw +1 -0
- package/bundled-references/maggiedash-booking/diagrams/manager-journey.mmd +11 -0
- package/bundled-references/maggiedash-booking/diagrams/manager-journey.png +0 -0
- package/bundled-references/maggiedash-booking/diagrams/manager-journey.svg +1 -0
- package/bundled-references/maggiedash-booking/diagrams/payment-sequence.mmd +20 -0
- package/bundled-references/maggiedash-booking/diagrams/payment-sequence.png +0 -0
- package/bundled-references/maggiedash-booking/diagrams/payment-sequence.svg +1 -0
- package/bundled-references/maggiedash-booking/diagrams/system-context.excalidraw +1 -0
- package/bundled-references/maggiedash-booking/diagrams/system-context.mmd +10 -0
- package/bundled-references/maggiedash-booking/diagrams/system-context.png +0 -0
- package/bundled-references/maggiedash-booking/diagrams/system-context.svg +1 -0
- package/bundled-skills/maggie-blog-bootstrap/SKILL.md +16 -0
- package/bundled-skills/maggie-booking/SKILL.md +103 -22
- package/bundled-skills/maggie-design/SKILL.md +35 -0
- package/bundled-skills/maggie-seo-geo/SKILL.md +12 -0
- package/bundled-skills/maggie-service-booking/SKILL.md +14 -0
- package/bundled-tools/clis/maggie_booking.py +231 -31
- package/bundled-tools/clis/maggie_contracts.py +282 -0
- package/bundled-tools/clis/maggie_dash.py +28 -6
- package/bundled-tools/clis/maggie_design.py +29 -12
- package/bundled-tools/clis/maggie_service_booking.py +50 -1
- package/bundled-tools/clis/site_audit.py +49 -0
- package/package.json +1 -1
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
# Booking host adapter contract
|
|
2
|
+
|
|
3
|
+
This is the versioned screen-level contract for `/_maggie/booking`. It extends
|
|
4
|
+
the current MaggieDash host adapter model rather than replacing it. The host
|
|
5
|
+
continues to own routes, email/password sessions, database access, provider
|
|
6
|
+
secrets, and deployment.
|
|
7
|
+
|
|
8
|
+
## 1. Route and auth rules
|
|
9
|
+
|
|
10
|
+
```text
|
|
11
|
+
Public/customer booking: host-owned public route, no admin session required
|
|
12
|
+
Manager UI: /_maggie/booking, host email/password session required
|
|
13
|
+
Manager API: /api/maggie/booking/*, same-origin session required
|
|
14
|
+
Provider webhooks: host server endpoint, provider signature required
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
The booking UI is `noindex,nofollow`. It uses the existing host-session cookie
|
|
18
|
+
and role/membership checks. Passkeys and passwordless login are not part of this
|
|
19
|
+
contract.
|
|
20
|
+
|
|
21
|
+
When the session role is `staff`, the host must return the linked Booking
|
|
22
|
+
`staffId` in the server-only session context. The repository then limits staff
|
|
23
|
+
reads and lifecycle mutations to allocations and schedule/location records
|
|
24
|
+
owned by that staff profile. A staff role without a linked profile is rejected;
|
|
25
|
+
the browser must never be allowed to choose or override this scope.
|
|
26
|
+
|
|
27
|
+
MaggieDash also ships a framework-neutral dispatcher at
|
|
28
|
+
`backend/booking/route-handler.mjs`. Hosts can inject `createBookingService`
|
|
29
|
+
plus their session lookup and verified webhook handler to obtain the complete
|
|
30
|
+
47-route mapping with common JSON parsing, idempotency, project scope, role
|
|
31
|
+
checks, correlation headers, and safe error responses. The host remains
|
|
32
|
+
responsible for the actual repository, transaction, provider verification, and
|
|
33
|
+
deployment. Validate the boundary with
|
|
34
|
+
`npm run booking:route-handler:test` before wiring framework routes.
|
|
35
|
+
|
|
36
|
+
Customer traffic uses a separate public-noindex dispatcher at
|
|
37
|
+
`backend/booking/customer-route-handler.mjs`. It does not use the manager
|
|
38
|
+
session. The host must bind the request to a tenant and apply origin/CSRF,
|
|
39
|
+
rate-limit, bot, and opaque payment-return-token controls. Its DTO and
|
|
40
|
+
notification boundary is in `backend/booking/customer-flow.mjs`.
|
|
41
|
+
|
|
42
|
+
## 2. Proposed endpoints
|
|
43
|
+
|
|
44
|
+
All JSON errors use:
|
|
45
|
+
|
|
46
|
+
```json
|
|
47
|
+
{
|
|
48
|
+
"error": "safe human-readable message",
|
|
49
|
+
"code": "stable.machine.code",
|
|
50
|
+
"correlationId": "corr_...",
|
|
51
|
+
"retryable": false
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
| ID | Method | Route | Purpose |
|
|
56
|
+
|---|---|---|---|
|
|
57
|
+
| `booking.overview.read` | GET | `/api/maggie/booking/overview.json` | KPI cards, provider health, readiness, next bookings |
|
|
58
|
+
| `booking.calendar.read` | GET | `/api/maggie/booking/calendar.json` | Day/week allocations and filters |
|
|
59
|
+
| `booking.bookings.read` | GET | `/api/maggie/booking/bookings.json` | Search and paginated booking list |
|
|
60
|
+
| `booking.booking.read` | GET | `/api/maggie/booking/bookings/{id}.json` | Detail, timeline, payments, notifications |
|
|
61
|
+
| `booking.booking.create` | POST | `/api/maggie/booking/bookings.json` | Manager-created booking |
|
|
62
|
+
| `booking.booking.transition` | POST | `/api/maggie/booking/bookings/{id}/transition.json` | Check-in, complete, cancel, no-show |
|
|
63
|
+
| `booking.booking.no-show-fee` | POST | `/api/maggie/booking/bookings/{id}/no-show-fee.json` | Explicitly charge a consented, policy-derived no-show fee |
|
|
64
|
+
| `booking.booking.reschedule` | POST | `/api/maggie/booking/bookings/{id}/reschedule.json` | Preview and apply a reschedule |
|
|
65
|
+
| `booking.availability.read` | GET | `/api/maggie/booking/availability.json` | Calculate valid slots |
|
|
66
|
+
| `booking.holds.create` | POST | `/api/maggie/booking/holds.json` | Create customer/manager hold |
|
|
67
|
+
| `booking.holds.release` | POST | `/api/maggie/booking/holds/{id}/release.json` | Release a hold explicitly |
|
|
68
|
+
| `booking.customers.read` | GET | `/api/maggie/booking/customers.json` | Search customers within scope |
|
|
69
|
+
| `booking.customer.read` | GET | `/api/maggie/booking/customers/{id}.json` | Customer profile and safe history |
|
|
70
|
+
| `booking.catalog.read` | GET | `/api/maggie/booking/catalog.json` | Services, variants, policies, readiness |
|
|
71
|
+
| `booking.catalog.write` | POST | `/api/maggie/booking/catalog.json` | Create/update catalog draft |
|
|
72
|
+
| `booking.packages.read` | GET | `/api/maggie/booking/packages.json` | Tenant-scoped prepaid treatment package catalogue |
|
|
73
|
+
| `booking.package.write` | POST | `/api/maggie/booking/packages.json` | Create/update package price, expiry, and included treatments |
|
|
74
|
+
| `booking.customer-packages.read` | GET | `/api/maggie/booking/customer-packages.json` | Read tenant/customer package balances and remaining visits |
|
|
75
|
+
| `booking.customer-package.grant` | POST | `/api/maggie/booking/customer-packages.json` | Grant a package entitlement to an existing customer |
|
|
76
|
+
| `booking.locations.read` | GET | `/api/maggie/booking/locations.json` | Tenant locations and setup state |
|
|
77
|
+
| `booking.location.write` | POST | `/api/maggie/booking/locations.json` | Create/update location configuration |
|
|
78
|
+
| `booking.staff.read` | GET | `/api/maggie/booking/staff.json` | Staff and eligibility |
|
|
79
|
+
| `booking.staff.write` | POST | `/api/maggie/booking/staff.json` | Create/update staff configuration |
|
|
80
|
+
| `booking.resources.read` | GET | `/api/maggie/booking/resources.json` | Resources and requirements |
|
|
81
|
+
| `booking.resources.write` | POST | `/api/maggie/booking/resources.json` | Create/update resource configuration |
|
|
82
|
+
| `booking.schedule.read` | GET | `/api/maggie/booking/schedule.json` | Hours, shifts, blocks, closures |
|
|
83
|
+
| `booking.schedule.write` | POST | `/api/maggie/booking/schedule.json` | Save a validated schedule change |
|
|
84
|
+
| `booking.payments.read` | GET | `/api/maggie/booking/payments.json` | Payment attempts, transactions, refunds |
|
|
85
|
+
| `booking.payment.start` | POST | `/api/maggie/booking/payments/start.json` | Start a normalized payment attempt |
|
|
86
|
+
| `booking.payment.reconcile` | POST | `/api/maggie/booking/payments/{id}/reconcile.json` | Request provider read/reconciliation |
|
|
87
|
+
| `booking.refund.start` | POST | `/api/maggie/booking/refunds.json` | Start a full or partial refund |
|
|
88
|
+
| `booking.notifications.read` | GET | `/api/maggie/booking/notifications.json` | Inspect redacted Resend delivery state |
|
|
89
|
+
| `booking.notification.replay` | POST | `/api/maggie/booking/notifications/{id}/replay.json` | Replay one dead-letter notification with an audited reason |
|
|
90
|
+
| `booking.payment-health.read` | GET | `/api/maggie/booking/payment-health.json` | Provider config and capability summary |
|
|
91
|
+
| `booking.payment-health.verify` | POST | `/api/maggie/booking/payment-health.json` | Server-side Stripe account verification; owner/manager may submit credentials once, which are encrypted at rest |
|
|
92
|
+
| `booking.settings.read` | GET | `/api/maggie/booking/settings.json` | Policy and integration settings, redacted |
|
|
93
|
+
| `booking.settings.update` | PATCH | `/api/maggie/booking/settings.json` | Save non-secret settings |
|
|
94
|
+
| `booking.audit.read` | GET | `/api/maggie/booking/audit.json` | Booking-scoped audit timeline |
|
|
95
|
+
| `booking.events.read` | GET | `/api/maggie/booking/events.json` | Outbox/reconciliation operational view |
|
|
96
|
+
| `booking.runtime.read` | GET | `/api/maggie/booking/runtime.json` | Sanitized screen/runtime evidence |
|
|
97
|
+
| `booking.provider.webhook` | POST | `/api/maggie/booking/webhooks/{provider}` | Server-only verified provider event ingress |
|
|
98
|
+
|
|
99
|
+
`booking.payment-health.verify` accepts `{ "provider": "stripe" }` for a
|
|
100
|
+
deployment-managed connection. An owner or manager may instead include
|
|
101
|
+
`secretKey` and `webhookSecret` in the same HTTPS request. The host verifies
|
|
102
|
+
the pair before sealing it with `BOOKING_TOKEN_SECRET`; the values are never
|
|
103
|
+
returned, logged, or included in the redacted payment-health response.
|
|
104
|
+
|
|
105
|
+
### Booking permission registry
|
|
106
|
+
|
|
107
|
+
The administrator-managed Team access contract exposes the complete
|
|
108
|
+
server-enforced capability list: `calendar.read`, `bookings.read`,
|
|
109
|
+
`bookings.manage`, `customers.read`, `waitlist.read`, `waitlist.manage`,
|
|
110
|
+
`catalog.read`, `catalog.manage`, `packages.read`, `packages.manage`,
|
|
111
|
+
`staff.read`, `staff.manage`, `resources.read`, `resources.manage`,
|
|
112
|
+
`schedule.read`, `schedule.manage`, `locations.read`, `locations.manage`,
|
|
113
|
+
`payments.read`, `payments.manage`, `refunds.manage`, `notifications.read`,
|
|
114
|
+
`notifications.manage`, `settings.read`, `settings.manage`, `reports.read`,
|
|
115
|
+
and `audit.read`. The UI receives the registry from `/access.json`; the route
|
|
116
|
+
handler applies it server-side, so a hidden UI control cannot grant or bypass
|
|
117
|
+
access. Owners and managers retain the full surface, while staff and finance
|
|
118
|
+
accounts require explicit capability entries.
|
|
119
|
+
|
|
120
|
+
Webhook routes are not called by the browser and should be separate from the
|
|
121
|
+
session-authenticated dashboard endpoint:
|
|
122
|
+
|
|
123
|
+
```text
|
|
124
|
+
POST /api/maggie/booking/webhooks/{provider}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Public customer routes
|
|
128
|
+
|
|
129
|
+
The eleven public routes are versioned separately in
|
|
130
|
+
`MaggieDash/contracts/booking-customer-surface-v1.json`:
|
|
131
|
+
|
|
132
|
+
| ID | Method | Route |
|
|
133
|
+
|---|---|---|
|
|
134
|
+
| `booking.public.catalog.read` | GET | `/api/maggie/booking/public/catalog.json` |
|
|
135
|
+
| `booking.public.availability.read` | GET | `/api/maggie/booking/public/availability.json?serviceVariantId={serviceVariantId}&locationId={locationId}&date={date}` |
|
|
136
|
+
| `booking.public.hold.create` | POST | `/api/maggie/booking/public/holds.json` |
|
|
137
|
+
| `booking.public.checkout.start` | POST | `/api/maggie/booking/public/checkout.json` |
|
|
138
|
+
| `booking.public.payment-return.read` | GET | `/api/maggie/booking/public/payment-return.json` |
|
|
139
|
+
| `booking.public.manage.read` | GET | `/api/maggie/booking/public/manage.json?token={token}` |
|
|
140
|
+
| `booking.public.booking-cancel` | POST | `/api/maggie/booking/public/bookings/{id}/cancel.json` |
|
|
141
|
+
| `booking.public.booking-reschedule` | POST | `/api/maggie/booking/public/bookings/{id}/reschedule.json` |
|
|
142
|
+
| `booking.public.waitlist.join` | POST | `/api/maggie/booking/public/waitlist.json` |
|
|
143
|
+
|
|
144
|
+
The public handler sets `no-store` and `X-Robots-Tag: noindex`, requires an
|
|
145
|
+
idempotency key for writes, and fails closed if the host cannot bind a tenant.
|
|
146
|
+
It returns only the redacted customer DTOs and payment-return states; a
|
|
147
|
+
redirect cannot mark a payment paid. Use the existing outbox adapter for
|
|
148
|
+
confirmation, cancellation, reschedule, and reminder email intents. The host
|
|
149
|
+
stores customer token purpose explicitly: payment-return tokens are short-lived
|
|
150
|
+
and the Resend worker uses a separate 30-day sealed `manage` token for links.
|
|
151
|
+
|
|
152
|
+
For a deterministic end-to-end public journey, run:
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
npm run booking:customer-reference-host:test
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
This wraps the reference state with the public customer dispatcher and verifies
|
|
159
|
+
hold replay, checkout-to-pending recovery, token-bound cancellation, manager
|
|
160
|
+
session isolation, and notification intents. It is test evidence, never a
|
|
161
|
+
production customer or payment host.
|
|
162
|
+
|
|
163
|
+
## 3. Response shapes
|
|
164
|
+
|
|
165
|
+
Overview:
|
|
166
|
+
|
|
167
|
+
```json
|
|
168
|
+
{
|
|
169
|
+
"date": "2026-09-20",
|
|
170
|
+
"timezone": "Europe/London",
|
|
171
|
+
"metrics": {
|
|
172
|
+
"bookings": 0,
|
|
173
|
+
"revenueMinor": 0,
|
|
174
|
+
"currency": "GBP",
|
|
175
|
+
"noShows": 0,
|
|
176
|
+
"balanceDueMinor": 0
|
|
177
|
+
},
|
|
178
|
+
"providerHealth": [],
|
|
179
|
+
"readiness": { "bookable": false, "checks": [] },
|
|
180
|
+
"nextBookings": [],
|
|
181
|
+
"correlationId": "corr_..."
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Availability:
|
|
186
|
+
|
|
187
|
+
```json
|
|
188
|
+
{
|
|
189
|
+
"query": {
|
|
190
|
+
"locationId": "loc_1",
|
|
191
|
+
"serviceVariantId": "variant_1",
|
|
192
|
+
"date": "2026-09-25",
|
|
193
|
+
"timezone": "Europe/London"
|
|
194
|
+
},
|
|
195
|
+
"slots": [
|
|
196
|
+
{
|
|
197
|
+
"startAt": "2026-09-25T09:00:00Z",
|
|
198
|
+
"endAt": "2026-09-25T10:00:00Z",
|
|
199
|
+
"localLabel": "10:00",
|
|
200
|
+
"staffIds": ["staff_1"],
|
|
201
|
+
"resourceIds": ["room_1"]
|
|
202
|
+
}
|
|
203
|
+
],
|
|
204
|
+
"warnings": [],
|
|
205
|
+
"correlationId": "corr_..."
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
Booking detail must include booking status and payment status separately, plus
|
|
210
|
+
segments, allocations, safe timeline events, payment summary, allowed actions,
|
|
211
|
+
and capability flags.
|
|
212
|
+
|
|
213
|
+
## 4. Request rules
|
|
214
|
+
|
|
215
|
+
- Mutations require a same-origin session and a role permission.
|
|
216
|
+
- Mutations require `Idempotency-Key`; missing keys return `400`.
|
|
217
|
+
- Requests carry `X-Correlation-Id` or receive a server-generated one.
|
|
218
|
+
- JSON mutating requests declare `content-type: application/json`.
|
|
219
|
+
- Server validates all IDs against tenant/location scope.
|
|
220
|
+
- Server ignores client-supplied role, amount, currency, status, and provider
|
|
221
|
+
capability claims.
|
|
222
|
+
- Mutations return the canonical persisted result, not the input echo.
|
|
223
|
+
- Errors are safe, bounded, and do not include SQL, stack traces, provider
|
|
224
|
+
secrets, or raw webhook payloads.
|
|
225
|
+
|
|
226
|
+
### Role-specific route boundary
|
|
227
|
+
|
|
228
|
+
The shared route handler enforces the coarse role boundary and any explicit
|
|
229
|
+
capabilities supplied on the session, while the host supplies the
|
|
230
|
+
session-derived tenant, location, and assignment scope:
|
|
231
|
+
|
|
232
|
+
- `staff` may read operational booking routes and transition assigned work to
|
|
233
|
+
`checked_in`, `in_progress`, `completed`, or `no_show`.
|
|
234
|
+
- `staff` must be denied payment routes, payment-health details, customer
|
|
235
|
+
directory routes, configuration writes, and all other mutations.
|
|
236
|
+
- `finance` may operate payment/refund routes and payment health, but does not
|
|
237
|
+
gain customer or configuration administration by implication.
|
|
238
|
+
- The host must filter staff results to permitted locations and assignments
|
|
239
|
+
before the service returns list or detail DTOs. The shipped PostgreSQL
|
|
240
|
+
repository applies the standard `staff_id` assignment filter; custom host
|
|
241
|
+
repositories and reporting endpoints must preserve the same invariant.
|
|
242
|
+
|
|
243
|
+
The source validator covers the coarse policy. A production host must add
|
|
244
|
+
authenticated route and browser evidence proving its narrower tenant/location
|
|
245
|
+
and assignment queries.
|
|
246
|
+
|
|
247
|
+
The MaggieDash source includes a provider-neutral service seam in
|
|
248
|
+
`backend/booking/request.mjs`, `dto.mjs`, and `service.mjs`. It is deliberately
|
|
249
|
+
repository/transaction injected: the host supplies the PostgreSQL repository,
|
|
250
|
+
session-derived project and role, clock, and provider adapter. The service
|
|
251
|
+
returns canonical DTOs and the versioned safe error object; it does not import a
|
|
252
|
+
database driver or payment SDK.
|
|
253
|
+
|
|
254
|
+
## 5. Capability and feature flags
|
|
255
|
+
|
|
256
|
+
```json
|
|
257
|
+
{
|
|
258
|
+
"booking": {
|
|
259
|
+
"nativeAvailability": true,
|
|
260
|
+
"nativeBooking": true,
|
|
261
|
+
"waitlist": true,
|
|
262
|
+
"resources": true
|
|
263
|
+
},
|
|
264
|
+
"payment": {
|
|
265
|
+
"provider": "stripe",
|
|
266
|
+
"onlinePayment": true,
|
|
267
|
+
"refunds": true,
|
|
268
|
+
"partialRefunds": true,
|
|
269
|
+
"terminal": false,
|
|
270
|
+
"savedPaymentMethod": false
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
Capabilities describe configured and verified behavior. They do not mean that
|
|
276
|
+
an SDK is installed. A missing capability must result in a safe disabled state,
|
|
277
|
+
not an invented UI action.
|
|
278
|
+
|
|
279
|
+
## 6. Conformance evidence
|
|
280
|
+
|
|
281
|
+
Add `booking.*` endpoints to a future version of the host-adapter contract and
|
|
282
|
+
capture sanitized observations with the existing `maggie dash conformance`
|
|
283
|
+
pattern. The evidence must include method, route, status, content type,
|
|
284
|
+
required fields, and `passed`, but never cookies, authorization headers,
|
|
285
|
+
provider payloads, or customer contact data.
|
|
286
|
+
|
|
287
|
+
The release gate should also verify:
|
|
288
|
+
|
|
289
|
+
- all booking screens mounted;
|
|
290
|
+
- no public booking/admin route is indexable accidentally;
|
|
291
|
+
- auth redirects work;
|
|
292
|
+
- database migration version is current;
|
|
293
|
+
- provider health is truthful;
|
|
294
|
+
- payment fixtures and webhook fixtures pass;
|
|
295
|
+
- browser screenshots have no overflow or console errors.
|
|
296
|
+
|
|
297
|
+
## 7. Local reference host
|
|
298
|
+
|
|
299
|
+
MaggieDash includes a secret-free, in-memory reference host for contract and
|
|
300
|
+
browser development. It is not a production database adapter and must never be
|
|
301
|
+
used to serve real customer or payment traffic.
|
|
302
|
+
|
|
303
|
+
From the MaggieDash source repository:
|
|
304
|
+
|
|
305
|
+
```bash
|
|
306
|
+
npm run booking:reference-host:test
|
|
307
|
+
npm run booking:reference-host -- --port 4175
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
The validator exercises all 47 endpoint IDs, required response fields,
|
|
311
|
+
email/password-session presence, project scope, role scope, idempotent replay,
|
|
312
|
+
provider webhook authentication, and fixture redaction. The local server is
|
|
313
|
+
useful for wiring a browser route before a host supplies PostgreSQL and real
|
|
314
|
+
provider adapters.
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
# ORA Wellness Booking integration audit
|
|
2
|
+
|
|
3
|
+
Date: 2026-09-21
|
|
4
|
+
Project: `/home/balalior/Dev/clients/orawellness.uk`
|
|
5
|
+
Source: MaggieDash Booking `0.2.8` plus ORA host adapter
|
|
6
|
+
|
|
7
|
+
## Short answer
|
|
8
|
+
|
|
9
|
+
The host now has the main Fresha-style foundation: manager workspace, services,
|
|
10
|
+
staff, resources, working hours, availability, holds, bookings, customer
|
|
11
|
+
tokens, Stripe payment boundary, Resend notification outbox, audit records,
|
|
12
|
+
email/password login, and separate Booking roles.
|
|
13
|
+
|
|
14
|
+
It is not production-ready yet. The remaining work is deployment evidence and
|
|
15
|
+
provider operations, not another UI shell.
|
|
16
|
+
|
|
17
|
+
The ORA `.env` currently contains a Stripe test secret under the existing
|
|
18
|
+
`ST_SECRECT_KEY` compatibility name and a publishable test key under
|
|
19
|
+
`ST_PUB_KEY`. The secret value is intentionally not recorded here. No
|
|
20
|
+
`STRIPE_WEBHOOK_SECRET` is configured yet, so the account is not considered
|
|
21
|
+
verified or connected for Booking.
|
|
22
|
+
|
|
23
|
+
Current database gate: the existing ORA application schema check passes and the
|
|
24
|
+
Booking migration dry-run passes transactionally, but the live Booking schema
|
|
25
|
+
has not been applied. The 2026-09-21 read-only preflight confirmed that the
|
|
26
|
+
core schema exists while `maggiedash_booking_allocations` and
|
|
27
|
+
`maggiedash_booking_user_roles` are still absent. The worker therefore fails
|
|
28
|
+
closed without touching production data. Do not enable the live dashboard or
|
|
29
|
+
scheduler until the owner approves the migration, verifies the backup/restore
|
|
30
|
+
path, creates the first owner, and captures runtime evidence.
|
|
31
|
+
|
|
32
|
+
## Verified in the codebase
|
|
33
|
+
|
|
34
|
+
| Capability | Evidence | State |
|
|
35
|
+
|---|---|---|
|
|
36
|
+
| Manager dashboard | `/_maggie/booking`, `_maggie/booking/booking.tsx` | Installed |
|
|
37
|
+
| Traditional authentication | `src/lib/maggie/auth.ts`, registration and login routes | Installed |
|
|
38
|
+
| Booking roles | `maggiedash_booking_user_roles`, Staff access panel, complete server-enforced capability registry for calendar/bookings/customers/waitlist/catalogue/packages/staff/resources/schedule/locations/payments/refunds/notifications/settings/reports/audit | Installed; explicit staff/finance grants and safe legacy defaults covered by BK-101 |
|
|
39
|
+
| Staff account lifecycle | Booking Staff panel creates accounts, sends Resend invitations, supports one-time password setup and password reset | Installed; real delivery/browser proof pending |
|
|
40
|
+
| Staff data scope | Linked `staff_id` passed into the server context and filtered in the repository | Installed; host migration/staging proof pending |
|
|
41
|
+
| Services/treatments | Searchable catalogue with editable service/variant details, payment policy, price, preparation/cleanup buffers, active/inactive state, manager multi-treatment appointments, public multi-treatment holds/checkout, and live service/location selectors | Installed; legacy allocation backfill and staging data verification pending |
|
|
42
|
+
| Treatment packages | Tenant-scoped manager catalogue, manager-granted entitlements, public package checkout/payment return and fully covered public customer redemption, webhook fulfillment, balance reads, expiry checks, atomic redemption, cancellation-safe package-credit restoration, guarded refunds, and package confirmation/refund Resend outbox events | Installed locally; real Stripe/DB migration, webhook, Resend, and staging delivery proof pending |
|
|
43
|
+
| Locations | Tenant-scoped Locations screen and `locations.json` route for first-location setup, timezone, locale, address, active state, and online-booking controls; public catalogue exposes all active online-booking locations | Installed; staging data verification pending |
|
|
44
|
+
| Staff/resources | Editable staff profiles, service/location assignments, bookable state, resources, capacity, resource service assignments, and overlap constraints | Installed; staging data verification pending |
|
|
45
|
+
| Calendar/availability | Day/week calendar, working hours, shifts, time off, closures, holds | Installed |
|
|
46
|
+
| Booking defaults | Settings screen edits venue timezone/currency, pauses new booking writes, and selects automatic/manual capture policy | Installed; staging policy verification pending |
|
|
47
|
+
| Stripe | Injected SDK gateway, account capability row, signed webhook boundary | Host-wired; staging proof pending |
|
|
48
|
+
| Resend | Notification outbox plus `scripts/maggie-booking-worker.mjs` dispatcher, including a separate 30-day sealed customer-manage link | Host-wired; scheduled delivery proof pending; worker waits for Booking schema |
|
|
49
|
+
| Notification operations | Tenant-scoped Notifications screen, redacted delivery-state list, and owner/manager-only dead-letter replay with reason/idempotency/audit controls | Installed; ORA validators/build passed; real delivery proof pending |
|
|
50
|
+
| Public self-booking | `/_maggie/booking/book`, catalog/location selector, location-scoped combined-duration availability, multi-treatment hold/checkout, return, token-bound segment-safe reschedule/cancel, and 30-day customer-manage history | Installed; staging proof pending |
|
|
51
|
+
| Waitlist | Public no-slot join, tenant-scoped manager queue, manual notify/cancel/priority actions, transactional conversion to a linked booking, priority/FIFO worker matching, and `booking.waitlist.available` Resend intent | Installed; explicit worker scope, real migration, scheduler, and delivery proof pending |
|
|
52
|
+
| Reports | `/reports.json` plus Booking Reports screen with period/service/staff/location breakdowns | Installed; staging data verification pending |
|
|
53
|
+
| Bookability readiness | Overview reports active location, catalogue variant, assigned bookable staff, working hours, overall bookable state, and payment capability | Installed; staging data verification pending |
|
|
54
|
+
| Customer history | Searchable tenant-scoped manager directory plus token-bound public customer-manage history with redacted appointment summaries | Installed; staging data verification pending |
|
|
55
|
+
| Schedule rules | Searchable/editable working hours, staff shifts, time off, and location closures through the audited schedule route | Installed; staging data verification pending |
|
|
56
|
+
| 24-hour reminders | Worker queues one idempotent `booking.reminder` email into the Resend outbox for each eligible confirmed booking | Installed; scheduled Resend delivery evidence pending |
|
|
57
|
+
| Payment policy and balance | Service-level full/deposit/pay-later/no-payment policy, purpose-labelled attempts, paid/balance projection, and refund projection | Installed; migration and Stripe staging evidence pending |
|
|
58
|
+
| Payment truth | Verified webhook/provider read projects payment and booking state | Implemented; Stripe event test pending |
|
|
59
|
+
| Legacy `/book` | Request-by-email flow | Kept as fallback |
|
|
60
|
+
|
|
61
|
+
## Fixes made during this audit
|
|
62
|
+
|
|
63
|
+
1. Public catalogue now returns all active online-booking locations plus a
|
|
64
|
+
backwards-compatible first `locationId`. The browser displays the tenant
|
|
65
|
+
locations, scopes availability to the selected location, and posts that
|
|
66
|
+
selected ID instead of using the fake `location-1` fallback.
|
|
67
|
+
2. Public origin and rate-limit failures now return safe 403/429 responses.
|
|
68
|
+
3. Stripe account status and capabilities are upserted into
|
|
69
|
+
`maggiedash_booking_payment_accounts`; no secret value is stored there.
|
|
70
|
+
4. Webhook records store a SHA-256 payload hash instead of using the provider
|
|
71
|
+
event ID as a misleading hash.
|
|
72
|
+
5. Customer cancellation queues the Booking notification through the same
|
|
73
|
+
Resend outbox.
|
|
74
|
+
6. Customer rescheduling now uses the same sealed token, transactional
|
|
75
|
+
allocation conflict checks, idempotent replay, and `booking.rescheduled`
|
|
76
|
+
Resend outbox path as manager rescheduling.
|
|
77
|
+
7. Customer checkout now creates a short-lived payment-return token and a
|
|
78
|
+
separate 30-day `manage` token. The Resend worker reuses or creates the
|
|
79
|
+
manage token for booking notifications without storing a raw token in the
|
|
80
|
+
outbox.
|
|
81
|
+
8. Verified payment events now project `pending_payment` to `confirmed` and
|
|
82
|
+
`paid`, or cancel failed payment bookings and release their allocations,
|
|
83
|
+
before the worker acknowledges the event. Confirmation/cancellation
|
|
84
|
+
notifications are then queued once.
|
|
85
|
+
9. Booking Staff can now create an email/password account directly, link its
|
|
86
|
+
staff profile, assign permissions, and resend a secure invitation without
|
|
87
|
+
using a separate People screen.
|
|
88
|
+
10. Added the `/_maggie/reset-password` middleware rewrite so invitation and
|
|
89
|
+
password-reset links resolve to the Astro reset page.
|
|
90
|
+
11. Added a manager Overview setup checklist that reads the existing payment
|
|
91
|
+
health response, shows Stripe status and test/live mode, and provides a
|
|
92
|
+
copyable webhook URL without exposing provider secrets.
|
|
93
|
+
12. Fixed the installed UI validator to resolve ORA's `_maggie/booking`
|
|
94
|
+
workspace instead of assuming a source-package `maggiedash/booking/src`
|
|
95
|
+
directory.
|
|
96
|
+
13. Added provider-neutral automatic waitlist matching. The worker matches one
|
|
97
|
+
eligible waiting customer per explicit service/location slot, persists the
|
|
98
|
+
offered interval, and queues an idempotent Resend notification without
|
|
99
|
+
auto-reserving the appointment.
|
|
100
|
+
14. Added the public `GET /api/maggie/booking/public/manage.json` history
|
|
101
|
+
surface. The existing 30-day Resend manage token now resolves the current
|
|
102
|
+
customer's tenant-scoped appointments through a redacted DTO; payment
|
|
103
|
+
tokens and manager credentials are not accepted by this endpoint.
|
|
104
|
+
15. Added manager multi-treatment appointments. The form can compose up to 12
|
|
105
|
+
service segments, while the host validates duration, availability, shared
|
|
106
|
+
location/currency, per-segment staff/resource allocation, and persists the
|
|
107
|
+
segments and allocations atomically with the booking.
|
|
108
|
+
16. Added public multi-treatment booking and segment-safe rescheduling. Customer
|
|
109
|
+
holds persist `segments_json`, checkout sums all treatment prices, and both
|
|
110
|
+
customer and manager rescheduling shift each segment/allocation together
|
|
111
|
+
while checking conflicts independently and preserving the total duration.
|
|
112
|
+
17. Removed install-time `location-1`/`service-1` assumptions. Catalog and
|
|
113
|
+
schedule reads now return tenant locations; manager forms derive defaults
|
|
114
|
+
from those responses, and resource writes persist service assignments.
|
|
115
|
+
18. Added tenant-scoped location management so a blank project can create its
|
|
116
|
+
first venue before configuring services, staff, resources, and schedules.
|
|
117
|
+
The same audited location contract is mirrored in ORA's installed Booking
|
|
118
|
+
workspace.
|
|
119
|
+
19. Fixed a runtime catalogue query that referenced the nonexistent
|
|
120
|
+
`service_variants.created_at` column. Variant reads now use stable existing
|
|
121
|
+
columns for ordering. Hardened the ORA initial catalogue seed so a partial
|
|
122
|
+
retry reuses matching services and upserts variants instead of creating
|
|
123
|
+
duplicate services.
|
|
124
|
+
20. Closed the treatment catalogue UI parity gap: the manager can now manage
|
|
125
|
+
every variant under a service, including duration, price, currency, and
|
|
126
|
+
active state, while preserving the existing idempotent backend write.
|
|
127
|
+
|
|
128
|
+
## Installer productization update
|
|
129
|
+
|
|
130
|
+
The MaggieDash distribution now declares an Astro host bootstrap. New Astro
|
|
131
|
+
projects can use:
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
maggie booking install --project . --confirm
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
The installer adds missing Booking routes, email/password registration/login,
|
|
138
|
+
PostgreSQL/Stripe adapter wiring, public booking route, middleware scaffold,
|
|
139
|
+
schema command, Resend worker, and `.env.maggie-booking.example`. Existing
|
|
140
|
+
host files are preserved. ORA already has host-owned versions of these files,
|
|
141
|
+
so a repeat install should preserve ORA's middleware, auth, and adapter rather
|
|
142
|
+
than overwrite them. Existing Astro middleware in either the full-context or
|
|
143
|
+
common destructured-context form now receives the idempotent rewrite block;
|
|
144
|
+
unknown middleware shapes remain fail-closed and are reported for manual review
|
|
145
|
+
before the Booking URL is exposed.
|
|
146
|
+
|
|
147
|
+
For hosts that use the installed Resend outbox and reminder worker, the CLI can
|
|
148
|
+
also generate a reviewed scheduler artifact:
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
maggie booking install --project . --confirm --bootstrap --schedule systemd
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
The command writes the systemd service/timer under `deploy/` but does not
|
|
155
|
+
enable or start it. Production still requires an approved service user,
|
|
156
|
+
migration, backup/restore, alert routing, and authenticated runtime evidence.
|
|
157
|
+
|
|
158
|
+
## Release blockers
|
|
159
|
+
|
|
160
|
+
| Priority | Work | Why it matters | Owner |
|
|
161
|
+
|---|---|---|---|
|
|
162
|
+
| P0 | Apply `maggiedash-booking-install.sql` and host role migration on staging | Current ORA database check shows core MaggieDash tables exist, but Booking and Booking-role tables are not installed | ORA deployment |
|
|
163
|
+
| P0 | Release the current MaggieDash source used by the default installer | The public `9d99de7` source is a validated `0.2.8` baseline, but the current 47-route/no-show changes remain uncommitted in the working tree | MaggieDash release owner |
|
|
164
|
+
| P0 | Configure the Stripe webhook secret and verify the existing test account; keep `BOOKING_TOKEN_SECRET` and Resend sender available | The test secret is present through `ST_SECRECT_KEY`, but signed webhook verification and connected readiness remain unavailable | ORA deployment |
|
|
165
|
+
| P0 | Run worker every minute with alerting | Holds, payment projections, and Resend delivery otherwise remain pending; `maggie booking worker-schedule` now generates the reviewed systemd/cron artifact, but host enablement and alert routing remain pending | ORA operations |
|
|
166
|
+
| P0 | Capture authenticated runtime/browser/ops evidence | Local build and reference fixtures cannot prove the real host | ORA + release owner |
|
|
167
|
+
| P1 | Run Stripe test-mode scenarios | Confirm success, failure, delayed/duplicate webhook, and refund behavior against the actual account | ORA + Stripe |
|
|
168
|
+
| P1 | Capture Resend invitation/reset evidence | Booking notifications are wired; staff account invitation and password reset now use the same server-side Resend configuration | ORA + release owner |
|
|
169
|
+
| P1 | Capture reminder delivery evidence | The worker now enqueues reminders; staging must prove scheduler timing, Resend acceptance, retry, and no duplicate send | ORA + release owner |
|
|
170
|
+
| P1 | Verify customer-manage links in real Resend emails | Staging must prove the 30-day link opens the noindex customer page and reschedule/cancel remain token-bound | ORA + release owner |
|
|
171
|
+
| P1 | Verify waitlist notification delivery and conversion workflow | Staging must prove queue scope, one-time notification behavior, Resend acceptance, conflict handling, and the linked booking/confirmation email | ORA + product owner |
|
|
172
|
+
| P1 | Switch marketing CTAs from `/book` to `/_maggie/booking/book` | Avoid sending customers to the new flow before staging proves it | Product owner |
|
|
173
|
+
| P2 | Add richer Fresha features | Package purchase/refund paths are implemented locally. Memberships, gift cards, advanced multi-location staff rules, and customer-side package/membership pricing remain roadmap items. Customer self-service history, bounded automatic waitlist matching, and segment-safe multi-treatment rescheduling still need real host delivery proof | Product roadmap |
|
|
174
|
+
|
|
175
|
+
## Evidence already run
|
|
176
|
+
|
|
177
|
+
- ORA `npm run build`: passed with no errors, warnings, or hints;
|
|
178
|
+
the Stripe setup checklist is included in the built Booking workspace.
|
|
179
|
+
- ORA `npm audit --omit=dev --audit-level=high`: passed with zero
|
|
180
|
+
vulnerabilities after refreshing the Cloudflare/Wrangler lockfile chain.
|
|
181
|
+
- ORA `maggie booking inspect --project .`: passed all installed workspace,
|
|
182
|
+
contract, schema, customer, worker, and ops checks.
|
|
183
|
+
- ORA installed UI and customer UI validators: passed after resolving the
|
|
184
|
+
`_maggie/booking` workspace path.
|
|
185
|
+
- Central and ORA Booking UI validators now also reject fixture location/service
|
|
186
|
+
IDs in the installed manager source; both copies passed.
|
|
187
|
+
- Central and ORA location configuration, service-contract, route-handler, and
|
|
188
|
+
reference-host validators now cover the 47-route manager surface; both
|
|
189
|
+
installed UI copies passed.
|
|
190
|
+
- ORA worker/runtime regression: passed for waitlist priority/FIFO matching,
|
|
191
|
+
one-time offered-slot persistence, and idempotent replay.
|
|
192
|
+
- ORA customer reference-host regression: passed public multi-treatment
|
|
193
|
+
availability, hold/checkout, and token-bound multi-treatment rescheduling;
|
|
194
|
+
the PostgreSQL core regression also passed segment-safe rescheduling.
|
|
195
|
+
- MaggieDash customer-flow, customer-UI, runtime-plan, worker-repository, and
|
|
196
|
+
syntax checks: passed.
|
|
197
|
+
- ORA `maggie booking release-gate --project .`: static contract/workspace gate
|
|
198
|
+
passed; runtime, browser, ops, and board evidence were not supplied.
|
|
199
|
+
- ORA `maggie booking setup --project .`: dependencies, database URL, public
|
|
200
|
+
URL, Booking token secret, Resend sender configuration, and a Stripe test
|
|
201
|
+
secret alias are present; the missing webhook secret keeps Stripe in pending
|
|
202
|
+
verification, while schema, first owner, and worker schedule remain explicit
|
|
203
|
+
verification steps.
|
|
204
|
+
- Full required release gate was run read-only on 2026-09-21 and correctly
|
|
205
|
+
returned `blocked` for the missing runtime, browser, ops, and unfinished-board
|
|
206
|
+
evidence. It did not run migrations, create bookings, send email, or deploy.
|
|
207
|
+
- ORA `npm run booking:schema -- --check`: `needs-migration` with core present,
|
|
208
|
+
Booking absent, and Booking access absent. This command was read-only; no
|
|
209
|
+
database migration was applied.
|
|
210
|
+
- Disposable local ORA Astro runtime: first-owner registration HTTP 201,
|
|
211
|
+
password login HTTP 200, authenticated overview/settings/catalog/staff HTTP
|
|
212
|
+
200, and public catalog HTTP 200 against a temporary PostgreSQL database.
|
|
213
|
+
This caught the variant ordering and partial-seed defects above; it is not
|
|
214
|
+
production or staging evidence.
|
|
215
|
+
- Central and ORA PostgreSQL core integrations now persist two treatment
|
|
216
|
+
variants, assert expanded allocation ranges after rescheduling, and reject a
|
|
217
|
+
buffer-overlapping adjacent booking. The reference hosts and customer
|
|
218
|
+
cursors also apply the same rule. The one-time
|
|
219
|
+
`schema/maggie-booking-buffer-backfill.sql` migration is included but still
|
|
220
|
+
needs staging/owner approval; no live ORA database was changed.
|
|
221
|
+
|
|
222
|
+
## Decision
|
|
223
|
+
|
|
224
|
+
Do not market this as a complete Fresha replacement yet. It is a valid Booking
|
|
225
|
+
foundation and installable host integration. The next safe step is staging
|
|
226
|
+
migration plus real Stripe/Resend/browser evidence, followed by a canary before
|
|
227
|
+
changing the public CTA.
|