create-ailk 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.
Files changed (599) hide show
  1. package/README.md +42 -20
  2. package/component-catalog.json +3 -3
  3. package/component-catalog.md +3 -3
  4. package/dist/add-module.js +4 -2
  5. package/dist/add-route.d.ts +12 -1
  6. package/dist/add-route.js +31 -3
  7. package/dist/cli.js +12 -7
  8. package/dist/derive-architecture.d.ts +3 -4
  9. package/dist/derive-architecture.js +65 -29
  10. package/dist/lib/design-checks.d.ts +9 -4
  11. package/dist/lib/design-checks.js +13 -7
  12. package/dist/lib/extract-module-bundle.js +29 -2
  13. package/dist/lib/fetch-template-snapshot.d.ts +1 -1
  14. package/dist/lib/fetch-template-snapshot.js +7 -3
  15. package/dist/lib/import-graph.d.ts +1 -1
  16. package/dist/lib/import-graph.js +4 -4
  17. package/dist/lib/module-license-gate.d.ts +12 -1
  18. package/dist/lib/module-license-gate.js +34 -12
  19. package/dist/module-architecture.d.ts +20 -3
  20. package/dist/module-architecture.js +117 -550
  21. package/dist/paid-sections.d.ts +25 -1
  22. package/dist/paid-sections.js +88 -3
  23. package/dist/surfaces.js +10 -2
  24. package/dist/template-record.d.ts +14 -4
  25. package/dist/template-record.js +23 -5
  26. package/dist/topology.d.ts +16 -3
  27. package/dist/topology.js +31 -19
  28. package/dist/update.d.ts +10 -1
  29. package/dist/update.js +540 -16
  30. package/package.json +3 -3
  31. package/release-scope.json +1 -1
  32. package/templates/.claude/cloudparity-repo-hooks.json +5 -0
  33. package/templates/.claude/hooks/template-guard.sh +137 -0
  34. package/templates/.claude/rules/extending.md +106 -0
  35. package/templates/.claude/rules/loop-contract.md +2 -2
  36. package/templates/.claude/settings.json +11 -0
  37. package/templates/.env.example +5 -5
  38. package/templates/.github/workflows/ci.yml +7 -4
  39. package/templates/CLAUDE.md +11 -1
  40. package/templates/CONVENTIONS.md +8 -10
  41. package/templates/README.md +14 -13
  42. package/templates/apps/api/.env.example +2 -2
  43. package/templates/apps/api/CLAUDE.md +102 -76
  44. package/templates/apps/api/jest.config.cjs +15 -5
  45. package/templates/apps/api/package.json +16 -20
  46. package/templates/apps/api/src/__tests__/trusted-origins.server.test.ts +2 -2
  47. package/templates/apps/api/src/__tests__/vercel-handler.test.ts +4 -4
  48. package/templates/apps/api/src/index.ts +1 -1
  49. package/templates/apps/api/src/lib/__mocks__/prisma.ts +3 -3
  50. package/templates/apps/api/src/modules/commerce.ts +10 -0
  51. package/templates/apps/api/src/modules/content-write.ts +10 -0
  52. package/templates/apps/api/src/modules/multi-tenant.ts +10 -0
  53. package/templates/apps/api/src/modules/scheduling.ts +10 -0
  54. package/templates/apps/api/src/modules/signal-collectors.ts +10 -0
  55. package/templates/apps/api/src/modules/workspace.ts +10 -0
  56. package/templates/apps/api/src/server.ts +117 -1882
  57. package/templates/apps/api/vercel.json +2 -2
  58. package/templates/apps/mcp/CLAUDE.md +67 -20
  59. package/templates/apps/mcp/__tests__/app-entry.test.ts +4 -254
  60. package/templates/apps/mcp/__tests__/boot-file.test.ts +92 -0
  61. package/templates/apps/mcp/jest.config.cjs +6 -1
  62. package/templates/apps/mcp/package.json +5 -13
  63. package/templates/apps/mcp/src/app.ts +8 -7
  64. package/templates/apps/mcp/src/index.ts +6 -34
  65. package/templates/apps/mcp/src/lib/paid-tools.generated.ts +10 -0
  66. package/templates/apps/mcp/src/lib/topology.generated.ts +2 -2
  67. package/templates/apps/mcp/src/site.ts +12 -0
  68. package/templates/apps/web/.env.example +1 -1
  69. package/templates/apps/web/CLAUDE.md +10 -3
  70. package/templates/apps/web/app/.well-known/mcp.json/route.ts +9 -3
  71. package/templates/apps/web/app/[locale]/contact/intake-analytics.ts +1 -1
  72. package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/magnet-page.test.tsx +22 -1
  73. package/templates/apps/web/app/[locale]/flows/[slug]/magnet-page.tsx +7 -3
  74. package/templates/apps/web/app/[locale]/pricing/__tests__/unconnected.test.tsx +43 -0
  75. package/templates/apps/web/app/[locale]/pricing/page.tsx +7 -3
  76. package/templates/apps/web/app/api/offerings/checkout/[lookupKey]/__tests__/route.test.ts +222 -0
  77. package/templates/apps/web/app/api/offerings/checkout/[lookupKey]/route.ts +10 -3
  78. package/templates/apps/web/app/api/revalidate/route.ts +3 -3
  79. package/templates/apps/web/auth.ts +2 -2
  80. package/templates/apps/web/jest.config.cjs +1 -0
  81. package/templates/apps/web/lib/auth-email.ts +1 -1
  82. package/templates/apps/web/lib/relay.ts +2 -2
  83. package/templates/apps/web/lib/release-scope.ts +47 -0
  84. package/templates/apps/web/lib/server-api.ts +1 -1
  85. package/templates/apps/web/src/lib/commerce-claim.ts +1 -1
  86. package/templates/customizations.yaml +37 -0
  87. package/templates/database/prisma.config.ts +10 -14
  88. package/templates/database/seed-test.ts +2 -2
  89. package/templates/database/seed.ts +5 -5
  90. package/templates/package.json +12 -6
  91. package/templates/pnpm-workspace.yaml +0 -1
  92. package/templates/project.yaml +16 -8
  93. package/templates/tools/jest/reporters.cjs +65 -0
  94. package/templates/tools/lint-architecture.ts +553 -7
  95. package/templates/tsconfig.json +1 -2
  96. package/versions.json +48 -35
  97. package/templates/apps/api/src/__tests__/commerce-claim-registration.test.ts +0 -409
  98. package/templates/apps/api/src/__tests__/factories/agent-caller.ts +0 -102
  99. package/templates/apps/api/src/__tests__/factories/content-fixture.ts +0 -138
  100. package/templates/apps/api/src/__tests__/factories/in-memory-prisma.ts +0 -441
  101. package/templates/apps/api/src/__tests__/factories/index.ts +0 -70
  102. package/templates/apps/api/src/__tests__/factories/lead-fixture.ts +0 -82
  103. package/templates/apps/api/src/__tests__/leads-forwarded-rate-limit.test.ts +0 -135
  104. package/templates/apps/api/src/__tests__/services/enrichment-shim.test.ts +0 -126
  105. package/templates/apps/api/src/__tests__/stripe-boot.test.ts +0 -132
  106. package/templates/apps/api/src/__tests__/support/hub-sign-in-fake-db.ts +0 -362
  107. package/templates/apps/api/src/bin/__tests__/rate-limit-probe.test.ts +0 -184
  108. package/templates/apps/api/src/bin/abandon-sweep.ts +0 -42
  109. package/templates/apps/api/src/bin/rate-limit-probe.ts +0 -53
  110. package/templates/apps/api/src/bin/spokes.ts +0 -198
  111. package/templates/apps/api/src/bin/stripe-connections-rekey.ts +0 -45
  112. package/templates/apps/api/src/config/__tests__/hub-require-spoke-key.test.ts +0 -196
  113. package/templates/apps/api/src/config/__tests__/index.test.ts +0 -233
  114. package/templates/apps/api/src/config/__tests__/modules.test.ts +0 -76
  115. package/templates/apps/api/src/config/__tests__/stripe-connection-key.test.ts +0 -185
  116. package/templates/apps/api/src/config/__tests__/trusted-origins.test.ts +0 -238
  117. package/templates/apps/api/src/config/index.ts +0 -596
  118. package/templates/apps/api/src/config/modules.ts +0 -83
  119. package/templates/apps/api/src/lib/__tests__/agent-store.test.ts +0 -581
  120. package/templates/apps/api/src/lib/__tests__/auth-email-budget.test.ts +0 -143
  121. package/templates/apps/api/src/lib/__tests__/consent-ledger-double.ts +0 -237
  122. package/templates/apps/api/src/lib/__tests__/consent-store.test.ts +0 -353
  123. package/templates/apps/api/src/lib/__tests__/content-adapter.test.ts +0 -201
  124. package/templates/apps/api/src/lib/__tests__/deliverable-asset-store.test.ts +0 -224
  125. package/templates/apps/api/src/lib/__tests__/error-serializer.test.ts +0 -120
  126. package/templates/apps/api/src/lib/__tests__/errors.test.ts +0 -94
  127. package/templates/apps/api/src/lib/__tests__/file-fallback.test.ts +0 -144
  128. package/templates/apps/api/src/lib/__tests__/fixtures/HomePage/home.mdx +0 -8
  129. package/templates/apps/api/src/lib/__tests__/flow-completion-store.test.ts +0 -149
  130. package/templates/apps/api/src/lib/__tests__/flow-rename-race.db.test.ts +0 -116
  131. package/templates/apps/api/src/lib/__tests__/hub-sign-in-store.test.ts +0 -209
  132. package/templates/apps/api/src/lib/__tests__/lead-capture-store.test.ts +0 -257
  133. package/templates/apps/api/src/lib/__tests__/lead-delivery.test.ts +0 -96
  134. package/templates/apps/api/src/lib/__tests__/outbound-http.test.ts +0 -125
  135. package/templates/apps/api/src/lib/__tests__/prisma.test.ts +0 -165
  136. package/templates/apps/api/src/lib/__tests__/require-commerce-claim.test.ts +0 -317
  137. package/templates/apps/api/src/lib/__tests__/require-paid-tier.test.ts +0 -129
  138. package/templates/apps/api/src/lib/__tests__/site.test.ts +0 -308
  139. package/templates/apps/api/src/lib/__tests__/slice-load.test.ts +0 -89
  140. package/templates/apps/api/src/lib/__tests__/spoke-store.test.ts +0 -202
  141. package/templates/apps/api/src/lib/__tests__/stripe-admission.test.ts +0 -217
  142. package/templates/apps/api/src/lib/__tests__/stripe.test.ts +0 -82
  143. package/templates/apps/api/src/lib/agent-store.ts +0 -613
  144. package/templates/apps/api/src/lib/auth-email-budget.ts +0 -161
  145. package/templates/apps/api/src/lib/consent-store.ts +0 -363
  146. package/templates/apps/api/src/lib/content-adapter.ts +0 -112
  147. package/templates/apps/api/src/lib/deliverable-asset-store.ts +0 -96
  148. package/templates/apps/api/src/lib/error-serializer.ts +0 -164
  149. package/templates/apps/api/src/lib/errors.ts +0 -95
  150. package/templates/apps/api/src/lib/file-fallback.ts +0 -87
  151. package/templates/apps/api/src/lib/flow-completion-store.ts +0 -136
  152. package/templates/apps/api/src/lib/hub-sign-in-store.ts +0 -455
  153. package/templates/apps/api/src/lib/lead-capture-store.ts +0 -122
  154. package/templates/apps/api/src/lib/lead-delivery.ts +0 -52
  155. package/templates/apps/api/src/lib/license-key-store.ts +0 -45
  156. package/templates/apps/api/src/lib/locales.ts +0 -201
  157. package/templates/apps/api/src/lib/outbound-http.ts +0 -127
  158. package/templates/apps/api/src/lib/prisma.ts +0 -21
  159. package/templates/apps/api/src/lib/proposal-paid-store.ts +0 -66
  160. package/templates/apps/api/src/lib/rate-limit-probe.ts +0 -165
  161. package/templates/apps/api/src/lib/rate-limit-store.ts +0 -142
  162. package/templates/apps/api/src/lib/require-commerce-claim.ts +0 -250
  163. package/templates/apps/api/src/lib/require-paid-tier.ts +0 -53
  164. package/templates/apps/api/src/lib/site.ts +0 -257
  165. package/templates/apps/api/src/lib/slice-load.ts +0 -90
  166. package/templates/apps/api/src/lib/spoke-store.ts +0 -180
  167. package/templates/apps/api/src/lib/stripe.ts +0 -321
  168. package/templates/apps/api/src/lib/webhook-idempotency.ts +0 -156
  169. package/templates/apps/api/src/middleware/__tests__/adversarial/bearer-token-format.test.ts +0 -111
  170. package/templates/apps/api/src/middleware/__tests__/adversarial/cookie-or-bearer-precedence.test.ts +0 -172
  171. package/templates/apps/api/src/middleware/__tests__/adversarial/csrf-bearer-skip.test.ts +0 -119
  172. package/templates/apps/api/src/middleware/__tests__/adversarial/csrf-cookie-path.test.ts +0 -138
  173. package/templates/apps/api/src/middleware/__tests__/adversarial/csrf-trusted-origins.test.ts +0 -142
  174. package/templates/apps/api/src/middleware/__tests__/adversarial/session-fixation.test.ts +0 -155
  175. package/templates/apps/api/src/middleware/__tests__/adversarial/session-timeout.test.ts +0 -139
  176. package/templates/apps/api/src/middleware/__tests__/auth.bearer-path.test.ts +0 -562
  177. package/templates/apps/api/src/middleware/__tests__/auth.both-present-precedence.test.ts +0 -76
  178. package/templates/apps/api/src/middleware/__tests__/auth.cookie-path.test.ts +0 -220
  179. package/templates/apps/api/src/middleware/__tests__/auth.database-not-configured.test.ts +0 -97
  180. package/templates/apps/api/src/middleware/__tests__/auth.hub-session-path.test.ts +0 -557
  181. package/templates/apps/api/src/middleware/__tests__/auth.neither-present.test.ts +0 -72
  182. package/templates/apps/api/src/middleware/__tests__/auth.optional-cookie.test.ts +0 -140
  183. package/templates/apps/api/src/middleware/__tests__/default-tenant.test.ts +0 -721
  184. package/templates/apps/api/src/middleware/__tests__/rate-limit-cross-isolate.db.test.ts +0 -220
  185. package/templates/apps/api/src/middleware/__tests__/rate-limit-store.test.ts +0 -430
  186. package/templates/apps/api/src/middleware/__tests__/rate-limit.test.ts +0 -1409
  187. package/templates/apps/api/src/middleware/__tests__/write-budget.test.ts +0 -174
  188. package/templates/apps/api/src/middleware/auth.ts +0 -864
  189. package/templates/apps/api/src/middleware/default-tenant.ts +0 -166
  190. package/templates/apps/api/src/middleware/rate-limit.ts +0 -983
  191. package/templates/apps/api/src/openapi/__tests__/openapi.test.ts +0 -391
  192. package/templates/apps/api/src/openapi/__tests__/spec-identity.test.ts +0 -182
  193. package/templates/apps/api/src/openapi/index.ts +0 -18
  194. package/templates/apps/api/src/openapi/spec.ts +0 -2148
  195. package/templates/apps/api/src/openapi/surface-drift.ts +0 -195
  196. package/templates/apps/api/src/routes/aeo/__tests__/index.test.ts +0 -175
  197. package/templates/apps/api/src/routes/aeo/index.ts +0 -107
  198. package/templates/apps/api/src/routes/auth/__tests__/auth-tokens.functional.test.ts +0 -196
  199. package/templates/apps/api/src/routes/auth/__tests__/auth-user.functional.test.ts +0 -249
  200. package/templates/apps/api/src/routes/auth/__tests__/hub-sign-in.test.ts +0 -532
  201. package/templates/apps/api/src/routes/auth/__tests__/tokens.test.ts +0 -313
  202. package/templates/apps/api/src/routes/auth/__tests__/transactional-email.test.ts +0 -413
  203. package/templates/apps/api/src/routes/auth/__tests__/user.test.ts +0 -609
  204. package/templates/apps/api/src/routes/auth/hub-sign-in.ts +0 -242
  205. package/templates/apps/api/src/routes/auth/tokens.ts +0 -211
  206. package/templates/apps/api/src/routes/auth/transactional-email.ts +0 -301
  207. package/templates/apps/api/src/routes/auth/user.ts +0 -305
  208. package/templates/apps/api/src/routes/billing/plan-checkout.ts +0 -332
  209. package/templates/apps/api/src/routes/checkout/__tests__/live-key.test.ts +0 -178
  210. package/templates/apps/api/src/routes/checkout/__tests__/offerings-authorization.test.ts +0 -1426
  211. package/templates/apps/api/src/routes/checkout/__tests__/session.test.ts +0 -448
  212. package/templates/apps/api/src/routes/checkout/__tests__/sessions.test.ts +0 -1742
  213. package/templates/apps/api/src/routes/checkout/index.ts +0 -34
  214. package/templates/apps/api/src/routes/checkout/session.ts +0 -171
  215. package/templates/apps/api/src/routes/checkout/sessions.ts +0 -540
  216. package/templates/apps/api/src/routes/consent/__tests__/account.test.ts +0 -386
  217. package/templates/apps/api/src/routes/consent/__tests__/sign-up-rate-limit.test.ts +0 -160
  218. package/templates/apps/api/src/routes/consent/account.ts +0 -268
  219. package/templates/apps/api/src/routes/consent/cookie.ts +0 -90
  220. package/templates/apps/api/src/routes/consent/index.ts +0 -26
  221. package/templates/apps/api/src/routes/consent/unsubscribe.ts +0 -127
  222. package/templates/apps/api/src/routes/content/__tests__/get-page.test.ts +0 -853
  223. package/templates/apps/api/src/routes/content/__tests__/list-pages.test.ts +0 -230
  224. package/templates/apps/api/src/routes/content/__tests__/list-types.test.ts +0 -44
  225. package/templates/apps/api/src/routes/content/__tests__/locale.test.ts +0 -118
  226. package/templates/apps/api/src/routes/content/__tests__/offerings.test.ts +0 -731
  227. package/templates/apps/api/src/routes/content/__tests__/pricing.test.ts +0 -753
  228. package/templates/apps/api/src/routes/content/__tests__/rate-limit.test.ts +0 -51
  229. package/templates/apps/api/src/routes/content/__tests__/search.test.ts +0 -450
  230. package/templates/apps/api/src/routes/content/__tests__/shown-offerings.test.ts +0 -762
  231. package/templates/apps/api/src/routes/content/get-page.ts +0 -183
  232. package/templates/apps/api/src/routes/content/index.ts +0 -49
  233. package/templates/apps/api/src/routes/content/list-pages.ts +0 -74
  234. package/templates/apps/api/src/routes/content/list-types.ts +0 -19
  235. package/templates/apps/api/src/routes/content/offerings.ts +0 -184
  236. package/templates/apps/api/src/routes/content/pricing.ts +0 -176
  237. package/templates/apps/api/src/routes/content/rate-limit.ts +0 -22
  238. package/templates/apps/api/src/routes/content/search.ts +0 -100
  239. package/templates/apps/api/src/routes/content/shown-offerings.ts +0 -229
  240. package/templates/apps/api/src/routes/leads/__tests__/capture.test.ts +0 -88
  241. package/templates/apps/api/src/routes/leads/__tests__/list.test.ts +0 -171
  242. package/templates/apps/api/src/routes/leads/__tests__/magnet-completion.test.ts +0 -515
  243. package/templates/apps/api/src/routes/leads/__tests__/spoke.test.ts +0 -392
  244. package/templates/apps/api/src/routes/leads/__tests__/track.test.ts +0 -165
  245. package/templates/apps/api/src/routes/leads/index.ts +0 -639
  246. package/templates/apps/api/src/routes/leads/list.ts +0 -104
  247. package/templates/apps/api/src/routes/project-listings/__tests__/configured-application.test.ts +0 -626
  248. package/templates/apps/api/src/routes/project-listings/__tests__/drafts.test.ts +0 -1268
  249. package/templates/apps/api/src/routes/project-listings/__tests__/founder-identity.test.ts +0 -847
  250. package/templates/apps/api/src/routes/project-listings/__tests__/me.test.ts +0 -491
  251. package/templates/apps/api/src/routes/project-listings/__tests__/public.test.ts +0 -476
  252. package/templates/apps/api/src/routes/project-listings/__tests__/resume-email.test.ts +0 -872
  253. package/templates/apps/api/src/routes/project-listings/__tests__/site-answers.test.ts +0 -1022
  254. package/templates/apps/api/src/routes/project-listings/__tests__/site-key.test.ts +0 -484
  255. package/templates/apps/api/src/routes/project-listings/__tests__/structured-address.test.ts +0 -535
  256. package/templates/apps/api/src/routes/project-listings/index.ts +0 -164
  257. package/templates/apps/api/src/routes/project-listings/me.ts +0 -87
  258. package/templates/apps/api/src/routes/project-listings/patch-copy.ts +0 -224
  259. package/templates/apps/api/src/routes/project-listings/patch-draft.ts +0 -102
  260. package/templates/apps/api/src/routes/project-listings/public.ts +0 -98
  261. package/templates/apps/api/src/routes/project-listings/respond.ts +0 -48
  262. package/templates/apps/api/src/routes/project-listings/resume-token.ts +0 -27
  263. package/templates/apps/api/src/routes/project-listings/start.ts +0 -140
  264. package/templates/apps/api/src/routes/project-listings/submit.ts +0 -130
  265. package/templates/apps/api/src/routes/project-listings/verify-email.ts +0 -150
  266. package/templates/apps/api/src/routes/requests/__tests__/confirm.test.ts +0 -686
  267. package/templates/apps/api/src/routes/requests/confirm.ts +0 -601
  268. package/templates/apps/api/src/routes/requests/index.ts +0 -54
  269. package/templates/apps/api/src/routes/test/auth/__tests__/session.test.ts +0 -306
  270. package/templates/apps/api/src/routes/test/auth/session.ts +0 -143
  271. package/templates/apps/api/src/routes/webhooks/README.md +0 -398
  272. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-checkout-consent.test.ts +0 -649
  273. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-dunning.test.ts +0 -749
  274. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-flow-checkout.test.ts +0 -449
  275. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-idempotency.test.ts +0 -264
  276. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-livemode-live.test.ts +0 -159
  277. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-livemode.test.ts +0 -158
  278. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-offerings.test.ts +0 -814
  279. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-org-billing.test.ts +0 -301
  280. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-proposal-paid.test.ts +0 -369
  281. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-rate-limit.test.ts +0 -215
  282. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-request-paid.test.ts +0 -301
  283. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-site-filter.test.ts +0 -809
  284. package/templates/apps/api/src/routes/webhooks/__tests__/stripe.test.ts +0 -1155
  285. package/templates/apps/api/src/routes/webhooks/index.ts +0 -141
  286. package/templates/apps/api/src/routes/webhooks/stripe-offerings.ts +0 -384
  287. package/templates/apps/api/src/routes/webhooks/stripe.ts +0 -2028
  288. package/templates/apps/api/src/services/__tests__/abandon-email.test.ts +0 -645
  289. package/templates/apps/api/src/services/__tests__/answer-distributions.test.ts +0 -132
  290. package/templates/apps/api/src/services/__tests__/audit-log.test.ts +0 -1028
  291. package/templates/apps/api/src/services/__tests__/checkout-plan.test.ts +0 -313
  292. package/templates/apps/api/src/services/__tests__/consent-ledger.test.ts +0 -503
  293. package/templates/apps/api/src/services/__tests__/consent-migration.test.ts +0 -65
  294. package/templates/apps/api/src/services/__tests__/consent.test.ts +0 -299
  295. package/templates/apps/api/src/services/__tests__/default-tenant.test.ts +0 -147
  296. package/templates/apps/api/src/services/__tests__/deliverable-fulfillment.test.ts +0 -877
  297. package/templates/apps/api/src/services/__tests__/deliverable-resend.test.ts +0 -379
  298. package/templates/apps/api/src/services/__tests__/dunning-policy.test.ts +0 -368
  299. package/templates/apps/api/src/services/__tests__/entitlements.test.ts +0 -142
  300. package/templates/apps/api/src/services/__tests__/hub-sign-in.test.ts +0 -854
  301. package/templates/apps/api/src/services/__tests__/keyless-workspace-predicate.test.ts +0 -234
  302. package/templates/apps/api/src/services/__tests__/lead-accept-user.test.ts +0 -251
  303. package/templates/apps/api/src/services/__tests__/lead-routing.test.ts +0 -2660
  304. package/templates/apps/api/src/services/__tests__/listing-config.test.ts +0 -166
  305. package/templates/apps/api/src/services/__tests__/magnet-completion.test.ts +0 -389
  306. package/templates/apps/api/src/services/__tests__/person.test.ts +0 -1204
  307. package/templates/apps/api/src/services/__tests__/plan-offerings.test.ts +0 -450
  308. package/templates/apps/api/src/services/__tests__/project-listings.counts.test.ts +0 -202
  309. package/templates/apps/api/src/services/__tests__/project-listings.fence.test.ts +0 -151
  310. package/templates/apps/api/src/services/__tests__/public-site-resolver.test.ts +0 -137
  311. package/templates/apps/api/src/services/__tests__/request-confirm.test.ts +0 -531
  312. package/templates/apps/api/src/services/__tests__/revalidation.test.ts +0 -372
  313. package/templates/apps/api/src/services/__tests__/slack-notify.test.ts +0 -348
  314. package/templates/apps/api/src/services/__tests__/spoke-resolution.test.ts +0 -660
  315. package/templates/apps/api/src/services/__tests__/usage-aggregation.test.ts +0 -941
  316. package/templates/apps/api/src/services/__tests__/usage-credits.test.ts +0 -588
  317. package/templates/apps/api/src/services/__tests__/verified-email.test.ts +0 -78
  318. package/templates/apps/api/src/services/abandon-email.ts +0 -336
  319. package/templates/apps/api/src/services/aeo-score.ts +0 -325
  320. package/templates/apps/api/src/services/answer-distributions.ts +0 -138
  321. package/templates/apps/api/src/services/audit-log.ts +0 -961
  322. package/templates/apps/api/src/services/checkout-buyer.ts +0 -168
  323. package/templates/apps/api/src/services/consent.ts +0 -834
  324. package/templates/apps/api/src/services/default-tenant.ts +0 -416
  325. package/templates/apps/api/src/services/deliverable-fulfillment.ts +0 -750
  326. package/templates/apps/api/src/services/dunning-policy.ts +0 -294
  327. package/templates/apps/api/src/services/enrichment-shim.ts +0 -53
  328. package/templates/apps/api/src/services/entitlements.ts +0 -338
  329. package/templates/apps/api/src/services/hub-sign-in.ts +0 -472
  330. package/templates/apps/api/src/services/lead-accept-user.ts +0 -126
  331. package/templates/apps/api/src/services/lead-promotion.ts +0 -160
  332. package/templates/apps/api/src/services/lead-routing.ts +0 -1372
  333. package/templates/apps/api/src/services/leads-inbox.ts +0 -312
  334. package/templates/apps/api/src/services/listing-config.ts +0 -178
  335. package/templates/apps/api/src/services/magnet-completion.ts +0 -242
  336. package/templates/apps/api/src/services/offerings/__tests__/catalog.test.ts +0 -348
  337. package/templates/apps/api/src/services/offerings/__tests__/checkout-session-record.test.ts +0 -268
  338. package/templates/apps/api/src/services/offerings/__tests__/connection.test.ts +0 -975
  339. package/templates/apps/api/src/services/offerings/__tests__/fixtures.ts +0 -416
  340. package/templates/apps/api/src/services/offerings/__tests__/org-products.test.ts +0 -400
  341. package/templates/apps/api/src/services/offerings/__tests__/readers.test.ts +0 -685
  342. package/templates/apps/api/src/services/offerings/__tests__/source.test.ts +0 -231
  343. package/templates/apps/api/src/services/offerings/catalog.ts +0 -318
  344. package/templates/apps/api/src/services/offerings/checkout-authorization.ts +0 -403
  345. package/templates/apps/api/src/services/offerings/checkout-session-record.ts +0 -192
  346. package/templates/apps/api/src/services/offerings/connection.ts +0 -1083
  347. package/templates/apps/api/src/services/offerings/index.ts +0 -614
  348. package/templates/apps/api/src/services/offerings/source.ts +0 -140
  349. package/templates/apps/api/src/services/offerings/store.ts +0 -150
  350. package/templates/apps/api/src/services/owner-workspaces.ts +0 -132
  351. package/templates/apps/api/src/services/person.ts +0 -1211
  352. package/templates/apps/api/src/services/plan-offerings.ts +0 -125
  353. package/templates/apps/api/src/services/project-listing-resume-email.ts +0 -326
  354. package/templates/apps/api/src/services/project-listings.ts +0 -2085
  355. package/templates/apps/api/src/services/public-site-resolver.ts +0 -396
  356. package/templates/apps/api/src/services/request-confirm.ts +0 -698
  357. package/templates/apps/api/src/services/revalidation.ts +0 -235
  358. package/templates/apps/api/src/services/slack-notify.ts +0 -291
  359. package/templates/apps/api/src/services/usage-aggregation.ts +0 -516
  360. package/templates/apps/api/src/services/usage-credits.ts +0 -340
  361. package/templates/apps/api/src/services/verified-email.ts +0 -71
  362. package/templates/apps/mcp/__tests__/abuse/daily-cap.test.ts +0 -52
  363. package/templates/apps/mcp/__tests__/abuse/email-validator.test.ts +0 -46
  364. package/templates/apps/mcp/__tests__/abuse/guard.test.ts +0 -198
  365. package/templates/apps/mcp/__tests__/abuse/honeypot.test.ts +0 -36
  366. package/templates/apps/mcp/__tests__/abuse/user-agent-deny.test.ts +0 -54
  367. package/templates/apps/mcp/__tests__/aeo-cli-parity.test.ts +0 -116
  368. package/templates/apps/mcp/__tests__/audit-single-page.test.ts +0 -299
  369. package/templates/apps/mcp/__tests__/boot.test.ts +0 -280
  370. package/templates/apps/mcp/__tests__/catalog-drift.test.ts +0 -359
  371. package/templates/apps/mcp/__tests__/config/modules.test.ts +0 -78
  372. package/templates/apps/mcp/__tests__/get_business_hours.test.ts +0 -82
  373. package/templates/apps/mcp/__tests__/get_faq.test.ts +0 -80
  374. package/templates/apps/mcp/__tests__/get_locations.test.ts +0 -65
  375. package/templates/apps/mcp/__tests__/get_offerings.test.ts +0 -557
  376. package/templates/apps/mcp/__tests__/get_pricing.test.ts +0 -524
  377. package/templates/apps/mcp/__tests__/get_site_info.test.ts +0 -81
  378. package/templates/apps/mcp/__tests__/http-transport.test.ts +0 -1232
  379. package/templates/apps/mcp/__tests__/index.test.ts +0 -195
  380. package/templates/apps/mcp/__tests__/lib/audit-single-page-readiness-scan.test.ts +0 -191
  381. package/templates/apps/mcp/__tests__/lib/commerce-claim.test.ts +0 -531
  382. package/templates/apps/mcp/__tests__/lib/content-adapter-parity.test.ts +0 -70
  383. package/templates/apps/mcp/__tests__/lib/content-adapter.test.ts +0 -162
  384. package/templates/apps/mcp/__tests__/lib/content-root.test.ts +0 -93
  385. package/templates/apps/mcp/__tests__/lib/errors.test.ts +0 -75
  386. package/templates/apps/mcp/__tests__/lib/fail-closed-tools.test.ts +0 -180
  387. package/templates/apps/mcp/__tests__/lib/public-workspace.test.ts +0 -124
  388. package/templates/apps/mcp/__tests__/list_pages.test.ts +0 -268
  389. package/templates/apps/mcp/__tests__/locale.test.ts +0 -120
  390. package/templates/apps/mcp/__tests__/module-exclusion.test.ts +0 -175
  391. package/templates/apps/mcp/__tests__/purchase-disabled.test.ts +0 -101
  392. package/templates/apps/mcp/__tests__/rate-limit-write.test.ts +0 -189
  393. package/templates/apps/mcp/__tests__/read_content.test.ts +0 -511
  394. package/templates/apps/mcp/__tests__/request_callback.test.ts +0 -160
  395. package/templates/apps/mcp/__tests__/search_content.test.ts +0 -271
  396. package/templates/apps/mcp/__tests__/server.test.ts +0 -388
  397. package/templates/apps/mcp/__tests__/start_purchase.test.ts +0 -448
  398. package/templates/apps/mcp/__tests__/submit_lead.test.ts +0 -222
  399. package/templates/apps/mcp/__tests__/subscribe_newsletter.test.ts +0 -152
  400. package/templates/apps/mcp/__tests__/tools/create_project.test.ts +0 -243
  401. package/templates/apps/mcp/__tests__/tools/purchase.test.ts +0 -451
  402. package/templates/apps/mcp/src/abuse/daily-cap.ts +0 -47
  403. package/templates/apps/mcp/src/abuse/email-validator.ts +0 -25
  404. package/templates/apps/mcp/src/abuse/honeypot.ts +0 -21
  405. package/templates/apps/mcp/src/abuse/index.ts +0 -349
  406. package/templates/apps/mcp/src/abuse/user-agent-deny.ts +0 -58
  407. package/templates/apps/mcp/src/boot.ts +0 -167
  408. package/templates/apps/mcp/src/config/modules.ts +0 -43
  409. package/templates/apps/mcp/src/http-transport.ts +0 -564
  410. package/templates/apps/mcp/src/lib/audit-single-page.ts +0 -308
  411. package/templates/apps/mcp/src/lib/commerce-claim.ts +0 -263
  412. package/templates/apps/mcp/src/lib/content-adapter.ts +0 -116
  413. package/templates/apps/mcp/src/lib/empty-content-adapter.ts +0 -140
  414. package/templates/apps/mcp/src/lib/errors.ts +0 -61
  415. package/templates/apps/mcp/src/lib/license-key-store.ts +0 -45
  416. package/templates/apps/mcp/src/lib/locales.ts +0 -171
  417. package/templates/apps/mcp/src/lib/prisma.ts +0 -39
  418. package/templates/apps/mcp/src/lib/public-workspace.ts +0 -133
  419. package/templates/apps/mcp/src/lib/resolve-locale.ts +0 -30
  420. package/templates/apps/mcp/src/lib/shown-offerings.ts +0 -105
  421. package/templates/apps/mcp/src/lib/site-config.ts +0 -53
  422. package/templates/apps/mcp/src/lib/stripe-tax-signal.ts +0 -59
  423. package/templates/apps/mcp/src/request-context.ts +0 -52
  424. package/templates/apps/mcp/src/server.ts +0 -343
  425. package/templates/apps/mcp/src/serverless-app.ts +0 -88
  426. package/templates/apps/mcp/src/tools/audit.ts +0 -127
  427. package/templates/apps/mcp/src/tools/capture_lead.ts +0 -66
  428. package/templates/apps/mcp/src/tools/create_project.ts +0 -134
  429. package/templates/apps/mcp/src/tools/get_business_hours.ts +0 -68
  430. package/templates/apps/mcp/src/tools/get_faq.ts +0 -71
  431. package/templates/apps/mcp/src/tools/get_locations.ts +0 -88
  432. package/templates/apps/mcp/src/tools/get_offerings.ts +0 -96
  433. package/templates/apps/mcp/src/tools/get_pricing.ts +0 -94
  434. package/templates/apps/mcp/src/tools/get_site_info.ts +0 -86
  435. package/templates/apps/mcp/src/tools/index.ts +0 -138
  436. package/templates/apps/mcp/src/tools/list_pages.ts +0 -68
  437. package/templates/apps/mcp/src/tools/person_notes.ts +0 -25
  438. package/templates/apps/mcp/src/tools/proposals.ts +0 -27
  439. package/templates/apps/mcp/src/tools/purchase.ts +0 -205
  440. package/templates/apps/mcp/src/tools/read_content.ts +0 -81
  441. package/templates/apps/mcp/src/tools/request_callback.ts +0 -52
  442. package/templates/apps/mcp/src/tools/search_content.ts +0 -63
  443. package/templates/apps/mcp/src/tools/subscribe_newsletter.ts +0 -54
  444. package/templates/apps/mcp/src/workspace-server.ts +0 -224
  445. package/templates/database/CHANGELOG.md +0 -981
  446. package/templates/database/LICENSE +0 -202
  447. package/templates/database/NOTICE +0 -2
  448. package/templates/database/README.md +0 -243
  449. package/templates/database/__tests__/agents.db.test.ts +0 -320
  450. package/templates/database/__tests__/appointment.db.test.ts +0 -106
  451. package/templates/database/__tests__/artifact-content-store.db.test.ts +0 -316
  452. package/templates/database/__tests__/composite-fence.db.test.ts +0 -206
  453. package/templates/database/__tests__/consent-ledger.db.test.ts +0 -345
  454. package/templates/database/__tests__/consent-source-checkout-migration.test.ts +0 -79
  455. package/templates/database/__tests__/fence-fan-out.db.test.ts +0 -715
  456. package/templates/database/__tests__/fixtures/appointment-create-probe.ts +0 -79
  457. package/templates/database/__tests__/fixtures/person-backfill.json +0 -264
  458. package/templates/database/__tests__/fixtures/person-contact-backfill.json +0 -182
  459. package/templates/database/__tests__/fixtures/project-listing-consent-probe.ts +0 -100
  460. package/templates/database/__tests__/flow-completion-migration.test.ts +0 -115
  461. package/templates/database/__tests__/flow-completion.db.test.ts +0 -136
  462. package/templates/database/__tests__/flow-workspace-key.db.test.ts +0 -263
  463. package/templates/database/__tests__/flows-listing-diagnostic.test.ts +0 -392
  464. package/templates/database/__tests__/flows-presets.test.ts +0 -173
  465. package/templates/database/__tests__/in-page-magnets-migration.test.ts +0 -161
  466. package/templates/database/__tests__/lead-idempotency-key.db.test.ts +0 -92
  467. package/templates/database/__tests__/member-area.db.test.ts +0 -257
  468. package/templates/database/__tests__/member-contract-migration.test.ts +0 -85
  469. package/templates/database/__tests__/member-contract.db.test.ts +0 -413
  470. package/templates/database/__tests__/offerings-checkout-session.db.test.ts +0 -270
  471. package/templates/database/__tests__/offerings-migration.test.ts +0 -197
  472. package/templates/database/__tests__/offerings-shown-price-ids-migration.test.ts +0 -86
  473. package/templates/database/__tests__/offerings.db.test.ts +0 -303
  474. package/templates/database/__tests__/outbound-message-action.db.test.ts +0 -80
  475. package/templates/database/__tests__/person-contact.db.test.ts +0 -563
  476. package/templates/database/__tests__/person-notes.db.test.ts +0 -249
  477. package/templates/database/__tests__/person.db.test.ts +0 -586
  478. package/templates/database/__tests__/piece-kind-migration.test.ts +0 -67
  479. package/templates/database/__tests__/piece-kind.db.test.ts +0 -208
  480. package/templates/database/__tests__/prefixed-ids.db.test.ts +0 -222
  481. package/templates/database/__tests__/project-listing-consent-at.db.test.ts +0 -111
  482. package/templates/database/__tests__/seed.test.ts +0 -272
  483. package/templates/database/__tests__/spoke-registry.db.test.ts +0 -191
  484. package/templates/database/__tests__/tenancy.test.ts +0 -141
  485. package/templates/database/__tests__/trial-magnet-migration.test.ts +0 -186
  486. package/templates/database/__tests__/user-cascade.test.ts +0 -140
  487. package/templates/database/_gitignore +0 -8
  488. package/templates/database/auth/.gitkeep +0 -0
  489. package/templates/database/auth/schema.prisma +0 -641
  490. package/templates/database/config/.gitkeep +0 -0
  491. package/templates/database/config/schema.prisma +0 -441
  492. package/templates/database/content/.gitkeep +0 -0
  493. package/templates/database/content/schema.prisma +0 -339
  494. package/templates/database/eslint.config.mjs +0 -69
  495. package/templates/database/flows/listing-diagnostic.ts +0 -182
  496. package/templates/database/flows/presets.ts +0 -315
  497. package/templates/database/inbox/.gitkeep +0 -0
  498. package/templates/database/inbox/README.md +0 -3
  499. package/templates/database/inbox/__tests__/schema.test.ts +0 -44
  500. package/templates/database/inbox/schema.prisma +0 -1447
  501. package/templates/database/jest.config.cjs +0 -36
  502. package/templates/database/migrations/20260508000000_add_inbox_namespace/migration.sql +0 -328
  503. package/templates/database/migrations/20260513000000_better_auth_migration/migration.sql +0 -100
  504. package/templates/database/migrations/20260515000000_add_user_billing_fields/migration.sql +0 -28
  505. package/templates/database/migrations/20260516000000_add_user_tier_care_plan_seat/migration.sql +0 -25
  506. package/templates/database/migrations/20260518000000_add_telemetry_records/migration.sql +0 -42
  507. package/templates/database/migrations/20260525000000_theme_wiring/migration.sql +0 -67
  508. package/templates/database/migrations/20260710000000_retire_commercial_tier/migration.sql +0 -21
  509. package/templates/database/migrations/20260712215647_add_multi_tenant_tenancy/migration.sql +0 -201
  510. package/templates/database/migrations/20260713143320_reanchor_site_config_to_workspace/migration.sql +0 -67
  511. package/templates/database/migrations/20260713174000_add_audit_logs/migration.sql +0 -46
  512. package/templates/database/migrations/20260713190000_drop_telemetry_records/migration.sql +0 -25
  513. package/templates/database/migrations/20260713192000_add_uuidv7_function/migration.sql +0 -49
  514. package/templates/database/migrations/20260713192429_prefixed_uuid_entity_ids/migration.sql +0 -197
  515. package/templates/database/migrations/20260713200000_add_org_billing/migration.sql +0 -32
  516. package/templates/database/migrations/20260714000000_add_lead_promotion_fields/migration.sql +0 -22
  517. package/templates/database/migrations/20260714010000_add_usage_billing_content_models/migration.sql +0 -151
  518. package/templates/database/migrations/20260714020000_add_usage_billing_auth_config_models/migration.sql +0 -223
  519. package/templates/database/migrations/20260714030000_credit_balance_non_negative/migration.sql +0 -22
  520. package/templates/database/migrations/20260714030000_widen_usage_billing_report_aggregates/migration.sql +0 -32
  521. package/templates/database/migrations/20260810233516_add_flow_engine_models/migration.sql +0 -40
  522. package/templates/database/migrations/20260811020000_add_flow_session_abandon_email_columns/migration.sql +0 -4
  523. package/templates/database/migrations/20260811030000_add_flow_session_abandon_email_index/migration.sql +0 -2
  524. package/templates/database/migrations/20260811040000_add_flow_session_segment/migration.sql +0 -2
  525. package/templates/database/migrations/20260811050000_add_deliverable_models/migration.sql +0 -29
  526. package/templates/database/migrations/20260812000000_add_deliverable_grant_send_columns/migration.sql +0 -6
  527. package/templates/database/migrations/20260902222948_add_waitlist_experiment_models/migration.sql +0 -39
  528. package/templates/database/migrations/20260902224500_add_waitlist_id_format_checks/migration.sql +0 -24
  529. package/templates/database/migrations/20260903004112_add_flow_session_flags_aeo_score/migration.sql +0 -3
  530. package/templates/database/migrations/20260903010000_add_playbook_instance/migration.sql +0 -33
  531. package/templates/database/migrations/20260904000000_add_waitlist_followup_send/migration.sql +0 -30
  532. package/templates/database/migrations/20260905230000_add_flow_checkout/migration.sql +0 -47
  533. package/templates/database/migrations/20260906000000_add_flow_checkout_idempotency/migration.sql +0 -16
  534. package/templates/database/migrations/20260907120000_add_project_listing/migration.sql +0 -47
  535. package/templates/database/migrations/20260907130000_add_project_listing_slack_columns/migration.sql +0 -10
  536. package/templates/database/migrations/20260907180000_add_listing_csv_send/migration.sql +0 -26
  537. package/templates/database/migrations/20260909120000_project_listings_platform/migration.sql +0 -90
  538. package/templates/database/migrations/20260909180000_listing_draft_and_fields/migration.sql +0 -174
  539. package/templates/database/migrations/20260910120000_listing_public_site_key/migration.sql +0 -14
  540. package/templates/database/migrations/20260911120000_listing_copy_edit_audit/migration.sql +0 -25
  541. package/templates/database/migrations/20260911140000_listing_structured_address/migration.sql +0 -32
  542. package/templates/database/migrations/20260911180000_consent_grants/migration.sql +0 -71
  543. package/templates/database/migrations/20260911200000_listing_site_answers/migration.sql +0 -30
  544. package/templates/database/migrations/20260912120000_listing_owner_link/migration.sql +0 -49
  545. package/templates/database/migrations/20260914120000_listing_founder_identity/migration.sql +0 -123
  546. package/templates/database/migrations/20260915120000_project_listing_solution/migration.sql +0 -15
  547. package/templates/database/migrations/20260916120000_artifact_content_store/migration.sql +0 -158
  548. package/templates/database/migrations/20260917120000_callback_request_confirm/migration.sql +0 -40
  549. package/templates/database/migrations/20260918120000_add_appointment/migration.sql +0 -67
  550. package/templates/database/migrations/20260918120000_asset_metadata_columns/migration.sql +0 -70
  551. package/templates/database/migrations/20260919120000_flow_workspace_key/migration.sql +0 -181
  552. package/templates/database/migrations/20260919130000_flow_definition_admin_columns/migration.sql +0 -172
  553. package/templates/database/migrations/20260919130000_workspace_meetings/migration.sql +0 -41
  554. package/templates/database/migrations/20260919140000_inbox_workspace_key/migration.sql +0 -185
  555. package/templates/database/migrations/20260920120000_lead_handled_at/migration.sql +0 -70
  556. package/templates/database/migrations/20260920130000_lead_workspace_source_index/migration.sql +0 -57
  557. package/templates/database/migrations/20260921120000_deliverable_grant_workspace_key/migration.sql +0 -68
  558. package/templates/database/migrations/20260922120000_tenancy_fence/migration.sql +0 -1067
  559. package/templates/database/migrations/20260923120000_listing_capturing_magnet/migration.sql +0 -210
  560. package/templates/database/migrations/20261003120000_spoke_registry/migration.sql +0 -80
  561. package/templates/database/migrations/20261003130000_scheduling_connection/migration.sql +0 -49
  562. package/templates/database/migrations/20261005120000_agents/migration.sql +0 -84
  563. package/templates/database/migrations/20261008120000_user_last_workspace/migration.sql +0 -35
  564. package/templates/database/migrations/20261008130000_lead_idempotency_key/migration.sql +0 -20
  565. package/templates/database/migrations/20261009120000_agent_grants/migration.sql +0 -33
  566. package/templates/database/migrations/20261010120000_person/migration.sql +0 -106
  567. package/templates/database/migrations/20261010121000_person_backfill/migration.sql +0 -132
  568. package/templates/database/migrations/20261010130000_agent_grants_people_read/migration.sql +0 -20
  569. package/templates/database/migrations/20261011120000_member_area/migration.sql +0 -158
  570. package/templates/database/migrations/20261011130000_agent_grants_member_pieces_manage/migration.sql +0 -21
  571. package/templates/database/migrations/20261012120000_member_contract/migration.sql +0 -192
  572. package/templates/database/migrations/20261013120000_lead_spoke_checkout/migration.sql +0 -20
  573. package/templates/database/migrations/20261014120000_consent_ledger/migration.sql +0 -122
  574. package/templates/database/migrations/20261014120000_person_contact/migration.sql +0 -231
  575. package/templates/database/migrations/20261015120000_person_notes/migration.sql +0 -77
  576. package/templates/database/migrations/20261015120000_rate_limit_counters/migration.sql +0 -43
  577. package/templates/database/migrations/20261016120000_piece_kind/migration.sql +0 -95
  578. package/templates/database/migrations/20261017120000_outbound_message_action/migration.sql +0 -30
  579. package/templates/database/migrations/20261018120000_flow_completion/migration.sql +0 -52
  580. package/templates/database/migrations/20261019120000_consent_source_checkout/migration.sql +0 -27
  581. package/templates/database/migrations/20261020120000_offerings_data_model/migration.sql +0 -146
  582. package/templates/database/migrations/20261021120000_offerings_checkout_session/migration.sql +0 -77
  583. package/templates/database/migrations/20261022120000_in_page_magnets/migration.sql +0 -45
  584. package/templates/database/migrations/20261023120000_offerings_shown_price_ids/migration.sql +0 -47
  585. package/templates/database/migrations/20261024120000_organization_plan_checkout_session/migration.sql +0 -16
  586. package/templates/database/migrations/20261025120000_trial_magnet/migration.sql +0 -28
  587. package/templates/database/migrations/20261026120000_trial_magnet_proof_line/migration.sql +0 -23
  588. package/templates/database/migrations/migration_lock.toml +0 -3
  589. package/templates/database/ops/.gitkeep +0 -0
  590. package/templates/database/ops/schema.prisma +0 -43
  591. package/templates/database/package.json +0 -89
  592. package/templates/database/schema.prisma +0 -71
  593. package/templates/database/scripts/db-generate-locked.sh +0 -80
  594. package/templates/database/scripts/person-backfill.sql +0 -132
  595. package/templates/database/tenancy.ts +0 -183
  596. package/templates/database/tsconfig.build.json +0 -16
  597. package/templates/database/tsconfig.flows.json +0 -15
  598. package/templates/database/tsconfig.json +0 -16
  599. package/templates/database/tsconfig.tenancy.json +0 -14
