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,339 +0,0 @@
1
- // content namespace — chat + artifact substrate (AgentSession, ConversationEvent,
2
- // SessionReadReceipt, Artifact, ArtifactVersion, Asset)
3
- //
4
- // Backs the event-sourced conversation transport + artifact persistence in
5
- // docs/research/ploy-capture/BACKEND-REQUIREMENTS.md (§1 transport R-T1..R-T7,
6
- // §2 event envelope, §3 endpoints). Workspaces own all domain content, so every
7
- // table here carries a non-null `workspaceId` tenant scope.
8
- //
9
- // Per ADR 0009 invariant 1: workspaceId / userId are plain String stable IDs —
10
- // NO @relation into the auth namespace (Workspace/User live in database/auth/).
11
- // Relations WITHIN this namespace (event → session, version → artifact) are
12
- // real FKs. Cross-namespace assembly (e.g. tenant guard resolving a session's
13
- // workspace) routes through apps/api/src/services/ (invariant 4).
14
- //
15
- // Generator + datasource blocks live in database/schema.prisma (the root schema
16
- // file). This file holds only model definitions for the content namespace.
17
-
18
- /// AgentSession — one agent conversation ("session"/captured "ploy") within a
19
- /// workspace. lastSeq is the append watermark for the event log (R-T1).
20
- model AgentSession {
21
- id String @id @default(dbgenerated("('agsess_'::text || (uuidv7())::text)")) @db.Text
22
- workspaceId String @map("workspace_id")
23
- title String?
24
- status String @default("idle")
25
- lastSeq Int @default(0) @map("last_seq")
26
- lastMessageAt DateTime? @map("last_message_at")
27
- draftMessage String? @map("draft_message")
28
- createdAt DateTime @default(now()) @map("created_at")
29
- updatedAt DateTime @updatedAt @map("updated_at")
30
-
31
- events ConversationEvent[]
32
- artifacts Artifact[]
33
- readReceipts SessionReadReceipt[]
34
-
35
- @@index([workspaceId, lastMessageAt(sort: Desc)])
36
- @@map("agent_sessions")
37
- }
38
-
39
- /// ConversationEvent — append-only, seq-ordered event log entry (R-T1/R-T4).
40
- /// Envelope: { agentId, seq, type, turnId, payload, createdAt } (§2).
41
- /// workspaceId is denormalized so the scope layer filters events without a
42
- /// join through agent_sessions.
43
- model ConversationEvent {
44
- id String @id @default(dbgenerated("('convev_'::text || (uuidv7())::text)")) @db.Text
45
- sessionId String @map("session_id")
46
- workspaceId String @map("workspace_id")
47
- agentId String @map("agent_id")
48
- seq Int
49
- type String
50
- turnId String? @map("turn_id")
51
- payload Json
52
- createdAt DateTime @default(now()) @map("created_at")
53
-
54
- session AgentSession @relation(fields: [sessionId], references: [id], onDelete: Cascade)
55
-
56
- @@unique([sessionId, seq])
57
- @@index([workspaceId])
58
- @@map("conversation_events")
59
- }
60
-
61
- /// SessionReadReceipt — per-user read position for a session (R-T7 mark-read;
62
- /// drives unread badges). userId is a stable auth-namespace ID — no FK.
63
- model SessionReadReceipt {
64
- id String @id @default(dbgenerated("('receipt_'::text || (uuidv7())::text)")) @db.Text
65
- sessionId String @map("session_id")
66
- workspaceId String @map("workspace_id")
67
- userId String @map("user_id")
68
- lastReadSeq Int @default(0) @map("last_read_seq")
69
- updatedAt DateTime @updatedAt @map("updated_at")
70
-
71
- session AgentSession @relation(fields: [sessionId], references: [id], onDelete: Cascade)
72
-
73
- @@unique([sessionId, userId])
74
- @@index([workspaceId])
75
- @@map("session_read_receipts")
76
- }
77
-
78
- /// Artifact — a piece of the WORKSPACE's versioned content (#3846, generalized
79
- /// by #5800 / roadmap D1). Originally "a session's produced output"; a session
80
- /// is now PROVENANCE, not ownership — `sessionId` is optional and `SetNull`, so
81
- /// deleting the conversation that produced a page leaves the page standing.
82
- ///
83
- /// `contentType` is the discriminator the content store reads: `text/page` is
84
- /// what the editor writes, `text/document` the legacy chat artifact. A page's
85
- /// public identity is `(workspaceId, contentType, locale, slug)`; `slug` stays
86
- /// NULL until publish, and NULLs never collide in a Postgres unique index, so a
87
- /// workspace may hold any number of unpublished drafts.
88
- ///
89
- /// `publishedVersionId` is a plain pointer at the ArtifactVersion the public
90
- /// read serves — deliberately NOT a relation (a FK back into `versions` would
91
- /// make the delete order of an artifact's own history circular), and
92
- /// deliberately NOT `ArtifactVersion.isCurrent`, which is the DRAFT TIP and is
93
- /// never the publish mechanism. Saving a draft moves `isCurrent`; only publish
94
- /// moves this pointer.
95
- ///
96
- /// `type` is the LEGACY discriminator. It predates `contentType` and is still
97
- /// read by apps/api/src/routes/workspaces/sessions.ts (the session-artifacts
98
- /// route, a hard-floor surface), so #5800 added `contentType` beside it and
99
- /// backfilled it from `type` rather than renaming the column out from under a
100
- /// live consumer. New code reads `contentType`; retiring `type` belongs to the
101
- /// card that moves that route.
102
- model Artifact {
103
- id String @id @default(dbgenerated("('artif_'::text || (uuidv7())::text)")) @db.Text
104
- sessionId String? @map("session_id")
105
- workspaceId String @map("workspace_id")
106
- type String @default("text/document")
107
- contentType String @default("text/document") @map("content_type")
108
- locale String @default("en")
109
- slug String?
110
- title String
111
- publishedVersionId String? @map("published_version_id")
112
- createdAt DateTime @default(now()) @map("created_at")
113
- updatedAt DateTime @updatedAt @map("updated_at")
114
-
115
- session AgentSession? @relation(fields: [sessionId], references: [id], onDelete: SetNull)
116
- versions ArtifactVersion[]
117
-
118
- @@unique([workspaceId, contentType, locale, slug])
119
- @@index([sessionId])
120
- @@index([workspaceId])
121
- @@index([workspaceId, contentType, updatedAt])
122
- @@map("artifacts")
123
- }
124
-
125
- /// ArtifactVersion — auto-saved version history; exactly one isCurrent per
126
- /// artifact (enforced at the service layer on save/restore).
127
- model ArtifactVersion {
128
- id String @id @default(dbgenerated("('artiv_'::text || (uuidv7())::text)")) @db.Text
129
- artifactId String @map("artifact_id")
130
- workspaceId String @map("workspace_id")
131
- content Json
132
- isCurrent Boolean @default(true) @map("is_current")
133
- savedAt DateTime @default(now()) @map("saved_at")
134
-
135
- artifact Artifact @relation(fields: [artifactId], references: [id], onDelete: Cascade)
136
-
137
- @@index([artifactId, savedAt(sort: Desc)])
138
- @@index([workspaceId])
139
- @@map("artifact_versions")
140
- }
141
-
142
- /// Asset — a workspace's uploaded binary (#5800 / roadmap D7), following the
143
- /// `DeliverableAsset` precedent in the inbox namespace: the bytes live in the
144
- /// row, not in object storage. That precedent was deliberate — no new
145
- /// infrastructure — and only the resolver changes if blob storage arrives later.
146
- ///
147
- /// `workspaceId` is a plain String stable id with no @relation (ADR 0009
148
- /// invariant 1), and `(workspaceId, key)` is the addressable identity. Ids are
149
- /// UUIDv7 (ADR 0031), so a re-upload is a NEW id and a served asset can be
150
- /// cached immutably. The upload route itself is #5802's scope, not this model's.
151
- ///
152
- /// Since #6310: this is also the store a magnet's `deliverables.assets[].assetKey`
153
- /// resolves against FIRST (by `(workspaceId, key)`), ahead of the legacy
154
- /// `DeliverableAsset` fallback (database/inbox/schema.prisma) — read through
155
- /// the scoped boundary in apps/api/src/lib/deliverable-asset-store.ts, never
156
- /// a raw query.
157
- model Asset {
158
- id String @id @default(dbgenerated("('asset_'::text || (uuidv7())::text)")) @db.Text
159
- workspaceId String @map("workspace_id")
160
- /// The caller-chosen name an artifact's content references the asset by.
161
- key String
162
- /// Download filename (Content-Disposition). Stored RAW; sanitize at SERVE
163
- /// time, exactly as the DeliverableAsset download route does.
164
- filename String
165
- contentType String @map("content_type")
166
- bytes Bytes
167
- size Int
168
- /// Owner-authored display name, shown above the filename in the lightbox
169
- /// (#6092, S4/D10). NULL means the owner has not written one — distinct from
170
- /// an empty string, which means they cleared it. Never backfilled from
171
- /// `filename`: the two are different facts (demo.html:782 renders both).
172
- title String?
173
- /// Owner-authored longer description. Same NULL-vs-empty contract as `title`.
174
- description String?
175
- /// Owner-controlled tag SLUGS (`ad-creative`, `workspace-memory`, …), never
176
- /// the human labels — the label is presentation, resolved by the surface from
177
- /// its own vocabulary (demo.html:358 `ATAGS`, :794 the Docs set). Free-form
178
- /// by design: the asset vocabulary and the document vocabulary (D8/D9) ride
179
- /// this one column, and the "fixed set" of D10 is a UI affordance, not a
180
- /// database constraint (#6092, D2 of the spec).
181
- tags String[] @default([])
182
- createdAt DateTime @default(now()) @map("created_at")
183
-
184
- @@unique([workspaceId, key])
185
- @@index([workspaceId])
186
- @@map("assets")
187
- }
188
-
189
- // ============================================================================
190
- // Usage-billing metering (FEAT-047 P1.S1, #3709 — Epic #3704)
191
- //
192
- // The metering event + its org-level aggregates. Per ADR 0009 D2 (roadmap §4),
193
- // the metering event + UsagePeriod + UsageBillingReport live in `content`;
194
- // balances/plans (S2) live in auth/config. organizationId/workspaceId/userId
195
- // are plain String stable-ids — no @relation into auth (ADR 0009 invariant 1).
196
- // Field roster ported from docs/research/wt-billing-capture/schema.md, modeled
197
- // on WT's TraceLog billing columns (spec D1), with workspaceId/userId added to
198
- // the event grain (spec D2). Cross-namespace assembly (e.g. resolving an
199
- // event's owning Workspace) routes through apps/api/src/services/.
200
- // ============================================================================
201
-
202
- /// ModelTier — the pricing tier at event time. BASE is unlimited/free-ish;
203
- /// PREMIUM/FRONTIER consume credits. Defined here (S1, the dependency root)
204
- /// per spec OQ-1 — S2's LlmModel references the same enum through the merged
205
- /// prismaSchemaFolder (one logical schema; an enum reference needs no
206
- /// @relation, so this is not a cross-namespace FK).
207
- enum ModelTier {
208
- BASE
209
- PREMIUM
210
- FRONTIER
211
- }
212
-
213
- /// UsageBillingStatus — UsageBillingReport lifecycle: PENDING → REPORTED →
214
- /// INVOICED → PAID, or FAILED.
215
- enum UsageBillingStatus {
216
- PENDING
217
- REPORTED
218
- INVOICED
219
- PAID
220
- FAILED
221
- }
222
-
223
- /// UsageEvent — one row per billable AI call (the metering event; modeled on
224
- /// WT's TraceLog billing columns, spec D1). org+workspace+user grain (spec
225
- /// D2); all three scope ids are plain String stable-ids — no cross-namespace
226
- /// @relation (ADR 0009 invariant 1, spec D3). The three attribution portion
227
- /// columns are the load-bearing billing split; only onDemandPortionCents is
228
- /// ever reported to Stripe (P4, spec D4). completionStatus 'success' rows
229
- /// drive billing — aggregation (P2) filters on it.
230
- model UsageEvent {
231
- id String @id @default(dbgenerated("('usagev_'::text || (uuidv7())::text)")) @db.Text
232
- organizationId String @map("organization_id")
233
- workspaceId String @map("workspace_id")
234
- userId String @map("user_id")
235
-
236
- provider String
237
- model String
238
-
239
- // Cache-aware token breakdown.
240
- inputTokensCacheWrite Int @map("input_tokens_cache_write")
241
- inputTokensNoCacheWrite Int @map("input_tokens_no_cache_write")
242
- cacheReadTokens Int @map("cache_read_tokens")
243
- outputTokens Int @map("output_tokens")
244
- thinkingTokens Int @map("thinking_tokens")
245
- totalTokens Int @map("total_tokens")
246
-
247
- providerCostUsd Decimal @map("provider_cost_usd") @db.Decimal(10, 6)
248
- billedCostUsd Decimal @map("billed_cost_usd") @db.Decimal(10, 6)
249
- markupPercent Decimal @map("markup_percent") @db.Decimal(5, 2)
250
-
251
- modelTier ModelTier @default(BASE) @map("model_tier")
252
- wasAutoModel Boolean @map("was_auto_model")
253
-
254
- // Attribution split — billedCostUsd apportioned across the three buckets;
255
- // only onDemandPortionCents is ever Stripe-metered (P4, spec D4).
256
- includedPortionCents Int @default(0) @map("included_portion_cents")
257
- creditBalancePortionCents Int @default(0) @map("credit_balance_portion_cents")
258
- onDemandPortionCents Int @default(0) @map("on_demand_portion_cents")
259
-
260
- completionStatus String @map("completion_status")
261
- createdAt DateTime @default(now()) @map("created_at")
262
-
263
- @@index([organizationId, createdAt])
264
- @@index([workspaceId, createdAt])
265
- @@index([userId, createdAt])
266
- @@index([provider, model])
267
- @@index([modelTier, wasAutoModel])
268
- @@map("usage_events")
269
- }
270
-
271
- /// UsagePeriod — one row per (organizationId, periodStart); the org-scoped
272
- /// spend/tier rollup the P2 write path upserts as UsageEvent rows land.
273
- /// Carries the event-grain roll-up support for the Org → Workspace → User
274
- /// aggregation (spec D2) — whether this model itself gains per-workspace
275
- /// sub-rows is a P2 decision, not a P1 schema requirement (spec OQ-2).
276
- model UsagePeriod {
277
- id String @id @default(dbgenerated("('usagper_'::text || (uuidv7())::text)")) @db.Text
278
- organizationId String @map("organization_id")
279
-
280
- periodStart DateTime @map("period_start")
281
- periodEnd DateTime @map("period_end")
282
-
283
- tokensConsumed BigInt @default(0) @map("tokens_consumed")
284
- baseTokensConsumed BigInt @default(0) @map("base_tokens_consumed")
285
- premiumTokensConsumed BigInt @default(0) @map("premium_tokens_consumed")
286
- frontierTokensConsumed BigInt @default(0) @map("frontier_tokens_consumed")
287
-
288
- usageSpendCents Int @default(0) @map("usage_spend_cents")
289
-
290
- @@unique([organizationId, periodStart])
291
- @@index([baseTokensConsumed, premiumTokensConsumed, frontierTokensConsumed], map: "usage_periods_tier_tracking_idx")
292
- @@map("usage_periods")
293
- }
294
-
295
- /// UsageBillingReport — one per (organizationId, periodStart, periodEnd); the
296
- /// Stripe-reporting unit rolled up from UsageEvent by P2 aggregation. Only
297
- /// onDemandCents is ever reported to Stripe (P4, spec D4) — includedCents/
298
- /// creditBalanceCents are informational attribution, never metered.
299
- model UsageBillingReport {
300
- id String @id @default(dbgenerated("('usagrept_'::text || (uuidv7())::text)")) @db.Text
301
- organizationId String @map("organization_id")
302
-
303
- periodStart DateTime @map("period_start")
304
- periodEnd DateTime @map("period_end")
305
-
306
- // AGGREGATE precision (#3738 H2) — these hold a MONTH of events, not one
307
- // event, so they must NOT reuse UsageEvent's per-event widths. At the
308
- // original Decimal(10,6)/Int, an org whose month crossed $9,999.999999 (or
309
- // 2.15B tokens) overflowed the column, the upsert threw, and the report was
310
- // never written on ANY subsequent run — silently stalling revenue for the
311
- // largest customers, worsening monotonically. Decimal(20,6) ≈ $1e14 and int8
312
- // give headroom far above the service's own MAX_TOTAL_USD / token caps, so
313
- // the service's loud `aggregate_overflow` assertion is always the gate and a
314
- // silent DB overflow is unreachable. See usage-aggregation.ts § Bounds.
315
- totalProviderCost Decimal @map("total_provider_cost") @db.Decimal(20, 6)
316
- totalMarkupAmount Decimal @map("total_markup_amount") @db.Decimal(20, 6)
317
- totalBilledAmount Decimal @map("total_billed_amount") @db.Decimal(20, 6)
318
-
319
- totalTokens BigInt @map("total_tokens")
320
- eventCount Int @map("event_count")
321
-
322
- // Attribution split — only onDemandCents is ever Stripe-metered (P4, spec D4).
323
- includedCents Int @default(0) @map("included_cents")
324
- creditBalanceCents Int @default(0) @map("credit_balance_cents")
325
- onDemandCents Int @default(0) @map("on_demand_cents")
326
-
327
- stripeUsageRecordId String? @map("stripe_usage_record_id")
328
- reportedToStripeAt DateTime? @map("reported_to_stripe_at")
329
- stripeInvoiceId String? @map("stripe_invoice_id")
330
-
331
- status UsageBillingStatus @default(PENDING)
332
- errorMessage String? @map("error_message")
333
-
334
- @@unique([organizationId, periodStart, periodEnd], map: "usage_billing_reports_period_key")
335
- @@index([organizationId, status])
336
- @@index([status])
337
- @@index([periodStart])
338
- @@map("usage_billing_reports")
339
- }
@@ -1,69 +0,0 @@
1
- // Self-contained ESLint flat config for this scaffolded package.
2
- //
3
- // It deliberately does NOT depend on @working-theory/eslint-config — that
4
- // package is internal to the AI Launch Kit monorepo and is not published, so
5
- // it cannot be a dependency of a scaffolded starter. Everything below comes
6
- // from public npm packages already pinned as devDependencies (see
7
- // package.json): @eslint/js, globals and typescript-eslint.
8
- //
9
- // Source file name (#5556): this file is checked in as `_eslint.config.mjs`,
10
- // not `eslint.config.mjs` — build-templates.mjs renames it at snapshot time
11
- // (renameScaffoldLintConfigs()). A file literally named `eslint.config.mjs`
12
- // anywhere under this monorepo (even one this repo's own root eslint.config.ts
13
- // lists in its `ignores`) is auto-discovered by ESLint's flat-config nested
14
- // resolution as a competing config root, which breaks the monorepo's own
15
- // lint runs (verified live: typescript-eslint's "multiple candidate
16
- // TSConfigRootDirs" parser error across unrelated packages/create-ailk
17
- // files). The underscore prefix keeps it invisible to that discovery while
18
- // it lives in this checkout; only the snapshot in templates/ — which ships
19
- // to the customer, not this repo — gets the real filename.
20
- import js from "@eslint/js";
21
- import globals from "globals";
22
- import tseslint from "typescript-eslint";
23
-
24
- export default tseslint.config(
25
- {
26
- ignores: [
27
- "**/.next/**",
28
- "**/dist/**",
29
- "**/generated/**",
30
- "**/node_modules/**",
31
- ],
32
- },
33
- js.configs.recommended,
34
- ...tseslint.configs.recommended,
35
- {
36
- languageOptions: {
37
- globals: {
38
- ...globals.node,
39
- ...globals.browser,
40
- ...globals.jest,
41
- },
42
- // Explicit, self-contained root — this scaffold config is never meant
43
- // to combine with any sibling scaffold package's config (each ships
44
- // standalone), and leaving it unset makes typescript-eslint's
45
- // candidate-root disambiguation ambiguous the moment more than one
46
- // scaffold package's config resolves in the same ESLint process (e.g.
47
- // this monorepo's own `templates/` build, where all four exist
48
- // side by side; a real customer scaffold never has that problem,
49
- // since it only ever ships and lints ONE of these four at a time).
50
- parserOptions: {
51
- tsconfigRootDir: import.meta.dirname,
52
- },
53
- },
54
- rules: {
55
- // Downgraded rather than off, so both stay visible without failing a
56
- // fresh scaffold's lint:
57
- // - unused-vars: most of the source follows the underscore-prefix
58
- // convention for intentionally-unused bindings, which this rule's
59
- // default options don't recognize; a handful of test fixtures also
60
- // carry genuinely-unused locals this minimal config doesn't try to
61
- // triage file-by-file.
62
- // - require-imports: CommonJS require() is the correct form in Jest
63
- // config/mock files and in a few test-only dynamic re-require
64
- // patterns.
65
- "@typescript-eslint/no-unused-vars": "warn",
66
- "@typescript-eslint/no-require-imports": "warn",
67
- },
68
- },
69
- );
@@ -1,182 +0,0 @@
1
- /**
2
- * @file listing-diagnostic.ts
3
- * @description The ONE scoring RULE every project-listing diagnostic shares
4
- * (#5001, reworked by #5036 D4) — the template's Q3–Q6 resolved by option
5
- * VALUE, never by option position.
6
- *
7
- * The mechanism (#5036 D4, "scoring by value, not position"): the generated
8
- * flow emits each scored option under the FOUNDER'S OWN `option.value`, and
9
- * the register's `optionWeights` map is keyed on those same values. Q3/Q4 are
10
- * founder-authored, so their weights map is built PER LISTING from that
11
- * listing's own options — the WEIGHT still comes from the founder's declared
12
- * order via `listingOptionPoints(index, arity)`, but it is stored against the
13
- * value rather than an index. Q5/Q6 carry fixed values
14
- * (`projectListingQuestionsSchema`, #4998), so their weights are declared once
15
- * here, shared by every listing.
16
- *
17
- * What that buys, and why the old `q{n}:{i}of{k}` encoding had to go: meaning
18
- * now travels with the value. A register may reorder or insert options and an
19
- * already-stored answer keeps scoring what it always meant, so the subset a
20
- * surface renders no longer has to be a prefix of the register's list — which
21
- * is what unblocks the shared team-composition value set (#5036 D3). It also
22
- * dissolves the "shared register needs a shared value universe" problem
23
- * (docs/lessons/2026-09-07-…): the generated experiment's `questionSet` now
24
- * declares the listing's OWN options, so
25
- * `waitlistExperimentConfigSchema`'s "every weights key must be a declared
26
- * option" cross-validation is satisfied by construction rather than by
27
- * declaring a finite universe of positional tokens.
28
- *
29
- * What is shared is therefore the RULE and the shape — same point names, same
30
- * `total` sum, same tier floors, same 0–12 range — not a single frozen
31
- * constant. Two listings' registers differ only in the Q3/Q4 KEYS, which are
32
- * the founders' own option values.
33
- *
34
- * Q5 runs STRONGEST-FIRST, deliberately. `projectListingQuestionsSchema` pins
35
- * Q5's values as `urgent | planning | exploring`, which is urgency descending,
36
- * while the positional rule scores index 0 lowest — so the old positional
37
- * encoding scored `urgent` 0 and `exploring` 3, backwards, a standing defect
38
- * recorded in docs/lessons/2026-09-07-q5-fixed-order-is-strongest-first.md.
39
- * Scoring by value is exactly the mechanism that resolves it: the weights
40
- * below name `urgent` 3 and `exploring` 0 explicitly, with no reordering of
41
- * the founder's rendered options and no per-question special case hidden
42
- * inside a positional formula. That lesson's open question is closed here.
43
- * Q6 (`low → critical`) is genuinely weakest-first and keeps 0 → 3.
44
- *
45
- * Q1 (contact), Q2 (segment), Q7 (free text) and the extras carry no points —
46
- * they are absent from `points` entirely, so they contribute 0 by
47
- * construction rather than by a zero weight that could drift.
48
- *
49
- * This module is data + the pure functions that generate it — it imports only
50
- * TYPES from `@working-theory/validation` and introduces no dependency from
51
- * `database/` toward `apps/*` (architecture.yaml's import boundary), exactly
52
- * like `presets.ts` beside it. The rule lives here and only here; the
53
- * projection (`apps/api/src/services/project-listing-flow.ts`) calls
54
- * `buildListingDiagnosticScoring` rather than re-deriving weights, so the
55
- * register and the flow can never disagree about what an answer is worth.
56
- */
57
-
58
- import type {
59
- ProjectListingQuestions,
60
- WaitlistScoring,
61
- } from "@working-theory/validation";
62
-
63
- /** The four scored template questions, in template order. */
64
- export const LISTING_DIAGNOSTIC_SCORED_QUESTIONS = ["q3", "q4", "q5", "q6"] as const;
65
- export type ListingDiagnosticScoredQuestion =
66
- (typeof LISTING_DIAGNOSTIC_SCORED_QUESTIONS)[number];
67
-
68
- /** The highest score any one question can contribute. */
69
- export const LISTING_DIAGNOSTIC_MAX_QUESTION_POINTS = 3;
70
-
71
- /**
72
- * The weight of option `index` (zero-based) of `arity` options —
73
- * `round(3·i/(k−1))`, so the founder's first option always scores 0 and their
74
- * last always scores 3, whatever the arity. This is still how a
75
- * founder-authored question's weights are DERIVED (the founder orders their
76
- * options weakest→strongest); what changed in #5036 D4 is where the result is
77
- * STORED — against the option's value, not its index.
78
- *
79
- * A single-option question (`arity <= 1`) has no spread to score and yields 0;
80
- * the template never produces one, and this guard exists so the expression can
81
- * never divide by zero.
82
- */
83
- export function listingOptionPoints(index: number, arity: number): number {
84
- if (arity <= 1) return 0;
85
- return Math.round((LISTING_DIAGNOSTIC_MAX_QUESTION_POINTS * index) / (arity - 1));
86
- }
87
-
88
- /**
89
- * `optionWeights` for one founder-authored question (Q3/Q4), keyed by the
90
- * founder's own option values and weighted by their declared order.
91
- */
92
- export function listingDiagnosticOptionWeights(
93
- options: readonly { value: string }[],
94
- ): Record<string, number> {
95
- const weights: Record<string, number> = {};
96
- options.forEach((option, index) => {
97
- weights[option.value] = listingOptionPoints(index, options.length);
98
- });
99
- return weights;
100
- }
101
-
102
- /**
103
- * Q5's fixed urgency weights — STRONGEST FIRST, against the positional rule
104
- * and deliberately so (see the file header). `urgent` is the strongest buying
105
- * signal the question can carry and scores 3; `exploring` is the weakest and
106
- * scores 0. The three weights are the same multiset a 3-option positional
107
- * question produces (`{0, 2, 3}`), so the 0–12 total range is unchanged.
108
- */
109
- export const LISTING_DIAGNOSTIC_Q5_WEIGHTS: Readonly<Record<string, number>> = {
110
- urgent: 3,
111
- planning: 2,
112
- exploring: 0,
113
- };
114
-
115
- /**
116
- * Q6's fixed band weights — weakest first, matching the schema's own
117
- * `low → critical` low→high ordering, so these are exactly what the positional
118
- * rule produced for a 4-option question.
119
- */
120
- export const LISTING_DIAGNOSTIC_Q6_WEIGHTS: Readonly<Record<string, number>> = {
121
- low: 0,
122
- medium: 1,
123
- high: 2,
124
- critical: 3,
125
- };
126
-
127
- /** The four tier keys, strongest first — the order `tiers` is evaluated in. */
128
- export const LISTING_DIAGNOSTIC_TIERS = ["now", "soon", "later", "curious"] as const;
129
-
130
- /**
131
- * The inclusive lower bound of each tier over the 0–12 total (4 questions ×
132
- * 3 points): `now` 10–12, `soon` 7–9, `later` 4–6, `curious` 0–3. Ordered
133
- * strongest-first because `evaluateWaitlistScoring` takes the FIRST matching
134
- * tier, so a `gte` ladder read top-down is total and unambiguous.
135
- */
136
- const TIER_FLOORS: Readonly<Record<(typeof LISTING_DIAGNOSTIC_TIERS)[number], number>> = {
137
- now: 10,
138
- soon: 7,
139
- later: 4,
140
- curious: 0,
141
- };
142
-
143
- /**
144
- * Build one listing's register from its own `questions` block. Embedded
145
- * verbatim into that listing's generated `WaitlistExperiment.config` —
146
- * `waitlistExperimentConfigSchema` carries the scoring block by value and
147
- * offers no by-reference slot.
148
- *
149
- * Every listing gets the same point names, the same `total` sum, the same
150
- * tier ladder and the same 0–12 range; only the Q3/Q4 weight KEYS differ,
151
- * because those keys are the founder's own option values (#5036 D4).
152
- */
153
- export function buildListingDiagnosticScoring(
154
- questions: ProjectListingQuestions,
155
- ): WaitlistScoring {
156
- const weights: Record<ListingDiagnosticScoredQuestion, Record<string, number>> = {
157
- q3: listingDiagnosticOptionWeights(questions.q3.options),
158
- q4: listingDiagnosticOptionWeights(questions.q4.options),
159
- q5: { ...LISTING_DIAGNOSTIC_Q5_WEIGHTS },
160
- q6: { ...LISTING_DIAGNOSTIC_Q6_WEIGHTS },
161
- };
162
-
163
- return {
164
- version: 1,
165
- points: LISTING_DIAGNOSTIC_SCORED_QUESTIONS.map((question) => ({
166
- name: `${question}_points`,
167
- question,
168
- kind: "optionWeights" as const,
169
- weights: weights[question],
170
- })),
171
- scores: {
172
- total: {
173
- sum: LISTING_DIAGNOSTIC_SCORED_QUESTIONS.map((q) => `${q}_points`),
174
- },
175
- },
176
- tiers: LISTING_DIAGNOSTIC_TIERS.map((key) => ({
177
- key,
178
- when: { score: "total", gte: TIER_FLOORS[key] },
179
- })),
180
- default: "curious",
181
- };
182
- }