create-ailk 0.24.0 → 0.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (638) hide show
  1. package/README.md +53 -22
  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 +2 -1
  14. package/dist/lib/fetch-template-snapshot.js +8 -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 +36 -15
  19. package/dist/lib/module-tier.d.ts +2 -8
  20. package/dist/lib/module-tier.js +13 -12
  21. package/dist/module-architecture.d.ts +20 -3
  22. package/dist/module-architecture.js +129 -552
  23. package/dist/paid-sections.d.ts +25 -1
  24. package/dist/paid-sections.js +88 -3
  25. package/dist/starter-grid.d.ts +6 -6
  26. package/dist/starter-grid.js +12 -5
  27. package/dist/surfaces.js +39 -2
  28. package/dist/template-record.d.ts +21 -3
  29. package/dist/template-record.js +38 -7
  30. package/dist/topology.d.ts +16 -3
  31. package/dist/topology.js +54 -23
  32. package/dist/update.d.ts +10 -1
  33. package/dist/update.js +715 -21
  34. package/package.json +3 -3
  35. package/release-scope.json +2 -2
  36. package/site-templates/marketing-site/TEMPLATE-MANIFEST.json +8 -2
  37. package/site-templates/marketing-site/TEMPLATE-MANIFEST.md +2 -2
  38. package/site-templates/marketing-site/ailk-template.json +7 -1
  39. package/site-templates/marketing-site/provenance.json +7 -1
  40. package/site-templates/saas-product/ailk-template.json +2 -1
  41. package/site-templates/saas-product/provenance.json +1 -0
  42. package/templates/.claude/cloudparity-repo-hooks.json +5 -0
  43. package/templates/.claude/hooks/template-guard.sh +137 -0
  44. package/templates/.claude/rules/extending.md +106 -0
  45. package/templates/.claude/rules/loop-contract.md +2 -2
  46. package/templates/.claude/settings.json +11 -0
  47. package/templates/.env.example +20 -5
  48. package/templates/.github/workflows/ci.yml +7 -4
  49. package/templates/CLAUDE.md +11 -1
  50. package/templates/CONVENTIONS.md +8 -10
  51. package/templates/README.md +14 -13
  52. package/templates/apps/api/.env.example +23 -2
  53. package/templates/apps/api/CLAUDE.md +119 -83
  54. package/templates/apps/api/jest.config.cjs +15 -5
  55. package/templates/apps/api/package.json +16 -20
  56. package/templates/apps/api/src/__tests__/trusted-origins.server.test.ts +2 -2
  57. package/templates/apps/api/src/__tests__/vercel-handler.test.ts +4 -4
  58. package/templates/apps/api/src/index.ts +1 -1
  59. package/templates/apps/api/src/lib/__mocks__/prisma-client.js +16 -0
  60. package/templates/apps/api/src/lib/__mocks__/prisma.ts +3 -3
  61. package/templates/apps/api/src/modules/commerce.ts +10 -0
  62. package/templates/apps/api/src/modules/content-write.ts +10 -0
  63. package/templates/apps/api/src/modules/multi-tenant.ts +10 -0
  64. package/templates/apps/api/src/modules/scheduling.ts +10 -0
  65. package/templates/apps/api/src/modules/signal-collectors.ts +10 -0
  66. package/templates/apps/api/src/modules/workspace.ts +10 -0
  67. package/templates/apps/api/src/server.ts +117 -1882
  68. package/templates/apps/api/vercel.json +2 -2
  69. package/templates/apps/mcp/CLAUDE.md +90 -26
  70. package/templates/apps/mcp/__tests__/app-entry.test.ts +4 -254
  71. package/templates/apps/mcp/__tests__/boot-file.test.ts +92 -0
  72. package/templates/apps/mcp/jest.config.cjs +6 -1
  73. package/templates/apps/mcp/package.json +5 -13
  74. package/templates/apps/mcp/src/app.ts +8 -7
  75. package/templates/apps/mcp/src/index.ts +6 -34
  76. package/templates/apps/mcp/src/lib/paid-tools.generated.ts +10 -0
  77. package/templates/apps/mcp/src/lib/topology.generated.ts +2 -2
  78. package/templates/apps/mcp/src/site.ts +12 -0
  79. package/templates/apps/web/.env.example +1 -1
  80. package/templates/apps/web/CLAUDE.md +31 -3
  81. package/templates/apps/web/app/.well-known/mcp.json/route.ts +9 -3
  82. package/templates/apps/web/app/[locale]/(auth)/__tests__/auth-pages.test.tsx +43 -4
  83. package/templates/apps/web/app/[locale]/(auth)/legal-footnote.tsx +35 -0
  84. package/templates/apps/web/app/[locale]/(auth)/sign-in/__tests__/page.test.tsx +117 -8
  85. package/templates/apps/web/app/[locale]/(auth)/sign-in/page.tsx +14 -37
  86. package/templates/apps/web/app/[locale]/(auth)/sign-in/sign-in-card.tsx +6 -6
  87. package/templates/apps/web/app/[locale]/(auth)/sign-in/sign-in-text.ts +20 -35
  88. package/templates/apps/web/app/[locale]/(auth)/sign-up/__tests__/page.test.tsx +108 -0
  89. package/templates/apps/web/app/[locale]/(auth)/sign-up/__tests__/sign-up-card.test.tsx +111 -5
  90. package/templates/apps/web/app/[locale]/(auth)/sign-up/page.tsx +78 -16
  91. package/templates/apps/web/app/[locale]/(auth)/sign-up/sign-up-card.tsx +132 -12
  92. package/templates/apps/web/app/[locale]/(authed)/__tests__/gate.test.tsx +53 -1
  93. package/templates/apps/web/app/[locale]/(authed)/account/__tests__/billing.test.tsx +38 -0
  94. package/templates/apps/web/app/[locale]/(authed)/account/billing/page.tsx +4 -2
  95. package/templates/apps/web/app/[locale]/(authed)/sign-in-gate.tsx +47 -24
  96. package/templates/apps/web/app/[locale]/(authed)/signed-out-gate.generated.tsx +23 -4
  97. package/templates/apps/web/app/[locale]/contact/intake-analytics.ts +1 -1
  98. package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/magnet-page.test.tsx +22 -1
  99. package/templates/apps/web/app/[locale]/flows/[slug]/magnet-page.tsx +7 -3
  100. package/templates/apps/web/app/[locale]/layout.tsx +33 -13
  101. package/templates/apps/web/app/[locale]/meet/confirmed/BookingHandOff.tsx +128 -0
  102. package/templates/apps/web/app/[locale]/meet/confirmed/__tests__/BookingHandOff.test.tsx +126 -0
  103. package/templates/apps/web/app/[locale]/pricing/__tests__/unconnected.test.tsx +43 -0
  104. package/templates/apps/web/app/[locale]/pricing/page.tsx +7 -3
  105. package/templates/apps/web/app/api/offerings/checkout/[lookupKey]/__tests__/route.test.ts +222 -0
  106. package/templates/apps/web/app/api/offerings/checkout/[lookupKey]/route.ts +10 -3
  107. package/templates/apps/web/app/api/revalidate/route.ts +3 -3
  108. package/templates/apps/web/auth.ts +10 -6
  109. package/templates/apps/web/i18n/request.ts +49 -1
  110. package/templates/apps/web/jest.config.cjs +1 -0
  111. package/templates/apps/web/lib/__tests__/account-config.test.ts +7 -0
  112. package/templates/apps/web/lib/__tests__/auth-email.test.ts +276 -0
  113. package/templates/apps/web/lib/auth-email.ts +103 -21
  114. package/templates/apps/web/lib/hub-session/__tests__/sign-in-gate.test.tsx +72 -23
  115. package/templates/apps/web/lib/hub-session/sign-in-gate.tsx +94 -70
  116. package/templates/apps/web/lib/prisma-for-auth.ts +5 -2
  117. package/templates/apps/web/lib/relay.ts +2 -2
  118. package/templates/apps/web/lib/release-scope.ts +47 -0
  119. package/templates/apps/web/lib/server-api.ts +1 -1
  120. package/templates/apps/web/lib/sign-up-agreements.ts +291 -28
  121. package/templates/apps/web/lib/site-contributions.ts +18 -0
  122. package/templates/apps/web/messages/en.json +186 -20
  123. package/templates/apps/web/messages/site/en.json +1 -0
  124. package/templates/apps/web/src/lib/commerce-claim.ts +1 -1
  125. package/templates/customizations.yaml +37 -0
  126. package/templates/database/prisma.config.ts +10 -14
  127. package/templates/database/seed-test.ts +2 -2
  128. package/templates/database/seed.ts +5 -5
  129. package/templates/package.json +12 -6
  130. package/templates/pnpm-workspace.yaml +0 -1
  131. package/templates/project.yaml +16 -8
  132. package/templates/tools/jest/reporters.cjs +65 -0
  133. package/templates/tools/lint-architecture.ts +553 -7
  134. package/templates/tsconfig.json +1 -2
  135. package/versions.json +49 -36
  136. package/templates/apps/api/src/__tests__/commerce-claim-registration.test.ts +0 -409
  137. package/templates/apps/api/src/__tests__/factories/agent-caller.ts +0 -102
  138. package/templates/apps/api/src/__tests__/factories/content-fixture.ts +0 -138
  139. package/templates/apps/api/src/__tests__/factories/in-memory-prisma.ts +0 -441
  140. package/templates/apps/api/src/__tests__/factories/index.ts +0 -70
  141. package/templates/apps/api/src/__tests__/factories/lead-fixture.ts +0 -82
  142. package/templates/apps/api/src/__tests__/leads-forwarded-rate-limit.test.ts +0 -135
  143. package/templates/apps/api/src/__tests__/services/enrichment-shim.test.ts +0 -126
  144. package/templates/apps/api/src/__tests__/stripe-boot.test.ts +0 -132
  145. package/templates/apps/api/src/__tests__/support/hub-sign-in-fake-db.ts +0 -362
  146. package/templates/apps/api/src/bin/__tests__/rate-limit-probe.test.ts +0 -184
  147. package/templates/apps/api/src/bin/abandon-sweep.ts +0 -42
  148. package/templates/apps/api/src/bin/rate-limit-probe.ts +0 -53
  149. package/templates/apps/api/src/bin/spokes.ts +0 -198
  150. package/templates/apps/api/src/bin/stripe-connections-rekey.ts +0 -45
  151. package/templates/apps/api/src/config/__tests__/hub-require-spoke-key.test.ts +0 -196
  152. package/templates/apps/api/src/config/__tests__/index.test.ts +0 -233
  153. package/templates/apps/api/src/config/__tests__/modules.test.ts +0 -76
  154. package/templates/apps/api/src/config/__tests__/stripe-connection-key.test.ts +0 -185
  155. package/templates/apps/api/src/config/__tests__/trusted-origins.test.ts +0 -238
  156. package/templates/apps/api/src/config/index.ts +0 -596
  157. package/templates/apps/api/src/config/modules.ts +0 -83
  158. package/templates/apps/api/src/lib/__tests__/agent-store.test.ts +0 -581
  159. package/templates/apps/api/src/lib/__tests__/auth-email-budget.test.ts +0 -143
  160. package/templates/apps/api/src/lib/__tests__/consent-ledger-double.ts +0 -237
  161. package/templates/apps/api/src/lib/__tests__/consent-store.test.ts +0 -353
  162. package/templates/apps/api/src/lib/__tests__/content-adapter.test.ts +0 -201
  163. package/templates/apps/api/src/lib/__tests__/deliverable-asset-store.test.ts +0 -224
  164. package/templates/apps/api/src/lib/__tests__/error-serializer.test.ts +0 -120
  165. package/templates/apps/api/src/lib/__tests__/errors.test.ts +0 -94
  166. package/templates/apps/api/src/lib/__tests__/file-fallback.test.ts +0 -144
  167. package/templates/apps/api/src/lib/__tests__/fixtures/HomePage/home.mdx +0 -8
  168. package/templates/apps/api/src/lib/__tests__/flow-completion-store.test.ts +0 -149
  169. package/templates/apps/api/src/lib/__tests__/flow-rename-race.db.test.ts +0 -116
  170. package/templates/apps/api/src/lib/__tests__/hub-sign-in-store.test.ts +0 -209
  171. package/templates/apps/api/src/lib/__tests__/lead-capture-store.test.ts +0 -257
  172. package/templates/apps/api/src/lib/__tests__/lead-delivery.test.ts +0 -96
  173. package/templates/apps/api/src/lib/__tests__/outbound-http.test.ts +0 -125
  174. package/templates/apps/api/src/lib/__tests__/prisma.test.ts +0 -165
  175. package/templates/apps/api/src/lib/__tests__/require-commerce-claim.test.ts +0 -317
  176. package/templates/apps/api/src/lib/__tests__/require-paid-tier.test.ts +0 -129
  177. package/templates/apps/api/src/lib/__tests__/site.test.ts +0 -308
  178. package/templates/apps/api/src/lib/__tests__/slice-load.test.ts +0 -89
  179. package/templates/apps/api/src/lib/__tests__/spoke-store.test.ts +0 -202
  180. package/templates/apps/api/src/lib/__tests__/stripe-admission.test.ts +0 -217
  181. package/templates/apps/api/src/lib/__tests__/stripe.test.ts +0 -82
  182. package/templates/apps/api/src/lib/agent-store.ts +0 -613
  183. package/templates/apps/api/src/lib/auth-email-budget.ts +0 -161
  184. package/templates/apps/api/src/lib/consent-store.ts +0 -363
  185. package/templates/apps/api/src/lib/content-adapter.ts +0 -112
  186. package/templates/apps/api/src/lib/deliverable-asset-store.ts +0 -96
  187. package/templates/apps/api/src/lib/error-serializer.ts +0 -164
  188. package/templates/apps/api/src/lib/errors.ts +0 -95
  189. package/templates/apps/api/src/lib/file-fallback.ts +0 -87
  190. package/templates/apps/api/src/lib/flow-completion-store.ts +0 -136
  191. package/templates/apps/api/src/lib/hub-sign-in-store.ts +0 -455
  192. package/templates/apps/api/src/lib/lead-capture-store.ts +0 -122
  193. package/templates/apps/api/src/lib/lead-delivery.ts +0 -52
  194. package/templates/apps/api/src/lib/license-key-store.ts +0 -45
  195. package/templates/apps/api/src/lib/locales.ts +0 -201
  196. package/templates/apps/api/src/lib/outbound-http.ts +0 -127
  197. package/templates/apps/api/src/lib/prisma.ts +0 -21
  198. package/templates/apps/api/src/lib/proposal-paid-store.ts +0 -66
  199. package/templates/apps/api/src/lib/rate-limit-probe.ts +0 -165
  200. package/templates/apps/api/src/lib/rate-limit-store.ts +0 -142
  201. package/templates/apps/api/src/lib/require-commerce-claim.ts +0 -250
  202. package/templates/apps/api/src/lib/require-paid-tier.ts +0 -53
  203. package/templates/apps/api/src/lib/site.ts +0 -257
  204. package/templates/apps/api/src/lib/slice-load.ts +0 -90
  205. package/templates/apps/api/src/lib/spoke-store.ts +0 -180
  206. package/templates/apps/api/src/lib/stripe.ts +0 -321
  207. package/templates/apps/api/src/lib/webhook-idempotency.ts +0 -156
  208. package/templates/apps/api/src/middleware/__tests__/adversarial/bearer-token-format.test.ts +0 -111
  209. package/templates/apps/api/src/middleware/__tests__/adversarial/cookie-or-bearer-precedence.test.ts +0 -172
  210. package/templates/apps/api/src/middleware/__tests__/adversarial/csrf-bearer-skip.test.ts +0 -119
  211. package/templates/apps/api/src/middleware/__tests__/adversarial/csrf-cookie-path.test.ts +0 -138
  212. package/templates/apps/api/src/middleware/__tests__/adversarial/csrf-trusted-origins.test.ts +0 -142
  213. package/templates/apps/api/src/middleware/__tests__/adversarial/session-fixation.test.ts +0 -155
  214. package/templates/apps/api/src/middleware/__tests__/adversarial/session-timeout.test.ts +0 -139
  215. package/templates/apps/api/src/middleware/__tests__/auth.bearer-path.test.ts +0 -562
  216. package/templates/apps/api/src/middleware/__tests__/auth.both-present-precedence.test.ts +0 -76
  217. package/templates/apps/api/src/middleware/__tests__/auth.cookie-path.test.ts +0 -220
  218. package/templates/apps/api/src/middleware/__tests__/auth.database-not-configured.test.ts +0 -97
  219. package/templates/apps/api/src/middleware/__tests__/auth.hub-session-path.test.ts +0 -557
  220. package/templates/apps/api/src/middleware/__tests__/auth.neither-present.test.ts +0 -72
  221. package/templates/apps/api/src/middleware/__tests__/auth.optional-cookie.test.ts +0 -140
  222. package/templates/apps/api/src/middleware/__tests__/default-tenant.test.ts +0 -721
  223. package/templates/apps/api/src/middleware/__tests__/rate-limit-cross-isolate.db.test.ts +0 -220
  224. package/templates/apps/api/src/middleware/__tests__/rate-limit-store.test.ts +0 -430
  225. package/templates/apps/api/src/middleware/__tests__/rate-limit.test.ts +0 -1409
  226. package/templates/apps/api/src/middleware/__tests__/write-budget.test.ts +0 -174
  227. package/templates/apps/api/src/middleware/auth.ts +0 -864
  228. package/templates/apps/api/src/middleware/default-tenant.ts +0 -166
  229. package/templates/apps/api/src/middleware/rate-limit.ts +0 -983
  230. package/templates/apps/api/src/openapi/__tests__/openapi.test.ts +0 -391
  231. package/templates/apps/api/src/openapi/__tests__/spec-identity.test.ts +0 -182
  232. package/templates/apps/api/src/openapi/index.ts +0 -18
  233. package/templates/apps/api/src/openapi/spec.ts +0 -2148
  234. package/templates/apps/api/src/openapi/surface-drift.ts +0 -195
  235. package/templates/apps/api/src/routes/aeo/__tests__/index.test.ts +0 -175
  236. package/templates/apps/api/src/routes/aeo/index.ts +0 -107
  237. package/templates/apps/api/src/routes/auth/__tests__/auth-tokens.functional.test.ts +0 -196
  238. package/templates/apps/api/src/routes/auth/__tests__/auth-user.functional.test.ts +0 -249
  239. package/templates/apps/api/src/routes/auth/__tests__/hub-sign-in.test.ts +0 -532
  240. package/templates/apps/api/src/routes/auth/__tests__/tokens.test.ts +0 -313
  241. package/templates/apps/api/src/routes/auth/__tests__/transactional-email.test.ts +0 -413
  242. package/templates/apps/api/src/routes/auth/__tests__/user.test.ts +0 -609
  243. package/templates/apps/api/src/routes/auth/hub-sign-in.ts +0 -242
  244. package/templates/apps/api/src/routes/auth/tokens.ts +0 -211
  245. package/templates/apps/api/src/routes/auth/transactional-email.ts +0 -301
  246. package/templates/apps/api/src/routes/auth/user.ts +0 -305
  247. package/templates/apps/api/src/routes/billing/plan-checkout.ts +0 -332
  248. package/templates/apps/api/src/routes/checkout/__tests__/live-key.test.ts +0 -178
  249. package/templates/apps/api/src/routes/checkout/__tests__/offerings-authorization.test.ts +0 -1426
  250. package/templates/apps/api/src/routes/checkout/__tests__/session.test.ts +0 -448
  251. package/templates/apps/api/src/routes/checkout/__tests__/sessions.test.ts +0 -1742
  252. package/templates/apps/api/src/routes/checkout/index.ts +0 -34
  253. package/templates/apps/api/src/routes/checkout/session.ts +0 -171
  254. package/templates/apps/api/src/routes/checkout/sessions.ts +0 -540
  255. package/templates/apps/api/src/routes/consent/__tests__/account.test.ts +0 -386
  256. package/templates/apps/api/src/routes/consent/__tests__/sign-up-rate-limit.test.ts +0 -160
  257. package/templates/apps/api/src/routes/consent/account.ts +0 -268
  258. package/templates/apps/api/src/routes/consent/cookie.ts +0 -90
  259. package/templates/apps/api/src/routes/consent/index.ts +0 -26
  260. package/templates/apps/api/src/routes/consent/unsubscribe.ts +0 -127
  261. package/templates/apps/api/src/routes/content/__tests__/get-page.test.ts +0 -853
  262. package/templates/apps/api/src/routes/content/__tests__/list-pages.test.ts +0 -230
  263. package/templates/apps/api/src/routes/content/__tests__/list-types.test.ts +0 -44
  264. package/templates/apps/api/src/routes/content/__tests__/locale.test.ts +0 -118
  265. package/templates/apps/api/src/routes/content/__tests__/offerings.test.ts +0 -731
  266. package/templates/apps/api/src/routes/content/__tests__/pricing.test.ts +0 -753
  267. package/templates/apps/api/src/routes/content/__tests__/rate-limit.test.ts +0 -51
  268. package/templates/apps/api/src/routes/content/__tests__/search.test.ts +0 -450
  269. package/templates/apps/api/src/routes/content/__tests__/shown-offerings.test.ts +0 -762
  270. package/templates/apps/api/src/routes/content/get-page.ts +0 -183
  271. package/templates/apps/api/src/routes/content/index.ts +0 -49
  272. package/templates/apps/api/src/routes/content/list-pages.ts +0 -74
  273. package/templates/apps/api/src/routes/content/list-types.ts +0 -19
  274. package/templates/apps/api/src/routes/content/offerings.ts +0 -184
  275. package/templates/apps/api/src/routes/content/pricing.ts +0 -176
  276. package/templates/apps/api/src/routes/content/rate-limit.ts +0 -22
  277. package/templates/apps/api/src/routes/content/search.ts +0 -100
  278. package/templates/apps/api/src/routes/content/shown-offerings.ts +0 -229
  279. package/templates/apps/api/src/routes/leads/__tests__/capture.test.ts +0 -88
  280. package/templates/apps/api/src/routes/leads/__tests__/list.test.ts +0 -171
  281. package/templates/apps/api/src/routes/leads/__tests__/magnet-completion.test.ts +0 -515
  282. package/templates/apps/api/src/routes/leads/__tests__/spoke.test.ts +0 -392
  283. package/templates/apps/api/src/routes/leads/__tests__/track.test.ts +0 -165
  284. package/templates/apps/api/src/routes/leads/index.ts +0 -639
  285. package/templates/apps/api/src/routes/leads/list.ts +0 -104
  286. package/templates/apps/api/src/routes/project-listings/__tests__/configured-application.test.ts +0 -626
  287. package/templates/apps/api/src/routes/project-listings/__tests__/drafts.test.ts +0 -1268
  288. package/templates/apps/api/src/routes/project-listings/__tests__/founder-identity.test.ts +0 -847
  289. package/templates/apps/api/src/routes/project-listings/__tests__/me.test.ts +0 -491
  290. package/templates/apps/api/src/routes/project-listings/__tests__/public.test.ts +0 -476
  291. package/templates/apps/api/src/routes/project-listings/__tests__/resume-email.test.ts +0 -872
  292. package/templates/apps/api/src/routes/project-listings/__tests__/site-answers.test.ts +0 -1022
  293. package/templates/apps/api/src/routes/project-listings/__tests__/site-key.test.ts +0 -484
  294. package/templates/apps/api/src/routes/project-listings/__tests__/structured-address.test.ts +0 -535
  295. package/templates/apps/api/src/routes/project-listings/index.ts +0 -164
  296. package/templates/apps/api/src/routes/project-listings/me.ts +0 -87
  297. package/templates/apps/api/src/routes/project-listings/patch-copy.ts +0 -224
  298. package/templates/apps/api/src/routes/project-listings/patch-draft.ts +0 -102
  299. package/templates/apps/api/src/routes/project-listings/public.ts +0 -98
  300. package/templates/apps/api/src/routes/project-listings/respond.ts +0 -48
  301. package/templates/apps/api/src/routes/project-listings/resume-token.ts +0 -27
  302. package/templates/apps/api/src/routes/project-listings/start.ts +0 -140
  303. package/templates/apps/api/src/routes/project-listings/submit.ts +0 -130
  304. package/templates/apps/api/src/routes/project-listings/verify-email.ts +0 -150
  305. package/templates/apps/api/src/routes/requests/__tests__/confirm.test.ts +0 -686
  306. package/templates/apps/api/src/routes/requests/confirm.ts +0 -601
  307. package/templates/apps/api/src/routes/requests/index.ts +0 -54
  308. package/templates/apps/api/src/routes/test/auth/__tests__/session.test.ts +0 -306
  309. package/templates/apps/api/src/routes/test/auth/session.ts +0 -143
  310. package/templates/apps/api/src/routes/webhooks/README.md +0 -398
  311. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-checkout-consent.test.ts +0 -649
  312. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-dunning.test.ts +0 -749
  313. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-flow-checkout.test.ts +0 -449
  314. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-idempotency.test.ts +0 -264
  315. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-livemode-live.test.ts +0 -159
  316. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-livemode.test.ts +0 -158
  317. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-offerings.test.ts +0 -814
  318. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-org-billing.test.ts +0 -301
  319. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-proposal-paid.test.ts +0 -369
  320. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-rate-limit.test.ts +0 -215
  321. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-request-paid.test.ts +0 -301
  322. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-site-filter.test.ts +0 -809
  323. package/templates/apps/api/src/routes/webhooks/__tests__/stripe.test.ts +0 -1155
  324. package/templates/apps/api/src/routes/webhooks/index.ts +0 -141
  325. package/templates/apps/api/src/routes/webhooks/stripe-offerings.ts +0 -384
  326. package/templates/apps/api/src/routes/webhooks/stripe.ts +0 -2028
  327. package/templates/apps/api/src/services/__tests__/abandon-email.test.ts +0 -645
  328. package/templates/apps/api/src/services/__tests__/answer-distributions.test.ts +0 -132
  329. package/templates/apps/api/src/services/__tests__/audit-log.test.ts +0 -1028
  330. package/templates/apps/api/src/services/__tests__/checkout-plan.test.ts +0 -313
  331. package/templates/apps/api/src/services/__tests__/consent-ledger.test.ts +0 -503
  332. package/templates/apps/api/src/services/__tests__/consent-migration.test.ts +0 -65
  333. package/templates/apps/api/src/services/__tests__/consent.test.ts +0 -299
  334. package/templates/apps/api/src/services/__tests__/default-tenant.test.ts +0 -147
  335. package/templates/apps/api/src/services/__tests__/deliverable-fulfillment.test.ts +0 -877
  336. package/templates/apps/api/src/services/__tests__/deliverable-resend.test.ts +0 -379
  337. package/templates/apps/api/src/services/__tests__/dunning-policy.test.ts +0 -368
  338. package/templates/apps/api/src/services/__tests__/entitlements.test.ts +0 -142
  339. package/templates/apps/api/src/services/__tests__/hub-sign-in.test.ts +0 -854
  340. package/templates/apps/api/src/services/__tests__/keyless-workspace-predicate.test.ts +0 -234
  341. package/templates/apps/api/src/services/__tests__/lead-accept-user.test.ts +0 -251
  342. package/templates/apps/api/src/services/__tests__/lead-routing.test.ts +0 -2660
  343. package/templates/apps/api/src/services/__tests__/listing-config.test.ts +0 -166
  344. package/templates/apps/api/src/services/__tests__/magnet-completion.test.ts +0 -389
  345. package/templates/apps/api/src/services/__tests__/person.test.ts +0 -1204
  346. package/templates/apps/api/src/services/__tests__/plan-offerings.test.ts +0 -450
  347. package/templates/apps/api/src/services/__tests__/project-listings.counts.test.ts +0 -202
  348. package/templates/apps/api/src/services/__tests__/project-listings.fence.test.ts +0 -151
  349. package/templates/apps/api/src/services/__tests__/public-site-resolver.test.ts +0 -137
  350. package/templates/apps/api/src/services/__tests__/request-confirm.test.ts +0 -531
  351. package/templates/apps/api/src/services/__tests__/revalidation.test.ts +0 -372
  352. package/templates/apps/api/src/services/__tests__/slack-notify.test.ts +0 -348
  353. package/templates/apps/api/src/services/__tests__/spoke-resolution.test.ts +0 -660
  354. package/templates/apps/api/src/services/__tests__/usage-aggregation.test.ts +0 -941
  355. package/templates/apps/api/src/services/__tests__/usage-credits.test.ts +0 -588
  356. package/templates/apps/api/src/services/__tests__/verified-email.test.ts +0 -78
  357. package/templates/apps/api/src/services/abandon-email.ts +0 -336
  358. package/templates/apps/api/src/services/aeo-score.ts +0 -325
  359. package/templates/apps/api/src/services/answer-distributions.ts +0 -138
  360. package/templates/apps/api/src/services/audit-log.ts +0 -961
  361. package/templates/apps/api/src/services/checkout-buyer.ts +0 -168
  362. package/templates/apps/api/src/services/consent.ts +0 -834
  363. package/templates/apps/api/src/services/default-tenant.ts +0 -416
  364. package/templates/apps/api/src/services/deliverable-fulfillment.ts +0 -750
  365. package/templates/apps/api/src/services/dunning-policy.ts +0 -294
  366. package/templates/apps/api/src/services/enrichment-shim.ts +0 -53
  367. package/templates/apps/api/src/services/entitlements.ts +0 -338
  368. package/templates/apps/api/src/services/hub-sign-in.ts +0 -472
  369. package/templates/apps/api/src/services/lead-accept-user.ts +0 -126
  370. package/templates/apps/api/src/services/lead-promotion.ts +0 -160
  371. package/templates/apps/api/src/services/lead-routing.ts +0 -1372
  372. package/templates/apps/api/src/services/leads-inbox.ts +0 -312
  373. package/templates/apps/api/src/services/listing-config.ts +0 -178
  374. package/templates/apps/api/src/services/magnet-completion.ts +0 -242
  375. package/templates/apps/api/src/services/offerings/__tests__/catalog.test.ts +0 -348
  376. package/templates/apps/api/src/services/offerings/__tests__/checkout-session-record.test.ts +0 -268
  377. package/templates/apps/api/src/services/offerings/__tests__/connection.test.ts +0 -975
  378. package/templates/apps/api/src/services/offerings/__tests__/fixtures.ts +0 -416
  379. package/templates/apps/api/src/services/offerings/__tests__/org-products.test.ts +0 -400
  380. package/templates/apps/api/src/services/offerings/__tests__/readers.test.ts +0 -685
  381. package/templates/apps/api/src/services/offerings/__tests__/source.test.ts +0 -231
  382. package/templates/apps/api/src/services/offerings/catalog.ts +0 -318
  383. package/templates/apps/api/src/services/offerings/checkout-authorization.ts +0 -403
  384. package/templates/apps/api/src/services/offerings/checkout-session-record.ts +0 -192
  385. package/templates/apps/api/src/services/offerings/connection.ts +0 -1083
  386. package/templates/apps/api/src/services/offerings/index.ts +0 -614
  387. package/templates/apps/api/src/services/offerings/source.ts +0 -140
  388. package/templates/apps/api/src/services/offerings/store.ts +0 -150
  389. package/templates/apps/api/src/services/owner-workspaces.ts +0 -132
  390. package/templates/apps/api/src/services/person.ts +0 -1211
  391. package/templates/apps/api/src/services/plan-offerings.ts +0 -125
  392. package/templates/apps/api/src/services/project-listing-resume-email.ts +0 -326
  393. package/templates/apps/api/src/services/project-listings.ts +0 -2085
  394. package/templates/apps/api/src/services/public-site-resolver.ts +0 -396
  395. package/templates/apps/api/src/services/request-confirm.ts +0 -698
  396. package/templates/apps/api/src/services/revalidation.ts +0 -235
  397. package/templates/apps/api/src/services/slack-notify.ts +0 -291
  398. package/templates/apps/api/src/services/usage-aggregation.ts +0 -516
  399. package/templates/apps/api/src/services/usage-credits.ts +0 -340
  400. package/templates/apps/api/src/services/verified-email.ts +0 -71
  401. package/templates/apps/mcp/__tests__/abuse/daily-cap.test.ts +0 -52
  402. package/templates/apps/mcp/__tests__/abuse/email-validator.test.ts +0 -46
  403. package/templates/apps/mcp/__tests__/abuse/guard.test.ts +0 -198
  404. package/templates/apps/mcp/__tests__/abuse/honeypot.test.ts +0 -36
  405. package/templates/apps/mcp/__tests__/abuse/user-agent-deny.test.ts +0 -54
  406. package/templates/apps/mcp/__tests__/aeo-cli-parity.test.ts +0 -116
  407. package/templates/apps/mcp/__tests__/audit-single-page.test.ts +0 -299
  408. package/templates/apps/mcp/__tests__/boot.test.ts +0 -280
  409. package/templates/apps/mcp/__tests__/catalog-drift.test.ts +0 -359
  410. package/templates/apps/mcp/__tests__/config/modules.test.ts +0 -78
  411. package/templates/apps/mcp/__tests__/get_business_hours.test.ts +0 -82
  412. package/templates/apps/mcp/__tests__/get_faq.test.ts +0 -80
  413. package/templates/apps/mcp/__tests__/get_locations.test.ts +0 -65
  414. package/templates/apps/mcp/__tests__/get_offerings.test.ts +0 -557
  415. package/templates/apps/mcp/__tests__/get_pricing.test.ts +0 -524
  416. package/templates/apps/mcp/__tests__/get_site_info.test.ts +0 -81
  417. package/templates/apps/mcp/__tests__/http-transport.test.ts +0 -1232
  418. package/templates/apps/mcp/__tests__/index.test.ts +0 -195
  419. package/templates/apps/mcp/__tests__/lib/audit-single-page-readiness-scan.test.ts +0 -191
  420. package/templates/apps/mcp/__tests__/lib/commerce-claim.test.ts +0 -531
  421. package/templates/apps/mcp/__tests__/lib/content-adapter-parity.test.ts +0 -70
  422. package/templates/apps/mcp/__tests__/lib/content-adapter.test.ts +0 -162
  423. package/templates/apps/mcp/__tests__/lib/content-root.test.ts +0 -93
  424. package/templates/apps/mcp/__tests__/lib/errors.test.ts +0 -75
  425. package/templates/apps/mcp/__tests__/lib/fail-closed-tools.test.ts +0 -180
  426. package/templates/apps/mcp/__tests__/lib/public-workspace.test.ts +0 -124
  427. package/templates/apps/mcp/__tests__/list_pages.test.ts +0 -268
  428. package/templates/apps/mcp/__tests__/locale.test.ts +0 -120
  429. package/templates/apps/mcp/__tests__/module-exclusion.test.ts +0 -175
  430. package/templates/apps/mcp/__tests__/purchase-disabled.test.ts +0 -101
  431. package/templates/apps/mcp/__tests__/rate-limit-write.test.ts +0 -189
  432. package/templates/apps/mcp/__tests__/read_content.test.ts +0 -511
  433. package/templates/apps/mcp/__tests__/request_callback.test.ts +0 -160
  434. package/templates/apps/mcp/__tests__/search_content.test.ts +0 -271
  435. package/templates/apps/mcp/__tests__/server.test.ts +0 -388
  436. package/templates/apps/mcp/__tests__/start_purchase.test.ts +0 -448
  437. package/templates/apps/mcp/__tests__/submit_lead.test.ts +0 -222
  438. package/templates/apps/mcp/__tests__/subscribe_newsletter.test.ts +0 -152
  439. package/templates/apps/mcp/__tests__/tools/create_project.test.ts +0 -243
  440. package/templates/apps/mcp/__tests__/tools/purchase.test.ts +0 -451
  441. package/templates/apps/mcp/src/abuse/daily-cap.ts +0 -47
  442. package/templates/apps/mcp/src/abuse/email-validator.ts +0 -25
  443. package/templates/apps/mcp/src/abuse/honeypot.ts +0 -21
  444. package/templates/apps/mcp/src/abuse/index.ts +0 -349
  445. package/templates/apps/mcp/src/abuse/user-agent-deny.ts +0 -58
  446. package/templates/apps/mcp/src/boot.ts +0 -167
  447. package/templates/apps/mcp/src/config/modules.ts +0 -43
  448. package/templates/apps/mcp/src/http-transport.ts +0 -564
  449. package/templates/apps/mcp/src/lib/audit-single-page.ts +0 -308
  450. package/templates/apps/mcp/src/lib/commerce-claim.ts +0 -263
  451. package/templates/apps/mcp/src/lib/content-adapter.ts +0 -116
  452. package/templates/apps/mcp/src/lib/empty-content-adapter.ts +0 -140
  453. package/templates/apps/mcp/src/lib/errors.ts +0 -61
  454. package/templates/apps/mcp/src/lib/license-key-store.ts +0 -45
  455. package/templates/apps/mcp/src/lib/locales.ts +0 -171
  456. package/templates/apps/mcp/src/lib/prisma.ts +0 -39
  457. package/templates/apps/mcp/src/lib/public-workspace.ts +0 -133
  458. package/templates/apps/mcp/src/lib/resolve-locale.ts +0 -30
  459. package/templates/apps/mcp/src/lib/shown-offerings.ts +0 -105
  460. package/templates/apps/mcp/src/lib/site-config.ts +0 -53
  461. package/templates/apps/mcp/src/lib/stripe-tax-signal.ts +0 -59
  462. package/templates/apps/mcp/src/request-context.ts +0 -52
  463. package/templates/apps/mcp/src/server.ts +0 -343
  464. package/templates/apps/mcp/src/serverless-app.ts +0 -88
  465. package/templates/apps/mcp/src/tools/audit.ts +0 -127
  466. package/templates/apps/mcp/src/tools/capture_lead.ts +0 -66
  467. package/templates/apps/mcp/src/tools/create_project.ts +0 -134
  468. package/templates/apps/mcp/src/tools/get_business_hours.ts +0 -68
  469. package/templates/apps/mcp/src/tools/get_faq.ts +0 -71
  470. package/templates/apps/mcp/src/tools/get_locations.ts +0 -88
  471. package/templates/apps/mcp/src/tools/get_offerings.ts +0 -96
  472. package/templates/apps/mcp/src/tools/get_pricing.ts +0 -94
  473. package/templates/apps/mcp/src/tools/get_site_info.ts +0 -86
  474. package/templates/apps/mcp/src/tools/index.ts +0 -138
  475. package/templates/apps/mcp/src/tools/list_pages.ts +0 -68
  476. package/templates/apps/mcp/src/tools/person_notes.ts +0 -25
  477. package/templates/apps/mcp/src/tools/proposals.ts +0 -27
  478. package/templates/apps/mcp/src/tools/purchase.ts +0 -205
  479. package/templates/apps/mcp/src/tools/read_content.ts +0 -81
  480. package/templates/apps/mcp/src/tools/request_callback.ts +0 -52
  481. package/templates/apps/mcp/src/tools/search_content.ts +0 -63
  482. package/templates/apps/mcp/src/tools/subscribe_newsletter.ts +0 -54
  483. package/templates/apps/mcp/src/workspace-server.ts +0 -224
  484. package/templates/database/CHANGELOG.md +0 -981
  485. package/templates/database/LICENSE +0 -202
  486. package/templates/database/NOTICE +0 -2
  487. package/templates/database/README.md +0 -243
  488. package/templates/database/__tests__/agents.db.test.ts +0 -320
  489. package/templates/database/__tests__/appointment.db.test.ts +0 -106
  490. package/templates/database/__tests__/artifact-content-store.db.test.ts +0 -316
  491. package/templates/database/__tests__/composite-fence.db.test.ts +0 -206
  492. package/templates/database/__tests__/consent-ledger.db.test.ts +0 -345
  493. package/templates/database/__tests__/consent-source-checkout-migration.test.ts +0 -79
  494. package/templates/database/__tests__/fence-fan-out.db.test.ts +0 -715
  495. package/templates/database/__tests__/fixtures/appointment-create-probe.ts +0 -79
  496. package/templates/database/__tests__/fixtures/person-backfill.json +0 -264
  497. package/templates/database/__tests__/fixtures/person-contact-backfill.json +0 -182
  498. package/templates/database/__tests__/fixtures/project-listing-consent-probe.ts +0 -100
  499. package/templates/database/__tests__/flow-completion-migration.test.ts +0 -115
  500. package/templates/database/__tests__/flow-completion.db.test.ts +0 -136
  501. package/templates/database/__tests__/flow-workspace-key.db.test.ts +0 -263
  502. package/templates/database/__tests__/flows-listing-diagnostic.test.ts +0 -392
  503. package/templates/database/__tests__/flows-presets.test.ts +0 -173
  504. package/templates/database/__tests__/in-page-magnets-migration.test.ts +0 -161
  505. package/templates/database/__tests__/lead-idempotency-key.db.test.ts +0 -92
  506. package/templates/database/__tests__/member-area.db.test.ts +0 -257
  507. package/templates/database/__tests__/member-contract-migration.test.ts +0 -85
  508. package/templates/database/__tests__/member-contract.db.test.ts +0 -413
  509. package/templates/database/__tests__/offerings-checkout-session.db.test.ts +0 -270
  510. package/templates/database/__tests__/offerings-migration.test.ts +0 -197
  511. package/templates/database/__tests__/offerings-shown-price-ids-migration.test.ts +0 -86
  512. package/templates/database/__tests__/offerings.db.test.ts +0 -303
  513. package/templates/database/__tests__/outbound-message-action.db.test.ts +0 -80
  514. package/templates/database/__tests__/person-contact.db.test.ts +0 -563
  515. package/templates/database/__tests__/person-notes.db.test.ts +0 -249
  516. package/templates/database/__tests__/person.db.test.ts +0 -586
  517. package/templates/database/__tests__/piece-kind-migration.test.ts +0 -67
  518. package/templates/database/__tests__/piece-kind.db.test.ts +0 -208
  519. package/templates/database/__tests__/prefixed-ids.db.test.ts +0 -222
  520. package/templates/database/__tests__/project-listing-consent-at.db.test.ts +0 -111
  521. package/templates/database/__tests__/seed.test.ts +0 -272
  522. package/templates/database/__tests__/spoke-registry.db.test.ts +0 -191
  523. package/templates/database/__tests__/tenancy.test.ts +0 -141
  524. package/templates/database/__tests__/trial-magnet-migration.test.ts +0 -186
  525. package/templates/database/__tests__/user-cascade.test.ts +0 -140
  526. package/templates/database/_gitignore +0 -8
  527. package/templates/database/auth/.gitkeep +0 -0
  528. package/templates/database/auth/schema.prisma +0 -641
  529. package/templates/database/config/.gitkeep +0 -0
  530. package/templates/database/config/schema.prisma +0 -441
  531. package/templates/database/content/.gitkeep +0 -0
  532. package/templates/database/content/schema.prisma +0 -339
  533. package/templates/database/eslint.config.mjs +0 -69
  534. package/templates/database/flows/listing-diagnostic.ts +0 -182
  535. package/templates/database/flows/presets.ts +0 -315
  536. package/templates/database/inbox/.gitkeep +0 -0
  537. package/templates/database/inbox/README.md +0 -3
  538. package/templates/database/inbox/__tests__/schema.test.ts +0 -44
  539. package/templates/database/inbox/schema.prisma +0 -1447
  540. package/templates/database/jest.config.cjs +0 -36
  541. package/templates/database/migrations/20260508000000_add_inbox_namespace/migration.sql +0 -328
  542. package/templates/database/migrations/20260513000000_better_auth_migration/migration.sql +0 -100
  543. package/templates/database/migrations/20260515000000_add_user_billing_fields/migration.sql +0 -28
  544. package/templates/database/migrations/20260516000000_add_user_tier_care_plan_seat/migration.sql +0 -25
  545. package/templates/database/migrations/20260518000000_add_telemetry_records/migration.sql +0 -42
  546. package/templates/database/migrations/20260525000000_theme_wiring/migration.sql +0 -67
  547. package/templates/database/migrations/20260710000000_retire_commercial_tier/migration.sql +0 -21
  548. package/templates/database/migrations/20260712215647_add_multi_tenant_tenancy/migration.sql +0 -201
  549. package/templates/database/migrations/20260713143320_reanchor_site_config_to_workspace/migration.sql +0 -67
  550. package/templates/database/migrations/20260713174000_add_audit_logs/migration.sql +0 -46
  551. package/templates/database/migrations/20260713190000_drop_telemetry_records/migration.sql +0 -25
  552. package/templates/database/migrations/20260713192000_add_uuidv7_function/migration.sql +0 -49
  553. package/templates/database/migrations/20260713192429_prefixed_uuid_entity_ids/migration.sql +0 -197
  554. package/templates/database/migrations/20260713200000_add_org_billing/migration.sql +0 -32
  555. package/templates/database/migrations/20260714000000_add_lead_promotion_fields/migration.sql +0 -22
  556. package/templates/database/migrations/20260714010000_add_usage_billing_content_models/migration.sql +0 -151
  557. package/templates/database/migrations/20260714020000_add_usage_billing_auth_config_models/migration.sql +0 -223
  558. package/templates/database/migrations/20260714030000_credit_balance_non_negative/migration.sql +0 -22
  559. package/templates/database/migrations/20260714030000_widen_usage_billing_report_aggregates/migration.sql +0 -32
  560. package/templates/database/migrations/20260810233516_add_flow_engine_models/migration.sql +0 -40
  561. package/templates/database/migrations/20260811020000_add_flow_session_abandon_email_columns/migration.sql +0 -4
  562. package/templates/database/migrations/20260811030000_add_flow_session_abandon_email_index/migration.sql +0 -2
  563. package/templates/database/migrations/20260811040000_add_flow_session_segment/migration.sql +0 -2
  564. package/templates/database/migrations/20260811050000_add_deliverable_models/migration.sql +0 -29
  565. package/templates/database/migrations/20260812000000_add_deliverable_grant_send_columns/migration.sql +0 -6
  566. package/templates/database/migrations/20260902222948_add_waitlist_experiment_models/migration.sql +0 -39
  567. package/templates/database/migrations/20260902224500_add_waitlist_id_format_checks/migration.sql +0 -24
  568. package/templates/database/migrations/20260903004112_add_flow_session_flags_aeo_score/migration.sql +0 -3
  569. package/templates/database/migrations/20260903010000_add_playbook_instance/migration.sql +0 -33
  570. package/templates/database/migrations/20260904000000_add_waitlist_followup_send/migration.sql +0 -30
  571. package/templates/database/migrations/20260905230000_add_flow_checkout/migration.sql +0 -47
  572. package/templates/database/migrations/20260906000000_add_flow_checkout_idempotency/migration.sql +0 -16
  573. package/templates/database/migrations/20260907120000_add_project_listing/migration.sql +0 -47
  574. package/templates/database/migrations/20260907130000_add_project_listing_slack_columns/migration.sql +0 -10
  575. package/templates/database/migrations/20260907180000_add_listing_csv_send/migration.sql +0 -26
  576. package/templates/database/migrations/20260909120000_project_listings_platform/migration.sql +0 -90
  577. package/templates/database/migrations/20260909180000_listing_draft_and_fields/migration.sql +0 -174
  578. package/templates/database/migrations/20260910120000_listing_public_site_key/migration.sql +0 -14
  579. package/templates/database/migrations/20260911120000_listing_copy_edit_audit/migration.sql +0 -25
  580. package/templates/database/migrations/20260911140000_listing_structured_address/migration.sql +0 -32
  581. package/templates/database/migrations/20260911180000_consent_grants/migration.sql +0 -71
  582. package/templates/database/migrations/20260911200000_listing_site_answers/migration.sql +0 -30
  583. package/templates/database/migrations/20260912120000_listing_owner_link/migration.sql +0 -49
  584. package/templates/database/migrations/20260914120000_listing_founder_identity/migration.sql +0 -123
  585. package/templates/database/migrations/20260915120000_project_listing_solution/migration.sql +0 -15
  586. package/templates/database/migrations/20260916120000_artifact_content_store/migration.sql +0 -158
  587. package/templates/database/migrations/20260917120000_callback_request_confirm/migration.sql +0 -40
  588. package/templates/database/migrations/20260918120000_add_appointment/migration.sql +0 -67
  589. package/templates/database/migrations/20260918120000_asset_metadata_columns/migration.sql +0 -70
  590. package/templates/database/migrations/20260919120000_flow_workspace_key/migration.sql +0 -181
  591. package/templates/database/migrations/20260919130000_flow_definition_admin_columns/migration.sql +0 -172
  592. package/templates/database/migrations/20260919130000_workspace_meetings/migration.sql +0 -41
  593. package/templates/database/migrations/20260919140000_inbox_workspace_key/migration.sql +0 -185
  594. package/templates/database/migrations/20260920120000_lead_handled_at/migration.sql +0 -70
  595. package/templates/database/migrations/20260920130000_lead_workspace_source_index/migration.sql +0 -57
  596. package/templates/database/migrations/20260921120000_deliverable_grant_workspace_key/migration.sql +0 -68
  597. package/templates/database/migrations/20260922120000_tenancy_fence/migration.sql +0 -1067
  598. package/templates/database/migrations/20260923120000_listing_capturing_magnet/migration.sql +0 -210
  599. package/templates/database/migrations/20261003120000_spoke_registry/migration.sql +0 -80
  600. package/templates/database/migrations/20261003130000_scheduling_connection/migration.sql +0 -49
  601. package/templates/database/migrations/20261005120000_agents/migration.sql +0 -84
  602. package/templates/database/migrations/20261008120000_user_last_workspace/migration.sql +0 -35
  603. package/templates/database/migrations/20261008130000_lead_idempotency_key/migration.sql +0 -20
  604. package/templates/database/migrations/20261009120000_agent_grants/migration.sql +0 -33
  605. package/templates/database/migrations/20261010120000_person/migration.sql +0 -106
  606. package/templates/database/migrations/20261010121000_person_backfill/migration.sql +0 -132
  607. package/templates/database/migrations/20261010130000_agent_grants_people_read/migration.sql +0 -20
  608. package/templates/database/migrations/20261011120000_member_area/migration.sql +0 -158
  609. package/templates/database/migrations/20261011130000_agent_grants_member_pieces_manage/migration.sql +0 -21
  610. package/templates/database/migrations/20261012120000_member_contract/migration.sql +0 -192
  611. package/templates/database/migrations/20261013120000_lead_spoke_checkout/migration.sql +0 -20
  612. package/templates/database/migrations/20261014120000_consent_ledger/migration.sql +0 -122
  613. package/templates/database/migrations/20261014120000_person_contact/migration.sql +0 -231
  614. package/templates/database/migrations/20261015120000_person_notes/migration.sql +0 -77
  615. package/templates/database/migrations/20261015120000_rate_limit_counters/migration.sql +0 -43
  616. package/templates/database/migrations/20261016120000_piece_kind/migration.sql +0 -95
  617. package/templates/database/migrations/20261017120000_outbound_message_action/migration.sql +0 -30
  618. package/templates/database/migrations/20261018120000_flow_completion/migration.sql +0 -52
  619. package/templates/database/migrations/20261019120000_consent_source_checkout/migration.sql +0 -27
  620. package/templates/database/migrations/20261020120000_offerings_data_model/migration.sql +0 -146
  621. package/templates/database/migrations/20261021120000_offerings_checkout_session/migration.sql +0 -77
  622. package/templates/database/migrations/20261022120000_in_page_magnets/migration.sql +0 -45
  623. package/templates/database/migrations/20261023120000_offerings_shown_price_ids/migration.sql +0 -47
  624. package/templates/database/migrations/20261024120000_organization_plan_checkout_session/migration.sql +0 -16
  625. package/templates/database/migrations/20261025120000_trial_magnet/migration.sql +0 -28
  626. package/templates/database/migrations/20261026120000_trial_magnet_proof_line/migration.sql +0 -23
  627. package/templates/database/migrations/migration_lock.toml +0 -3
  628. package/templates/database/ops/.gitkeep +0 -0
  629. package/templates/database/ops/schema.prisma +0 -43
  630. package/templates/database/package.json +0 -89
  631. package/templates/database/schema.prisma +0 -71
  632. package/templates/database/scripts/db-generate-locked.sh +0 -80
  633. package/templates/database/scripts/person-backfill.sql +0 -132
  634. package/templates/database/tenancy.ts +0 -183
  635. package/templates/database/tsconfig.build.json +0 -16
  636. package/templates/database/tsconfig.flows.json +0 -15
  637. package/templates/database/tsconfig.json +0 -16
  638. package/templates/database/tsconfig.tenancy.json +0 -14
