@topy-ai/maggie 0.7.38 → 0.7.41
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 +82 -6
- package/README.md +99 -7
- package/bin/maggie.js +30 -3
- package/bundled-contracts/maggie-clone/interaction-state-v1.schema.json +26 -0
- package/bundled-contracts/maggie-content/provenance-v1.schema.json +20 -0
- package/bundled-contracts/maggie-design/brand-kit-v1.schema.json +18 -0
- package/bundled-contracts/maggie-design/browser-interactions-v1.schema.json +27 -0
- 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-design/style-editing-v1.schema.json +35 -0
- package/bundled-contracts/maggie-media/image-generation-policy-v1.json +28 -0
- package/bundled-contracts/maggie-media/video-generation-policy-v1.json +40 -0
- package/bundled-contracts/maggie-media/video-job-v1.schema.json +20 -0
- package/bundled-contracts/maggie-media/video-playback-evidence-v1.schema.json +15 -0
- package/bundled-contracts/maggie-ops/npm11-preflight-v1.schema.json +17 -0
- package/bundled-contracts/maggie-scaffold/host-scaffold-v1.schema.json +25 -0
- package/bundled-contracts/maggie-seo/gsc-readiness-v1.schema.json +19 -0
- package/bundled-contracts/maggie-seo/privacy-origin-evidence-v1.schema.json +11 -0
- package/bundled-contracts/maggie-service-booking/delivery-provider-default-v1.json +8 -0
- package/bundled-contracts/maggie-service-booking/delivery-provider-v1.schema.json +16 -0
- 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 +14 -2
- package/bundled-contracts/maggiedash/booking-runtime.v1.json +41 -0
- package/bundled-contracts/maggiedash/browser-session-v1.schema.json +18 -0
- package/bundled-contracts/maggiedash/content-overrides-v1.schema.json +19 -0
- package/bundled-contracts/maggiedash/execution-board.json +526 -26
- package/bundled-contracts/maggiedash/host-capabilities-v1.schema.json +10 -0
- package/bundled-contracts/maggiedash/public-session-cache-v1.schema.json +17 -0
- package/bundled-contracts/maggiedash/site-structure-v1.schema.json +13 -0
- package/bundled-references/browser-inspection.md +21 -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/SKILL.md +12 -0
- package/bundled-skills/maggie-blog-bootstrap/SKILL.md +39 -0
- package/bundled-skills/maggie-booking/SKILL.md +112 -18
- package/bundled-skills/maggie-clone/SKILL.md +13 -0
- package/bundled-skills/maggie-deployment/SKILL.md +6 -0
- package/bundled-skills/maggie-design/SKILL.md +64 -3
- package/bundled-skills/maggie-ops/SKILL.md +12 -0
- package/bundled-skills/maggie-seo-geo/SKILL.md +45 -0
- package/bundled-skills/maggie-service-booking/SKILL.md +14 -0
- package/bundled-tools/clis/maggie_analytics.py +43 -1
- package/bundled-tools/clis/maggie_booking.py +161 -26
- package/bundled-tools/clis/maggie_browser_audit.py +99 -3
- package/bundled-tools/clis/maggie_clone.py +46 -1
- package/bundled-tools/clis/maggie_contracts.py +393 -0
- package/bundled-tools/clis/maggie_dash.py +22 -6
- package/bundled-tools/clis/maggie_design.py +84 -12
- package/bundled-tools/clis/maggie_service_booking.py +50 -1
- package/bundled-tools/clis/maggie_workflows.py +387 -0
- package/bundled-tools/clis/site_audit.py +77 -1
- package/bundled-tools/integrations/analytics.md +14 -0
- package/bundled-tools/runtime/site_baseline.py +3 -0
- package/package.json +1 -1
- package/references/browser-inspection.md +21 -0
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"title": "MaggieDash host capability manifest",
|
|
4
|
+
"type": "object",
|
|
5
|
+
"required": ["schemaVersion", "endpoints"],
|
|
6
|
+
"properties": {
|
|
7
|
+
"schemaVersion": {"const": "maggie-host-capabilities.v1"},
|
|
8
|
+
"endpoints": {"type": "array", "minItems": 1, "items": {"type": "object", "required": ["id", "path", "enabled"]}}
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://maggiedash.noblox.app/contracts/public-session-cache-v1.schema.json",
|
|
4
|
+
"title": "MaggieDash public session cache boundary v1",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"required": ["schemaVersion", "publicHtmlVariesBySession", "sessionCookieHttpOnly", "identityHintCookieReadable", "identityRequestWhenHintAbsent"],
|
|
7
|
+
"properties": {
|
|
8
|
+
"schemaVersion": {"const": "maggie-public-session-cache.v1"},
|
|
9
|
+
"publicHtmlVariesBySession": {"const": false},
|
|
10
|
+
"sessionCookieHttpOnly": {"const": true},
|
|
11
|
+
"identityHintCookieReadable": {"const": true},
|
|
12
|
+
"identityRequestWhenHintAbsent": {"const": false},
|
|
13
|
+
"hintCookieName": {"type": "string", "minLength": 1},
|
|
14
|
+
"sessionCookieName": {"type": "string", "minLength": 1}
|
|
15
|
+
},
|
|
16
|
+
"additionalProperties": false
|
|
17
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"title": "Provider-neutral Maggie site structure",
|
|
4
|
+
"type": "object",
|
|
5
|
+
"required": ["schemaVersion", "menus", "templates", "pages", "bands"],
|
|
6
|
+
"properties": {
|
|
7
|
+
"schemaVersion": {"const": "maggie-site-structure.v1"},
|
|
8
|
+
"menus": {"type": "array"},
|
|
9
|
+
"templates": {"type": "array"},
|
|
10
|
+
"pages": {"type": "array"},
|
|
11
|
+
"bands": {"type": "array"}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -27,6 +27,27 @@ interaction states and triggers
|
|
|
27
27
|
responsive differences
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
+
Behavioral checks may be declared instead of hidden in a bespoke script. The
|
|
31
|
+
manifest is safe to commit because input values are not copied into evidence:
|
|
32
|
+
|
|
33
|
+
```json
|
|
34
|
+
{
|
|
35
|
+
"schemaVersion": "maggie-browser-interactions.v1",
|
|
36
|
+
"steps": [
|
|
37
|
+
{"id": "open", "action": "click", "selector": "[data-menu]"},
|
|
38
|
+
{"id": "visible", "action": "assert-visible", "selector": "[data-drawer]"},
|
|
39
|
+
{"id": "styles", "action": "assert-style", "selector": "[data-drawer]", "property": "display", "value": "block"},
|
|
40
|
+
{"id": "privacy", "action": "assert-no-request", "origin": "third-party.example"}
|
|
41
|
+
]
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Run it with `maggie browser-audit ... --interactions .maggie/interactions.json`.
|
|
46
|
+
Supported actions cover click, fill, type, select, press, wait, visibility and
|
|
47
|
+
state assertions, computed-style assertions, and new-request assertions. The
|
|
48
|
+
browser adapter owns the session and the audit records only step IDs and
|
|
49
|
+
redacted outcomes.
|
|
50
|
+
|
|
30
51
|
If a target requires login, a bot challenge, a consent interaction, or a
|
|
31
52
|
private browser profile, stop at that boundary and ask the user to provide
|
|
32
53
|
authorized access. Do not bypass access controls or record cookies in project
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
# Booking workspace architecture
|
|
2
|
+
|
|
3
|
+
This document explains the boundary between MaggieDash, the host project, the
|
|
4
|
+
booking domain, and external providers. The manager workspace, distribution
|
|
5
|
+
manifest, starter schema, versioned contracts, reference host, PostgreSQL
|
|
6
|
+
seams, Stripe boundary, Resend outbox, and Astro host scaffold are implemented
|
|
7
|
+
locally. Production credentials, migrations, scheduler enablement, and
|
|
8
|
+
real-host evidence remain the host integration boundary.
|
|
9
|
+
|
|
10
|
+
## 1. Current boundary and target boundary
|
|
11
|
+
|
|
12
|
+
### Current, verified in repository
|
|
13
|
+
|
|
14
|
+
- MaggieDash installs its React source into `./_maggie/admin`.
|
|
15
|
+
- The host owns the framework route, email/password session, database,
|
|
16
|
+
`/api/maggie/*` endpoints, provider credential boundary, and deployment.
|
|
17
|
+
Stripe may come from the deployment secret store or the owner/manager-only
|
|
18
|
+
dashboard setup path, where it is verified before authenticated encryption;
|
|
19
|
+
raw credentials never cross into the public browser bundle.
|
|
20
|
+
- The dashboard uses `/api/maggie` and a versioned host adapter contract.
|
|
21
|
+
- `maggie-service-booking` imports and validates provider-owned service data. It
|
|
22
|
+
does not claim live booking mutation or availability when provider evidence is
|
|
23
|
+
missing.
|
|
24
|
+
- The shared PostgreSQL starter schema covers projects, users, memberships,
|
|
25
|
+
sessions, documents, media, section presets, and audit events.
|
|
26
|
+
- MaggieDash distributes a sibling `./_maggie/booking` workspace with overview,
|
|
27
|
+
calendar, booking, customer, catalogue, staff, resource, payment, settings,
|
|
28
|
+
and audit screens.
|
|
29
|
+
- The Booking host adapter v1, provider-neutral starter schema, runtime worker,
|
|
30
|
+
reference host, and Astro host wiring are shipped with the distribution; the
|
|
31
|
+
host still supplies production database/provider credentials and evidence.
|
|
32
|
+
|
|
33
|
+
### Host runtime extension
|
|
34
|
+
|
|
35
|
+
The first-party Booking workspace is installed under `/_maggie/booking`. It shares
|
|
36
|
+
the host session, project identity, design primitives, HTTP transport, audit
|
|
37
|
+
conventions, and runtime evidence model with `/_maggie/admin`, but owns booking
|
|
38
|
+
screens and booking-specific API contracts.
|
|
39
|
+
|
|
40
|
+
The two workspaces should be siblings, not one huge admin screen:
|
|
41
|
+
|
|
42
|
+
```text
|
|
43
|
+
/_maggie/admin content, SEO, media, AI operations, project settings
|
|
44
|
+
/_maggie/booking calendar, bookings, customers, services, staff, payments
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Both routes may import shared UI primitives, but booking must not reach into
|
|
48
|
+
content-specific tables or assume that a provider page is a transactional
|
|
49
|
+
booking record.
|
|
50
|
+
|
|
51
|
+
## 2. Runtime topology
|
|
52
|
+
|
|
53
|
+
```text
|
|
54
|
+
Browser
|
|
55
|
+
|
|
|
56
|
+
| email/password host session cookie
|
|
57
|
+
v
|
|
58
|
+
Host framework route
|
|
59
|
+
|-- /_maggie/admin -> MaggieDash admin UI
|
|
60
|
+
|-- /_maggie/booking -> MaggieDash booking UI
|
|
61
|
+
|-- /api/maggie/* -> host adapter endpoints
|
|
62
|
+
|-- /api/maggie/booking/*-> booking adapter endpoints
|
|
63
|
+
|
|
|
64
|
+
| server-only
|
|
65
|
+
v
|
|
66
|
+
Booking application services
|
|
67
|
+
|-- catalog
|
|
68
|
+
|-- availability
|
|
69
|
+
|-- holds and allocation
|
|
70
|
+
|-- booking lifecycle
|
|
71
|
+
|-- payment orchestration
|
|
72
|
+
|-- customer and consent
|
|
73
|
+
|-- notifications and outbox
|
|
74
|
+
|-- audit and reporting
|
|
75
|
+
|
|
|
76
|
+
+--> PostgreSQL: business truth
|
|
77
|
+
+--> PaymentGateway: Stripe first, others later
|
|
78
|
+
+--> Email/SMS adapters
|
|
79
|
+
+--> Calendar adapters, optional
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
The browser receives normalized DTOs and capability flags. It does not receive
|
|
83
|
+
database connections, Stripe secret keys, raw provider objects, or unrestricted
|
|
84
|
+
agent tools.
|
|
85
|
+
|
|
86
|
+
## 3. Logical modules
|
|
87
|
+
|
|
88
|
+
| Module | Owns | Must not own |
|
|
89
|
+
|---|---|---|
|
|
90
|
+
| Tenant and access | project, tenant, location scope, role checks | provider credential values |
|
|
91
|
+
| Catalog | services, variants, treatment packages, provider facts | availability decisions, customer balances |
|
|
92
|
+
| Schedule | opening hours, shifts, time off, blocks, closures | payment status |
|
|
93
|
+
| Resource | rooms, equipment, capacity, requirements | customer identity |
|
|
94
|
+
| Availability | candidate slots, exclusion reasons, holds | gateway-specific objects |
|
|
95
|
+
| Booking | booking, segments, transitions, reschedules, cancellation | card data |
|
|
96
|
+
| Payment | attempts, transactions, refunds, reconciliation | staff schedules |
|
|
97
|
+
| Customer | contact, consent, notes, booking history, package entitlements | raw payment method |
|
|
98
|
+
| Notification | durable events, templates, delivery attempts | booking truth mutation |
|
|
99
|
+
| Reporting | read models, daily totals, utilization, reconciliation | source-of-truth writes |
|
|
100
|
+
| Audit | append-only actor/action/reason trail | secret or full payload storage |
|
|
101
|
+
| Provider adapters | translate external APIs and events | canonical business rules |
|
|
102
|
+
|
|
103
|
+
## 4. Source-of-truth rules
|
|
104
|
+
|
|
105
|
+
| Question | Source of truth | Why |
|
|
106
|
+
|---|---|---|
|
|
107
|
+
| Does a slot conflict? | PostgreSQL allocation constraints plus availability service | UI checks alone race |
|
|
108
|
+
| Is a booking confirmed? | Booking state machine in PostgreSQL | Gateway success is not a booking transition |
|
|
109
|
+
| Did money settle? | Verified gateway event or provider read, projected into payment tables | Redirects can be abandoned or forged |
|
|
110
|
+
| What did the manager change? | Audit events and booking events | Support needs actor and reason |
|
|
111
|
+
| What can a provider do? | Provider capability declaration and health result | UI must fail closed |
|
|
112
|
+
| What does the customer see? | Host-rendered booking/public DTO | External provider UI is not the product contract |
|
|
113
|
+
| What is a service fact? | Approved catalogue provenance | AI copy must not invent price, duration, or URL |
|
|
114
|
+
|
|
115
|
+
## 5. Request and command flow
|
|
116
|
+
|
|
117
|
+
Every mutating request follows this shape:
|
|
118
|
+
|
|
119
|
+
1. Resolve the host session and project/tenant scope.
|
|
120
|
+
2. Authorize the action against role, location, and object ownership.
|
|
121
|
+
3. Validate the request DTO and idempotency key.
|
|
122
|
+
4. Load current state and required policy version.
|
|
123
|
+
5. Apply a transaction with database constraints.
|
|
124
|
+
6. Append a domain event and audit event in the same transaction where possible.
|
|
125
|
+
7. Commit an outbox record for notifications, provider side effects, and reports.
|
|
126
|
+
8. Return the canonical result plus `correlationId`, current state, and safe
|
|
127
|
+
next actions.
|
|
128
|
+
|
|
129
|
+
External side effects are not allowed to decide whether the local booking
|
|
130
|
+
transaction commits. A worker handles retries and reconciliation.
|
|
131
|
+
|
|
132
|
+
## 6. Booking allocation strategy
|
|
133
|
+
|
|
134
|
+
The availability query produces candidates. The hold or booking command takes
|
|
135
|
+
the final allocation lock. The database must reject overlapping active
|
|
136
|
+
allocations for a staff member or resource within the same tenant and location.
|
|
137
|
+
|
|
138
|
+
For PostgreSQL, the implementation should evaluate an exclusion constraint over
|
|
139
|
+
a range built from `start_at` and `end_at`, with an explicit status predicate
|
|
140
|
+
for active holds/bookings. The exact migration must be reviewed against the
|
|
141
|
+
host's PostgreSQL version and tenancy model before implementation.
|
|
142
|
+
|
|
143
|
+
Application checks remain useful for good error messages, but they are not the
|
|
144
|
+
correctness boundary.
|
|
145
|
+
|
|
146
|
+
## 7. Time and money
|
|
147
|
+
|
|
148
|
+
- Persist instants as `timestamptz` or an equivalent UTC representation.
|
|
149
|
+
- Persist the venue IANA timezone on the location and copy the resolved
|
|
150
|
+
timezone/fold into booking input evidence.
|
|
151
|
+
- Reject nonexistent local times during DST transitions.
|
|
152
|
+
- Require an explicit fold for ambiguous local times.
|
|
153
|
+
- Persist amount in integer minor units and a three-letter ISO currency.
|
|
154
|
+
- Never derive money from a formatted display string.
|
|
155
|
+
- Store the policy, tax, discount, and rounding decisions used for the booking.
|
|
156
|
+
|
|
157
|
+
## 8. Provider-neutral payment boundary
|
|
158
|
+
|
|
159
|
+
Booking services depend on the interface described in
|
|
160
|
+
[PAYMENT-GATEWAY.md](./PAYMENT-GATEWAY.md). The first implementation is
|
|
161
|
+
`StripePaymentGateway`. It translates local payment intents into Stripe
|
|
162
|
+
PaymentIntents, SetupIntents, refunds, or Terminal operations as configured.
|
|
163
|
+
|
|
164
|
+
The local `payment_attempts`, `payment_transactions`, and `payment_webhook_events`
|
|
165
|
+
tables remain the system's reconciliation record. A Stripe object ID is an
|
|
166
|
+
external reference, never the only local payment record.
|
|
167
|
+
|
|
168
|
+
## 9. Failure isolation
|
|
169
|
+
|
|
170
|
+
The UI and write API must distinguish:
|
|
171
|
+
|
|
172
|
+
- configuration missing;
|
|
173
|
+
- provider unavailable;
|
|
174
|
+
- payment action required;
|
|
175
|
+
- payment failed;
|
|
176
|
+
- webhook pending;
|
|
177
|
+
- reconciliation pending;
|
|
178
|
+
- booking conflict;
|
|
179
|
+
- notification failed;
|
|
180
|
+
- permission denied.
|
|
181
|
+
|
|
182
|
+
One failed email or analytics delivery must not roll back a confirmed booking.
|
|
183
|
+
One failed payment read must not mark a captured payment as failed. One
|
|
184
|
+
provider timeout must not cause a second charge without an explicit new payment
|
|
185
|
+
attempt and idempotency key.
|
|
186
|
+
|
|
187
|
+
## 10. Route integration
|
|
188
|
+
|
|
189
|
+
Astro currently rewrites underscore-prefixed dashboard filesystem paths once in
|
|
190
|
+
middleware because Astro excludes those segments. The booking adapter should
|
|
191
|
+
follow the same rule:
|
|
192
|
+
|
|
193
|
+
```text
|
|
194
|
+
/_maggie/booking -> /maggie/booking
|
|
195
|
+
/_maggie/booking/* -> /maggie/booking/*
|
|
196
|
+
/_maggie/booking/book -> public host route using the customer page starter
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
The manager URL stays `/_maggie/booking`; the internal route must not rewrite
|
|
200
|
+
to itself. The manager page is server-rendered only for the shell, carries
|
|
201
|
+
`noindex`, and redirects unauthenticated users to the host login. The optional
|
|
202
|
+
customer page is `/_maggie/booking/book`; it is public/noindex and must use the
|
|
203
|
+
host's separate tenant-bound public API policy.
|
|
204
|
+
|
|
205
|
+
## 11. Extension points
|
|
206
|
+
|
|
207
|
+
The design intentionally leaves these ports stable:
|
|
208
|
+
|
|
209
|
+
- `PaymentGateway`: Stripe, Square, Adyen, Mollie, or a future provider;
|
|
210
|
+
- `NotificationProvider`: email, SMS, WhatsApp, push;
|
|
211
|
+
- `CalendarProvider`: internal calendar, Google, Outlook, or none;
|
|
212
|
+
- `BookingProvider`: local transactional engine, or a provider link for
|
|
213
|
+
projects that have not enabled native booking;
|
|
214
|
+
- `MediaStorageProvider`: the existing provider-neutral media contract;
|
|
215
|
+
- `AnalyticsSink`: local event/outbox consumer, never a booking dependency.
|
|
216
|
+
|
|
217
|
+
Provider-specific metadata is namespaced and stored as external references.
|
|
218
|
+
Canonical booking state, amount, and lifecycle remain provider-neutral.
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# MaggieDash Booking current state and gaps
|
|
2
|
+
|
|
3
|
+
Status: current snapshot, 2026-09-21
|
|
4
|
+
|
|
5
|
+
This is the canonical status document for the Booking implementation. The
|
|
6
|
+
append-only [`PROGRESS.md`](./PROGRESS.md) keeps historical counts and decisions
|
|
7
|
+
from earlier delivery turns; those historical values must not be read as the
|
|
8
|
+
current contract.
|
|
9
|
+
|
|
10
|
+
## Verified implementation surface
|
|
11
|
+
|
|
12
|
+
| Surface | Current state | Authoritative evidence |
|
|
13
|
+
|---|---|---|
|
|
14
|
+
| MaggieDash source | Package `0.2.9`, with host capability, site-structure, and treatment-group contracts; the working tree contains the current Booking release changes | `/home/balalior/Dev/MaggieDash/package.json`, `maggiedash.json`, `git status` |
|
|
15
|
+
| Manager host contract | 47 endpoint IDs, email/password session, server-side role/capability checks | `MaggieDash/contracts/booking-host-adapter-v1.json` |
|
|
16
|
+
| Public customer contract | 11 endpoint IDs, separate noindex/no-store boundary and token policy | `MaggieDash/contracts/booking-customer-surface-v1.json` |
|
|
17
|
+
| Booking access contract | 4 administrator-only access endpoints, staff/manager/finance roles and granular permissions | `MaggieDash/contracts/booking-access-v1.json` |
|
|
18
|
+
| Resend template contract | 10 tenant-scoped events, allowlisted variables, preview/publish/rollback and server-only recipient/provider data | `MaggieDash/contracts/booking-email-templates-v1.json` |
|
|
19
|
+
| Browser evidence contract | 15 manager routes × 3 viewports = 45 screens | `MaggieDash/contracts/booking-browser-evidence-v1.json` |
|
|
20
|
+
| Execution board | 87 tasks: 84 `passed`, 3 `needs-evidence` (`BK-030`, `BK-031`, `BK-032`) | [`EXECUTION-BOARD.json`](./EXECUTION-BOARD.json) |
|
|
21
|
+
| Local regression | AI-CMO Python suite: 364 tests passed; MaggieDash `npm test`, ORA contract checks, and ORA Astro build passed | recorded in the current verification output and [`PROGRESS.md`](./PROGRESS.md) |
|
|
22
|
+
|
|
23
|
+
## What is implemented locally
|
|
24
|
+
|
|
25
|
+
- Traditional email/password owner registration, login, staff invitations,
|
|
26
|
+
password reset, revocation, disabled-account protection, and server-enforced
|
|
27
|
+
granular Booking permissions.
|
|
28
|
+
- Tenant-scoped locations, services/variants, treatment packages, customer
|
|
29
|
+
entitlements, staff, resources, schedules, closures, buffers, availability,
|
|
30
|
+
holds, multi-treatment bookings, rescheduling, cancellation, waitlist, and
|
|
31
|
+
customer-manage history.
|
|
32
|
+
- Provider-neutral payment orchestration plus the Stripe adapter seam,
|
|
33
|
+
PaymentIntent saved-method flow, SetupIntent setup-only flow, Stripe Customer
|
|
34
|
+
mapping, webhook normalization, refunds, package purchase/refund settlement,
|
|
35
|
+
and explicit consented no-show fee charging.
|
|
36
|
+
- Resend outbox delivery, ten event templates, invitations, reminders,
|
|
37
|
+
customer-manage links, waitlist/package/refund/no-show notification intents,
|
|
38
|
+
retry, dead-letter, and audited replay.
|
|
39
|
+
- PostgreSQL repository seams, schema/preflight tooling, worker scheduling
|
|
40
|
+
artifacts, reference-host validators, runtime/browser/ops evidence contracts,
|
|
41
|
+
and the ai-cmo-skills installer/inspect/release gates.
|
|
42
|
+
|
|
43
|
+
“Implemented locally” means source, contract, fixture, and local/reference-host
|
|
44
|
+
evidence exist. It does not mean a production tenant has been migrated or that
|
|
45
|
+
provider delivery has been proven on the live host.
|
|
46
|
+
|
|
47
|
+
## Open gaps
|
|
48
|
+
|
|
49
|
+
| Priority | Gap | Current evidence | Exit evidence |
|
|
50
|
+
|---|---|---|---|
|
|
51
|
+
| P0 | ORA Booking schema and access tables are not installed in the configured database | Read-only schema check reported `needs-migration`; core exists, Booking/access tables do not | Owner-approved backup/restore rehearsal, then `node scripts/maggie-booking-schema.mjs --apply --confirm` and a post-migration check |
|
|
52
|
+
| P0 | Stripe test account is not fully verified for Booking | ORA `.env` has the existing `ST_SECRECT_KEY` test secret alias and `ST_PUB_KEY`; `STRIPE_WEBHOOK_SECRET` is absent | Add webhook signing secret, run the authenticated **Verify Stripe connection** action, and capture signed success/failure/delayed/duplicate/refund/no-show test evidence |
|
|
53
|
+
| P0 | Worker and alerting are not enabled on the real host | systemd/cron artifacts are generated, but no host schedule, lock, alert route, or recovery evidence has been supplied | Enable one scheduler, run a disposable/staging worker cycle, prove lock/retry/dead-letter/recovery alerts, and retain sanitized ops evidence |
|
|
54
|
+
| P0 | Real-host runtime and browser conformance is missing | Reference-host, fixture, and local build evidence pass; no authenticated HTTPS runtime/browser artifact exists | Run all 47 manager endpoints and all 45 browser screens against a dedicated staging/test tenant, then pass `release-gate --require-runtime --require-browser --require-ops` |
|
|
55
|
+
| P1 | Published npm package is behind the current Booking contracts | Local AI-CMO package source is `0.7.40`; publish and registry readback are the remaining release actions | Verify the installed public tarball, and rerun `maggie booking inspect` against ORA |
|
|
56
|
+
| P1 | ORA staging data and legacy allocation backfill need approval | `maggie-booking-buffer-backfill.sql` is present but not applied; active locations/catalogue/staff/schedule/payment policy still need real data verification | Apply the reviewed additive/backfill migration in staging, seed a test location/catalogue/staff schedule, and prove readiness plus conflict behavior |
|
|
57
|
+
| P1 | End-to-end Resend delivery is unproven | Outbox/worker code and validators pass, but invitation, reset, reminder, waitlist, package, refund, and no-show messages have not been observed in a staging mailbox | Capture redacted delivery, retry, dead-letter, replay, and duplicate-suppression evidence |
|
|
58
|
+
| P1 | Release/canary ownership is incomplete | `BK-032` remains `needs-evidence`; no final release artifact or canary report is recorded | Produce the board-complete release report, rollback rehearsal, canary window, and feedback closure |
|
|
59
|
+
| P2 | Product scope remains intentionally narrower than Fresha | Memberships, gift-card ledger, recurring appointments, SMS/WhatsApp, tax/accounting, advanced waitlist optimization, and multi-provider production adapters are not in v1 | Create separate contracts/PRDs before promising these capabilities |
|
|
60
|
+
|
|
61
|
+
## Required host sequence
|
|
62
|
+
|
|
63
|
+
1. Back up the database and rehearse restore into an empty disposable target.
|
|
64
|
+
2. Apply the Booking and access migrations with explicit owner approval.
|
|
65
|
+
3. Register the first owner and verify staff/role boundaries.
|
|
66
|
+
4. Configure Stripe test secret plus webhook secret and verify capabilities.
|
|
67
|
+
5. Configure and test the Resend worker and one scheduler with alerting.
|
|
68
|
+
6. Seed a staging location, service variants, bookable staff, hours, and policy.
|
|
69
|
+
7. Capture runtime, browser, and ops evidence; run the final release gate.
|
|
70
|
+
8. Canary one location, monitor conflicts/payments/outbox, then decide whether to
|
|
71
|
+
enable public booking.
|
|
72
|
+
|
|
73
|
+
## Re-audit commands
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
# ai-cmo-skills
|
|
77
|
+
python3 -m unittest discover -s tools/tests -p 'test_*.py'
|
|
78
|
+
python3 tools/clis/maggie_booking.py tasks validate
|
|
79
|
+
|
|
80
|
+
# MaggieDash
|
|
81
|
+
npm test
|
|
82
|
+
node scripts/validate-booking-service-contract.mjs
|
|
83
|
+
node scripts/validate-booking-host-contract.mjs
|
|
84
|
+
|
|
85
|
+
# ORA host (read-only checks)
|
|
86
|
+
npm run contract:check
|
|
87
|
+
npm run build
|
|
88
|
+
npm run booking:schema -- --check
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Do not put Stripe, Resend, database, session, or customer secrets into this
|
|
92
|
+
document or into evidence artifacts.
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# Booking data flow
|
|
2
|
+
|
|
3
|
+
This document defines the system's data-flow boundaries. The rendered diagrams
|
|
4
|
+
are linked images so they work in GitHub even when Mermaid rich display is
|
|
5
|
+
unavailable.
|
|
6
|
+
|
|
7
|
+
## Level 0: context
|
|
8
|
+
|
|
9
|
+

|
|
10
|
+
|
|
11
|
+
[Open Mermaid source](./diagrams/system-context.mmd) · [PNG](./diagrams/system-context.png)
|
|
12
|
+
|
|
13
|
+
External actors exchange normalized commands, facts, and events with the
|
|
14
|
+
Booking application. The browser never talks directly to Stripe with a secret
|
|
15
|
+
or writes the database.
|
|
16
|
+
|
|
17
|
+
## Level 1: booking DFD
|
|
18
|
+
|
|
19
|
+

|
|
20
|
+
|
|
21
|
+
[Open Mermaid source](./diagrams/booking-dfd.mmd) · [PNG](./diagrams/booking-dfd.png)
|
|
22
|
+
|
|
23
|
+
### Flow descriptions
|
|
24
|
+
|
|
25
|
+
| Flow | Producer | Consumer | Data | Trust rule |
|
|
26
|
+
|---|---|---|---|---|
|
|
27
|
+
| `availability.query` | booking UI/public page | availability service | service, location, date, preferences | Treat all client values as untrusted; public response uses the customer DTO |
|
|
28
|
+
| `hold.create` | booking UI/public page/manager UI | booking service | candidate allocation, customer, policy version, idempotency key | Recheck availability inside transaction; public route is tenant-bound and rate-limited |
|
|
29
|
+
| `payment.start` | booking service | payment adapter | local payment attempt, amount, currency, return context | Provider receives only normalized payment request |
|
|
30
|
+
| `payment.event` | payment provider | webhook endpoint | signed provider event | Verify signature and deduplicate before projection |
|
|
31
|
+
| `booking.confirmed` | booking transaction | outbox consumers | local booking ID and safe facts | Notifications do not mutate booking truth; public customer intent is allowlisted |
|
|
32
|
+
| `package.grant` | manager dashboard | booking service | customer, package, quantities, expiry, idempotency key | Grant is tenant-scoped and audited; it is not a payment confirmation |
|
|
33
|
+
| `package.redeem` | manager or public customer booking transaction | entitlement ledger | booking, customer-bound matching service variants, quantities | Lock entitlement and item rows; tenant/customer binding and decrement happen in the same transaction as the booking |
|
|
34
|
+
| `package.redeem.reverse` | successful manager or eligible customer cancellation | entitlement ledger | booking, active redemption rows, cancellation reason | Lock the redemption/item rows; restore each quantity once, mark the ledger row reversed, and keep no-show/completed debits |
|
|
35
|
+
| `no_show_fee.charge` | authorized manager/finance action | Stripe adapter and payment repository | no-show booking, policy amount, saved method, explicit confirmation | Require customer consent, saved provider method, verified off-session capability, and idempotency; never charge on status transition |
|
|
36
|
+
| `notification.delivery` | notification worker | email/SMS provider | rendered message and delivery key | Failure is retryable and non-blocking |
|
|
37
|
+
| `audit.append` | command/event transaction | audit store and activity UI | actor, action, entity, reason, correlation ID | Redact secrets and customer-sensitive payloads |
|
|
38
|
+
| `report.project` | reporting worker | manager dashboard | aggregate counts and money totals | Derived data can be rebuilt |
|
|
39
|
+
|
|
40
|
+
The implemented provider-neutral command layer sits between the HTTP adapter
|
|
41
|
+
and the transaction boundary. It normalizes local wall time with an explicit
|
|
42
|
+
IANA timezone/fold, checks every segment against active allocations, then
|
|
43
|
+
returns the booking/hold mutation together with event and audit intent. A host
|
|
44
|
+
must persist that result atomically; the command layer does not bypass the
|
|
45
|
+
database overlap constraints.
|
|
46
|
+
|
|
47
|
+
## Level 2: paid booking sequence
|
|
48
|
+
|
|
49
|
+

|
|
50
|
+
|
|
51
|
+
[Open Mermaid source](./diagrams/payment-sequence.mmd) · [PNG](./diagrams/payment-sequence.png)
|
|
52
|
+
|
|
53
|
+
The sequence has two independent confirmations:
|
|
54
|
+
|
|
55
|
+
1. The local database confirms the allocation and booking transition.
|
|
56
|
+
2. The provider confirms the money state through a verified event or a provider
|
|
57
|
+
read.
|
|
58
|
+
|
|
59
|
+
The final local transition joins those facts transactionally. A provider
|
|
60
|
+
redirect only starts reconciliation; it cannot complete the transition alone.
|
|
61
|
+
|
|
62
|
+
An ordinary paid booking may save a method through
|
|
63
|
+
`setup_future_usage=off_session`. A later no-show fee is a separate explicit
|
|
64
|
+
adjustment: the no-show transition produces review state, and only an
|
|
65
|
+
authorized manager/finance command can request the off-session charge. A
|
|
66
|
+
successful charge is persisted and then queues `payment.no_show_fee` through
|
|
67
|
+
the Resend outbox; pending or failed results remain operator-visible.
|
|
68
|
+
|
|
69
|
+
## State flow
|
|
70
|
+
|
|
71
|
+

|
|
72
|
+
|
|
73
|
+
[Open Mermaid source](./diagrams/booking-state-machine.mmd) · [PNG](./diagrams/booking-state-machine.png)
|
|
74
|
+
|
|
75
|
+
Booking and payment states are separate. A confirmed booking may have a deposit
|
|
76
|
+
paid and a balance due. A cancelled booking may have a refund pending. The UI
|
|
77
|
+
must show both values.
|
|
78
|
+
|
|
79
|
+
## Event and outbox flow
|
|
80
|
+
|
|
81
|
+
```text
|
|
82
|
+
Command request
|
|
83
|
+
-> database transaction
|
|
84
|
+
-> booking / payment / allocation rows
|
|
85
|
+
-> booking event
|
|
86
|
+
-> audit event
|
|
87
|
+
-> outbox event
|
|
88
|
+
-> response
|
|
89
|
+
|
|
90
|
+
Outbox worker
|
|
91
|
+
-> notification adapter
|
|
92
|
+
-> provider reconciliation
|
|
93
|
+
-> analytics/read model projection
|
|
94
|
+
-> retry / dead-letter record
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
The outbox record contains a stable event ID, event type, tenant/project ID,
|
|
98
|
+
aggregate ID, correlation ID, schema version, safe payload, attempt count, next
|
|
99
|
+
attempt time, and processing state. It does not contain card details, provider
|
|
100
|
+
secrets, or raw webhook bodies.
|
|
101
|
+
|
|
102
|
+
## Consistency rules
|
|
103
|
+
|
|
104
|
+
### Strong consistency
|
|
105
|
+
|
|
106
|
+
- tenant and location authorization;
|
|
107
|
+
- allocation conflict checks;
|
|
108
|
+
- hold creation and expiry transition;
|
|
109
|
+
- booking lifecycle transition;
|
|
110
|
+
- payment/refund transaction totals;
|
|
111
|
+
- package entitlement balance and redemption ledger;
|
|
112
|
+
- idempotency-key response ownership;
|
|
113
|
+
- audit event creation for a successful material mutation.
|
|
114
|
+
|
|
115
|
+
### Eventual consistency
|
|
116
|
+
|
|
117
|
+
- email/SMS/push delivery;
|
|
118
|
+
- analytics and attribution projections;
|
|
119
|
+
- daily metrics and utilization reports;
|
|
120
|
+
- provider health snapshots;
|
|
121
|
+
- search/read-model indexes;
|
|
122
|
+
- webhook retry and reconciliation queues.
|
|
123
|
+
|
|
124
|
+
## Idempotency keys
|
|
125
|
+
|
|
126
|
+
Every external or retryable command has a scope-specific idempotency key:
|
|
127
|
+
|
|
128
|
+
```text
|
|
129
|
+
tenant:{tenantId}:booking:create:{clientKey}
|
|
130
|
+
tenant:{tenantId}:booking:{bookingId}:payment:{attemptKey}
|
|
131
|
+
tenant:{tenantId}:payment:{paymentId}:refund:{refundKey}
|
|
132
|
+
provider:{providerId}:webhook:{providerEventId}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
The key is stored with request hash, response reference, status, and expiry.
|
|
136
|
+
Reusing a key with a different request hash is a conflict, not a new action.
|
|
137
|
+
|
|
138
|
+
## Privacy boundary
|
|
139
|
+
|
|
140
|
+
Customer contact data is available only to authorized services and roles. The
|
|
141
|
+
activity screen gets a redacted summary. The dashboard never receives raw
|
|
142
|
+
webhook bodies, secret headers, card numbers, CVC, access tokens, or provider
|
|
143
|
+
credentials.
|