@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,367 @@
1
+ # Booking data model
2
+
3
+ The model is normalized around a tenant, location, service, allocation, booking,
4
+ payment, and event boundary. The exact SQL migration belongs in MaggieDash, but
5
+ this document is the contract that the migration and adapters must implement.
6
+
7
+ ## 0. MaggieDash physical mapping
8
+
9
+ The current MaggieDash schema uses the existing `maggiedash_projects` identity
10
+ as the Booking tenant. Booking tables therefore use `project_id` as the
11
+ physical tenant key rather than introducing a second `tenant_id` hierarchy.
12
+ The host resolves the authenticated email/password session through
13
+ `maggiedash_memberships` before every query and mutation. This is an intentional
14
+ MVP simplification: a future multi-brand tenancy layer may add a logical
15
+ `booking_tenants` view or bridge without changing the source-of-truth rule.
16
+
17
+ The migration includes locations, catalog, staff/resources, schedules,
18
+ customers, holds, bookings, segments, allocations, payment accounts/attempts/
19
+ transactions/refunds, package purchases/refunds, webhook events, outbox, notifications, audit, and
20
+ idempotency records. `blocks` and `closures` remain host-owned schedule
21
+ projections for this version; the current UI contract represents them through
22
+ the schedule DTO until their dedicated policy commands are implemented.
23
+
24
+ Run the source and database checks with:
25
+
26
+ ```bash
27
+ npm run booking:schema:validate
28
+ node scripts/validate-booking-schema.mjs \
29
+ --database-url "$DATABASE_URL" --confirm
30
+ ```
31
+
32
+ The second command is an explicitly mutating migration check and must only be
33
+ used against a disposable or approved migration-test database.
34
+
35
+ ## 1. Entity map
36
+
37
+ ```text
38
+ Tenant
39
+ -> Location
40
+ -> UserMembership
41
+ -> Staff
42
+ -> Service -> ServiceVariant
43
+ -> Resource -> ServiceResourceRequirement
44
+ -> AvailabilityRule / Shift / TimeOff / Block / Closure
45
+ -> Customer
46
+ -> Booking -> BookingSegment -> Allocation
47
+ -> CustomerPackageEntitlement -> PackageRedemption
48
+ -> PackagePurchase -> PackagePurchaseRefund
49
+ -> PaymentAttempt -> PaymentTransaction -> Refund
50
+ -> PaymentWebhookEvent
51
+ -> Notification / OutboxEvent / AuditEvent
52
+ ```
53
+
54
+ ## 2. Core entities
55
+
56
+ ### Tenant and access
57
+
58
+ `booking_tenants` extends or references the existing MaggieDash project identity.
59
+ Every booking-owned table carries `tenant_id`; location-scoped records also
60
+ carry `location_id` where the query boundary needs it.
61
+
62
+ ```text
63
+ booking_tenants
64
+ id, project_id, name, default_timezone, default_currency, status
65
+
66
+ booking_memberships
67
+ tenant_id, user_id, role, location_scope_json, status
68
+ ```
69
+
70
+ Use the existing host email/password session. Do not create a second login
71
+ system in the booking bundle.
72
+
73
+ ### Locations
74
+
75
+ ```text
76
+ booking_locations
77
+ id, tenant_id, name, slug, timezone, locale, currency
78
+ address_json, phone, active, booking_enabled
79
+ created_at, updated_at
80
+ ```
81
+
82
+ `timezone` is an IANA identifier such as `Europe/London`. It is not a browser
83
+ offset or a fixed `+01:00` string.
84
+
85
+ ### Catalog
86
+
87
+ ```text
88
+ booking_services
89
+ id, tenant_id, category_id, name, description
90
+ booking_enabled, online_booking_enabled, status
91
+ default_duration_minutes, default_amount_minor, currency
92
+ buffer_before_minutes, buffer_after_minutes
93
+ processing_minutes, finishing_minutes
94
+ cancellation_policy_json, deposit_policy_json
95
+ source_provider, source_record_id, source_url, source_revision
96
+ created_at, updated_at
97
+
98
+ booking_service_variants
99
+ id, service_id, name, duration_minutes
100
+ amount_minor, currency, active, sort_order
101
+ provider_variant_id, source_json
102
+
103
+ booking_staff_services
104
+ tenant_id, staff_id, service_id, location_id
105
+ duration_override_minutes, amount_override_minor, currency_override
106
+ active
107
+ ```
108
+
109
+ Imported provider facts should map to the existing universal service catalogue
110
+ or an explicit bridge table. AI-generated copy is not a source of price,
111
+ duration, provider ID, or booking URL.
112
+
113
+ ### Treatment packages and customer entitlements
114
+
115
+ The package catalogue and a customer's prepaid entitlement are separate
116
+ aggregates. A package definition is reusable; an entitlement is tenant-scoped
117
+ to one customer and records the granted balance, expiry, source, and audit
118
+ history.
119
+
120
+ ```text
121
+ booking_treatment_packages
122
+ id, tenant_id, name, description, price_minor, currency
123
+ expiration_days, active, metadata_json
124
+
125
+ booking_treatment_package_items
126
+ package_id, service_variant_id, quantity, sort_order
127
+
128
+ booking_customer_packages
129
+ id, tenant_id, customer_id, package_id
130
+ status, source, purchased_at, expires_at, metadata_json
131
+
132
+ booking_customer_package_items
133
+ entitlement_id, service_variant_id
134
+ quantity_granted, quantity_redeemed
135
+
136
+ booking_package_redemptions
137
+ id, tenant_id, booking_id, entitlement_id
138
+ service_variant_id, quantity, status, created_at
139
+ reversed_at, reversal_reason, reversed_by
140
+ ```
141
+
142
+ The current release supports manager-granted entitlements, balance reads,
143
+ expiry projection, atomic redemption while creating a manager or public
144
+ customer booking, and a separate customer package purchase/refund aggregate.
145
+ Cancelling a booking reverses its active redemption rows exactly once and
146
+ restores the matching `quantity_redeemed` values in the same transaction;
147
+ completed and no-show bookings intentionally retain their debits. A reversed
148
+ ledger row is never deleted, so the package balance history remains auditable.
149
+ Public package checkout uses the same tenant-bound customer surface as
150
+ appointment checkout; Stripe webhooks or provider reads fulfill the
151
+ entitlement, while refunds are rejected after any visit has been redeemed.
152
+
153
+ ### Staff and resources
154
+
155
+ ```text
156
+ booking_staff
157
+ id, tenant_id, user_id, display_name, email, phone
158
+ role, active, bookable, commission_policy_json
159
+
160
+ booking_staff_locations
161
+ tenant_id, staff_id, location_id, active
162
+
163
+ booking_resources
164
+ id, tenant_id, location_id, name, type, capacity, active
165
+
166
+ booking_service_resource_requirements
167
+ service_id, resource_id, quantity, mode
168
+ ```
169
+
170
+ `mode` can later support exclusive, shared-capacity, or quantity-based
171
+ allocation. The MVP should implement exclusive allocation first.
172
+
173
+ ### Schedule and allocation
174
+
175
+ ```text
176
+ booking_working_hours
177
+ id, tenant_id, location_id, staff_id, weekday
178
+ start_local, end_local, timezone, active
179
+
180
+ booking_shifts
181
+ id, tenant_id, location_id, staff_id, start_at, end_at, status
182
+
183
+ booking_time_off
184
+ id, tenant_id, staff_id, start_at, end_at, reason
185
+
186
+ booking_blocks
187
+ id, tenant_id, location_id, staff_id, resource_id
188
+ start_at, end_at, reason, status
189
+
190
+ booking_closures
191
+ id, tenant_id, location_id, start_at, end_at, reason
192
+
193
+ booking_holds
194
+ id, tenant_id, location_id, customer_id
195
+ expires_at, status, idempotency_key, release_reason
196
+
197
+ booking_allocations
198
+ id, tenant_id, location_id, hold_id, booking_id, segment_id
199
+ staff_id, resource_id, start_at, end_at, status
200
+ ```
201
+
202
+ Active allocations must be protected by a database-level non-overlap rule. The
203
+ exact active statuses must be explicit in the migration and match the service
204
+ transition code.
205
+
206
+ ### Booking
207
+
208
+ ```text
209
+ booking_bookings
210
+ id, tenant_id, location_id, customer_id
211
+ status, payment_status, source, channel
212
+ start_at, end_at, timezone, timezone_fold
213
+ subtotal_minor, discount_minor, tax_minor, total_minor
214
+ currency, payment_policy_json, initial_due_minor
215
+ deposit_due_minor, paid_minor, balance_due_minor
216
+ cancellation_policy_snapshot_json
217
+ attribution_json, notes_redacted_or_policy_checked
218
+ created_by, created_at, updated_at
219
+
220
+ booking_segments
221
+ id, booking_id, service_id, variant_id
222
+ staff_id, resource_id, start_at, end_at
223
+ amount_minor, currency, duration_minutes, sort_order
224
+
225
+ booking_events
226
+ id, tenant_id, booking_id, type, from_status, to_status
227
+ actor_id, reason, correlation_id, payload_json, created_at
228
+ ```
229
+
230
+ Do not use a boolean `booked`. Booking lifecycle and payment lifecycle are
231
+ separate state machines.
232
+
233
+ ### Customer and consent
234
+
235
+ ```text
236
+ booking_customers
237
+ id, tenant_id, email, phone, name
238
+ marketing_consent, service_consent_json
239
+ provider_customer_ref, provider_payment_method_ref
240
+ notes_policy_state, created_at, updated_at
241
+
242
+ booking_customer_events
243
+ id, tenant_id, customer_id, type, source, created_at
244
+ ```
245
+
246
+ Medical, allergy, patch-test, or consultation data requires a separate consent
247
+ and retention design. It is not part of the basic customer table.
248
+
249
+ ### Payments and providers
250
+
251
+ ```text
252
+ booking_payment_accounts
253
+ id, tenant_id, provider, account_ref, mode, capabilities_json, status
254
+
255
+ booking_payment_attempts
256
+ id, tenant_id, booking_id, purpose, provider
257
+ amount_minor, currency, status, idempotency_key
258
+ external_intent_ref, client_reference, error_code_safe
259
+ created_at, updated_at
260
+
261
+ booking_payment_transactions
262
+ id, tenant_id, booking_id, attempt_id, provider
263
+ type, amount_minor, currency, external_ref
264
+ status, occurred_at, metadata_json
265
+
266
+ booking_refunds
267
+ id, tenant_id, booking_id, payment_transaction_id
268
+ amount_minor, currency, provider, external_ref, status
269
+ idempotency_key, reason, created_at, updated_at
270
+
271
+ booking_payment_webhook_events
272
+ id, tenant_id, provider, external_event_id
273
+ customer_id, provider_payment_method_ref
274
+ event_type, signature_verified, received_at, processed_at
275
+ processing_status, safe_error, payload_hash
276
+ ```
277
+
278
+ The raw provider body is not stored by default. A short-lived encrypted
279
+ quarantine or provider dashboard link may be used under a separately reviewed
280
+ retention policy.
281
+
282
+ Provider customer and payment-method values are opaque external references;
283
+ they are tenant-scoped and never exposed as raw provider objects to the
284
+ browser. Customer service consent records the `noShowFee` consent used by the
285
+ separate explicit no-show adjustment route. `adjustment` attempts are excluded
286
+ from ordinary paid/refundable booking totals and are written only after a
287
+ confirmed off-session provider result.
288
+
289
+ ### Events, notifications, and audit
290
+
291
+ ```text
292
+ booking_outbox_events
293
+ id, tenant_id, aggregate_type, aggregate_id, event_type
294
+ schema_version, correlation_id, payload_json
295
+ status, attempts, next_attempt_at, last_error_safe
296
+
297
+ booking_notifications
298
+ id, tenant_id, booking_id, waitlist_entry_id, package_purchase_id
299
+ channel, template, recipient_hash
300
+ status, idempotency_key, provider_ref, last_error_safe
301
+
302
+ booking_audit_events
303
+ id, tenant_id, actor_id, action, entity_type, entity_id
304
+ reason, correlation_id, before_summary_json, after_summary_json
305
+ created_at
306
+ ```
307
+
308
+ ## 3. State machines
309
+
310
+ ### Booking state
311
+
312
+ ```text
313
+ draft -> held -> pending_payment -> confirmed
314
+ confirmed -> checked_in -> in_progress -> completed
315
+ held -> expired
316
+ held -> cancelled
317
+ pending_payment -> payment_failed -> held | cancelled
318
+ confirmed -> rescheduled -> confirmed
319
+ confirmed -> cancelled | no_show
320
+ ```
321
+
322
+ The implementation may combine `rescheduled` into an event rather than a long-
323
+ lived status, but the old and new allocations must be auditable.
324
+
325
+ ### Payment state
326
+
327
+ ```text
328
+ not_required
329
+ requires_payment -> action_required -> processing -> paid
330
+ requires_payment -> failed
331
+ processing -> failed | paid
332
+ paid -> partially_refunded -> refunded
333
+ paid -> refund_pending -> partially_refunded | refunded | refund_failed
334
+ ```
335
+
336
+ ### Hold state
337
+
338
+ ```text
339
+ active -> converted
340
+ active -> released
341
+ active -> expired
342
+ ```
343
+
344
+ ## 4. Required constraints and indexes
345
+
346
+ - Unique `(tenant_id, slug)` for locations.
347
+ - Unique `(tenant_id, provider, provider_service_id)` for imported services.
348
+ - Unique `(tenant_id, idempotency_key, command_type)` for commands.
349
+ - Unique `(provider, external_event_id)` for webhook deduplication.
350
+ - Unique `(tenant_id, booking_id, active_attempt_sequence)` or an equivalent
351
+ local attempt sequence.
352
+ - Index bookings by tenant, location, start time, status, and customer.
353
+ - Index allocations by tenant, staff, resource, time range, and active status.
354
+ - Index outbox by tenant, status, and next attempt time.
355
+ - Database-level overlap protection for active staff/resource allocations.
356
+
357
+ ## 5. Migration order
358
+
359
+ 1. Add tenant/location/access bridge and feature flag.
360
+ 2. Add catalog, staff, resource, schedule, and policy tables.
361
+ 3. Add holds, allocations, bookings, segments, and events.
362
+ 4. Add payment accounts, attempts, transactions, refunds, and webhook events.
363
+ 5. Add treatment packages, customer entitlements, redemption ledger, outbox,
364
+ notifications, audit, and read-model indexes.
365
+ 6. Backfill only reviewed provider facts; never backfill invented availability.
366
+ 7. Run migration preflight, shadow reads, and conflict tests before enabling
367
+ writes.
@@ -0,0 +1,94 @@
1
+ # Booking decision log
2
+
3
+ This is the durable decision record for the Booking workspace. D-001, D-002,
4
+ D-007 and the v1 contract boundaries have landed in MaggieDash. The remaining
5
+ runtime decisions stay explicit until the host services and production tests
6
+ land.
7
+
8
+ ## D-001: Separate `/_maggie/booking` workspace
9
+
10
+ Status: accepted and implemented in MaggieDash
11
+
12
+ Create a separate booking workspace beside `/_maggie/admin`. Booking has a
13
+ different information architecture, permission model, operational density, and
14
+ failure vocabulary. Sharing primitives and session infrastructure is useful;
15
+ merging the screens would make the existing admin surface harder to operate.
16
+
17
+ ## D-002: PostgreSQL is business truth
18
+
19
+ Status: accepted for the starter schema; host migration pending
20
+
21
+ The local database owns tenants, catalog, schedule, availability, holds,
22
+ bookings, customers, payment projections, audit, and outbox. External providers
23
+ are sources of external facts and money state, not the local booking database.
24
+
25
+ ## D-003: Holds are first-class
26
+
27
+ Status: accepted and implemented locally; host transaction evidence pending
28
+
29
+ A selected slot is reserved before payment starts. Holds have expiry, scope,
30
+ idempotency, and release reason. This prevents two successful payments for one
31
+ allocation and gives the customer a bounded payment window.
32
+
33
+ ## D-004: Database constraints enforce allocation correctness
34
+
35
+ Status: accepted and implemented in the starter schema and repository seams;
36
+ host concurrency evidence pending
37
+
38
+ The availability UI is advisory. A database-level overlap constraint and
39
+ transactional allocation are the final double-booking guard.
40
+
41
+ ## D-005: Payment adapter, not payment logic in Booking
42
+
43
+ Status: accepted and implemented locally; live provider evidence pending
44
+
45
+ Booking uses a `PaymentGateway` port. Stripe is implemented first. This keeps
46
+ provider changes out of booking transitions, data tables, and manager screens.
47
+
48
+ ## D-006: Webhook or provider reconciliation is payment proof
49
+
50
+ Status: accepted and implemented locally; signed live webhook evidence pending
51
+
52
+ A redirect is a navigation event. A verified provider event or server-side
53
+ provider read is required before local payment projection and booking
54
+ confirmation.
55
+
56
+ ## D-007: Email/password auth stays host-owned
57
+
58
+ Status: accepted from current MaggieDash contract
59
+
60
+ MaggieDash uses the host's traditional email/password session. Booking must use
61
+ the same boundary and must not add passkeys, passwordless login, or a second
62
+ identity store.
63
+
64
+ ## D-008: Provider capability flags fail closed
65
+
66
+ Status: accepted and implemented locally; host account verification pending
67
+
68
+ If a provider does not support live availability, refunds, saved methods, or
69
+ Terminal, the UI and API do not pretend that it does. Public links remain a
70
+ safe fallback where native booking is not enabled.
71
+
72
+ ## D-009: Domain features are phased
73
+
74
+ Status: accepted phased rollout; packages and bounded waitlist are in the local
75
+ v1 slice, while memberships, gifts, loyalty, and recurring appointments remain
76
+ future modules
77
+
78
+ Ship catalog, schedule, availability, holds, booking, payment, treatment
79
+ packages, and a bounded priority/FIFO waitlist matcher before memberships,
80
+ gifts, loyalty, marketplace, and AI concierge. Advanced optimization across
81
+ multiple services, locations, and alternative staff remains a later phase. The
82
+ first proof is reliable Calendar -> Availability -> Booking -> Payment behavior.
83
+
84
+ ## Remaining decisions
85
+
86
+ 1. Which PostgreSQL versions and deployment platforms belong in the supported
87
+ production matrix?
88
+ 2. Whether future multi-location tenants need separate payment accounts per
89
+ location; v1 currently uses one tenant-scoped account.
90
+ 3. Which future module gets a separate contract first: memberships, gift cards,
91
+ recurring appointments, loyalty, or SMS/WhatsApp.
92
+
93
+ Until these are resolved, implementation should use the provider-neutral
94
+ interfaces and avoid irreversible migrations.