@odla-ai/chapter 0.24.0 → 0.25.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@odla-ai/chapter",
3
- "version": "0.24.0",
3
+ "version": "0.25.1",
4
4
  "description": "A leader/follower foundation for branded membership sites: shared CRM, admin, auth, payments, booking, and explicit record delivery from one defineChapter config.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://odla.ai/docs/packages/chapter",
@@ -68,6 +68,16 @@ Create or extend root `MIGRATION.md`; never replace its history. Record state
68
68
  render sink;
69
69
  - telemetry, freshness/error alerts, deploy commands, and CI auto-deploys.
70
70
 
71
+ For every route, record the method/path, current consumer, owning implementation
72
+ (`legacy`, Chapter, or an explicit host adapter), request and response schemas,
73
+ status/error/auth/cache behavior, and its evidence. Source evidence names the
74
+ checked-in path plus commit; deployment evidence names the origin plus immutable
75
+ Worker/deployment version. A response observed on an unversioned deployment
76
+ describes only that deployed build at that moment. It does not establish route
77
+ ownership or the contract of the branch being changed. Treat old branches, git
78
+ history, and unrelated deployments as leads to verify, never as the migration
79
+ specification.
80
+
71
81
  ### Freeze visual and behavior evidence
72
82
 
73
83
  Capture representative production screenshots and measured layouts at 390,
@@ -112,15 +122,26 @@ Allowed states: `not-started`, `canary`, `parallel`, `verified`,
112
122
  Install the version-matched agent guidance and inspect the automation boundary:
113
123
 
114
124
  ```sh
115
- npx @odla-ai/cli@0.17.1 setup
116
- npx @odla-ai/cli@0.17.1 capabilities --json
125
+ npm install \
126
+ @odla-ai/chapter @odla-ai/brand @odla-ai/ui \
127
+ @odla-ai/crm @odla-ai/db \
128
+ @odla-ai/calendar @odla-ai/email \
129
+ @odla-ai/auth-clerk @odla-ai/o11y \
130
+ jose preact
131
+ npm install --save-dev \
132
+ @odla-ai/cli @odla-ai/security \
133
+ @cloudflare/workers-types \
134
+ typescript vite vitest wrangler
135
+ npx odla-ai setup
136
+ npm ls @odla-ai/chapter @odla-ai/crm @odla-ai/ui @odla-ai/cli
137
+ npx odla-ai capabilities --json
117
138
  ```
118
139
 
119
- Pin the exact known-good package matrix from the installed Chapter README.
120
- For this runbook, first require
121
- `npm view @odla-ai/chapter@0.24.0 version` to succeed. Install every runtime,
122
- toolchain, CLI, and security package with the exact versions in that README;
123
- never use `latest`, a range, or `--legacy-peer-deps`.
140
+ Use normal dependency declarations while ODLA is under active development.
141
+ Review and commit `package.json` plus `package-lock.json`, use `npm ci` after
142
+ the intentional dependency update, record resolved versions in PM, and rerun
143
+ the frozen acceptance and Chapter conformance suites. Do not use
144
+ `--legacy-peer-deps` or preserve an incompatible peer.
124
145
 
125
146
  Write `src/chapter.config.mjs` from the inventory. Make every behavior decision
126
147
  explicit:
@@ -139,13 +160,20 @@ explicit:
139
160
 
140
161
  Before deleting old schema/rules/provisioning:
141
162
 
142
- 1. freeze the legacy schema and rules as reviewed test fixtures;
143
- 2. normalize only approved representational differences;
144
- 3. compare `createChapterIntegration(chapter)` namespaces, attrs, links, rules,
145
- and seeds to the fixtures;
146
- 4. fail on missing fields, widened rules, cardinality changes, renamed natural
163
+ 1. freeze the legacy schema and rules from an exact reviewed source path and
164
+ commit, with a recorded content digest;
165
+ 2. make that baseline independent: use the untouched legacy source or a literal
166
+ fixture that does not import Chapter, the active descriptor/schema alias, or
167
+ another generated candidate; do not modify baseline and candidate in the
168
+ same approval;
169
+ 3. normalize only approved representational differences;
170
+ 4. compare `createChapterIntegration(chapter)` namespaces, attrs, links, rules,
171
+ and seeds to the independent baseline;
172
+ 5. run a negative control by removing or changing a known field/rule on one side
173
+ and prove the parity test fails before trusting a green result;
174
+ 6. fail on missing fields, widened rules, cardinality changes, renamed natural
147
175
  keys, new client-readable data, or unapproved seed differences;