@@ -1,392 +0,0 @@
1
- /**
2
- * @file flows-listing-diagnostic.test.ts
3
- * @description The shared scoring RULE (#5001 AC2/AC3, reworked by #5036 D4):
4
- * a register built from one listing's own questions scores its weakest path
5
- * `curious`, its strongest `now`, and a mixed path where the 0–12 total says
6
- * it does — evaluated through the real `evaluateWaitlistScoring`, never a
7
- * reimplementation of the ladder.
8
- *
9
- * The load-bearing test here is "a reordered register scores an answer
10
- * identically": #5036 D4 moved resolution from option POSITION to option
11
- * VALUE, so reordering a founder's Q3/Q4 options and rebuilding the register
12
- * leaves an already-stored answer scoring exactly what it always meant. Under
13
- * the old `q{n}:{i}of{k}` encoding that assertion was not even expressible.
14
- *
15
- * The register must also parse against `waitlistScoringSchema` (the grammar
16
- * `upsertWaitlistExperiment` validates on every write) AND survive
17
- * `waitlistExperimentConfigSchema`'s config-level cross-validation, which is
18
- * the only place the "every `optionWeights` key must be a declared option of
19
- * the question it names" rule fires
20
- * (docs/lessons/2026-09-07-shared-register-needs-a-shared-value-universe.md).
21
- * The projection's REAL config is asserted the same way in
22
- * `apps/api/src/services/__tests__/project-listing-flow.test.ts`; the minimal
23
- * wrapper below exists so a register that could never be persisted fails in
24
- * this package rather than one layer away.
25
- */
26
-
27
- import {
28
- evaluateWaitlistScoring,
29
- projectListingQuestionsSchema,
30
- waitlistExperimentConfigSchema,
31
- waitlistScoringSchema,
32
- type ProjectListingQuestions,
33
- } from "@working-theory/validation";
34
-
35
- import {
36
- buildListingDiagnosticScoring,
37
- listingDiagnosticOptionWeights,
38
- listingOptionPoints,
39
- LISTING_DIAGNOSTIC_Q5_WEIGHTS,
40
- LISTING_DIAGNOSTIC_Q6_WEIGHTS,
41
- } from "../flows/listing-diagnostic";
42
-
43
- /**
44
- * A listing's template instance: Q3/Q4 at their 4-option maximum with
45
- * founder-authored values, Q5's three fixed urgency values, Q6's four fixed
46
- * bands. Parsed through the real schema so the fixture cannot drift from the
47
- * contract the projection reads.
48
- */
49
- const QUESTIONS: ProjectListingQuestions = projectListingQuestionsSchema.parse({
50
- q2: {
51
- prompt: "What brings you here?",
52
- options: [
53
- { value: "shipping-now", label: "I'm shipping something now" },
54
- { value: "just-curious", label: "Just curious" },
55
- ],
56
- },
57
- q3: {
58
- prompt: "How painful is this problem today?",
59
- options: [
60
- { value: "none", label: "Not a problem" },
61
- { value: "mild", label: "Mildly annoying" },
62
- { value: "real", label: "A real drag" },
63
- { value: "blocking", label: "It's blocking me" },
64
- ],
65
- },
66
- q4: {
67
- prompt: "How close is this to what you need?",
68
- options: [
69
- { value: "off", label: "Not what I need" },
70
- { value: "adjacent", label: "Adjacent" },
71
- { value: "close", label: "Close" },
72
- { value: "exact", label: "Exactly it" },
73
- ],
74
- },
75
- q5: {
76
- prompt: "When would you use this?",
77
- options: [
78
- { value: "urgent", label: "Right away" },
79
- { value: "planning", label: "Next quarter" },
80
- { value: "exploring", label: "Just looking" },
81
- ],
82
- },
83
- q6: {
84
- prompt: "What would you pay?",
85
- options: [
86
- { value: "low", label: "Nothing yet" },
87
- { value: "medium", label: "A little" },
88
- { value: "high", label: "A real budget" },
89
- { value: "critical", label: "Whatever it takes" },
90
- ],
91
- },
92
- q7: { prompt: "Anything else we should know?" },
93
- extras: [],
94
- });
95
-
96
- const SCORING = buildListingDiagnosticScoring(QUESTIONS);
97
-
98
- /** The `optionWeights` map the register declares for one scored question. */
99
- function weightsOf(
100
- scoring: ReturnType<typeof buildListingDiagnosticScoring>,
101
- question: string,
102
- ): Record<string, number> {
103
- const point = scoring.points.find((p) => p.question === question);
104
- if (!point || point.kind !== "optionWeights") {
105
- throw new Error(`no optionWeights point for "${question}"`);
106
- }
107
- return point.weights;
108
- }
109
-
110
- /**
111
- * The minimal experiment config that carries a register — enough to fire
112
- * `waitlistExperimentConfigSchema`'s weights-key cross-validation, and
113
- * nothing more. The question set declares THIS listing's own options, which
114
- * is precisely what value-keyed scoring makes possible.
115
- */
116
- function experimentConfigFor(questions: ProjectListingQuestions): unknown {
117
- const scored = (["q3", "q4", "q5", "q6"] as const).map((id) => ({
118
- id,
119
- prompt: { en: questions[id].prompt },
120
- answerType: "single" as const,
121
- options: questions[id].options.map((o) => ({
122
- value: o.value,
123
- label: { en: o.label },
124
- })),
125
- }));
126
-
127
- return {
128
- key: "orbit-notes",
129
- mode: "qualifying",
130
- status: "live",
131
- waitlists: [{ key: "listing_orbit_notes", flowSlug: "orbit-notes" }],
132
- questionSet: {
133
- version: 1,
134
- questions: [
135
- {
136
- id: "email",
137
- prompt: { en: "Email" },
138
- answerType: "email",
139
- mapsTo: "email",
140
- },
141
- ...scored,
142
- ],
143
- },
144
- scoring: buildListingDiagnosticScoring(questions),
145
- tracking: {
146
- version: 1,
147
- utm: { source: "utm_source", medium: "utm_medium", campaign: "utm_campaign" },
148
- waitlists: { listing_orbit_notes: { campaign: "orbit-notes", channels: ["direct"] } },
149
- },
150
- stripeConfigRef: null,
151
- };
152
- }
153
-
154
- describe("listingOptionPoints — the founder's declared order → 0..3", () => {
155
- it("spans 0..3 whatever the arity, weakest first", () => {
156
- expect([0, 1, 2].map((i) => listingOptionPoints(i, 3))).toEqual([0, 2, 3]);
157
- expect([0, 1, 2, 3].map((i) => listingOptionPoints(i, 4))).toEqual([0, 1, 2, 3]);
158
- });
159
-
160
- it("yields 0 for a question with no spread to score", () => {
161
- expect(listingOptionPoints(0, 1)).toBe(0);
162
- });
163
- });
164
-
165
- describe("listingDiagnosticOptionWeights — keyed by value, weighted by order", () => {
166
- it("keys the founder's own values and weights them by their declared order", () => {
167
- expect(
168
- listingDiagnosticOptionWeights([
169
- { value: "none" },
170
- { value: "mild" },
171
- { value: "real" },
172
- { value: "blocking" },
173
- ]),
174
- ).toEqual({ none: 0, mild: 1, real: 2, blocking: 3 });
175
- });
176
-
177
- it("still spans 0..3 at three options", () => {
178
- expect(
179
- listingDiagnosticOptionWeights([{ value: "x" }, { value: "y" }, { value: "z" }]),
180
- ).toEqual({ x: 0, y: 2, z: 3 });
181
- });
182
- });
183
-
184
- describe("the fixed-value questions", () => {
185
- it("scores Q5 STRONGEST-first — `urgent` 3, `exploring` 0", () => {
186
- // #4998 pins Q5's values urgency-descending, so the positional rule
187
- // scored `urgent` 0 (docs/lessons/2026-09-07-q5-fixed-order-is-
188
- // strongest-first.md). Value-keyed weights say what is meant instead.
189
- expect(LISTING_DIAGNOSTIC_Q5_WEIGHTS).toEqual({
190
- urgent: 3,
191
- planning: 2,
192
- exploring: 0,
193
- });
194
- });
195
-
196
- it("keeps Q6 weakest-first — `low` 0, `critical` 3", () => {
197
- expect(LISTING_DIAGNOSTIC_Q6_WEIGHTS).toEqual({
198
- low: 0,
199
- medium: 1,
200
- high: 2,
201
- critical: 3,
202
- });
203
- });
204
-
205
- it("leaves the per-question spread at 0..3, so the total stays 0..12", () => {
206
- for (const question of ["q3", "q4", "q5", "q6"]) {
207
- const values = Object.values(weightsOf(SCORING, question));
208
- expect(Math.min(...values)).toBe(0);
209
- expect(Math.max(...values)).toBe(3);
210
- }
211
- });
212
- });
213
-
214
- describe("buildListingDiagnosticScoring — the register", () => {
215
- it("parses against waitlistScoringSchema", () => {
216
- expect(waitlistScoringSchema.safeParse(SCORING).success).toBe(true);
217
- });
218
-
219
- it("parses against waitlistExperimentConfigSchema at the config level", () => {
220
- // The weights-key cross-validation only fires here — the question set
221
- // declares this listing's OWN options, and the register keys on the same
222
- // values, so no value universe is needed.
223
- const parsed = waitlistExperimentConfigSchema.safeParse(experimentConfigFor(QUESTIONS));
224
- expect(parsed.success).toBe(true);
225
- });
226
-
227
- it("scores Q3–Q6 only — Q1/Q2/Q7 and the extras carry no points", () => {
228
- expect(SCORING.points.map((p) => p.question)).toEqual(["q3", "q4", "q5", "q6"]);
229
- });
230
-
231
- it("keys every weight on the founder's own option values, and nothing else", () => {
232
- for (const question of ["q3", "q4", "q5", "q6"] as const) {
233
- expect(Object.keys(weightsOf(SCORING, question)).sort()).toEqual(
234
- QUESTIONS[question].options.map((o) => o.value).sort(),
235
- );
236
- }
237
- });
238
-
239
- it("gives two listings the same RULE — same shape, same tiers, same fixed weights", () => {
240
- const other = buildListingDiagnosticScoring(
241
- projectListingQuestionsSchema.parse({
242
- ...QUESTIONS,
243
- q3: {
244
- prompt: "How badly does this hurt?",
245
- options: [
246
- { value: "x", label: "Not at all" },
247
- { value: "y", label: "Somewhat" },
248
- { value: "z", label: "Badly" },
249
- ],
250
- },
251
- }),
252
- );
253
-
254
- expect(other.points.map((p) => p.name)).toEqual(SCORING.points.map((p) => p.name));
255
- expect(other.scores).toEqual(SCORING.scores);
256
- expect(other.tiers).toEqual(SCORING.tiers);
257
- expect(other.default).toEqual(SCORING.default);
258
- // Only the founder-authored questions' KEYS differ.
259
- expect(weightsOf(other, "q5")).toEqual(weightsOf(SCORING, "q5"));
260
- expect(weightsOf(other, "q6")).toEqual(weightsOf(SCORING, "q6"));
261
- expect(weightsOf(other, "q3")).toEqual({ x: 0, y: 2, z: 3 });
262
- });
263
-
264
- // ── The three paths (#5001 AC2) ────────────────────────────────────────
265
-
266
- it("scores the WEAKEST path 0 → curious", () => {
267
- const result = evaluateWaitlistScoring(SCORING, {
268
- q3: "none",
269
- q4: "off",
270
- q5: "exploring",
271
- q6: "low",
272
- });
273
- expect(result.score).toBe(0);
274
- expect(result.tier).toBe("curious");
275
- });
276
-
277
- it("scores the STRONGEST path 12 → now", () => {
278
- const result = evaluateWaitlistScoring(SCORING, {
279
- q3: "blocking",
280
- q4: "exact",
281
- q5: "urgent",
282
- q6: "critical",
283
- });
284
- expect(result.score).toBe(12);
285
- expect(result.tier).toBe("now");
286
- });
287
-
288
- it("scores a MIXED path by the sum of its answers", () => {
289
- // q3 `real` 2 · q4 `adjacent` 1 · q5 `urgent` 3 · q6 `medium` 1 = 7 →
290
- // soon (7–9).
291
- const result = evaluateWaitlistScoring(SCORING, {
292
- q3: "real",
293
- q4: "adjacent",
294
- q5: "urgent",
295
- q6: "medium",
296
- });
297
- expect(result.score).toBe(7);
298
- expect(result.tier).toBe("soon");
299
- });
300
-
301
- it.each([
302
- [{ q3: "none", q4: "off", q5: "exploring", q6: "critical" }, 3, "curious"],
303
- [{ q3: "mild", q4: "adjacent", q5: "exploring", q6: "high" }, 4, "later"],
304
- [{ q3: "real", q4: "close", q5: "exploring", q6: "high" }, 6, "later"],
305
- [{ q3: "blocking", q4: "exact", q5: "exploring", q6: "critical" }, 9, "soon"],
306
- [{ q3: "blocking", q4: "exact", q5: "planning", q6: "critical" }, 11, "now"],
307
- ])("puts total %j (%i) in the %s band", (answers, expectedScore, expectedTier) => {
308
- const result = evaluateWaitlistScoring(SCORING, answers as Record<string, string>);
309
- expect(result.score).toBe(expectedScore);
310
- expect(result.tier).toBe(expectedTier);
311
- });
312
-
313
- it("is total — an unanswered diagnostic still lands on a tier", () => {
314
- const result = evaluateWaitlistScoring(SCORING, {});
315
- expect(result.score).toBe(0);
316
- expect(result.tier).toBe("curious");
317
- });
318
-
319
- // ── #5036 D4: resolution by value, not position ────────────────────────
320
-
321
- it("a reordered register scores an answer identically", () => {
322
- // The founder swaps the two middle Q3 options and the two middle Q4
323
- // options — a real edit to the register, which changes what those two
324
- // options are worth. The ANSWERED options (`blocking`, the strongest Q3;
325
- // `off`, the weakest Q4) keep the strength the founder declared, so the
326
- // same stored answer must score exactly what it scored before.
327
- //
328
- // This test is not expressible under the old `q{n}:{i}of{k}` encoding:
329
- // there was no founder value to answer with, and a stored `q3:3of4`
330
- // token was a POSITION, so any reorder or insert silently repointed it at
331
- // a different option. Resolving by value is what makes the answer survive
332
- // an edit to the register.
333
- const answers = { q3: "blocking", q4: "off", q5: "urgent", q6: "high" };
334
- const before = evaluateWaitlistScoring(SCORING, answers);
335
-
336
- const reordered = buildListingDiagnosticScoring(
337
- projectListingQuestionsSchema.parse({
338
- ...QUESTIONS,
339
- q3: {
340
- prompt: QUESTIONS.q3.prompt,
341
- options: [
342
- { value: "none", label: "Not a problem" },
343
- { value: "real", label: "A real drag" },
344
- { value: "mild", label: "Mildly annoying" },
345
- { value: "blocking", label: "It's blocking me" },
346
- ],
347
- },
348
- q4: {
349
- prompt: QUESTIONS.q4.prompt,
350
- options: [
351
- { value: "off", label: "Not what I need" },
352
- { value: "close", label: "Close" },
353
- { value: "adjacent", label: "Adjacent" },
354
- { value: "exact", label: "Exactly it" },
355
- ],
356
- },
357
- }),
358
- );
359
- const after = evaluateWaitlistScoring(reordered, answers);
360
-
361
- expect(before.score).toBe(8);
362
- expect(after.score).toBe(before.score);
363
- expect(after.tier).toBe(before.tier);
364
-
365
- // The reorder is not a no-op: the two moved options really did trade
366
- // weights, and the register the answer was resolved against is a
367
- // different object than the one it was stored under.
368
- expect(weightsOf(reordered, "q3")).not.toEqual(weightsOf(SCORING, "q3"));
369
- expect(weightsOf(reordered, "q4")).not.toEqual(weightsOf(SCORING, "q4"));
370
- expect(weightsOf(reordered, "q3")).toEqual({ none: 0, real: 1, mild: 2, blocking: 3 });
371
- });
372
-
373
- it("still parses at the config level after a reorder", () => {
374
- // A reordered register's keys are still exactly the (reordered) options
375
- // the question set declares, so the cross-validation holds.
376
- const reordered = projectListingQuestionsSchema.parse({
377
- ...QUESTIONS,
378
- q3: {
379
- prompt: QUESTIONS.q3.prompt,
380
- options: [
381
- { value: "none", label: "Not a problem" },
382
- { value: "real", label: "A real drag" },
383
- { value: "mild", label: "Mildly annoying" },
384
- { value: "blocking", label: "It's blocking me" },
385
- ],
386
- },
387
- });
388
- expect(
389
- waitlistExperimentConfigSchema.safeParse(experimentConfigFor(reordered)).success,
390
- ).toBe(true);
391
- });
392
- });
@@ -1,173 +0,0 @@
1
- /**
2
- * @file flows-presets.test.ts
3
- * @description Parse-validity for the four static capture presets (#3958
4
- * §3.5; the `roadmap` preset added by #3963 D2). This is the AC1 + AC3
5
- * verification: each preset must parse against
6
- * `flowConfigSchema` and every user-facing string must be a
7
- * `LocalizedString` carrying the flow's `defaultLocale` key. A bare-string
8
- * literal is not assignable to `LocalizedString` at the type layer — caught
9
- * by `pnpm type-check`'s `tsc -b`, via `database/tsconfig.flows.json`'s
10
- * flows-directory TypeScript include (built in the `db:generate` -> `build`
11
- * chain; the root `tsconfig.json` project-references
12
- * `database/tsconfig.build.json`, not `database/tsconfig.json`, so
13
- * `tsconfig.flows.json` is what actually puts `flows/presets.ts` on the
14
- * whole-monorepo `tsc -b` graph). `database/tsconfig.json`'s own matching
15
- * include entry (added alongside) serves a SEPARATE consumer —
16
- * `eslint.config.ts`'s typed-lint project discovery, so this file isn't an
17
- * unlinted "orphan" — and is rejected here at the schema layer as a
18
- * belt-and-suspenders runtime check.
19
- */
20
-
21
- import { flowConfigSchema } from "@working-theory/validation";
22
-
23
- import { FLOW_PRESETS } from "../flows/presets";
24
-
25
- describe("FLOW_PRESETS", () => {
26
- it("declares exactly the four static presets, by slug", () => {
27
- expect(FLOW_PRESETS.map((p) => p.slug).sort()).toEqual([
28
- "form",
29
- "lead-magnet",
30
- "roadmap",
31
- "waitlist",
32
- ]);
33
- });
34
-
35
- it.each(["form", "waitlist", "lead-magnet", "roadmap"])(
36
- "the %s preset validates against flowConfigSchema",
37
- (slug) => {
38
- const preset = FLOW_PRESETS.find((p) => p.slug === slug);
39
- expect(preset?.slug).toBe(slug);
40
-
41
- const parsed = flowConfigSchema.safeParse(preset);
42
- expect(parsed.success).toBe(true);
43
- },
44
- );
45
-
46
- it("every preset declares defaultLocale: en with a key present on every LocalizedString", () => {
47
- for (const preset of FLOW_PRESETS) {
48
- expect(preset.defaultLocale).toBe("en");
49
- // A parse failure here means some LocalizedString is missing the
50
- // defaultLocale key (flowConfigSchema's superRefine) — re-assert with
51
- // full issue detail for a failing preset's diagnosis.
52
- const parsed = flowConfigSchema.safeParse(preset);
53
- if (!parsed.success) {
54
- throw new Error(
55
- `${preset.slug} failed validation: ${JSON.stringify(parsed.error.issues, null, 2)}`,
56
- );
57
- }
58
- }
59
- });
60
-
61
- it("the lead-magnet preset's qualifier step carries no segments band map (spec §7 item 4)", () => {
62
- const preset = FLOW_PRESETS.find((p) => p.slug === "lead-magnet");
63
- const qualifier = preset?.steps.find((s) => s.key === "qualifier");
64
- expect(qualifier?.type).toBe("segmentation");
65
- if (qualifier?.type === "segmentation") {
66
- expect(qualifier.segments).toBeUndefined();
67
- }
68
- });
69
-
70
- it("every preset declares exactly one field mapped to mapsTo: email — some steps collapse name+email into one 'contact' step, roadmap splits them (spec #3963 D2)", () => {
71
- for (const preset of FLOW_PRESETS) {
72
- const emailFields = preset.steps.flatMap((step) =>
73
- step.type === "field"
74
- ? step.fields.filter((f) => f.mapsTo === "email")
75
- : [],
76
- );
77
- expect(emailFields).toHaveLength(1);
78
- expect(emailFields[0]?.name).toBe("email");
79
- }
80
- });
81
-
82
- it("no field step in any preset declares copy.cta — the FlowStepper default fallback (#4708) is what renders their submit control", () => {
83
- // #4708's drift guard, the other half of which is
84
- // packages/ui/src/sections/__tests__/FlowStepper.test.tsx's
85
- // `roadmapShapedConfig()` / `noCtaConfig()` — packages/ui cannot import
86
- // FLOW_PRESETS directly (database/flows is not a workspace package and
87
- // packages/ui declares no dependency on it — a first-time cross-tier
88
- // import architecture.yaml's boundary lint would refuse), so this
89
- // in-package assertion is the closest mechanical proof that the shape
90
- // the UI-side mirror configs cover is the shape these real presets
91
- // actually carry. If a preset ever gains an explicit cta, this
92
- // assertion needs updating — re-check the UI-side mirror still matches.
93
- for (const preset of FLOW_PRESETS) {
94
- for (const step of preset.steps) {
95
- if (step.type !== "field") continue;
96
- expect(step.copy.cta).toBeUndefined();
97
- }
98
- }
99
- });
100
-
101
- it("rejects a preset carrying a bare-string title instead of a LocalizedString", () => {
102
- const mutated = {
103
- ...FLOW_PRESETS[0],
104
- steps: [
105
- {
106
- ...FLOW_PRESETS[0]!.steps[0]!,
107
- copy: { ...FLOW_PRESETS[0]!.steps[0]!.copy, title: "Get in touch" },
108
- },
109
- ...FLOW_PRESETS[0]!.steps.slice(1),
110
- ],
111
- };
112
-
113
- const parsed = flowConfigSchema.safeParse(mutated);
114
- expect(parsed.success).toBe(false);
115
- });
116
- });
117
-
118
- // ─── FLOW_PRESETS — roadmap preset (#3963 D2) ────────────────────────────────
119
-
120
- describe("roadmap preset (#3963 D2)", () => {
121
- const preset = FLOW_PRESETS.find((p) => p.slug === "roadmap");
122
-
123
- it("exists and validates against flowConfigSchema", () => {
124
- expect(preset?.slug).toBe("roadmap");
125
- expect(flowConfigSchema.safeParse(preset).success).toBe(true);
126
- });
127
-
128
- it("declares a two-band segments map on its segmentation step", () => {
129
- const stage = preset?.steps.find((s) => s.key === "stage");
130
- expect(stage?.type).toBe("segmentation");
131
- if (stage?.type === "segmentation") {
132
- expect(stage.segments?.bands.map((b) => b.key).sort()).toEqual([
133
- "early",
134
- "scaling",
135
- ]);
136
- }
137
- });
138
-
139
- it("maps each band to a distinct thankYou slug (AC2 — two different segmentation answers derive different TY slugs)", () => {
140
- expect(preset?.thankYou?.default).toBe("roadmap-thanks");
141
- expect(preset?.thankYou?.bySegment).toEqual({
142
- early: "roadmap-thanks",
143
- scaling: "roadmap-thanks-qualified",
144
- });
145
- // The "scaling" (qualified) arm resolves to a DIFFERENT TY page than the
146
- // "early" arm and the default — the divergence the AC requires.
147
- expect(preset?.thankYou?.bySegment?.scaling).not.toBe(
148
- preset?.thankYou?.default,
149
- );
150
- });
151
-
152
- it("maps each band to a distinct deliverables assetKey (AC2 — different asset grants)", () => {
153
- const assets = preset?.deliverables?.assets ?? [];
154
- const early = assets.find((a) => a.segment === "early");
155
- const scaling = assets.find((a) => a.segment === "scaling");
156
- expect(early?.assetKey).toBe("roadmap-early");
157
- expect(scaling?.assetKey).toBe("roadmap-scaling");
158
- expect(early?.assetKey).not.toBe(scaling?.assetKey);
159
- });
160
-
161
- it("declares abandonEmail authored but dark (#3962 D2 — shipped off, no send)", () => {
162
- expect(preset?.abandonEmail?.mode).toBe("dark");
163
- expect(preset?.abandonEmail?.delayMinutes).toBeGreaterThanOrEqual(5);
164
- });
165
-
166
- it("collects no phone/address fields (the acquisition-capture's §5 over-collection is deliberately not reproduced)", () => {
167
- const fieldNames = (preset?.steps ?? []).flatMap((step) =>
168
- step.type === "field" ? step.fields.map((f) => f.name) : [],
169
- );
170
- expect(fieldNames).not.toContain("phone");
171
- expect(fieldNames).not.toContain("address");
172
- });
173
- });