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,210 +0,0 @@
1
- -- #6314 — ProjectListing gains `captured_by_flow_id`: the listicle-kind
2
- -- FlowDefinition that CAPTURED the application, so a magnet's own
3
- -- Applications list can be scoped to its own submissions rather than to the
4
- -- whole workspace. Nothing constrains a workspace to one listicle magnet
5
- -- ("flow_definitions" carries a (site_id, slug) unique and no
6
- -- (site_id, kind) one), so workspace-only scoping would silently conflate
7
- -- two listicle magnets' applications.
8
- --
9
- -- A NEW MIGRATION DIRECTORY, not an amendment of the already-merged
10
- -- 20260922120000_tenancy_fence (spec D8). #6254 AC-1's one-migration-per-
11
- -- milestone rule names #6314 by number in that migration's own header, so
12
- -- this is a DEPARTURE taken deliberately and with the operator's
13
- -- confirmation (2026-09-20), not a gap that rule failed to cover. Two
14
- -- reasons, in order of weight:
15
- -- 1. Prisma records a per-migration CHECKSUM. `prisma migrate deploy`
16
- -- refuses a migration whose file no longer matches `_prisma_migrations`,
17
- -- so a database that already applied the fence directory would never
18
- -- receive this column or its index while the new code assumes both.
19
- -- "Editing it in place is a silent no-op" is true of the SQL; it is not
20
- -- true of the checksum.
21
- -- 2. apps/api/CLAUDE.md: "Never edit a shipped migration — add a new one."
22
- -- Where a spec's convenience and an in-repo rule disagree, the rule wins.
23
- --
24
- -- PURELY ADDITIVE: one nullable column, one index. NO UPDATE, NO backfill,
25
- -- and NO foreign key.
26
- --
27
- -- NO BACKFILL, deliberately (spec § 3.5 / AC-3, operator ruling 2026-09-19).
28
- -- No existing row carries evidence naming the magnet that captured it — no
29
- -- referrer, no session link, no slug. A backfill would have to guess "the
30
- -- workspace's only listicle magnet", which is exactly the conflation this
31
- -- column exists to remove, made permanent and unauditable. Every row written
32
- -- before this migration therefore reads NULL for the life of the row:
33
- -- unattributed, excluded from every per-magnet list (NULL never equals a
34
- -- magnet id, so the exclusion is a property of the query, not a filter that
35
- -- can be forgotten), and UNCHANGED in the workspace Inbox — no operator loses
36
- -- access to any application. This is the same discipline the founder-name
37
- -- parts (#5407), the address parts (#5279) and `owner_user_id` (#5295) each
38
- -- follow: a value that can only be guessed must not be asserted.
39
- --
40
- -- NO foreign key, deliberately (spec § 3.2, operator decision 2026-09-20,
41
- -- which withdrew the 2026-09-19 ruling's "on-delete set-null" clause). Both
42
- -- models live in the `inbox` namespace, so ADR 0009 invariant #1 (which bans
43
- -- CROSS-namespace relations) does not reach this column — permission was
44
- -- never the question. The convention is: of the 24 foreign-key constraints
45
- -- under database/migrations/**, every one targets the `auth` namespace
46
- -- ("users"); the intra-inbox columns listing_id, lead_id, grant_id and
47
- -- flow_session_id carry none. The composite (workspace_id, …) shape was
48
- -- itself offered and declined on "listing_csv_sends" the day before this
49
- -- spec's pin. Integrity rests on the server-side resolve in
50
- -- `startProjectListingDraft` (site_id + workspace_id + kind = 'listicle')
51
- -- and on the read carrying the injected workspace_id alongside the magnet id
52
- -- — so a dangling or foreign value yields no rows, never another workspace's.
53
- -- Nothing deletes a flow_definitions row either (routes/magnets D5: "No
54
- -- DELETE"), so ON DELETE SET NULL would have described no live code path.
55
- --
56
- -- RE-RUNNABLE: IF NOT EXISTS on both DDL statements, the census temp table is
57
- -- dropped-if-exists before it is built, and post-assertion 2 is skipped on a
58
- -- re-apply (it proves this file grew no backfill, which only the first
59
- -- application can show — see its own comment). So re-applying this directory
60
- -- against a database that already has the column is inert rather than an abort
61
- -- that would wedge the ledger.
62
- --
63
- -- ORDER-SAFE: the index references "workspace_id", added by
64
- -- 20260919140000_inbox_workspace_key and made NOT NULL by
65
- -- 20260922120000_tenancy_fence — both of which this migration sorts strictly
66
- -- after. The guard below is therefore a formality in the normal case, kept
67
- -- for the reason 20260920130000_lead_workspace_source_index keeps one: IF NOT
68
- -- EXISTS guards the INDEX's own name, not the column it references, so an
69
- -- unguarded CREATE INDEX would abort inside prisma migrate's per-migration
70
- -- transaction and wedge the ledger for the whole deployment if that earlier
71
- -- migration were ever skipped, renamed, or rolled back on a given database.
72
- --
73
- -- CREATE INDEX is NOT CONCURRENT, and cannot be: CONCURRENTLY may not run
74
- -- inside prisma migrate's per-migration transaction. It therefore takes a
75
- -- lock on "project_listings" for its duration — the same accepted risk
76
- -- 20260920130000_lead_workspace_source_index names. A deployment with a large
77
- -- project_listings table should create this index out-of-band with
78
- -- CONCURRENTLY first; the IF NOT EXISTS guard then makes the statement a
79
- -- no-op.
80
- --
81
- -- Rollback:
82
- -- DROP INDEX "project_listings_workspace_id_captured_by_flow_id_idx";
83
- -- ALTER TABLE "project_listings" DROP COLUMN "captured_by_flow_id";
84
- -- Safe at any point: the column is nullable and unconstrained, and no row's
85
- -- correctness depends on it beyond per-magnet attribution.
86
-
87
- -- A census, so the post-assertions below can prove nothing moved.
88
- --
89
- -- `column_preexisted` is captured HERE, before the ALTER, and it is what keeps
90
- -- assertion 2 honest on a RE-APPLY. That assertion proves a property of THIS
91
- -- FILE (it performs no backfill), which is only observable on the application
92
- -- that first adds the column: once the application has written even one real
93
- -- attribution, "no row is attributed" is false for reasons this migration had
94
- -- nothing to do with. Asserting it unconditionally would abort inside prisma
95
- -- migrate's per-migration transaction and wedge the ledger for every later
96
- -- migration on that database — on a restored snapshot, a `migrate resolve
97
- -- --rolled-back` redeploy, or a branch of production.
98
- -- `pg_temp.`-qualified: DROP TABLE does not distinguish temporary from
99
- -- permanent relations, and at this point the session holds no temp table, so
100
- -- an unqualified name would resolve through search_path to `public` and drop
101
- -- a same-named PERMANENT table — inside the transaction prisma commits.
102
- DROP TABLE IF EXISTS pg_temp."_6314_capture_census";
103
- CREATE TEMP TABLE "_6314_capture_census" AS
104
- SELECT
105
- count(*) AS p,
106
- EXISTS (
107
- SELECT 1 FROM information_schema.columns
108
- -- `table_schema = current_schema()` is load-bearing, not tidiness:
109
- -- `information_schema.columns` spans EVERY schema in the database, so
110
- -- without it the probe answers "does any table anywhere named
111
- -- project_listings carry this column" rather than "does the table this
112
- -- migration is about to alter carry it". A pre-migration snapshot in a
113
- -- side schema (`CREATE TABLE backup.project_listings AS SELECT ...`, a
114
- -- `pg_dump -n` restore) would then make a genuine FIRST apply take the
115
- -- skip branch below and wave a real backfill through unchecked — the
116
- -- exact AC-8 property assertion 2 exists to prove.
117
- WHERE table_schema = current_schema()
118
- AND table_name = 'project_listings'
119
- AND column_name = 'captured_by_flow_id'
120
- ) AS column_preexisted
121
- FROM "project_listings";
122
-
123
- -- AlterTable — the capturing magnet's id. Nullable and unconstrained, so a
124
- -- row predating this migration reads NULL and nothing here can reject it.
125
- ALTER TABLE "project_listings" ADD COLUMN IF NOT EXISTS "captured_by_flow_id" TEXT;
126
-
127
- -- CreateIndex — the read is workspace_id = $1 AND captured_by_flow_id = $2,
128
- -- ordered by created_at desc. A two-column (workspace_id, captured_by_flow_id)
129
- -- index serves it directly. With no foreign key there is no cascade, so no
130
- -- referencing-side index is owed beyond this one.
131
- DO $$ BEGIN
132
- IF EXISTS (
133
- SELECT 1 FROM information_schema.columns
134
- -- `table_schema = current_schema()` for the same reason the census probe
135
- -- above carries it, and the failure direction here is WORSE. A decoy
136
- -- `project_listings` in another schema makes this EXISTS spuriously true;
137
- -- the CREATE INDEX below then runs against the table search_path actually
138
- -- resolves, hits `column "workspace_id" does not exist`, and aborts the
139
- -- whole migration transaction — a wedged ledger, where the census probe's
140
- -- equivalent merely skips an assertion. The guard must ask about the table
141
- -- the statement it protects will really touch.
142
- WHERE table_schema = current_schema()
143
- AND table_name = 'project_listings'
144
- AND column_name = 'workspace_id'
145
- ) THEN
146
- CREATE INDEX IF NOT EXISTS "project_listings_workspace_id_captured_by_flow_id_idx"
147
- ON "project_listings"("workspace_id", "captured_by_flow_id");
148
- ELSE
149
- RAISE NOTICE '#6314: project_listings.workspace_id absent — index skipped. 20260919140000_inbox_workspace_key has not run against this database; the per-magnet Applications read cannot be served efficiently until it does.';
150
- END IF;
151
- END $$;
152
-
153
- -- Post-assertions, in 20260922120000_tenancy_fence's own idiom.
154
- DO $$
155
- DECLARE
156
- before_p bigint;
157
- after_p bigint;
158
- attributed bigint;
159
- preexisted boolean;
160
- BEGIN
161
- SELECT p, column_preexisted INTO before_p, preexisted FROM "_6314_capture_census";
162
- SELECT count(*) INTO after_p FROM "project_listings";
163
-
164
- -- 1. Nothing LOST. Deliberately `<`, not `<>`.
165
- --
166
- -- An equality test here has no true-positive mode and one guaranteed
167
- -- false-positive mode, which is the worst shape a guard can have. No
168
- -- statement in this file modifies a row of "project_listings" (the whole
169
- -- file is five statements; read them), so the two counts can only diverge
170
- -- through a write committed by ANOTHER session between them. The census
171
- -- takes ACCESS SHARE; the ALTER takes ACCESS EXCLUSIVE, and until it does,
172
- -- the table stays open to writers. "project_listings" is written by an
173
- -- ANONYMOUS, unauthenticated route, so on a live deploy one application
174
- -- started mid-migration aborts the migration — and the retry meets the
175
- -- same race. That is a wedged ledger caused by the system working
176
- -- normally.
177
- --
178
- -- `<` keeps the property the assertion is actually for — this migration
179
- -- must never destroy a row — while letting a concurrent INSERT through.
180
- -- A DELETE or TRUNCATE creeping into this file still trips it.
181
- IF after_p < before_p THEN
182
- RAISE EXCEPTION
183
- '#6314 post-assertion: project_listings LOST row(s) across a purely additive migration (% -> %)',
184
- before_p, after_p;
185
- END IF;
186
-
187
- -- 2. Nothing guessed (AC-8): every PRE-EXISTING row reads NULL. This
188
- -- migration performs no UPDATE, so a non-NULL row on the application that
189
- -- first adds the column would mean the file grew a backfill the ruling
190
- -- refused.
191
- --
192
- -- Skipped when the column already existed: on a re-apply, attributed rows
193
- -- are the APPLICATION's own writes, not a backfill, and failing on them
194
- -- would wedge the migration ledger (see the census above). The assertion
195
- -- still fires where it can mean anything — the first application, which is
196
- -- the only run that can introduce a backfill.
197
- IF preexisted THEN
198
- RAISE NOTICE '#6314 post-assertion 2 skipped: captured_by_flow_id already existed, so this is a re-apply and any attributed row is an application write rather than a backfill.';
199
- ELSE
200
- SELECT count(*) INTO attributed
201
- FROM "project_listings" WHERE "captured_by_flow_id" IS NOT NULL;
202
- IF attributed <> 0 THEN
203
- RAISE EXCEPTION
204
- '#6314 post-assertion: % project_listings row(s) carry a captured_by_flow_id after a migration that performs no UPDATE — existing rows must stay unattributed (no backfill by guess)',
205
- attributed;
206
- END IF;
207
- END IF;
208
- END $$;
209
-
210
- DROP TABLE pg_temp."_6314_capture_census";
@@ -1,80 +0,0 @@
1
- -- #7532 — the hub's spoke registry and the booking-origin record (spec
2
- -- docs/specs/7532-a-spoke-s-public-reads-spec.md D1, D5).
3
- --
4
- -- spokes (auth) — one row per separately deployed site that
5
- -- calls this hub, bound to ONE workspace. It
6
- -- stores the SHA-256 digest of the spoke's
7
- -- hub-minted key, never the key. Deleting a
8
- -- workspace deletes its spokes (the FK below).
9
- -- appointment_origins (inbox) — (provider, booking uid) → workspace, written
10
- -- when a spoke's booking is created so the
11
- -- deployment-wide Cal.com webhook stores the
12
- -- booking in the spoke's workspace. One origin
13
- -- per booking uid. No foreign key and no
14
- -- relation (ADR 0009): workspace_id and
15
- -- spoke_id are plain columns with format CHECKs.
16
- --
17
- -- PURELY ADDITIVE: two new tables, their indexes and one FK to "workspaces".
18
- -- No statement touches an existing table's rows or columns, so there is no
19
- -- pre-assertion block — this migration cannot lose a row.
20
- --
21
- -- Rollback: DROP TABLE "appointment_origins"; DROP TABLE "spokes". Safe while
22
- -- nothing but #7532's own code reads them.
23
-
24
- -- CreateTable
25
- CREATE TABLE "spokes" (
26
- "id" TEXT NOT NULL DEFAULT ('spoke_'::text || (uuidv7())::text),
27
- "workspace_id" TEXT NOT NULL,
28
- "name" VARCHAR(120) NOT NULL,
29
- "credential_hash" CHAR(64) NOT NULL,
30
- "credential_prefix" VARCHAR(24) NOT NULL,
31
- "revoked_at" TIMESTAMP(3),
32
- "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
33
- "updated_at" TIMESTAMP(3) NOT NULL,
34
-
35
- CONSTRAINT "spokes_pkey" PRIMARY KEY ("id")
36
- );
37
-
38
- -- CreateTable
39
- CREATE TABLE "appointment_origins" (
40
- "id" TEXT NOT NULL DEFAULT ('apptorg_'::text || (uuidv7())::text),
41
- "provider" VARCHAR(32) NOT NULL DEFAULT 'cal',
42
- "provider_booking_uid" VARCHAR(200) NOT NULL,
43
- "workspace_id" TEXT NOT NULL,
44
- "spoke_id" TEXT NOT NULL,
45
- "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
46
-
47
- CONSTRAINT "appointment_origins_pkey" PRIMARY KEY ("id")
48
- );
49
-
50
- -- CreateIndex
51
- -- The lookup a spoke's every request makes (`findSpokeByKeyHash`).
52
- CREATE UNIQUE INDEX "spokes_credential_hash_key" ON "spokes"("credential_hash");
53
-
54
- -- CreateIndex
55
- CREATE INDEX "spokes_workspace_id_idx" ON "spokes"("workspace_id");
56
-
57
- -- CreateIndex
58
- CREATE INDEX "appointment_origins_workspace_id_idx" ON "appointment_origins"("workspace_id");
59
-
60
- -- CreateIndex
61
- -- One origin per booking uid (spec D5). The bind inserts with
62
- -- ON CONFLICT DO NOTHING against this key.
63
- CREATE UNIQUE INDEX "appointment_origins_provider_provider_booking_uid_key" ON "appointment_origins"("provider", "provider_booking_uid");
64
-
65
- -- AddForeignKey
66
- ALTER TABLE "spokes" ADD CONSTRAINT "spokes_workspace_id_fkey" FOREIGN KEY ("workspace_id") REFERENCES "workspaces"("id") ON DELETE CASCADE ON UPDATE CASCADE;
67
-
68
- -- ADR-0031 rule 3 — spokes: spoke_, appointment_origins: apptorg_ (registered
69
- -- in packages/ids/src/registry.ts; this migration's path is added to
70
- -- migration-sync.test.ts's PK_CHECK_MIGRATIONS).
71
- ALTER TABLE "spokes" ALTER COLUMN "id" TYPE text COLLATE "C";
72
- ALTER TABLE "spokes" ALTER COLUMN "id" SET DEFAULT ('spoke_'::text || (uuidv7())::text);
73
- ALTER TABLE "spokes" ADD CONSTRAINT "spokes_id_format" CHECK ("id" ~ '^spoke_[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$');
74
- ALTER TABLE "spokes" ADD CONSTRAINT "spokes_workspace_id_format" CHECK ("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}$');
75
-
76
- ALTER TABLE "appointment_origins" ALTER COLUMN "id" TYPE text COLLATE "C";
77
- ALTER TABLE "appointment_origins" ALTER COLUMN "id" SET DEFAULT ('apptorg_'::text || (uuidv7())::text);
78
- ALTER TABLE "appointment_origins" ADD CONSTRAINT "appointment_origins_id_format" CHECK ("id" ~ '^apptorg_[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$');
79
- ALTER TABLE "appointment_origins" ADD CONSTRAINT "appointment_origins_spoke_id_format" CHECK ("spoke_id" ~ '^spoke_[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$');
80
- ALTER TABLE "appointment_origins" ADD CONSTRAINT "appointment_origins_workspace_id_format" CHECK ("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}$');
@@ -1,49 +0,0 @@
1
- -- #7533 — the SchedulingConnection model: a workspace's own scheduling
2
- -- provider account (spec docs/specs/7533-a-scheduling-connection-per-workspace-spec.md
3
- -- D1). One row per workspace, keyed `@unique(workspace_id)` like its config
4
- -- sibling workspace_meetings; the credential and webhook secret columns hold
5
- -- AES-256-GCM ciphertext written only by apps/api's
6
- -- services/scheduling/connections.ts. `webhook_token` is the per-connection
7
- -- webhook entry point's routing id, unique so a delivery resolves at most
8
- -- one row.
9
- --
10
- -- One new table, two unique indexes, in the house style of
11
- -- 20260919130000_workspace_meetings (CreateTable + CreateIndex immediately
12
- -- followed by the ADR-0031 rule-3 id-format completion, in ONE migration
13
- -- since the table is new and needs no retrofit). No `workspace_id_format`
14
- -- CHECK and no `provider` CHECK, matching that same precedent (the API
15
- -- accepts only the provider ids its factory table knows).
16
- --
17
- -- No backfill, no constraint relaxed, no existing table touched.
18
- --
19
- -- Rollback: DROP TABLE "scheduling_connections". Every stored connection is
20
- -- lost; each workspace returns to the unconfigured state (or, on a
21
- -- one-workspace deployment, to the CAL_API_KEY env fallback).
22
-
23
- -- CreateTable
24
- CREATE TABLE "scheduling_connections" (
25
- "id" TEXT NOT NULL DEFAULT ('schconn_'::text || (uuidv7())::text),
26
- "workspace_id" TEXT NOT NULL,
27
- "provider" VARCHAR(32) NOT NULL,
28
- "credential_ciphertext" TEXT NOT NULL,
29
- "webhook_token" VARCHAR(64) NOT NULL,
30
- "webhook_secret_ciphertext" TEXT NOT NULL,
31
- "base_url" TEXT,
32
- "created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
33
- "updated_at" TIMESTAMPTZ NOT NULL,
34
-
35
- CONSTRAINT "scheduling_connections_pkey" PRIMARY KEY ("id")
36
- );
37
-
38
- -- CreateIndex
39
- CREATE UNIQUE INDEX "scheduling_connections_workspace_id_key" ON "scheduling_connections"("workspace_id");
40
-
41
- -- CreateIndex
42
- CREATE UNIQUE INDEX "scheduling_connections_webhook_token_key" ON "scheduling_connections"("webhook_token");
43
-
44
- -- ADR-0031 rule 3 — scheduling_connections: schconn_ (registered in
45
- -- packages/ids/src/registry.ts ENTITY_PREFIX.schedulingConnection; this
46
- -- migration's path is added to migration-sync.test.ts's PK_CHECK_MIGRATIONS).
47
- ALTER TABLE "scheduling_connections" ALTER COLUMN "id" TYPE text COLLATE "C";
48
- ALTER TABLE "scheduling_connections" ALTER COLUMN "id" SET DEFAULT ('schconn_'::text || (uuidv7())::text);
49
- ALTER TABLE "scheduling_connections" ADD CONSTRAINT "scheduling_connections_id_format" CHECK ("id" ~ '^schconn_[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$');
@@ -1,84 +0,0 @@
1
- -- #3591 — the agent seat, step A (spec
2
- -- docs/specs/3591-tenant-scoped-agent-auth-secure-spec.md D1).
3
- --
4
- -- agents (auth) — one row per agent: a stored delegate of ONE person (its
5
- -- responsible Membership), bound to ONE workspace. It stores
6
- -- the SHA-256 digest of the agent's key, never the key.
7
- -- Deleting the organization, the workspace or the person's
8
- -- membership deletes the agent; deleting the membership of
9
- -- the person who was last shown its key sets
10
- -- key_issued_to_membership_id null, which the guard refuses
11
- -- until the agent is re-keyed. created_by_user_id is a plain
12
- -- column with no foreign key, so deleting the creator does
13
- -- not delete the agents they made for someone else.
14
- --
15
- -- PURELY ADDITIVE: one new enum, one new table, its indexes and four FKs (to
16
- -- "organizations", "workspaces" and twice to "memberships"). No statement
17
- -- touches an existing table's rows or columns, so there is no pre-assertion
18
- -- block — this migration cannot lose a row.
19
- --
20
- -- Rollback: DROP TABLE "agents"; DROP TYPE "AgentPermissionLevel". Safe while
21
- -- nothing but #3591's own code reads them.
22
-
23
- -- CreateEnum
24
- CREATE TYPE "AgentPermissionLevel" AS ENUM ('member');
25
-
26
- -- CreateTable
27
- CREATE TABLE "agents" (
28
- "id" TEXT NOT NULL DEFAULT ('agent_'::text || (uuidv7())::text),
29
- "organization_id" TEXT NOT NULL,
30
- "workspace_id" TEXT NOT NULL,
31
- "responsible_membership_id" TEXT NOT NULL,
32
- "name" VARCHAR(80) NOT NULL,
33
- "permission_level" "AgentPermissionLevel" NOT NULL DEFAULT 'member',
34
- "enabled" BOOLEAN NOT NULL DEFAULT true,
35
- "credential_hash" CHAR(64) NOT NULL,
36
- "credential_prefix" VARCHAR(24) NOT NULL,
37
- "last_active_at" TIMESTAMP(3),
38
- "created_by_user_id" TEXT NOT NULL,
39
- "key_issued_to_membership_id" TEXT,
40
- "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
41
- "updated_at" TIMESTAMP(3) NOT NULL,
42
-
43
- CONSTRAINT "agents_pkey" PRIMARY KEY ("id")
44
- );
45
-
46
- -- CreateIndex
47
- -- The lookup an agent's every request makes (`findAgentByKeyHash`).
48
- CREATE UNIQUE INDEX "agents_credential_hash_key" ON "agents"("credential_hash");
49
-
50
- -- CreateIndex
51
- CREATE INDEX "agents_organization_id_idx" ON "agents"("organization_id");
52
-
53
- -- CreateIndex
54
- CREATE INDEX "agents_workspace_id_idx" ON "agents"("workspace_id");
55
-
56
- -- CreateIndex
57
- CREATE INDEX "agents_responsible_membership_id_idx" ON "agents"("responsible_membership_id");
58
-
59
- -- AddForeignKey
60
- ALTER TABLE "agents" ADD CONSTRAINT "agents_organization_id_fkey" FOREIGN KEY ("organization_id") REFERENCES "organizations"("id") ON DELETE CASCADE ON UPDATE CASCADE;
61
-
62
- -- AddForeignKey
63
- ALTER TABLE "agents" ADD CONSTRAINT "agents_workspace_id_fkey" FOREIGN KEY ("workspace_id") REFERENCES "workspaces"("id") ON DELETE CASCADE ON UPDATE CASCADE;
64
-
65
- -- AddForeignKey
66
- -- Leaving stops the agent: removing the person's membership deletes it.
67
- ALTER TABLE "agents" ADD CONSTRAINT "agents_responsible_membership_id_fkey" FOREIGN KEY ("responsible_membership_id") REFERENCES "memberships"("id") ON DELETE CASCADE ON UPDATE CASCADE;
68
-
69
- -- AddForeignKey
70
- -- A key dies with the person who received it: SET NULL, which the guard refuses.
71
- ALTER TABLE "agents" ADD CONSTRAINT "agents_key_issued_to_membership_id_fkey" FOREIGN KEY ("key_issued_to_membership_id") REFERENCES "memberships"("id") ON DELETE SET NULL ON UPDATE CASCADE;
72
-
73
- -- ADR-0031 rule 3 — agents: agent_ (registered in packages/ids/src/registry.ts;
74
- -- this migration's path is added to migration-sync.test.ts's
75
- -- PK_CHECK_MIGRATIONS). Each reference column carries the format CHECK of the
76
- -- entity it names, in the exact pattern the spoke migration uses.
77
- ALTER TABLE "agents" ALTER COLUMN "id" TYPE text COLLATE "C";
78
- ALTER TABLE "agents" ALTER COLUMN "id" SET DEFAULT ('agent_'::text || (uuidv7())::text);
79
- ALTER TABLE "agents" ADD CONSTRAINT "agents_id_format" CHECK ("id" ~ '^agent_[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$');
80
- ALTER TABLE "agents" ADD CONSTRAINT "agents_organization_id_format" CHECK ("organization_id" ~ '^org_[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$');
81
- ALTER TABLE "agents" ADD CONSTRAINT "agents_workspace_id_format" CHECK ("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}$');
82
- ALTER TABLE "agents" ADD CONSTRAINT "agents_responsible_membership_id_format" CHECK ("responsible_membership_id" ~ '^member_[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$');
83
- ALTER TABLE "agents" ADD CONSTRAINT "agents_key_issued_to_membership_id_format" CHECK ("key_issued_to_membership_id" ~ '^member_[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$');
84
- ALTER TABLE "agents" ADD CONSTRAINT "agents_created_by_user_id_format" CHECK ("created_by_user_id" ~ '^user_[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$');
@@ -1,35 +0,0 @@
1
- -- #7803 — sign-in lands in the user's last workspace (spec
2
- -- docs/specs/7803-sign-in-last-workspace-spec.md D1).
3
- --
4
- -- users.last_workspace_id (auth) — the workspace this person last activated.
5
- -- Written only by activateWorkspace after its membership
6
- -- grant; read only by listTenancy, which reports it only
7
- -- when the workspace is in the caller's own listing
8
- -- (apps/api/src/services/tenant-context.ts). Deleting the
9
- -- workspace sets it null.
10
- --
11
- -- PURELY ADDITIVE: one nullable column with no default, its index, one FK to
12
- -- "workspaces" and the ADR-0031 format CHECK on the new reference column. No
13
- -- backfill runs and no existing row changes, so there is no pre-assertion
14
- -- block — this migration cannot lose a row. A NULL passes the CHECK.
15
- --
16
- -- Rollout: deploy this migration BEFORE the API code that reads the column
17
- -- (SEC-7803-3). Being nullable, it is safe to apply ahead of the code.
18
- --
19
- -- Rollback: ALTER TABLE "users" DROP COLUMN "last_workspace_id"; (this drops
20
- -- the index, the FK and the CHECK with it). Safe while nothing but #7803's own
21
- -- code reads it.
22
-
23
- -- AlterTable
24
- ALTER TABLE "users" ADD COLUMN "last_workspace_id" TEXT;
25
-
26
- -- CreateIndex
27
- CREATE INDEX "users_last_workspace_id_idx" ON "users"("last_workspace_id");
28
-
29
- -- AddForeignKey
30
- -- A deleted workspace clears every pointer to it.
31
- ALTER TABLE "users" ADD CONSTRAINT "users_last_workspace_id_fkey" FOREIGN KEY ("last_workspace_id") REFERENCES "workspaces"("id") ON DELETE SET NULL ON UPDATE CASCADE;
32
-
33
- -- ADR-0031 rule 3 — the reference column carries the format CHECK of the
34
- -- entity it names (wksp_), in the exact pattern the agents migration uses.
35
- ALTER TABLE "users" ADD CONSTRAINT "users_last_workspace_id_format" CHECK ("last_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}$');
@@ -1,20 +0,0 @@
1
- -- #7869 (spoke-pattern roadmap Phase 1, D5) — Lead idempotency key: the
2
- -- caller's optional `Idempotency-Key` header on POST /v1/leads/submit, so a
3
- -- retried lead write (a client retry, a spoke's fulfilment replay) finds the
4
- -- first lead instead of writing a second. Mirrors the column-add shape of
5
- -- 20260906000000_add_flow_checkout_idempotency (one AlterTable, one unique
6
- -- index under the Prisma section headers).
7
- --
8
- -- The column is nullable with no default, so no pre-existing row needs a
9
- -- backfill and none collides on the new unique — Postgres treats NULLs as
10
- -- distinct. The unique is scoped by workspace_id: one key in two workspaces
11
- -- is two leads.
12
- --
13
- -- Rollback: ALTER TABLE "leads" DROP COLUMN "idempotency_key"; (the index
14
- -- goes with it).
15
-
16
- -- AlterTable
17
- ALTER TABLE "leads" ADD COLUMN "idempotency_key" TEXT;
18
-
19
- -- CreateIndex
20
- CREATE UNIQUE INDEX "leads_workspace_id_idempotency_key_key" ON "leads"("workspace_id", "idempotency_key");
@@ -1,33 +0,0 @@
1
- -- #7864 — grant an agent key five named abilities (spec
2
- -- docs/specs/7864-agent-key-grants-spec.md D2).
3
- --
4
- -- agents.grants (auth) — the permissions an owner or admin granted this
5
- -- agent one by one. Written only by setServedAgentGrants
6
- -- (apps/api/src/lib/agent-store.ts, the PUT
7
- -- …/agents/:agentId/grants route); read by the auth
8
- -- preHandler's key lookup and the agent list. The tenant
9
- -- guards hold an agent to the grants its person's own role
10
- -- also holds, so a stored grant never outranks the person.
11
- --
12
- -- The CHECK names the same five permissions as @working-theory/validation's
13
- -- AGENT_GRANTABLE_PERMISSIONS; database/__tests__/agents.db.test.ts reads
14
- -- this file and fails if the two lists differ (SEC-7864-G).
15
- --
16
- -- PURELY ADDITIVE: one NOT NULL column with an empty-array default and its
17
- -- CHECK. No backfill runs: every existing agent takes the default, no
18
- -- grants, and so behaves exactly as before. No existing row changes beyond
19
- -- the default fill, so there is no pre-assertion block.
20
- --
21
- -- Rollout: deploy this migration BEFORE the API code that reads the column.
22
- -- Code without the column fails closed — its key lookup errors and every
23
- -- agent is answered 401 (SEC-7864-F).
24
- --
25
- -- Rollback: ALTER TABLE "agents" DROP COLUMN "grants"; (this drops the CHECK
26
- -- with it). Safe while nothing but #7864's own code reads it.
27
-
28
- -- AlterTable
29
- ALTER TABLE "agents" ADD COLUMN "grants" TEXT[] NOT NULL DEFAULT ARRAY[]::TEXT[];
30
-
31
- -- Only the five grantable permissions may be stored.
32
- ALTER TABLE "agents" ADD CONSTRAINT "agents_grants_allowed"
33
- CHECK ("grants" <@ ARRAY['content-edit','content-publish','assets-write','magnets-manage','meeting-types-manage']::TEXT[]);
@@ -1,106 +0,0 @@
1
- -- #852 — Person, the per-workspace client record (spec
2
- -- docs/specs/852-person-the-per-workspace-client-spec.md D1, D2).
3
- --
4
- -- people (inbox) — one client of one workspace, keyed on a lowercased,
5
- -- trimmed email unique per workspace. Created only by
6
- -- apps/api/src/services/person.ts's findOrCreatePerson.
7
- -- workspace_id and user_id are plain columns with no
8
- -- foreign key (ADR 0009): they name auth-namespace rows.
9
- -- leads.person_id, appointments.person_id — the Person each row belongs
10
- -- to, stamped at creation by the intake paths.
11
- --
12
- -- PURELY ADDITIVE, DDL ONLY: one new table with its indexes and CHECKs, and
13
- -- one nullable column with no default on each of "leads" and "appointments",
14
- -- so Postgres changes only the catalog for those two. No existing row's
15
- -- values change here — the backfill is the next migration,
16
- -- 20261010121000_person_backfill, split out so its row updates never run
17
- -- under the exclusive locks these ALTER TABLEs take (SEC-852-E). Prisma runs
18
- -- this file as one transaction, so each ALTER TABLE's ACCESS EXCLUSIVE lock
19
- -- is held until the file commits — through the plain CREATE INDEX on the new
20
- -- column — blocking reads AND writes of "leads" and "appointments" (lead
21
- -- capture included) for one heap scan of each. Accepted: the scan is short
22
- -- next to the backfill it is split from.
23
- --
24
- -- Rollout: deploy this migration (and the backfill) BEFORE the API code that
25
- -- writes person_id; code without the column fails every lead write.
26
- --
27
- -- Rollback: ALTER TABLE "leads" DROP COLUMN "person_id"; ALTER TABLE
28
- -- "appointments" DROP COLUMN "person_id"; DROP TABLE "people"; (the indexes
29
- -- and CHECKs go with them). Safe while nothing but #852's own code reads them.
30
-
31
- -- AlterTable
32
- ALTER TABLE "appointments" ADD COLUMN "person_id" TEXT;
33
-
34
- -- AlterTable
35
- ALTER TABLE "leads" ADD COLUMN "person_id" TEXT;
36
-
37
- -- CreateTable
38
- CREATE TABLE "people" (
39
- "id" TEXT NOT NULL DEFAULT ('person_'::text || (uuidv7())::text),
40
- "workspace_id" TEXT NOT NULL,
41
- "email" VARCHAR(254) NOT NULL,
42
- "name" VARCHAR(200),
43
- "user_id" TEXT,
44
- "billing_provider" VARCHAR(32),
45
- "billing_customer_id" VARCHAR(255),
46
- "plan_offering" VARCHAR(100),
47
- "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
48
- "updated_at" TIMESTAMP(3) NOT NULL,
49
-
50
- CONSTRAINT "people_pkey" PRIMARY KEY ("id")
51
- );
52
-
53
- -- CreateIndex
54
- -- The webhook's first match: a customer id within one workspace (D3 step 2).
55
- -- NOT unique — the spokes share one Stripe account.
56
- CREATE INDEX "people_workspace_id_billing_customer_id_idx" ON "people"("workspace_id", "billing_customer_id");
57
-
58
- -- CreateIndex
59
- -- The People list: workspace_id = $1 ORDER BY created_at DESC (D7).
60
- CREATE INDEX "people_workspace_id_created_at_idx" ON "people"("workspace_id", "created_at");
61
-
62
- -- CreateIndex
63
- -- One Person per address per workspace — what findOrCreatePerson's
64
- -- INSERT … ON CONFLICT DO NOTHING absorbs a concurrent duplicate on.
65
- CREATE UNIQUE INDEX "people_workspace_id_email_key" ON "people"("workspace_id", "email");
66
-
67
- -- CreateIndex
68
- -- One Person per User per workspace. NULLs are distinct, so any number of
69
- -- unlinked Persons fit.
70
- CREATE UNIQUE INDEX "people_workspace_id_user_id_key" ON "people"("workspace_id", "user_id");
71
-
72
- -- CreateIndex
73
- CREATE INDEX "appointments_person_id_idx" ON "appointments"("person_id");
74
-
75
- -- CreateIndex
76
- CREATE INDEX "leads_person_id_idx" ON "leads"("person_id");
77
-
78
- -- ADR-0031 rule 3 — people: person_ (registered in packages/ids/src/registry.ts;
79
- -- this migration's path is added to migration-sync.test.ts's
80
- -- PK_CHECK_MIGRATIONS). Each reference column carries the format CHECK of the
81
- -- entity it names, in the agents-migration shape.
82
- ALTER TABLE "people" ALTER COLUMN "id" TYPE text COLLATE "C";
83
- ALTER TABLE "people" ALTER COLUMN "id" SET DEFAULT ('person_'::text || (uuidv7())::text);
84
- ALTER TABLE "people" ADD CONSTRAINT "people_id_format" CHECK ("id" ~ '^person_[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$');
85
- ALTER TABLE "people" ADD CONSTRAINT "people_workspace_id_format" CHECK ("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}$');
86
- ALTER TABLE "people" ADD CONSTRAINT "people_user_id_format" CHECK ("user_id" ~ '^user_[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$');
87
-
88
- -- The stored address is already normalized: printable ASCII only (no
89
- -- whitespace, no control or invisible character), exactly one @ with a
90
- -- non-empty side each, lower case. findOrCreatePerson's
91
- -- isStorablePersonEmail applies the same rule before any write (D3).
92
- ALTER TABLE "people" ADD CONSTRAINT "people_email_normalized"
93
- CHECK ("email" = lower("email" COLLATE "C") AND "email" ~ '^[!-?A-~]+@[!-?A-~]+$');
94
-
95
- -- A provider and its customer id are written together or not at all — the
96
- -- same provider-agnostic pair User and Organization carry.
97
- ALTER TABLE "people" ADD CONSTRAINT "people_billing_pair"
98
- CHECK (("billing_provider" IS NULL) = ("billing_customer_id" IS NULL));
99
-
100
- -- The two new reference columns carry the person_ format CHECK, added NOT
101
- -- VALID and then validated: the file runs as one transaction, so the ALTER
102
- -- TABLE's lock is still held, and the scan is of an all-NULL column.
103
- ALTER TABLE "leads" ADD CONSTRAINT "leads_person_id_format" CHECK ("person_id" ~ '^person_[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$') NOT VALID;
104
- ALTER TABLE "leads" VALIDATE CONSTRAINT "leads_person_id_format";
105
- ALTER TABLE "appointments" ADD CONSTRAINT "appointments_person_id_format" CHECK ("person_id" ~ '^person_[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$') NOT VALID;
106
- ALTER TABLE "appointments" VALIDATE CONSTRAINT "appointments_person_id_format";