148
- 5. record every intentional delta and migration mapping in `MIGRATION.md`.
176
+ 7. record every intentional delta and migration mapping in `MIGRATION.md`.
149
177
 
150
178
  `createChapterIntegration()` inserts the group seed only when absent. Existing
151
179
  runtime owner edits do not update from later config changes. Compare the current
@@ -163,8 +191,10 @@ At minimum audit:
163
191
  - stock `JoinIsland` generates a fresh `submissionId` on each invocation, so an
164
192
  ambiguous retry after a lost response is not idempotent even though a
165
193
  concurrent click is disabled;
166
- - `profileFields` now defaults to `[]`; enumerate every field that may remain
167
- Clerk-client-readable rather than relying on implicit projection;
194
+ - `profileFields` now defaults to `[]`; enumerate the small account/admin
195
+ signals that may be mirrored into backend-only Clerk private metadata rather
196
+ than relying on implicit projection. Keep the application row and CRM
197
+ canonical;
168
198
  - application-to-CRM projection fields;
169
199
  - `requireDisclaimerAck` now defaults to `true`; set `false` explicitly only
170
200
  when the existing product has no consent control, and preserve
@@ -330,10 +360,25 @@ Do not replace schema, worker, routes, and UI in one unreviewable change.
330
360
  routes run before built-ins and receive Chapter's existing context
331
361
  (`verifyUser`, `makeDb`, `roleFor`, `isAdmin`); do not verify JWTs twice.
332
362
  3. Initially keep every bespoke endpoint as a host route. Alias legacy URLs to
333
- Chapter behavior instead of breaking clients.
334
- 4. Compare built-in and legacy behavior route by route; only then remove a host
335
- route that Chapter fully owns.
336
- 5. Keep static fallback and API handling explicit so unknown APIs cannot fall
363
+ Chapter behavior only when the route-contract matrix proves method, auth,
364
+ request body, response status, JSON keys/types/nesting, units, null/omission
365
+ semantics, and relevant headers are compatible. Matching business values
366
+ alone is not response-shape parity.
367
+ 4. When contracts differ, keep the legacy route until its consumer adopts the
368
+ packaged Chapter component end to end, or add an explicit adapter with
369
+ contract tests. Do not simply repoint the existing browser code.
370
+ 5. In Chapter 0.25, `/api/join-config` is Chapter-owned and returns the
371
+ group-scoped join configuration, raw cent values, policy copy, and readiness;
372
+ it is not a promise to reproduce a legacy route's prebuilt Stripe line items
373
+ or publishable key. `JoinIsland` delegates payment to `PaymentStep`, which
374
+ obtains `clientSecret`, `publishableKey`, and `lineItems` from
375
+ `POST /api/payments/subscription` after application submission and refund
376
+ acknowledgement. Verify this installed-version contract before retiring a
377
+ legacy join route.
378
+ 6. Compare built-in and legacy behavior route by route; only then remove a host
379
+ route that Chapter fully owns and whose consumers use the verified Chapter
380
+ contract or adapter.
381
+ 7. Keep static fallback and API handling explicit so unknown APIs cannot fall
337
382
  through to a successful SPA document.
338
383
 
339
384
  Test public/private method policies, body limits, idempotency, auth 401 vs 403,
@@ -437,6 +482,22 @@ Do not substitute `secrets set-clerk-key`; it writes the platform-reserved
437
482
  command does not validate Clerk instance prefixes: independently confirm dev
438
483
  uses `sk_test_`. Never put `sk_live_` in dev.
439
484
 