@@ -1,181 +0,0 @@
1
- -- #6155 — FlowDefinition and FlowSession gain a workspace isolation key.
2
- --
3
- -- The ownership brief (docs/internal/decisions/workspace-owns-data-surfaces-render.md)
4
- -- and AD-2 (docs/internal/decisions/flow-engine-admin-surface.md): a workspace
5
- -- owns data, and the flow engine's tenant-scope fence grows to cover it.
6
- -- `siteId` stays a legacy alias for the public path (unchanged); `workspaceId`
7
- -- is the isolation key every authenticated read/write will go through
8
- -- (apps/api/src/lib/tenant-db.ts's new `flows`/`flowSessions` accessors).
9
- --
10
- -- NULLABLE, no default (spec D3) — a row whose `siteId` matches no workspace
11
- -- is left UNSET rather than guessed, and stays invisible to every accessor
12
- -- rather than visible to the wrong tenant (the same "fails empty, never
13
- -- wide" posture apps/api/src/services/leads-inbox.ts already takes).
14
- --
15
- -- RE-RUNNABLE (NFR3): `ADD COLUMN IF NOT EXISTS` / `CREATE INDEX IF NOT
16
- -- EXISTS` cover the column and index. Postgres has no
17
- -- `ADD CONSTRAINT IF NOT EXISTS`, so each format CHECK is wrapped in its own
18
- -- existence-guarded `DO $$` block — the stated exception to NFR3's "in the
19
- -- house style of 20260918120000_asset_metadata_columns" note: that
20
- -- precedent (and 20260713192429_prefixed_uuid_entity_ids's own CHECK
21
- -- additions) rely on `prisma migrate`'s per-migration transaction and
22
- -- ledger, not on idempotent DDL — the guard below is this migration's own
23
- -- addition.
24
- --
25
- -- Rollback: DROP INDEX "flow_definitions_workspace_id_idx",
26
- -- "flow_sessions_workspace_id_idx"; ALTER TABLE "flow_definitions" DROP
27
- -- CONSTRAINT "flow_definitions_workspace_id_format", DROP COLUMN
28
- -- "workspace_id"; ALTER TABLE "flow_sessions" DROP CONSTRAINT
29
- -- "flow_sessions_workspace_id_format", DROP COLUMN "workspace_id". Safe
30
- -- unconditionally at this pin — nothing reads the column until #6156+.
31
-
32
- -- The census the post-assertions compare against. ON COMMIT DROP: `prisma
33
- -- migrate` runs each migration in one transaction, so this disappears with it.
34
- CREATE TEMP TABLE "_6155_flow_census" ON COMMIT DROP AS
35
- SELECT (SELECT count(*) FROM "flow_definitions") AS d,
36
- (SELECT count(*) FROM "flow_sessions") AS s;
37
-
38
- -- AlterTable
39
- ALTER TABLE "flow_definitions" ADD COLUMN IF NOT EXISTS "workspace_id" TEXT;
40
- ALTER TABLE "flow_sessions" ADD COLUMN IF NOT EXISTS "workspace_id" TEXT;
41
-
42
- -- Format CHECKs — NULL-permitting, in the exact shape of the CHECKs
43
- -- 20260713192429_prefixed_uuid_entity_ids/migration.sql:170-197 already
44
- -- applies to every other `workspace_id` column. Existence-guarded because
45
- -- Postgres has no `ADD CONSTRAINT IF NOT EXISTS`.
46
- DO $$ BEGIN
47
- IF NOT EXISTS (
48
- SELECT 1 FROM pg_constraint WHERE conname = 'flow_definitions_workspace_id_format'
49
- ) THEN
50
- ALTER TABLE "flow_definitions" ADD CONSTRAINT "flow_definitions_workspace_id_format"
51
- CHECK ("workspace_id" IS NULL OR "workspace_id" ~ '^wksp_[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$');
52
- END IF;
53
- END $$;
54
-
55
- DO $$ BEGIN
56
- IF NOT EXISTS (
57
- SELECT 1 FROM pg_constraint WHERE conname = 'flow_sessions_workspace_id_format'
58
- ) THEN
59
- ALTER TABLE "flow_sessions" ADD CONSTRAINT "flow_sessions_workspace_id_format"
60
- CHECK ("workspace_id" IS NULL OR "workspace_id" ~ '^wksp_[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$');
61
- END IF;
62
- END $$;
63
-
64
- -- CreateIndex
65
- CREATE INDEX IF NOT EXISTS "flow_definitions_workspace_id_idx" ON "flow_definitions"("workspace_id");
66
- CREATE INDEX IF NOT EXISTS "flow_sessions_workspace_id_idx" ON "flow_sessions"("workspace_id");
67
-
68
- -- ── Backfill (spec D2) ──────────────────────────────────────────────────────
69
- -- Both spellings of the alias, one statement per table. The literal alias
70
- -- "default" resolves to the seeded sentinel workspace
71
- -- (database/tenancy.ts DEFAULT_WORKSPACE_ID); every other alias resolves
72
- -- only by exact workspaces.id equality. An inner join to "workspaces" means a
73
- -- row whose alias resolves to nothing is simply not updated and stays NULL
74
- -- — the correct, stated behavior (D3), not an error.
75
- --
76
- -- The sentinel id is written as a literal because SQL cannot import
77
- -- database/tenancy.ts; database/__tests__/tenancy.test.ts pins the same
78
- -- literal against the exported constant so the two cannot drift.
79
- UPDATE "flow_definitions" f
80
- SET "workspace_id" = w."id"
81
- FROM "workspaces" w
82
- WHERE f."workspace_id" IS NULL
83
- AND w."id" = CASE WHEN f."site_id" = 'default'
84
- THEN 'wksp_00000000-0000-7000-8000-000000000001'
85
- ELSE f."site_id" END;
86
-
87
- UPDATE "flow_sessions" f
88
- SET "workspace_id" = w."id"
89
- FROM "workspaces" w
90
- WHERE f."workspace_id" IS NULL
91
- AND w."id" = CASE WHEN f."site_id" = 'default'
92
- THEN 'wksp_00000000-0000-7000-8000-000000000001'
93
- ELSE f."site_id" END;
94
-
95
- -- ── POST-ASSERTIONS ─────────────────────────────────────────────────────────
96
- -- AC-1's own enforcement: nothing lost, nothing guessed, nothing missed that
97
- -- was resolvable. The fourth check is a NOTICE, not an exception — an
98
- -- unpinned/unseeded deployment leaving rows NULL is the expected, documented
99
- -- case (spec § 1.3), never an error this migration should refuse to run over.
100
- DO $$
101
- DECLARE
102
- before_d bigint;
103
- before_s bigint;
104
- after_d bigint;
105
- after_s bigint;
106
- guessed bigint;
107
- missed bigint;
108
- null_d bigint;
109
- null_s bigint;
110
- BEGIN
111
- SELECT d, s INTO before_d, before_s FROM "_6155_flow_census";
112
- SELECT count(*) INTO after_d FROM "flow_definitions";
113
- SELECT count(*) INTO after_s FROM "flow_sessions";
114
-
115
- -- 1. Nothing lost: row counts unchanged on both tables.
116
- IF before_d <> after_d OR before_s <> after_s THEN
117
- RAISE EXCEPTION
118
- '#6155 post-assertion: row count changed across a purely additive migration (flow_definitions % -> %, flow_sessions % -> %)',
119
- before_d, after_d, before_s, after_s;
120
- END IF;
121
-
122
- -- 2. Nothing guessed: no row's workspace_id was set to a value absent
123
- -- from "workspaces" (the inner-join backfill above cannot produce this
124
- -- on its own, but a re-run against a database missing the sentinel row
125
- -- must never leave a dangling reference).
126
- SELECT count(*) INTO guessed FROM "flow_definitions" f
127
- WHERE f."workspace_id" IS NOT NULL
128
- AND NOT EXISTS (SELECT 1 FROM "workspaces" w WHERE w."id" = f."workspace_id");
129
- IF guessed <> 0 THEN
130
- RAISE EXCEPTION
131
- '#6155 post-assertion: % flow_definitions row(s) carry a workspace_id absent from workspaces',
132
- guessed;
133
- END IF;
134
- SELECT count(*) INTO guessed FROM "flow_sessions" f
135
- WHERE f."workspace_id" IS NOT NULL
136
- AND NOT EXISTS (SELECT 1 FROM "workspaces" w WHERE w."id" = f."workspace_id");
137
- IF guessed <> 0 THEN
138
- RAISE EXCEPTION
139
- '#6155 post-assertion: % flow_sessions row(s) carry a workspace_id absent from workspaces',
140
- guessed;
141
- END IF;
142
-
143
- -- 3. Nothing missed: no row whose site_id names a workspace that actually
144
- -- exists came out of the backfill with workspace_id still NULL.
145
- SELECT count(*) INTO missed FROM "flow_definitions" f
146
- WHERE f."workspace_id" IS NULL
147
- AND EXISTS (
148
- SELECT 1 FROM "workspaces" w
149
- WHERE w."id" = CASE WHEN f."site_id" = 'default'
150
- THEN 'wksp_00000000-0000-7000-8000-000000000001'
151
- ELSE f."site_id" END
152
- );
153
- IF missed <> 0 THEN
154
- RAISE EXCEPTION
155
- '#6155 post-assertion: % flow_definitions row(s) had a resolvable site_id but came out of the backfill NULL',
156
- missed;
157
- END IF;
158
- SELECT count(*) INTO missed FROM "flow_sessions" f
159
- WHERE f."workspace_id" IS NULL
160
- AND EXISTS (
161
- SELECT 1 FROM "workspaces" w
162
- WHERE w."id" = CASE WHEN f."site_id" = 'default'
163
- THEN 'wksp_00000000-0000-7000-8000-000000000001'
164
- ELSE f."site_id" END
165
- );
166
- IF missed <> 0 THEN
167
- RAISE EXCEPTION
168
- '#6155 post-assertion: % flow_sessions row(s) had a resolvable site_id but came out of the backfill NULL',
169
- missed;
170
- END IF;
171
-
172
- -- 4. A NOTICE, never an exception: an unpinned/unseeded deployment leaving
173
- -- rows NULL is the expected, documented case (spec § 1.3).
174
- SELECT count(*) INTO null_d FROM "flow_definitions" WHERE "workspace_id" IS NULL;
175
- SELECT count(*) INTO null_s FROM "flow_sessions" WHERE "workspace_id" IS NULL;
176
- IF null_d <> 0 OR null_s <> 0 THEN
177
- RAISE NOTICE
178
- '#6155: % flow_definitions row(s) and % flow_sessions row(s) left workspace_id unset — their site_id did not resolve to a workspace this database holds',
179
- null_d, null_s;
180
- END IF;
181
- END $$;
@@ -1,172 +0,0 @@
1
- -- #6156 — S5b: a magnet is a flow row. FlowDefinition gains four
2
- -- operator-facing columns — kind, title, landingPage, status — spec D1.
3
- --
4
- -- STRICTLY ADDITIVE. Nothing dropped, renamed or relaxed; @@unique
5
- -- ([siteId, slug]), the `flow_`+UUIDv7 id default, and `listing_id` are all
6
- -- untouched. The visitor-facing `config` column is byte-identical across
7
- -- this migration (FR4, asserted below) — these four columns are how the
8
- -- operator MANAGES a magnet, never what a visitor's session SEES
9
- -- (AD-3, spec D1/§1.2).
10
- --
11
- -- `status` is backfilled 'live' (every row that exists today is already
12
- -- serving — D1's availability half) and carries NO column default (D1's
13
- -- publication-safety half, SEC-08): a DEFAULT 'live' would make
14
- -- PUBLICATION the thing that happens when a future writer says nothing,
15
- -- which is the exact asymmetry the brief's "a magnet created from the
16
- -- Admin opens as a draft" commitment forbids. So `status` is added
17
- -- nullable, backfilled, then SET NOT NULL with no default — every future
18
- -- writer must name a status or fail to compile.
19
- --
20
- -- `title` is NOT NULL with no column default, by the same three-step, for
21
- -- the positive reason: a nameless magnet must never enter the table
22
- -- silently. The slug backfills every existing row's title — an honest
23
- -- placeholder the operator renames.
24
- --
25
- -- `kind` KEEPS its column default ('contact') — unlike `status`, a
26
- -- mis-classified magnet is a mislabel in a list, not a publication or
27
- -- security control (D1). The backfill below reclassifies the rows D3's
28
- -- structural rule actually matches; every other row stays the default.
29
- --
30
- -- `landing_page` is nullable with NO backfill (D1): a magnet has THREE
31
- -- public addresses (the indexed landing route, the walk route one segment
32
- -- deeper, and the results route), so seeding a derived guess would freeze
33
- -- a route as if it were an operator decision. NULL means "no
34
- -- operator-declared landing page; the canonical route serves it" — true of
35
- -- every existing row.
36
- --
37
- -- `flow_definitions_status_domain` (D2) is a closed two-value CHECK,
38
- -- deliberately narrower than the precedent this namespace otherwise follows
39
- -- (WaitlistExperiment.status, FlowCheckout.status, ProjectListing.status —
40
- -- all plain String with no CHECK): `status` is what makes D10's
41
- -- deny-list gate in `resolveSession` SAFE rather than merely convenient —
42
- -- an unstorable unknown value means "not 'draft'" and "'live'" are the same
43
- -- set at the database level. No CHECK on `kind`: its vocabulary is six
44
- -- values and growing (Epic #6025), so a CHECK there would make every new
45
- -- kind a migration that RELAXES a constraint.
46
- --
47
- -- Statement order (D9) is fixed and load-bearing, not incidental: the
48
- -- `ADD COLUMN` runs FIRST, acquiring ACCESS EXCLUSIVE on `flow_definitions`
49
- -- before the census is taken, so no concurrent committed write (a listing
50
- -- approval via `upsertFlowDefinition`, a waitlist-register materialize) can
51
- -- land between the census and the assertions and falsely trip them. The
52
- -- whole sequence blocks every read AND write to `flow_definitions` for its
53
- -- duration — acceptable only because the table is tiny today (§1.4's
54
- -- census: four seeded presets plus two generated families); a later unit
55
- -- that grows this table materially owes a re-read of this decision rather
56
- -- than an inherited assumption.
57
- --
58
- -- Not re-runnable by `IF NOT EXISTS` guards (unlike #6155's
59
- -- 20260919120000_flow_workspace_key, whose NFR3 needed it for a reason
60
- -- specific to that migration): `prisma migrate`'s per-migration transaction
61
- -- + the `_prisma_migrations` ledger already make re-runnability a
62
- -- non-requirement here.
63
- --
64
- -- Rollback: ALTER TABLE "flow_definitions" DROP COLUMN "kind", DROP COLUMN
65
- -- "title", DROP COLUMN "landing_page", DROP COLUMN "status". Safe
66
- -- unconditionally — dropping "status" drops "flow_definitions_status_domain"
67
- -- with it, the four columns carry no other constraint, no index and no
68
- -- relation, and nothing outside this diff references them.
69
-
70
- -- AlterTable — all four, one statement, taking ACCESS EXCLUSIVE before
71
- -- anything else in this transaction reads the table (D9).
72
- ALTER TABLE "flow_definitions"
73
- ADD COLUMN "kind" TEXT NOT NULL DEFAULT 'contact',
74
- ADD COLUMN "title" TEXT,
75
- ADD COLUMN "landing_page" TEXT,
76
- ADD COLUMN "status" TEXT;
77
-
78
- -- The census the post-assertions compare against — taken SECOND, under the
79
- -- lock the ADD COLUMN above already holds, so it is a stable baseline for
80
- -- every assertion below (D9 / SEC-07). ON COMMIT DROP: `prisma migrate`
81
- -- runs each migration in one transaction, so this disappears with it.
82
- CREATE TEMP TABLE "_6156_flow_def_census" ON COMMIT DROP AS
83
- SELECT count(*) AS n,
84
- md5(string_agg("config"::text, '' ORDER BY "id")) AS config_hash
85
- FROM "flow_definitions";
86
-
87
- -- ── Backfill (D3 / D1) ───────────────────────────────────────────────────
88
- -- 1. `kind` — D3's structural rule, first match wins. Every row not
89
- -- matched by a branch below keeps the column default written above.
90
- UPDATE "flow_definitions"
91
- SET "kind" = CASE
92
- WHEN "listing_id" IS NOT NULL THEN 'diagnostic'
93
- WHEN "config"->>'mode' = 'recommending' THEN 'diagnostic'
94
- WHEN "config" ? 'deliverables' THEN 'special-report'
95
- ELSE 'contact'
96
- END;
97
-
98
- -- 2. `title` = the slug (an honest placeholder); `status` = 'live' (every
99
- -- row that exists today is already serving — D1's availability half).
100
- UPDATE "flow_definitions"
101
- SET "title" = "slug",
102
- "status" = 'live';
103
-
104
- -- SET NOT NULL + the status domain CHECK — AFTER the backfill, so neither
105
- -- constraint is ever evaluated against a NULL this migration itself wrote.
106
- ALTER TABLE "flow_definitions" ALTER COLUMN "title" SET NOT NULL;
107
- ALTER TABLE "flow_definitions" ALTER COLUMN "status" SET NOT NULL;
108
- ALTER TABLE "flow_definitions"
109
- ADD CONSTRAINT "flow_definitions_status_domain"
110
- CHECK ("status" IN ('draft', 'live'));
111
-
112
- -- ── POST-ASSERTIONS (FR2/FR3/FR4 — AC-1) ────────────────────────────────
113
- -- Asserted against the rows the target database actually holds, not a
114
- -- fixture's. A raised exception here rolls the whole migration back
115
- -- (`prisma migrate`'s per-migration transaction).
116
- DO $$
117
- DECLARE
118
- before_n bigint;
119
- before_hash text;
120
- after_n bigint;
121
- after_hash text;
122
- null_cols bigint;
123
- wrong_kind bigint;
124
- BEGIN
125
- SELECT n, config_hash INTO before_n, before_hash FROM "_6156_flow_def_census";
126
- SELECT count(*), md5(string_agg("config"::text, '' ORDER BY "id"))
127
- INTO after_n, after_hash
128
- FROM "flow_definitions";
129
-
130
- -- 1. Nothing lost or gained: row count unchanged across a purely
131
- -- additive-plus-backfill migration.
132
- IF before_n <> after_n THEN
133
- RAISE EXCEPTION
134
- '#6156 post-assertion: flow_definitions row count changed (% -> %)',
135
- before_n, after_n;
136
- END IF;
137
-
138
- -- 2. `config` is byte-identical (FR4) — this migration writes NO column
139
- -- other than kind/title/landing_page/status.
140
- IF before_hash IS DISTINCT FROM after_hash THEN
141
- RAISE EXCEPTION
142
- '#6156 post-assertion: flow_definitions.config changed across a migration that must not touch it';
143
- END IF;
144
-
145
- -- 3. Every pre-existing row leaves with a non-NULL status/title/kind
146
- -- (landing_page is NOT asserted — D1: it is deliberately unbackfilled).
147
- SELECT count(*) INTO null_cols FROM "flow_definitions"
148
- WHERE "status" IS NULL OR "title" IS NULL OR "kind" IS NULL;
149
- IF null_cols <> 0 THEN
150
- RAISE EXCEPTION
151
- '#6156 post-assertion: % flow_definitions row(s) came out of the backfill with a NULL status/title/kind',
152
- null_cols;
153
- END IF;
154
-
155
- -- 4. Backfill rule correctness (D3) — every listing-projected row, and
156
- -- every recommending-mode row, classified 'diagnostic'.
157
- SELECT count(*) INTO wrong_kind FROM "flow_definitions"
158
- WHERE "listing_id" IS NOT NULL AND "kind" <> 'diagnostic';
159
- IF wrong_kind <> 0 THEN
160
- RAISE EXCEPTION
161
- '#6156 post-assertion: % flow_definitions row(s) with listing_id set did not classify as diagnostic',
162
- wrong_kind;
163
- END IF;
164
-
165
- SELECT count(*) INTO wrong_kind FROM "flow_definitions"
166
- WHERE "config"->>'mode' = 'recommending' AND "kind" <> 'diagnostic';
167
- IF wrong_kind <> 0 THEN
168
- RAISE EXCEPTION
169
- '#6156 post-assertion: % flow_definitions row(s) with config.mode = recommending did not classify as diagnostic',
170
- wrong_kind;
171
- END IF;
172
- END $$;
@@ -1,41 +0,0 @@
1
- -- #6183 (S9b) — the WorkspaceMeetings model: the operator's enabled-slug
2
- -- gate for meeting types (spec docs/specs/6183-s9b-enabled-meeting-slugs-live-spec.md
3
- -- D1, D11). A fourth workspace site-config blob, structurally identical to
4
- -- its three siblings (workspace_themes / workspace_site_identities /
5
- -- workspace_seos) — same `@unique(workspace_id)` key, same Json-column
6
- -- convention, validation happens at the API layer.
7
- --
8
- -- One new table, one unique index, in the house style of
9
- -- 20260918120000_add_appointment (CreateTable + CreateIndex immediately
10
- -- followed by the ADR-0031 rule-3 id-format completion, in ONE migration
11
- -- since the table is new and needs no retrofit). No `workspace_id_format`
12
- -- CHECK, matching that same precedent — the baseline migration's 12
13
- -- relation-free scope checks are pinned to it alone
14
- -- (packages/ids/src/__tests__/migration-sync.test.ts), and no per-entity
15
- -- migration since has added one.
16
- --
17
- -- No backfill, no constraint relaxed, no existing table touched.
18
- --
19
- -- Rollback: DROP TABLE "workspace_meetings". Safe unconditionally while
20
- -- nothing but #6183's own code reads it.
21
-
22
- -- CreateTable
23
- CREATE TABLE "workspace_meetings" (
24
- "id" TEXT NOT NULL DEFAULT ('meet_'::text || (uuidv7())::text),
25
- "workspace_id" TEXT NOT NULL,
26
- "data" JSONB NOT NULL,
27
- "created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
28
- "updated_at" TIMESTAMPTZ NOT NULL,
29
-
30
- CONSTRAINT "workspace_meetings_pkey" PRIMARY KEY ("id")
31
- );
32
-
33
- -- CreateIndex
34
- CREATE UNIQUE INDEX "workspace_meetings_workspace_id_key" ON "workspace_meetings"("workspace_id");
35
-
36
- -- ADR-0031 rule 3 — workspace_meetings: meet_ (registered in
37
- -- packages/ids/src/registry.ts ENTITY_PREFIX.workspaceMeetings; this
38
- -- migration's path is added to migration-sync.test.ts's PK_CHECK_MIGRATIONS).
39
- ALTER TABLE "workspace_meetings" ALTER COLUMN "id" TYPE text COLLATE "C";
40
- ALTER TABLE "workspace_meetings" ALTER COLUMN "id" SET DEFAULT ('meet_'::text || (uuidv7())::text);
41
- ALTER TABLE "workspace_meetings" ADD CONSTRAINT "workspace_meetings_id_format" CHECK ("id" ~ '^meet_[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$');
@@ -1,185 +0,0 @@
1
- -- #6203 — ProjectListing and Lead gain a workspace isolation key.
2
- --
3
- -- The ownership brief (docs/internal/decisions/workspace-owns-data-surfaces-render.md)
4
- -- and AD-4 (docs/internal/decisions/flow-engine-admin-surface.md): a workspace
5
- -- owns data, and the Inbox's tenant-scope fence grows to cover the two
6
- -- models it reads. `siteId` stays a legacy alias for the anonymous write
7
- -- paths (unchanged); `workspaceId` is the isolation key every Admin read
8
- -- will go through (apps/api/src/lib/tenant-db.ts's new
9
- -- `projectListings`/`leads` accessors). Mirrors
10
- -- database/migrations/20260919120000_flow_workspace_key step for step
11
- -- (#6155's precedent for FlowDefinition/FlowSession).
12
- --
13
- -- NULLABLE, no default (spec D2) — a row whose `siteId` matches no workspace
14
- -- is left UNSET rather than guessed, and stays invisible to every accessor
15
- -- rather than visible to the wrong tenant (the same "fails empty, never
16
- -- wide" posture apps/api/src/services/leads-inbox.ts already takes).
17
- --
18
- -- RE-RUNNABLE (NFR3): `ADD COLUMN IF NOT EXISTS` / `CREATE INDEX IF NOT
19
- -- EXISTS` cover the column and index. Postgres has no
20
- -- `ADD CONSTRAINT IF NOT EXISTS`, so each format CHECK is wrapped in its own
21
- -- existence-guarded `DO $$` block, exactly as the #6155 precedent does.
22
- --
23
- -- Rollback: DROP INDEX "project_listings_workspace_id_idx",
24
- -- "leads_workspace_id_idx"; ALTER TABLE "project_listings" DROP
25
- -- CONSTRAINT "project_listings_workspace_id_format", DROP COLUMN
26
- -- "workspace_id"; ALTER TABLE "leads" DROP CONSTRAINT
27
- -- "leads_workspace_id_format", DROP COLUMN "workspace_id". Safe
28
- -- unconditionally at this pin — nothing reads the column until #6204+.
29
-
30
- -- The census the post-assertions compare against. ON COMMIT DROP: `prisma
31
- -- migrate` runs each migration in one transaction, so this disappears with it.
32
- CREATE TEMP TABLE "_6203_inbox_census" ON COMMIT DROP AS
33
- SELECT (SELECT count(*) FROM "project_listings") AS p,
34
- (SELECT count(*) FROM "leads") AS l;
35
-
36
- -- AlterTable
37
- ALTER TABLE "project_listings" ADD COLUMN IF NOT EXISTS "workspace_id" TEXT;
38
- ALTER TABLE "leads" ADD COLUMN IF NOT EXISTS "workspace_id" TEXT;
39
-
40
- -- Format CHECKs — NULL-permitting, in the exact shape of the CHECKs
41
- -- 20260713192429_prefixed_uuid_entity_ids/migration.sql already applies to
42
- -- every other `workspace_id` column. Existence-guarded because Postgres has
43
- -- no `ADD CONSTRAINT IF NOT EXISTS`. This is what makes the Lead.siteId
44
- -- provenance gap (spec §1.3, §9 SEC-1) non-exploitable as an id-SHAPE
45
- -- attack: a site_id that is not a well-formed wksp_<uuidv7> cannot land in
46
- -- this column at all.
47
- DO $$ BEGIN
48
- IF NOT EXISTS (
49
- SELECT 1 FROM pg_constraint WHERE conname = 'project_listings_workspace_id_format'
50
- ) THEN
51
- ALTER TABLE "project_listings" ADD CONSTRAINT "project_listings_workspace_id_format"
52
- CHECK ("workspace_id" IS NULL OR "workspace_id" ~ '^wksp_[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$');
53
- END IF;
54
- END $$;
55
-
56
- DO $$ BEGIN
57
- IF NOT EXISTS (
58
- SELECT 1 FROM pg_constraint WHERE conname = 'leads_workspace_id_format'
59
- ) THEN
60
- ALTER TABLE "leads" ADD CONSTRAINT "leads_workspace_id_format"
61
- CHECK ("workspace_id" IS NULL OR "workspace_id" ~ '^wksp_[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$');
62
- END IF;
63
- END $$;
64
-
65
- -- CreateIndex
66
- CREATE INDEX IF NOT EXISTS "project_listings_workspace_id_idx" ON "project_listings"("workspace_id");
67
- CREATE INDEX IF NOT EXISTS "leads_workspace_id_idx" ON "leads"("workspace_id");
68
-
69
- -- ── Backfill (spec D2, §5.4) ────────────────────────────────────────────────
70
- -- Both spellings of the alias, one statement per table. The literal alias
71
- -- "default" resolves to the seeded sentinel workspace
72
- -- (database/tenancy.ts DEFAULT_WORKSPACE_ID); every other alias resolves
73
- -- only by exact workspaces.id equality. An inner join to "workspaces" means a
74
- -- row whose alias resolves to nothing is simply not updated and stays NULL
75
- -- — the correct, stated behavior (D2), not an error.
76
- --
77
- -- The sentinel id is a literal because SQL cannot import
78
- -- database/tenancy.ts. It is ADR 0031's reserved-range sentinel and changes
79
- -- only with that ADR — no test pins it against SQL (#6155's own migration
80
- -- carries the identical correction: the sibling tenancy.test.ts compares
81
- -- only the imported constant, not this SQL literal).
82
- UPDATE "project_listings" p
83
- SET "workspace_id" = w."id"
84
- FROM "workspaces" w
85
- WHERE p."workspace_id" IS NULL
86
- AND w."id" = CASE WHEN p."site_id" = 'default'
87
- THEN 'wksp_00000000-0000-7000-8000-000000000001'
88
- ELSE p."site_id" END;
89
-
90
- UPDATE "leads" l
91
- SET "workspace_id" = w."id"
92
- FROM "workspaces" w
93
- WHERE l."workspace_id" IS NULL
94
- AND w."id" = CASE WHEN l."site_id" = 'default'
95
- THEN 'wksp_00000000-0000-7000-8000-000000000001'
96
- ELSE l."site_id" END;
97
-
98
- -- ── POST-ASSERTIONS ─────────────────────────────────────────────────────────
99
- -- AC-1's own enforcement: nothing lost, nothing guessed, nothing missed that
100
- -- was resolvable. The fourth check is a NOTICE, not an exception — an
101
- -- unpinned/unseeded deployment leaving rows NULL is the expected, documented
102
- -- case (spec §1.9, NFR4), never an error this migration should refuse to
103
- -- run over.
104
- DO $$
105
- DECLARE
106
- before_p bigint;
107
- before_l bigint;
108
- after_p bigint;
109
- after_l bigint;
110
- guessed bigint;
111
- missed bigint;
112
- null_p bigint;
113
- null_l bigint;
114
- BEGIN
115
- SELECT p, l INTO before_p, before_l FROM "_6203_inbox_census";
116
- SELECT count(*) INTO after_p FROM "project_listings";
117
- SELECT count(*) INTO after_l FROM "leads";
118
-
119
- -- 1. Nothing lost: row counts unchanged on both tables.
120
- IF before_p <> after_p OR before_l <> after_l THEN
121
- RAISE EXCEPTION
122
- '#6203 post-assertion: row count changed across a purely additive migration (project_listings % -> %, leads % -> %)',
123
- before_p, after_p, before_l, after_l;
124
- END IF;
125
-
126
- -- 2. Nothing guessed: no row's workspace_id was set to a value absent
127
- -- from "workspaces" (the inner-join backfill above cannot produce this
128
- -- on its own, but a re-run against a database missing the sentinel row
129
- -- must never leave a dangling reference).
130
- SELECT count(*) INTO guessed FROM "project_listings" p
131
- WHERE p."workspace_id" IS NOT NULL
132
- AND NOT EXISTS (SELECT 1 FROM "workspaces" w WHERE w."id" = p."workspace_id");
133
- IF guessed <> 0 THEN
134
- RAISE EXCEPTION
135
- '#6203 post-assertion: % project_listings row(s) carry a workspace_id absent from workspaces',
136
- guessed;
137
- END IF;
138
- SELECT count(*) INTO guessed FROM "leads" l
139
- WHERE l."workspace_id" IS NOT NULL
140
- AND NOT EXISTS (SELECT 1 FROM "workspaces" w WHERE w."id" = l."workspace_id");
141
- IF guessed <> 0 THEN
142
- RAISE EXCEPTION
143
- '#6203 post-assertion: % leads row(s) carry a workspace_id absent from workspaces',
144
- guessed;
145
- END IF;
146
-
147
- -- 3. Nothing missed: no row whose site_id names a workspace that actually
148
- -- exists came out of the backfill with workspace_id still NULL.
149
- SELECT count(*) INTO missed FROM "project_listings" p
150
- WHERE p."workspace_id" IS NULL
151
- AND EXISTS (
152
- SELECT 1 FROM "workspaces" w
153
- WHERE w."id" = CASE WHEN p."site_id" = 'default'
154
- THEN 'wksp_00000000-0000-7000-8000-000000000001'
155
- ELSE p."site_id" END
156
- );
157
- IF missed <> 0 THEN
158
- RAISE EXCEPTION
159
- '#6203 post-assertion: % project_listings row(s) had a resolvable site_id but came out of the backfill NULL',
160
- missed;
161
- END IF;
162
- SELECT count(*) INTO missed FROM "leads" l
163
- WHERE l."workspace_id" IS NULL
164
- AND EXISTS (
165
- SELECT 1 FROM "workspaces" w
166
- WHERE w."id" = CASE WHEN l."site_id" = 'default'
167
- THEN 'wksp_00000000-0000-7000-8000-000000000001'
168
- ELSE l."site_id" END
169
- );
170
- IF missed <> 0 THEN
171
- RAISE EXCEPTION
172
- '#6203 post-assertion: % leads row(s) had a resolvable site_id but came out of the backfill NULL',
173
- missed;
174
- END IF;
175
-
176
- -- 4. A NOTICE, never an exception: an unpinned/unseeded deployment leaving
177
- -- rows NULL is the expected, documented case (spec §1.9).
178
- SELECT count(*) INTO null_p FROM "project_listings" WHERE "workspace_id" IS NULL;
179
- SELECT count(*) INTO null_l FROM "leads" WHERE "workspace_id" IS NULL;
180
- IF null_p <> 0 OR null_l <> 0 THEN
181
- RAISE NOTICE
182
- '#6203: % project_listings row(s) and % leads row(s) left workspace_id unset — their site_id did not resolve to a workspace this database holds',
183
- null_p, null_l;
184
- END IF;
185
- END $$;
@@ -1,70 +0,0 @@
1
- -- #6204 — Lead gains a nullable triage stamp.
2
- --
3
- -- Operator decision Q1(a) (#6026, 2026-09-18): a message is a lead that needs
4
- -- an answer — same capture path, same routing, same tenancy, different
5
- -- follow-up. One nullable column beats a second entity, and
6
- -- docs/internal/decisions/flow-engine-admin-surface.md AD-4 stays true: the
7
- -- Inbox is a READ PROJECTION over tables that already hold decidable state,
8
- -- never a new decision table.
9
- --
10
- -- PURELY ADDITIVE (spec NFR1): two ADD COLUMNs, one CREATE INDEX. No UPDATE, no
11
- -- backfill, no DEFAULT, no NOT NULL — every existing row keeps NULL, which is
12
- -- exactly "unhandled" (spec D5, AC-1). There is no data transformation here, so
13
- -- this migration carries none of the census/post-assertion apparatus
14
- -- 20260919140000_inbox_workspace_key needed to prove ITS backfill correct.
15
- --
16
- -- RE-RUNNABLE (spec NFR2): IF NOT EXISTS on every statement, the house style of
17
- -- 20260919140000_inbox_workspace_key/migration.sql.
18
- --
19
- -- ORDER-SAFE (spec NFR2, security finding S-9): the index references
20
- -- "workspace_id", which 20260919140000_inbox_workspace_key adds — a migration
21
- -- this one sorts strictly after (20260920 > 20260919), so in the normal case
22
- -- the guard below is a formality. It stays a guard rather than an assumption:
23
- -- `IF NOT EXISTS` guards the INDEX's own name, not the column it references,
24
- -- so an unguarded CREATE INDEX would abort inside prisma migrate's
25
- -- per-migration transaction and wedge the ledger for the whole deployment if
26
- -- that migration were ever skipped, renamed, or rolled back on a given
27
- -- database. The two ADD COLUMNs above it are unconditional because they
28
- -- reference nothing another migration owns.
29
- --
30
- -- CREATE INDEX is NOT CONCURRENT (security finding S-11), and cannot be:
31
- -- CONCURRENTLY may not run inside prisma migrate's per-migration transaction.
32
- -- It therefore takes a lock on "leads" for its duration, which blocks the three
33
- -- anonymous capture routes (a write failure there surfaces as 503
34
- -- persist_failed, routes/leads/index.ts), and every subsequent insert
35
- -- pays a fourth index write. Accepted: "leads" carries four indexes already
36
- -- (siteId, createdAt, email, workspaceId) and is small at this pin. A
37
- -- deployment with a large leads table should create this index out-of-band
38
- -- with CONCURRENTLY first — the IF NOT EXISTS guard then makes this
39
- -- statement a no-op.
40
- --
41
- -- Rollback: DROP INDEX "leads_workspace_id_handled_at_idx";
42
- -- ALTER TABLE "leads" DROP COLUMN "handled_at", DROP COLUMN "handled_by".
43
- -- Safe ONLY at this pin, and the qualifier is load-bearing: once the Needs-you
44
- -- section ships, dropping these columns destroys operator triage state. After
45
- -- that point the rollback is a forward migration, not a DROP.
46
-
47
- -- AlterTable
48
- ALTER TABLE "leads" ADD COLUMN IF NOT EXISTS "handled_at" TIMESTAMP(3);
49
- -- The actor (spec D4, security finding S-7) — the sibling of
50
- -- project_listings."decided_by". Plain TEXT, no FK:
51
- -- ADR 0009 D2 forbids a relation crossing from inbox into auth.
52
- ALTER TABLE "leads" ADD COLUMN IF NOT EXISTS "handled_by" TEXT;
53
-
54
- -- CreateIndex — the read is
55
- -- workspace_id = $1 AND handled_at IS NULL AND source = ANY($2)
56
- -- ordered by created_at desc. A two-column (workspace_id, handled_at) index is
57
- -- the one that serves it: it narrows to the tenant and then to the unhandled
58
- -- partition, which is the small side and the side that shrinks as an operator
59
- -- works the queue. `source` is deliberately NOT a third column (spec D10).
60
- DO $$ BEGIN
61
- IF EXISTS (
62
- SELECT 1 FROM information_schema.columns
63
- WHERE table_name = 'leads' AND column_name = 'workspace_id'
64
- ) THEN
65
- CREATE INDEX IF NOT EXISTS "leads_workspace_id_handled_at_idx"
66
- ON "leads"("workspace_id", "handled_at");
67
- ELSE
68
- RAISE NOTICE '#6204: leads.workspace_id absent — index skipped. 20260919140000_inbox_workspace_key has not run against this database; the Needs-you read cannot be served until it does (spec § 10.1).';
69
- END IF;
70
- END $$;