@odla-ai/chapter 0.25.0 → 0.25.2
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.md +42 -5
- package/dist/{chunk-ZPAJL7KG.js → chunk-AWBRQH7E.js} +7 -1
- package/dist/chunk-AWBRQH7E.js.map +1 -0
- package/dist/ui/admin/index.d.ts +3 -0
- package/dist/ui/admin/index.js +1 -1
- package/dist/ui/index.js +1 -1
- package/package.json +1 -1
- package/runbooks/adopt-existing.md +105 -31
- package/runbooks/greenfield.md +56 -9
- package/dist/chunk-ZPAJL7KG.js.map +0 -1
|
@@ -49,8 +49,24 @@ runtime and data rollback remain proven.
|
|
|
49
49
|
|
|
50
50
|
## Phase 0 — Freeze the operating baseline
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
|
|
52
|
+
Use odla PM as the migration's durable coordination state; do not create a
|
|
53
|
+
parallel migration diary. If the odla app already exists, begin by listing
|
|
54
|
+
doing tasks, open bugs, open goals, and recent decisions for the `appId` from
|
|
55
|
+
`odla.config.mjs`. Read the active task, its linked goal, and their comments
|
|
56
|
+
before inspecting code.
|
|
57
|
+
|
|
58
|
+
If the app is not registered yet, choose the intended stable `appId`, keep
|
|
59
|
+
Phase 0/early provisioning evidence in focused commits and checkpoint
|
|
60
|
+
handoffs, and rerun the inventory when a fresh agent resumes. Old branches,
|
|
61
|
+
git history, unrelated deployments, and earlier experiments are only leads to
|
|
62
|
+
verify. Immediately after the first provision registers the app, create PM
|
|
63
|
+
goals/tasks/decisions and backfill the approved baseline evidence; PM is
|
|
64
|
+
authoritative from then on.
|
|
65
|
+
|
|
66
|
+
Use one conformance goal per acceptance outcome, parallel tasks for independent
|
|
67
|
+
tracks, decisions for product/data/identity/route/rollback choices, and bugs
|
|
68
|
+
for defects. Comments carry the source commit, immutable deployment version,
|
|
69
|
+
verification command/result, and rollback checkpoint. Never put secrets in PM.
|
|
54
70
|
|
|
55
71
|
### Inventory the product
|
|
56
72
|
|
|
@@ -68,6 +84,16 @@ Create or extend root `MIGRATION.md`; never replace its history. Record state
|
|
|
68
84
|
render sink;
|
|
69
85
|
- telemetry, freshness/error alerts, deploy commands, and CI auto-deploys.
|
|
70
86
|
|
|
87
|
+
For every route, record the method/path, current consumer, owning implementation
|
|
88
|
+
(`legacy`, Chapter, or an explicit host adapter), request and response schemas,
|
|
89
|
+
status/error/auth/cache behavior, and its evidence. Source evidence names the
|
|
90
|
+
checked-in path plus commit; deployment evidence names the origin plus immutable
|
|
91
|
+
Worker/deployment version. A response observed on an unversioned deployment
|
|
92
|
+
describes only that deployed build at that moment. It does not establish route
|
|
93
|
+
ownership or the contract of the branch being changed. Treat old branches, git
|
|
94
|
+
history, and unrelated deployments as leads to verify, never as the migration
|
|
95
|
+
specification.
|
|
96
|
+
|
|
71
97
|
### Freeze visual and behavior evidence
|
|
72
98
|
|
|
73
99
|
Capture representative production screenshots and measured layouts at 390,
|
|
@@ -150,13 +176,21 @@ explicit:
|
|
|
150
176
|
|
|
151
177
|
Before deleting old schema/rules/provisioning:
|
|
152
178
|
|
|
153
|
-
1. freeze the legacy schema and rules
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
179
|
+
1. freeze the legacy schema and rules from an exact reviewed source path and
|
|
180
|
+
commit, with a recorded content digest;
|
|
181
|
+
2. make that baseline independent: use the untouched legacy source or a literal
|
|
182
|
+
fixture that does not import Chapter, the active descriptor/schema alias, or
|
|
183
|
+
another generated candidate; do not modify baseline and candidate in the
|
|
184
|
+
same approval;
|
|
185
|
+
3. normalize only approved representational differences;
|
|
186
|
+
4. compare `createChapterIntegration(chapter)` namespaces, attrs, links, rules,
|
|
187
|
+
and seeds to the independent baseline;
|
|
188
|
+
5. run a negative control by removing or changing a known field/rule on one side
|
|
189
|
+
and prove the parity test fails before trusting a green result;
|
|
190
|
+
6. fail on missing fields, widened rules, cardinality changes, renamed natural
|
|
158
191
|
keys, new client-readable data, or unapproved seed differences;
|
|
159
|
-
|
|
192
|
+
7. record every intentional delta and migration mapping as a PM decision, and
|
|
193
|
+
attach the comparator evidence to the linked conformance goal/task.
|
|
160
194
|
|
|
161
195
|
`createChapterIntegration()` inserts the group seed only when absent. Existing
|
|
162
196
|
runtime owner edits do not update from later config changes. Compare the current
|
|
@@ -343,10 +377,25 @@ Do not replace schema, worker, routes, and UI in one unreviewable change.
|
|
|
343
377
|
routes run before built-ins and receive Chapter's existing context
|
|
344
378
|
(`verifyUser`, `makeDb`, `roleFor`, `isAdmin`); do not verify JWTs twice.
|
|
345
379
|
3. Initially keep every bespoke endpoint as a host route. Alias legacy URLs to
|
|
346
|
-
Chapter behavior
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
380
|
+
Chapter behavior only when the route-contract matrix proves method, auth,
|
|
381
|
+
request body, response status, JSON keys/types/nesting, units, null/omission
|
|
382
|
+
semantics, and relevant headers are compatible. Matching business values
|
|
383
|
+
alone is not response-shape parity.
|
|
384
|
+
4. When contracts differ, keep the legacy route until its consumer adopts the
|
|
385
|
+
packaged Chapter component end to end, or add an explicit adapter with
|
|
386
|
+
contract tests. Do not simply repoint the existing browser code.
|
|
387
|
+
5. In Chapter 0.25, `/api/join-config` is Chapter-owned and returns the
|
|
388
|
+
group-scoped join configuration, raw cent values, policy copy, and readiness;
|
|
389
|
+
it is not a promise to reproduce a legacy route's prebuilt Stripe line items
|
|
390
|
+
or publishable key. `JoinIsland` delegates payment to `PaymentStep`, which
|
|
391
|
+
obtains `clientSecret`, `publishableKey`, and `lineItems` from
|
|
392
|
+
`POST /api/payments/subscription` after application submission and refund
|
|
393
|
+
acknowledgement. Verify this installed-version contract before retiring a
|
|
394
|
+
legacy join route.
|
|
395
|
+
6. Compare built-in and legacy behavior route by route; only then remove a host
|
|
396
|
+
route that Chapter fully owns and whose consumers use the verified Chapter
|
|
397
|
+
contract or adapter.
|
|
398
|
+
7. Keep static fallback and API handling explicit so unknown APIs cannot fall
|
|
350
399
|
through to a successful SPA document.
|
|
351
400
|
|
|
352
401
|
Test public/private method policies, body limits, idempotency, auth 401 vs 403,
|
|
@@ -388,10 +437,15 @@ fixture. Compare markup/behavior and the Phase 0 screenshots before deletion.
|
|
|
388
437
|
`renderHeader` when the header belongs inside the Chapter scope. Chapter mode
|
|
389
438
|
defaults to Dashboard, People, and Settings; move former global Billing,
|
|
390
439
|
Calendar, Email, and per-record operations into nested tabs.
|
|
391
|
-
- Preserve
|
|
392
|
-
`collectionSection`'s `renderSummary`,
|
|
393
|
-
`renderDetailHeader
|
|
394
|
-
|
|
440
|
+
- Preserve distinctive People summary content, list presentation, record
|
|
441
|
+
heading, and specialized panels with `collectionSection`'s `renderSummary`,
|
|
442
|
+
`renderMaster`, `renderDetailHeader`, and record-tab slots. These slots
|
|
443
|
+
customize content; they do not fix pane geometry.
|
|
444
|
+
- Operational usability is not pixel parity with a cramped legacy admin. At
|
|
445
|
+
desktop widths, the unselected People collection must use the full workspace
|
|
446
|
+
width; after a record opens it becomes master/detail. This is the
|
|
447
|
+
`collapseClosedDetail` default. Set it to `false` only when the empty detail
|
|
448
|
+
pane contains intentional, useful content approved by the human.
|
|
395
449
|
- Application-backed pipeline changes must use a lifecycle adapter that invokes
|
|
396
450
|
the authoritative application endpoints. Prove approve/refund/manual
|
|
397
451
|
transition side effects; a raw CRM `setStage` is not parity.
|
|
@@ -416,6 +470,9 @@ At 390, 768, 1280, and 1440 pixels in every theme, compare:
|
|
|
416
470
|
- wordmark, text baseline, theme control, active state, and hover/focus;
|
|
417
471
|
- join fields/errors, payment and slot picker, Clerk sign-in containment;
|
|
418
472
|
- member cards/actions and every admin section/table/drawer;
|
|
473
|
+
- at 1280 and 1440, every unselected collection table uses the full content
|
|
474
|
+
width: no empty detail pane and no wide table squeezed into a narrow rail;
|
|
475
|
+
after selection, both master and detail remain usable;
|
|
419
476
|
- no clipped labels, card text escape, accidental document scroll, or
|
|
420
477
|
horizontal overflow;
|
|
421
478
|
- loading, empty, error, unauthorized, 404, and reduced-motion states.
|
|
@@ -427,16 +484,21 @@ not visual parity.
|
|
|
427
484
|
|
|
428
485
|
### Clerk
|
|
429
486
|
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
487
|
+
For the one website being converted, retain that website's existing Clerk
|
|
488
|
+
application/workspace unless the human approves an identity migration. A
|
|
489
|
+
leader and follower are different websites and use different Clerk
|
|
490
|
+
applications, publishable keys, issuers, roles, and local session tokens. A
|
|
491
|
+
Clerk JWT never authenticates a cross-site delivery.
|
|
492
|
+
|
|
493
|
+
Chapter claim mode requires session claims for both email and role; hub table
|
|
494
|
+
mode uses lowercase `admins` rows. Prove signed-out, allowed, forbidden,
|
|
495
|
+
provisional, member, admin, super-admin, malformed, expired, wrong-issuer,
|
|
496
|
+
sign-out, and return-target behavior. If the site's verifier intentionally
|
|
497
|
+
enforces JWT `aud` or `azp`, retain that check with a host verifier until
|
|
498
|
+
Chapter exposes the same policy and add wrong-audience/wrong-authorized-party
|
|
499
|
+
fixtures. If it never enforced those claims, mark those two cases `n/a` only
|
|
500
|
+
after the full matrix is recorded; do not call their absence an auth success or
|
|
501
|
+
use it to skip the remaining authorization tests.
|
|
440
502
|
|
|
441
503
|
When Chapter needs server-side account/role operations, set the named
|
|
442
504
|
app-readable `clerk_secret_key` through:
|
|
@@ -493,9 +555,12 @@ selected account invitation effect. Never let dev send to imported members.
|
|
|
493
555
|
|
|
494
556
|
Check in an executable acceptance manifest with:
|
|
495
557
|
|
|
496
|
-
- actual dev URLs and Worker version ids
|
|
558
|
+
- actual dev URLs and immutable Worker version ids, paired with the source
|
|
559
|
+
commit they are expected to run;
|
|
497
560
|
- deterministic synthetic member/application ids;
|
|
498
|
-
- expected
|
|
561
|
+
- expected route owners and full request/response contracts—not only paths,
|
|
562
|
+
statuses, or equal values—plus schema/counts/freshness and Chapter backend
|
|
563
|
+
marker;
|
|
499
564
|
- expected migration-readiness inputs and a `200` only when each is green;
|
|
500
565
|
- expected account, payment, booking, email, CRM, and admin outcomes;
|
|
501
566
|
- expected o11y service/release and safe trace;
|
|
@@ -521,6 +586,14 @@ Run the real journey:
|
|
|
521
586
|
`doctor`, unit tests, build, CLI smoke, a login page, and a human-looking admin
|
|
522
587
|
screen are necessary but not sufficient.
|
|
523
588
|
|
|
589
|
+
Before filing a route bug from deployed evidence, prove that the probed
|
|
590
|
+
deployment runs the intended commit/version. Repeat the request against the
|
|
591
|
+
direct candidate origin and the public domain with a unique non-secret query
|
|
592
|
+
value, capture `Age`, `Cache-Control`, `CF-Cache-Status`, `ETag`, and the Worker
|
|
593
|
+
version marker, and re-test after the documented edge/config propagation
|
|
594
|
+
window. A cached pre-deploy or pre-credential `404` is not evidence that the
|
|
595
|
+
current route is absent.
|
|
596
|
+
|
|
524
597
|
## Phase 8 — Production parallel run and cutover
|
|
525
598
|
|
|
526
599
|
Do not add production until the human approves the full dev report and both
|
|
@@ -565,6 +638,7 @@ Keep both rollback capabilities through the approved observation window
|
|
|
565
638
|
webhook, job, and secret only in a separate human-approved change with a fresh
|
|
566
639
|
journey afterward.
|
|
567
640
|
|
|
568
|
-
|
|
569
|
-
`retired`, the observation window passes,
|
|
570
|
-
product—not merely a Chapter
|
|
641
|
+
Mark the migration goals met and tasks done only when every applicable track is
|
|
642
|
+
`primary-prod` or `retired`, the observation window passes, evidence is attached
|
|
643
|
+
in PM, and the human confirms the existing product—not merely a Chapter
|
|
644
|
+
canary—has been converted.
|
package/runbooks/greenfield.md
CHANGED
|
@@ -67,9 +67,19 @@ consumer, not a visual identity to rename.
|
|
|
67
67
|
|
|
68
68
|
## Phase 0 — Resolve the product and brand brief
|
|
69
69
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
70
|
+
Record decisions rather than inventing business facts. Ask the human only for
|
|
71
|
+
missing choices that change money, identity, outbound communication,
|
|
72
|
+
authorization, or the public brand. Do not create a parallel product or
|
|
73
|
+
migration diary.
|
|
74
|
+
|
|
75
|
+
PM requires a registered, co-owned odla app. Before Phase 3 registration, use a
|
|
76
|
+
focused branch/commit and checkpoint handoff for the approved brief and rerun
|
|
77
|
+
the Phase 0 checks when a fresh agent resumes. Immediately after provision
|
|
78
|
+
registers the app, create PM conformance goals and track tasks, record these
|
|
79
|
+
product/brand/identity decisions, and backfill the earlier evidence. PM is
|
|
80
|
+
authoritative from then on; start every later session by listing doing tasks,
|
|
81
|
+
open bugs/goals, and recent decisions for the `appId` in
|
|
82
|
+
`odla.config.mjs`. Never put secrets in PM.
|
|
73
83
|
|
|
74
84
|
| Decision | Required answer |
|
|
75
85
|
| --- | --- |
|
|
@@ -158,7 +168,6 @@ Recommended minimum tree:
|
|
|
158
168
|
|
|
159
169
|
```text
|
|
160
170
|
.
|
|
161
|
-
├── PRODUCT.md
|
|
162
171
|
├── package.json
|
|
163
172
|
├── index.html
|
|
164
173
|
├── vite.config.mjs
|
|
@@ -344,9 +353,8 @@ the private profile write and records `clerkPrivateMetadataSyncedAt`.
|
|
|
344
353
|
`copy` is a recursive partial of `ChapterCopy`. `defineChapter()` resolves it
|
|
345
354
|
to a complete `chapter.copy`, which is the voice source for packaged join,
|
|
346
355
|
member, and admin surfaces. Put plain text in `copy`; use render slots for
|
|
347
|
-
markup or a different composition. Include the voice constraints
|
|
348
|
-
|
|
349
|
-
terminology.
|
|
356
|
+
markup or a different composition. Include the approved voice constraints in a
|
|
357
|
+
contract test, such as banned punctuation or required terminology.
|
|
350
358
|
|
|
351
359
|
In this release, `prices.currency` and `prices.interval` record intent but do
|
|
352
360
|
not control the group row, public join config, or Stripe charge. The Stripe
|
|
@@ -376,6 +384,32 @@ Snapshot these resolved values in `chapter-contract.test.ts`:
|
|
|
376
384
|
schema/rules/seeds/probes, using the fixed clock because the integration seed
|
|
377
385
|
carries the timestamp.
|
|
378
386
|
|
|
387
|
+
### When this site is a leader or follower
|
|
388
|
+
|
|
389
|
+
Model the network as website nodes joined by directed delivery edges. Every
|
|
390
|
+
website keeps its own `appId`, ODLA tenant/key, CRM config, Clerk application,
|
|
391
|
+
issuer, roles, and users. A leader edge is one `network.targets[]` record with
|
|
392
|
+
the follower id/name/origin, optional vault secret name, and a per-record-type
|
|
393
|
+
field allowlist. The follower declares compatible CRM types and fields; it does
|
|
394
|
+
not need the leader's Clerk configuration.
|
|
395
|
+
|
|
396
|
+
The leader browser authenticates only to the leader. Its Worker authorizes the
|
|
397
|
+
local admin, reads the edge's share secret from the leader vault, and sends a
|
|
398
|
+
versioned `{ version, type, hubRecordId, input }` payload to the follower. The
|
|
399
|
+
follower validates that share secret and its local CRM config, then writes with
|
|
400
|
+
its own `ODLA_API_KEY`. Never send either website's Clerk JWT or ODLA key across
|
|
401
|
+
the edge. Pipeline, account, billing, and roles remain authoritative locally.
|
|
402
|
+
|
|
403
|
+
Conformance must prove:
|
|
404
|
+
|
|
405
|
+
- the target metadata returned to the browser contains no secret;
|
|
406
|
+
- only allowlisted fields leave the leader;
|
|
407
|
+
- unknown follower types/fields fail before a write;
|
|
408
|
+
- wrong share secret returns `401` and writes nothing;
|
|
409
|
+
- retry updates the provenance-matched follower record instead of duplicating;
|
|
410
|
+
- neither Clerk token nor either `ODLA_API_KEY` appears in the cross-site
|
|
411
|
+
request or client bundle.
|
|
412
|
+
|
|
379
413
|
## Phase 3 — Provisioning and Worker shell
|
|
380
414
|
|
|
381
415
|
```js
|
|
@@ -448,6 +482,10 @@ separate browser-owned booking-consent checkpoint for availability plus
|
|
|
448
482
|
create/reschedule/cancel access. A grant created for the retired read-only
|
|
449
483
|
mirror must be reconnected. No OAuth code or token passes through the agent.
|
|
450
484
|
|
|
485
|
+
The app now exists. Initialize PM, backfill the approved Phase 0–2 decisions
|
|
486
|
+
and evidence, create linked tasks/goals for the remaining tracks, and read that
|
|
487
|
+
state before continuing.
|
|
488
|
+
|
|
451
489
|
## Phase 4 — Build the four application surfaces
|
|
452
490
|
|
|
453
491
|
Import the public site's application theme once. For the admin application,
|
|
@@ -564,6 +602,13 @@ anchors; record details are record-tab anchors. Do not promote those tabs into
|
|
|
564
602
|
the global site header. Use `chrome="standalone"` only for an admin-only product
|
|
565
603
|
that has no host shell.
|
|
566
604
|
|
|
605
|
+
The People collection uses the full workspace width until a record is selected,
|
|
606
|
+
then becomes master/detail. Keep the default
|
|
607
|
+
`collectionSection({ collapseClosedDetail: true })`; set it to `false` only
|
|
608
|
+
when an intentional empty-detail panel contains useful approved content. At
|
|
609
|
+
1280 and 1440 pixels, verify a wide collection table is not squeezed into a
|
|
610
|
+
narrow rail beside an empty pane.
|
|
611
|
+
|
|
567
612
|
The router must serve and reload `/`, every public page, `/join`, `/members/`,
|
|
568
613
|
and `/admin/` without accidentally sending API paths to the SPA. Chapter
|
|
569
614
|
terminates unknown `/api/*` paths as JSON 404s before the static asset fallback.
|
|
@@ -571,8 +616,10 @@ terminates unknown `/api/*` paths as JSON 404s before the static asset fallback.
|
|
|
571
616
|
## Phase 5 — Configure Clerk and bootstrap authority
|
|
572
617
|
|
|
573
618
|
At this step, read Clerk's current agent-facing CLI documentation. Use one
|
|
574
|
-
Clerk application with development and production instances
|
|
575
|
-
second application for production
|
|
619
|
+
Clerk application with development and production instances **for this
|
|
620
|
+
website**; do not create a second application merely for this site's production
|
|
621
|
+
environment. A leader and a follower are separate websites and use separate
|
|
622
|
+
Clerk applications, issuers, users, and roles.
|
|
576
623
|
|
|
577
624
|
For default chapter claim auth, the session token must include both:
|
|
578
625
|
|