485
+ Chapter now reserves `public_metadata` for the small authorization role and
486
+ stores its `applicationId`/allowlisted profile snapshot in backend-only
487
+ `private_metadata`. After deploying the schema update, run the authenticated
488
+ admin repair endpoint in bounded batches:
489
+
490
+ ```text
491
+ POST /api/admin/clerk/private-profiles/sync?offset=0&limit=50
492
+ ```
493
+
494
+ Continue with each returned `nextOffset` until it is `null`. Prove that the
495
+ public `role` and unrelated host metadata survive, the former public
496
+ `applicationId`/`profile` keys are absent, the private snapshot matches the
497
+ latest application, and `clerkPrivateMetadataSyncedAt` plus `clerkUserId` are
498
+ recorded locally. The application row and CRM remain canonical; this is an
499
+ account/admin signal mirror, not a third editable profile database.
500
+
440
501
  ### Stripe
441
502
 
442
503
  Use test resources and an isolated dev webhook. Store `stripe_secret_key` and
@@ -464,9 +525,12 @@ selected account invitation effect. Never let dev send to imported members.
464
525
 
465
526
  Check in an executable acceptance manifest with:
466
527
 
467
- - actual dev URLs and Worker version ids;
528
+ - actual dev URLs and immutable Worker version ids, paired with the source
529
+ commit they are expected to run;
468
530
  - deterministic synthetic member/application ids;
469
- - expected routes/statuses, schema/counts/freshness, and Chapter backend marker;
531
+ - expected route owners and full request/response contracts—not only paths,
532
+ statuses, or equal values—plus schema/counts/freshness and Chapter backend
533
+ marker;
470
534
  - expected migration-readiness inputs and a `200` only when each is green;
471
535
  - expected account, payment, booking, email, CRM, and admin outcomes;
472
536
  - expected o11y service/release and safe trace;
@@ -492,6 +556,14 @@ Run the real journey:
492
556
  `doctor`, unit tests, build, CLI smoke, a login page, and a human-looking admin
493
557
  screen are necessary but not sufficient.
494
558
 
559
+ Before filing a route bug from deployed evidence, prove that the probed
560
+ deployment runs the intended commit/version. Repeat the request against the
561
+ direct candidate origin and the public domain with a unique non-secret query
562
+ value, capture `Age`, `Cache-Control`, `CF-Cache-Status`, `ETag`, and the Worker
563
+ version marker, and re-test after the documented edge/config propagation
564
+ window. A cached pre-deploy or pre-credential `404` is not evidence that the
565
+ current route is absent.
566
+
495
567
  ## Phase 8 — Production parallel run and cutover
496
568
 
497
569
  Do not add production until the human approves the full dev report and both
@@ -41,8 +41,9 @@ consumer, not a visual identity to rename.
41
41
 
42
42
  ## Non-negotiable boundaries
43
43
 
44
- 1. Pin every ODLA package to an exact tested version. Never use `latest`, `^`,
45
- `~`, or `--legacy-peer-deps` in a committed Chapter site.
44
+ 1. Use normal dependency declarations while ODLA is under active development.
45
+ Commit the lockfile, use `npm ci` for repeatable installs, and rerun
46
+ conformance after updates. Never use `--legacy-peer-deps`.
46
47
  2. Build and prove `dev` before adding `prod`. Production provisioning, secret
47
48
  transfer, deploy, DNS, billing activation, and real outbound email are human
48
49
  checkpoints.
@@ -113,38 +114,31 @@ renamed reference site.
113
114
 
114
115
  `@odla-ai/chapter` has no scaffolding binary. The agent creates the host files.
115
116
 
116
- Initialize npm, install the exact CLI named by this release, and install its
117
- agent guidance:
117
+ Initialize npm, install Chapter and the Preact host with normal dependency
118
+ declarations, then install the CLI's agent guidance:
118
119
 
