@odla-ai/chapter 0.43.2 → 0.45.0

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 CHANGED
@@ -859,6 +859,47 @@ and relations by composing its own config before passing it to Chapter.
859
859
  Formation is off unless configured. Chapter intentionally does not ship a
860
860
  public form design: the site renders the fields in its own voice and brand.
861
861
 
862
+ ### Shared-Stripe commercial shadow
863
+
864
+ A hub may opt into a read-only network commercial projection when multiple
865
+ chapters intentionally bill through one Stripe account. Every accepted source
866
+ is an exact partition, including Stripe test/live mode:
867
+
868
+ ```ts
869
+ networkCommercialReadModel: {
870
+ mode: "shadow",
871
+ sources: [{
872
+ stripeMode: "test",
873
+ appId: "example-chapter",
874
+ chapterId: "example-chapter",
875
+ environment: "dev",
876
+ dataEnvironment: "dev",
877
+ runtime: "cory",
878
+ }],
879
+ },
880
+ ```
881
+
882
+ The dedicated `/api/network-commercial/stripe-webhook` verifies Stripe's
883
+ signature with `network_commercial_stripe_webhook_secret` before writing an
884
+ append-only, PII-free event fact. The projector is rebuildable and deterministic:
885
+ late metadata-less events may inherit a partition only through an unambiguous
886
+ provider customer/subscription/invoice/charge reference. Wrong, missing,
887
+ ambiguous, unsupported, and colliding events remain explained exceptions.
888
+
889
+ `GET /api/admin/network-commercial-read-model` is super-admin-only and exposes
890
+ current customer, subscription, invoice, refund, and currency-total facts for a
891
+ BNF operator surface. `POST` with `{ command: "rebuild", mutationId }` rebuilds
892
+ from the local event log without calling or mutating Stripe. `POST` with
893
+ `{ command: "reconcile-stripe" }` performs bounded, GET-only current-object
894
+ reads through the hub's vaulted `stripe_secret_key` and reports missing,
895
+ unexpected, mismatched, truncated, and totals exceptions without changing the
896
+ event log or projection. Objects outside the configured exact partitions are
897
+ counted as ignored rather than adopted. This shadow never
898
+ authorizes charges, refunds, subscription changes, or Chapter lifecycle writes;
899
+ removing it changes no customer-facing behavior. The BNF frontend may be down
900
+ while the webhook continues to ingest. Registering a Stripe endpoint and
901
+ enabling production remain separate reviewed operations.
902
+
862
903
  For a hub with network targets, the standard admin catalog is Dashboard,
863
904
  Network, People, Portfolio, and Settings. Dashboard Overview renders aggregate network
864
905
  health; People contains CRM types whose `workspace` is absent or `"people"`;
@@ -134,6 +134,39 @@ interface ResolvedBuilderLibrary {
134
134
  sources: readonly ResolvedBuilderLibrarySource[];
135
135
  }
136
136
 
137
+ /** Opt-in network-scoped Person registry. Shadow mode never gates Chapter work. */
138
+ interface ChapterNetworkPersonRegistry {
139
+ mode: "shadow";
140
+ /** Chapter ids that may be attached to imported source rows. Defaults to the
141
+ * hub's configured network target ids. */
142
+ chapterIds?: readonly string[];
143
+ }
144
+ /** Validated network Person registry settings carried by a resolved Chapter. */
145
+ interface ResolvedNetworkPersonRegistry {
146
+ mode: "shadow";
147
+ chapterIds: readonly string[];
148
+ }
149
+
150
+ /** One exact Stripe event partition accepted by the network commercial shadow. */
151
+ interface NetworkCommercialSource {
152
+ appId: string;
153
+ chapterId: string;
154
+ environment: string;
155
+ dataEnvironment: string;
156
+ runtime: string;
157
+ stripeMode: "test" | "live";
158
+ }
159
+ /** Opt-in, read-only projection of a shared Stripe account. */
160
+ interface ChapterNetworkCommercialReadModel {
161
+ mode: "shadow";
162
+ sources: readonly NetworkCommercialSource[];
163
+ }
164
+ /** Validated settings carried by a resolved hub. */
165
+ interface ResolvedNetworkCommercialReadModel {
166
+ mode: "shadow";
167
+ sources: readonly NetworkCommercialSource[];
168
+ }
169
+
137
170
  /** Scalar kinds accepted by the Chapter schema adapter. */
138
171
  type AttrType = "string" | "number" | "boolean" | "json";
139
172
  /** One odla-db attribute: its type and index/uniqueness/optionality flags. */
@@ -538,6 +571,11 @@ interface ChapterConfig {
538
571
  memberContent?: ChapterMemberContent;
539
572
  /** Private docs, Brand asset references, and links for authorized site-building agents. */
540
573
  builderLibrary?: ChapterBuilderLibrary;
574
+ /** Network-scoped canonical Person registry. Shadow mode is additive only:
575
+ * Chapter workflows and access continue to read their existing authority. */
576
+ networkPersonRegistry?: ChapterNetworkPersonRegistry;
577
+ /** Read-only, rebuildable commercial projection from a shared Stripe account. */
578
+ networkCommercialReadModel?: ChapterNetworkCommercialReadModel;
541
579
  /** Enable a public, host-rendered formation application workflow. */
542
580
  formation?: LeaderFormationConfig;
543
581
  thesis?: unknown;
@@ -638,6 +676,10 @@ interface Chapter {
638
676
  memberContent: ResolvedMemberContent | null;
639
677
  /** Null unless the private scoped Builder Library is enabled. */
640
678
  builderLibrary: ResolvedBuilderLibrary | null;
679
+ /** Null unless this hub explicitly enables the shadow Person registry. */
680
+ networkPersonRegistry: ResolvedNetworkPersonRegistry | null;
681
+ /** Null unless this hub explicitly enables the commercial shadow. */
682
+ networkCommercialReadModel: ResolvedNetworkCommercialReadModel | null;
641
683
  /** Resolved public formation intake contract (disabled when omitted). */
642
684
  formation: ResolvedLeaderFormation;
643
685
  /** Resolved CRM engine (from `defineCrm`). */