119
120
  ```sh
120
121
  npm init -y
121
- npx @odla-ai/cli@0.17.1 setup
122
- ```
123
-
124
- Verify every release target exists, then install the exact known-good Preact
125
- host matrix. Do not copy these commands into a pre-release branch where
126
- `@odla-ai/chapter@0.24.0` is not yet on npm.
127
-
128
- ```sh
129
- npm view @odla-ai/chapter@0.24.0 version
130
- npm install --save-exact \
131
- @odla-ai/chapter@0.24.0 @odla-ai/brand@0.2.0 @odla-ai/ui@0.12.1 \
132
- @odla-ai/crm@0.3.1 @odla-ai/db@0.6.7 \
133
- @odla-ai/calendar@0.2.0 @odla-ai/email@0.3.1 \
134
- @odla-ai/auth-clerk@0.4.1 @odla-ai/o11y@2.2.2 \
135
- jose@6.2.3 preact@10.29.7
136
- npm install --save-dev --save-exact \
137
- @odla-ai/cli@0.17.1 @odla-ai/security@0.3.1 \
138
- @cloudflare/workers-types@4.20260702.1 \
139
- typescript@6.0.3 \
140
- vite@8.1.4 vitest@4.1.10 wrangler@4.107.0
122
+ npm install \
123
+ @odla-ai/chapter @odla-ai/brand @odla-ai/ui \
124
+ @odla-ai/crm @odla-ai/db \
125
+ @odla-ai/calendar @odla-ai/email \
126
+ @odla-ai/auth-clerk @odla-ai/o11y \
127
+ jose preact
128
+ npm install --save-dev \
129
+ @odla-ai/cli @odla-ai/security \
130
+ @cloudflare/workers-types \
131
+ typescript vite vitest wrangler
132
+ npx odla-ai setup
133
+ npm ls @odla-ai/chapter @odla-ai/crm @odla-ai/ui @odla-ai/cli
141
134
  npx odla-ai capabilities --json
142
135
  ```
143
136
 
144
- The parent `README.md` repeats this version matrix. This runbook standardizes on
145
- Preact. Install auth-clerk explicitly when adopting the admin entry; it is an
146
- optional Chapter peer because worker-only and member-only consumers do not need
147
- it.
137
+ Commit `package-lock.json`, use `npm ci` after the initial dependency change,
138
+ and rerun conformance whenever the lockfile resolves new ODLA versions. Do not
139
+ bypass peer-dependency validation. Install auth-clerk explicitly when adopting
140
+ the admin entry; it is an optional Chapter peer because worker-only and
141
+ member-only consumers do not need it.
148
142
 
149
143
  Required host scripts:
150
144
 
@@ -341,8 +335,11 @@ both require a named app-readable vault secret `clerk_secret_key`. Keep
341
335
  defaults to `true`, and `application.profileFields` defaults to `[]`. Keep all
342
336
  three decisions explicit in the checked-in config and snapshot their resolved
343
337
  values. A site with no consent control must deliberately set
344
- `requireDisclaimerAck: false`; an application field reaches client-readable
345
- Clerk metadata only when it is deliberately listed in `profileFields`.
338
+ `requireDisclaimerAck: false`; an application field reaches backend-only Clerk
339
+ private metadata only when it is deliberately listed in `profileFields`. Keep
340
+ that mirror small and use the application row/CRM as the canonical profile.
341
+ With `account: "invite"`, prove the first signed-in `/api/me` request completes
342
+ the private profile write and records `clerkPrivateMetadataSyncedAt`.
346
343
 
347
344
  `copy` is a recursive partial of `ChapterCopy`. `defineChapter()` resolves it
348
345
  to a complete `chapter.copy`, which is the voice source for packaged join,
@@ -704,7 +701,10 @@ Run a real deployed journey:
704
701
 
705
702
  1. public home and every navigation/deep link;
706
703
  2. join-config readiness, application submit, test payment, booking;
707
- 3. Clerk account/invite behavior selected by config;
704
+ 3. Clerk account/invite behavior selected by config; prove `role` is the only
705
+ Chapter-owned public metadata and the allowlisted account snapshot appears
706
+ in private metadata. For an invite, the first authenticated `/api/me`
707
+ completes that write exactly once;
708
708
  4. provisional and member area;
709
709
  5. admin sign-in, people/CRM, application approval, meeting, billing, email;
710
710
  6. replay/idempotency and one safe error;