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,49 +0,0 @@
1
- -- The verified owner link on `project_listings` (#5295).
2
- --
3
- -- A listing carried `founder_email` and `lead_id` and no user link, so there
4
- -- was no query for "the listings belonging to this signed-in person". The only
5
- -- join available was a session's email against `founder_email` — and
6
- -- `founder_email` is an UNVERIFIED string typed into an anonymous form, so that
7
- -- join hands a stranger someone else's submission the first time two people
8
- -- type the same address. These two columns are the ownership claim instead.
9
- --
10
- -- Plain scalars, no foreign key into `users`: ADR 0009 invariant #1 forbids a
11
- -- relation across the namespace boundary, and `leads.promoted_user_id` /
12
- -- `promoted_at` (20260714000000_add_lead_promotion_fields) are the same shape
13
- -- for the same reason. The join is stable-id matching in the service layer.
14
- --
15
- -- `apps/api/src/services/listing-promotion.ts` is the sole writer, and it sets
16
- -- the pair only when all three of these hold:
17
- -- 1. the reconciling user's OWN email is verified (`users.email_verified`) —
18
- -- never a claimed or session-asserted address;
19
- -- 2. that verified address matches the row's `founder_email`;
20
- -- 3. the row's `site_id` is one of that user's own tenant workspaces.
21
- -- Any one failing writes nothing.
22
- --
23
- -- NO BACKFILL, deliberately and permanently. Every existing row predates
24
- -- verification, so deriving `owner_user_id` from `founder_email` here would
25
- -- assert exactly the link nobody proved — the bug the column exists to remove.
26
- -- Existing rows stay null, and a listing submitted by someone who never signs
27
- -- in stays null for the life of the row: that is a legitimate resting state,
28
- -- not a backlog to clean up.
29
- --
30
- -- The index backs the self-scoped read's whole WHERE clause
31
- -- (`GET /v1/project-listings/me` — `owner_user_id = $1`, and nothing else: the
32
- -- owner link IS the scope, so no site term joins it). Single-column by design —
33
- -- the promotion match (`founder_email` + `site_id` + a null owner) is already
34
- -- served by the existing (site_id, founder_email) index.
35
- --
36
- -- Forward-additive only: both columns are nullable with no default, so every
37
- -- existing read and write is unaffected.
38
- --
39
- -- Rollback:
40
- -- DROP INDEX "project_listings_owner_user_id_idx";
41
- -- ALTER TABLE "project_listings" DROP COLUMN "owner_linked_at";
42
- -- ALTER TABLE "project_listings" DROP COLUMN "owner_user_id";
43
-
44
- -- AlterTable
45
- ALTER TABLE "project_listings" ADD COLUMN "owner_user_id" TEXT,
46
- ADD COLUMN "owner_linked_at" TIMESTAMP(3);
47
-
48
- -- CreateIndex
49
- CREATE INDEX "project_listings_owner_user_id_idx" ON "project_listings"("owner_user_id");
@@ -1,123 +0,0 @@
1
- -- The founder's structured identity and PROVEN email address on
2
- -- `project_listings` (#5407).
3
- --
4
- -- Step one of the application collected ONE `founder_name` line and an email.
5
- -- samhenry spec 316 D1 asks for first name, last name, email and phone, with
6
- -- the two name parts stored separately, and 316 D6b asks that an application
7
- -- whose emailed resume link was opened be marked verified so the operator can
8
- -- filter on it at review.
9
- --
10
- -- FIVE NULLABLE COLUMNS, NO BACKFILL, NO CHANGE TO ANY EXISTING ONE.
11
- --
12
- -- `founder_first_name` / `founder_last_name` sit BESIDE `founder_name`, not
13
- -- instead of it — the #5279 precedent that put six address parts beside the
14
- -- single-line `address`. `founder_name` stays NOT NULL and stays the DISPLAY
15
- -- string every existing reader already reads (the submit-time slug fallback,
16
- -- the approve/reject email's greeting, the Slack review card's Founder row,
17
- -- the build issue, the `routeLead` identity); where the parts are written the
18
- -- server COMPOSES it from them, and where they are not it is the line the
19
- -- founder typed, verbatim.
20
- --
21
- -- Composition runs ONE WAY ONLY, and that is why nothing here backfills.
22
- -- "First" + "Last" composes into a display line deterministically; a display
23
- -- line does not decompose into parts. Splitting on the last space mangles
24
- -- "van der Berg", "Maria del Carmen" and every mononym, and a wrong split is
25
- -- silent — it would put an invented surname on the row the approve email
26
- -- greets and the operator reviews, with nothing to mark it as invented. A
27
- -- null part is honest; a guessed one is not. Every existing row therefore
28
- -- keeps `founder_name` byte-for-byte and keeps both parts NULL for the life
29
- -- of the row.
30
- --
31
- -- `founder_phone` is the contact detail spec 316 D1 adds. Nullable at rest
32
- -- for the #5036 D1 reason — every field the submit payload requires must be
33
- -- storable half-filled — and nullable permanently besides: a row written
34
- -- before #5407 has none, and a site may declare the question optional through
35
- -- its own listing config. It NEVER rides the public read; the public row
36
- -- shape omits it beside `founder_email`.
37
- --
38
- -- `email_verify_nonce_hash` and `email_verified_at` are the verification pair,
39
- -- and the first is what makes the second mean what it says.
40
- --
41
- -- The obvious design is to stamp verification when the emailed resume link is
42
- -- opened, keyed on the resume token that link carries. That design does not
43
- -- work, and the reason is worth stating here because the column name does not
44
- -- carry it: `start` returns the resume token to WHOEVER POSTED THE FORM, in
45
- -- its own 201 body. The emailed link is a second copy of a credential the
46
- -- applicant already holds — so two HTTP calls (open a draft under a
47
- -- stranger's address, take the token out of the response, present it back)
48
- -- would forge the stamp with no mailbox involved. Caught by this PR's
49
- -- security review before it shipped.
50
- --
51
- -- So verification requires a SECOND credential the applicant never receives
52
- -- any other way. `email_verify_nonce_hash` holds the sha-256 digest of a
53
- -- 256-bit nonce minted at `start`, handed to nothing except the resume-email
54
- -- builder (apps/api/src/services/project-listing-resume-email.ts), and
55
- -- present in no response body and no log line. It reaches exactly one place:
56
- -- the `?verify=` parameter of the link inside the email. Holding it means
57
- -- having read mail sent to `founder_email`, which is what the stamp claims.
58
- --
59
- -- `email_verified_at` is therefore genuine evidence of address control, and
60
- -- is still WRITE-ONCE: the verify call sets it only where it is still NULL,
61
- -- by compare-and-swap, so a founder who opens the link five times is stamped
62
- -- with the first opening and two concurrent openings produce one stamp
63
- -- between them.
64
- --
65
- -- WHAT IT STILL DOES NOT SAY is who the founder is. `owner_user_id`
66
- -- (20260912120000_listing_owner_link) is the identity claim and needs a
67
- -- signed-in user whose own address the auth system verified. A row can carry
68
- -- either, both, or neither.
69
- --
70
- -- Neither is a backfill target. Stamping an existing row would assert exactly
71
- -- the event nobody recorded. NULL means "not verified", never "verification
72
- -- failed" — and it is also what a site that has not switched the resume email
73
- -- on will read forever, because the nonce is minted there and simply never
74
- -- delivered. That is the correct outcome, not a gap.
75
- --
76
- -- `email_verify_nonce_hash` is UNIQUE, mirroring `resume_token_hash`: two
77
- -- rows can never share a nonce, and the digest lookup is indexed. It is
78
- -- cleared at `submit` beside the resume-token digest, so a credential that
79
- -- leaks after the draft stops being a draft is inert twice over. It has NO
80
- -- EXPIRY otherwise, by design and for the reason the service records: the
81
- -- same message carries the resume token, so a TTL on the nonce alone would
82
- -- bound nothing.
83
- --
84
- -- OPERATIONAL NOTE on the index. `CREATE UNIQUE INDEX` below is not
85
- -- `CONCURRENTLY`, so it takes a SHARE lock and blocks writes to
86
- -- `project_listings` while it builds. Every existing row is NULL there and
87
- -- Postgres treats NULLs as distinct in a unique index (no NULLS NOT
88
- -- DISTINCT), so it cannot fail on existing data and builds fast — and the
89
- -- same property is why `submit` setting many rows back to NULL never
90
- -- collides. Stated so whoever runs this against a large table knows it is
91
- -- write-blocking DDL; it matches the `resume_token_hash` precedent.
92
- --
93
- -- Distinct from `owner_user_id` (20260912120000_listing_owner_link), which
94
- -- needs a SIGNED-IN user whose own address the auth system verified. This
95
- -- column needs no account at all: it records that a capability sent to
96
- -- `founder_email` came back. A row can carry either, both, or neither.
97
- --
98
- -- NO INDEX on the other four. The verify write is keyed by the row's primary
99
- -- key plus two digests, both already UNIQUE, and the operator filters
100
- -- verified applications inside a site's already-indexed page of listings
101
- -- (`project_listings_site_id_status_idx`) rather than by scanning on
102
- -- `email_verified_at`.
103
- --
104
- -- Forward-additive only: all five columns are nullable with no default, so
105
- -- every existing read and write is unaffected.
106
- --
107
- -- Rollback:
108
- -- DROP INDEX "project_listings_email_verify_nonce_hash_key";
109
- -- ALTER TABLE "project_listings" DROP COLUMN "email_verified_at";
110
- -- ALTER TABLE "project_listings" DROP COLUMN "email_verify_nonce_hash";
111
- -- ALTER TABLE "project_listings" DROP COLUMN "founder_phone";
112
- -- ALTER TABLE "project_listings" DROP COLUMN "founder_last_name";
113
- -- ALTER TABLE "project_listings" DROP COLUMN "founder_first_name";
114
-
115
- -- AlterTable
116
- ALTER TABLE "project_listings" ADD COLUMN "founder_first_name" TEXT,
117
- ADD COLUMN "founder_last_name" TEXT,
118
- ADD COLUMN "founder_phone" TEXT,
119
- ADD COLUMN "email_verify_nonce_hash" TEXT,
120
- ADD COLUMN "email_verified_at" TIMESTAMP(3);
121
-
122
- -- CreateIndex
123
- CREATE UNIQUE INDEX "project_listings_email_verify_nonce_hash_key" ON "project_listings"("email_verify_nonce_hash");
@@ -1,15 +0,0 @@
1
- -- The founder's "how are you solving it?" answer on `project_listings` (#5096).
2
- --
3
- -- `problem` (step five) has had a column since the surface shipped; its
4
- -- narrative other half has not, so samhenry PR #324's step six had nowhere to
5
- -- write.
6
- --
7
- -- ONE NULLABLE COLUMN, NO DEFAULT, NO BACKFILL, NO CHANGE TO ANY EXISTING ONE.
8
- -- Additive and opt-in: the field is absent from the platform's default
9
- -- `collectedFields` mask (#5096 DD1), so no existing site can have it written
10
- -- until that site names it. Every row written before this migration keeps a
11
- -- NULL here, which the row schema already allows for every application field
12
- -- (#5036 D1 — a half-filled draft is a legitimate row).
13
- --
14
- -- Rollback: ALTER TABLE "project_listings" DROP COLUMN "solution";
15
- ALTER TABLE "project_listings" ADD COLUMN "solution" TEXT;
@@ -1,158 +0,0 @@
1
- -- #5800 — the Artifact content store: roadmap D1 (generalize `Artifact`) and
2
- -- D7 (`Asset`, workspace-scoped).
3
- --
4
- -- D1's one sentence: THE SESSION BECOMES PROVENANCE, THE WORKSPACE OWNS THE
5
- -- ARTIFACT. Today `artifacts.session_id` is NOT NULL behind an ON DELETE
6
- -- CASCADE, so deleting a conversation deletes the pages it produced. After this
7
- -- migration the column is nullable behind ON DELETE SET NULL: the session is
8
- -- where the artifact came from, not what keeps it alive.
9
- --
10
- -- The relaxation is bracketed by ZERO-ROW ASSERTIONS. It applies to an empty
11
- -- database and to a populated one, and each assertion names a specific way the
12
- -- relaxation could have lost data. A failed assertion aborts the transaction
13
- -- with a message that says which rows to look at — the migration never proceeds
14
- -- on a silent surprise, and it never backfills its way past one.
15
- --
16
- -- The rest is additive: four nullable-or-defaulted columns, two indexes, and a
17
- -- new `assets` table. `content_type` is BACKFILLED from the legacy `type`
18
- -- column rather than replacing it, because
19
- -- apps/api/src/routes/workspaces/sessions.ts (a hard-floor surface) reads
20
- -- `type` and must keep working unchanged; the two agree row-for-row when this
21
- -- migration commits, and retiring `type` belongs to the card that moves that
22
- -- route.
23
- --
24
- -- Rollback: drop the two indexes and the four columns, drop "assets", restore
25
- -- the FK as NOT NULL + ON DELETE CASCADE. That restore is only safe while no
26
- -- artifact has yet outlived its session.
27
-
28
- -- ── PRE-ASSERTIONS (zero rows, or this migration does not run) ──────────────
29
- DO $$
30
- DECLARE
31
- already_null bigint;
32
- orphaned bigint;
33
- BEGIN
34
- -- "session_id" is NOT NULL today. A non-zero count here means the column is
35
- -- not the shape this migration was written against — stop rather than guess.
36
- SELECT count(*) INTO already_null FROM "artifacts" WHERE "session_id" IS NULL;
37
- IF already_null <> 0 THEN
38
- RAISE EXCEPTION
39
- '#5800 pre-assertion: % artifact row(s) already carry a NULL session_id before the FK was relaxed; the column was expected NOT NULL',
40
- already_null;
41
- END IF;
42
-
43
- -- The outgoing FK is what guarantees this is zero. Proving it BEFORE the
44
- -- swap is what lets the post-assertion below attribute any orphan to the
45
- -- swap itself.
46
- SELECT count(*) INTO orphaned
47
- FROM "artifacts" a
48
- LEFT JOIN "agent_sessions" s ON s."id" = a."session_id"
49
- WHERE s."id" IS NULL;
50
- IF orphaned <> 0 THEN
51
- RAISE EXCEPTION
52
- '#5800 pre-assertion: % artifact row(s) point at an agent_sessions row that does not exist',
53
- orphaned;
54
- END IF;
55
- END $$;
56
-
57
- -- The census the post-assertion compares against. ON COMMIT DROP: `prisma
58
- -- migrate` runs each migration in one transaction, so this disappears with it.
59
- CREATE TEMP TABLE "_5800_artifact_census" ON COMMIT DROP AS
60
- SELECT count(*) AS n FROM "artifacts";
61
-
62
- -- ── The FK relaxation (D1) ─────────────────────────────────────────────────
63
- -- DropForeignKey
64
- ALTER TABLE "artifacts" DROP CONSTRAINT "artifacts_session_id_fkey";
65
-
66
- -- AlterTable
67
- ALTER TABLE "artifacts" ADD COLUMN "content_type" TEXT NOT NULL DEFAULT 'text/document',
68
- ADD COLUMN "locale" TEXT NOT NULL DEFAULT 'en',
69
- ADD COLUMN "published_version_id" TEXT,
70
- ADD COLUMN "slug" TEXT,
71
- ALTER COLUMN "session_id" DROP NOT NULL;
72
-
73
- -- AddForeignKey
74
- ALTER TABLE "artifacts" ADD CONSTRAINT "artifacts_session_id_fkey" FOREIGN KEY ("session_id") REFERENCES "agent_sessions"("id") ON DELETE SET NULL ON UPDATE CASCADE;
75
-
76
- -- Backfill: the new discriminator starts life agreeing with the legacy one, so
77
- -- a pre-existing chat artifact reads identically through either column.
78
- UPDATE "artifacts" SET "content_type" = "type";
79
-
80
- -- ── POST-ASSERTIONS (zero rows lost, zero rows nulled, zero drift) ─────────
81
- DO $$
82
- DECLARE
83
- before_n bigint;
84
- after_n bigint;
85
- nulled bigint;
86
- drift bigint;
87
- BEGIN
88
- SELECT n INTO before_n FROM "_5800_artifact_census";
89
- SELECT count(*) INTO after_n FROM "artifacts";
90
- IF before_n <> after_n THEN
91
- RAISE EXCEPTION
92
- '#5800 post-assertion: artifact count changed across the FK relaxation (% -> %)',
93
- before_n, after_n;
94
- END IF;
95
-
96
- -- Relaxing the constraint must not itself null anyone's provenance. Rows
97
- -- become NULL later, one at a time, as sessions are deleted.
98
- SELECT count(*) INTO nulled FROM "artifacts" WHERE "session_id" IS NULL;
99
- IF nulled <> 0 THEN
100
- RAISE EXCEPTION
101
- '#5800 post-assertion: relaxing the FK left % artifact row(s) with a NULL session_id',
102
- nulled;
103
- END IF;
104
-
105
- SELECT count(*) INTO drift
106
- FROM "artifacts" WHERE "content_type" IS DISTINCT FROM "type";
107
- IF drift <> 0 THEN
108
- RAISE EXCEPTION
109
- '#5800 post-assertion: % artifact row(s) disagree between content_type and the legacy type column',
110
- drift;
111
- END IF;
112
- END $$;
113
-
114
- -- ── Content-store identity + the list index (D1) ───────────────────────────
115
- -- CreateIndex
116
- CREATE INDEX "artifacts_workspace_id_content_type_updated_at_idx" ON "artifacts"("workspace_id", "content_type", "updated_at");
117
-
118
- -- CreateIndex
119
- -- `slug` is NULL until publish and NULLs never collide in a Postgres unique
120
- -- index, so a workspace may hold any number of unpublished drafts while
121
- -- exactly one artifact may claim a given published path.
122
- CREATE UNIQUE INDEX "artifacts_workspace_id_content_type_locale_slug_key" ON "artifacts"("workspace_id", "content_type", "locale", "slug");
123
-
124
- -- ── Asset (D7) ─────────────────────────────────────────────────────────────
125
- -- Shaped after `deliverable_assets` (20260811050000_add_deliverable_models):
126
- -- the bytes live in the row. Same CreateTable + CreateIndex + ADR-0031 rule-3
127
- -- id-format completion in ONE migration as
128
- -- 20260911180000_consent_grants, since the table is new and needs no retrofit.
129
- -- CreateTable
130
- CREATE TABLE "assets" (
131
- "id" TEXT NOT NULL DEFAULT ('asset_'::text || (uuidv7())::text),
132
- "workspace_id" TEXT NOT NULL,
133
- "key" TEXT NOT NULL,
134
- "filename" TEXT NOT NULL,
135
- "content_type" TEXT NOT NULL,
136
- "bytes" BYTEA NOT NULL,
137
- "size" INTEGER NOT NULL,
138
- "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
139
-
140
- CONSTRAINT "assets_pkey" PRIMARY KEY ("id")
141
- );
142
-
143
- -- CreateIndex
144
- CREATE INDEX "assets_workspace_id_idx" ON "assets"("workspace_id");
145
-
146
- -- CreateIndex
147
- CREATE UNIQUE INDEX "assets_workspace_id_key_key" ON "assets"("workspace_id", "key");
148
-
149
- -- ADR-0031 rule 3 — assets: asset_ (registered in
150
- -- packages/ids/src/registry.ts ENTITY_PREFIX.asset; this migration's path is
151
- -- added to migration-sync.test.ts's PK_CHECK_MIGRATIONS). workspace_id is a
152
- -- relation-free scope column (ADR-0009 invariant 1) and gets the same CHECK
153
- -- every other content-namespace table's does.
154
- ALTER TABLE "assets" ALTER COLUMN "id" TYPE text COLLATE "C";
155
- ALTER TABLE "assets" ALTER COLUMN "id" SET DEFAULT ('asset_'::text || (uuidv7())::text);
156
- ALTER TABLE "assets" ADD CONSTRAINT "assets_id_format" CHECK ("id" ~ '^asset_[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$');
157
- ALTER TABLE "assets" ALTER COLUMN "workspace_id" TYPE text COLLATE "C";
158
- ALTER TABLE "assets" ADD CONSTRAINT "assets_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,40 +0,0 @@
1
- -- #5970 — request-and-confirm: the callback row gains a confirm/pay lifecycle
2
- -- (D-67 / SUB-100, spec docs/specs/5970-request-and-confirm-spec.md § 4.3).
3
- --
4
- -- Eleven nullable columns and two indexes on "callbacks". Every column is
5
- -- NULL-able with no default, so on Postgres this ALTER TABLE is metadata-only:
6
- -- no table rewrite, no backfill, no lock held for the length of a scan.
7
- --
8
- -- Nothing here relaxes a constraint and nothing here backfills, so — unlike
9
- -- 20260916120000_artifact_content_store — this migration carries no zero-row
10
- -- pre-assertion block: there is no way for it to lose a row.
11
- --
12
- -- The two indexes are the webhook stamp's `where` (spec § D8). Without them
13
- -- every checkout.session.completed carrying a payment_link would sequential-
14
- -- scan "callbacks" on a hot path. "stripe_checkout_session_id" carries no
15
- -- index deliberately: nothing queries by it — it is a support-lookup column.
16
- --
17
- -- Rollback: drop the two indexes and the eleven columns. Safe unconditionally
18
- -- while nothing but #5970's own code reads them.
19
-
20
- ALTER TABLE "callbacks"
21
- ADD COLUMN "confirm_token_hash" TEXT,
22
- ADD COLUMN "confirm_token_expires_at" TIMESTAMP(3),
23
- ADD COLUMN "confirmed_at" TIMESTAMP(3),
24
- ADD COLUMN "confirmed_time" TEXT,
25
- ADD COLUMN "buyer_email" TEXT,
26
- ADD COLUMN "amount_minor" INTEGER,
27
- ADD COLUMN "currency" TEXT,
28
- ADD COLUMN "stripe_payment_link_id" TEXT,
29
- ADD COLUMN "stripe_checkout_session_id" TEXT,
30
- ADD COLUMN "stripe_invoice_id" TEXT,
31
- ADD COLUMN "paid_at" TIMESTAMP(3);
32
-
33
- -- The digest is unique: two rows sharing one is a mint bug, and the constraint
34
- -- is what turns that bug into a write failure instead of a silent cross-row
35
- -- credential.
36
- CREATE UNIQUE INDEX "callbacks_confirm_token_hash_key" ON "callbacks"("confirm_token_hash");
37
-
38
- CREATE INDEX "callbacks_stripe_payment_link_id_idx" ON "callbacks"("stripe_payment_link_id");
39
-
40
- CREATE INDEX "callbacks_stripe_invoice_id_idx" ON "callbacks"("stripe_invoice_id");
@@ -1,67 +0,0 @@
1
- -- #6085 — the Appointment model: a Cal.com booking normalized from the new
2
- -- webhook receiver (brief H7, spec docs/specs/6085-appointments-from-cal-com-webhooks-spec.md § 4.3).
3
- --
4
- -- One new table, three indexes, in the house style of
5
- -- 20260903010000_add_playbook_instance (CreateTable + CreateIndex immediately
6
- -- followed by the ADR-0031 rule-3 id-format completion, in ONE migration
7
- -- since the table is new and needs no retrofit).
8
- --
9
- -- The unique index over (site_id, provider, provider_booking_uid) is the
10
- -- LOAD-BEARING line of this migration: it is the spec's own idempotency key
11
- -- (§ D4) — a table without it makes "exactly one Appointment row per booking
12
- -- uid" unenforceable, and § D7(a)'s guarded-write shape races on precisely
13
- -- this index.
14
- --
15
- -- No backfill, no constraint relaxed, no existing table touched, so this
16
- -- migration carries no zero-row pre-assertion block — there is no way for it
17
- -- to lose a row.
18
- --
19
- -- Rollback: DROP TABLE "appointments". Safe unconditionally while nothing but
20
- -- #6085's own code reads it.
21
-
22
- -- CreateTable
23
- CREATE TABLE "appointments" (
24
- "id" TEXT NOT NULL DEFAULT ('appt_'::text || (uuidv7())::text),
25
- "site_id" VARCHAR(200) NOT NULL,
26
- "provider_booking_uid" VARCHAR(200) NOT NULL,
27
- "provider" VARCHAR(32) NOT NULL DEFAULT 'cal',
28
- "start_time" TIMESTAMP(3) NOT NULL,
29
- "end_time" TIMESTAMP(3) NOT NULL,
30
- "title" VARCHAR(300),
31
- "attendee_name" VARCHAR(120) NOT NULL,
32
- "attendee_email" VARCHAR(254) NOT NULL,
33
- "attendee_time_zone" VARCHAR(64),
34
- "status" VARCHAR(32) NOT NULL,
35
- "paid" BOOLEAN NOT NULL DEFAULT false,
36
- "payment_initiated_at" TIMESTAMP(3),
37
- "no_show" BOOLEAN NOT NULL DEFAULT false,
38
- "cancelled_at" TIMESTAMP(3),
39
- "lifecycle_event_at" TIMESTAMP(3) NOT NULL,
40
- "payment_event_at" TIMESTAMP(3),
41
- "no_show_event_at" TIMESTAMP(3),
42
- "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
43
- "updated_at" TIMESTAMP(3) NOT NULL,
44
-
45
- CONSTRAINT "appointments_pkey" PRIMARY KEY ("id")
46
- );
47
-
48
- -- CreateIndex
49
- -- The idempotency key (§ D4) — see the file header. `provider` is included
50
- -- per § 9 SEC-10 so a second scheduling provider's uid space cannot collide
51
- -- with this one's (#4288).
52
- CREATE UNIQUE INDEX "appointments_site_id_provider_provider_booking_uid_key" ON "appointments"("site_id", "provider", "provider_booking_uid");
53
-
54
- -- CreateIndex
55
- -- The read's `where` + `order by` (§ D6). Without it every appointments page
56
- -- load sequential-scans "appointments".
57
- CREATE INDEX "appointments_site_id_start_time_idx" ON "appointments"("site_id", "start_time");
58
-
59
- -- CreateIndex
60
- CREATE INDEX "appointments_created_at_idx" ON "appointments"("created_at");
61
-
62
- -- ADR-0031 rule 3 — appointments: appt_ (registered in
63
- -- packages/ids/src/registry.ts ENTITY_PREFIX.appointment; this migration's
64
- -- path is added to migration-sync.test.ts's PK_CHECK_MIGRATIONS).
65
- ALTER TABLE "appointments" ALTER COLUMN "id" TYPE text COLLATE "C";
66
- ALTER TABLE "appointments" ALTER COLUMN "id" SET DEFAULT ('appt_'::text || (uuidv7())::text);
67
- ALTER TABLE "appointments" ADD CONSTRAINT "appointments_id_format" CHECK ("id" ~ '^appt_[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$');
@@ -1,70 +0,0 @@
1
- -- #6092 — S4's data tier: an asset carries title, description and tags.
2
- --
3
- -- Today `assets` holds bytes and a filename and nothing the owner wrote
4
- -- (decisions.html D10: "an asset has a filename and dimensions only"). The
5
- -- lightbox edits three things in place — a title, a description and a set of
6
- -- tags — so the table gains exactly those three columns.
7
- --
8
- -- STRICTLY ADDITIVE. Nothing is dropped, renamed, relaxed or backfilled. The
9
- -- `(workspace_id, key)` identity, the `assets_id_format` and
10
- -- `assets_workspace_id_format` CHECKs and the `asset_`+UUIDv7 default are all
11
- -- untouched, so a pre-existing row stays valid and an INSERT written before
12
- -- this migration keeps working unchanged.
13
- --
14
- -- `tags` is TEXT[] with an empty-array default rather than a nullable column:
15
- -- an untagged asset is an empty set, not an unknown one, and a NULL would give
16
- -- two spellings of the same state. It carries tag SLUGS, never the human
17
- -- labels, and it is deliberately UNCONSTRAINED — two vocabularies ride it (the
18
- -- twelve asset tags and D9's four document tags, since a document is a row in
19
- -- this same store), and the "fixed set" of D10 is a surface affordance. A tag
20
- -- whose slug a surface cannot resolve is that surface's problem to render, not
21
- -- a reason to reject an upload.
22
- --
23
- -- `title` and `description` are nullable with no default: NULL means the owner
24
- -- has not written one, which is distinct from an empty string meaning they
25
- -- cleared it. `title` is NOT backfilled from `filename` — they are different
26
- -- facts and the lightbox shows both.
27
- --
28
- -- Rollback: ALTER TABLE "assets" DROP COLUMN "tags", DROP COLUMN
29
- -- "description", DROP COLUMN "title". Safe unconditionally; the columns carry
30
- -- no constraint and nothing references them.
31
-
32
- -- The census the post-assertion compares against. ON COMMIT DROP: `prisma
33
- -- migrate` runs each migration in one transaction, so this disappears with it.
34
- CREATE TEMP TABLE "_6092_asset_census" ON COMMIT DROP AS
35
- SELECT count(*) AS n FROM "assets";
36
-
37
- -- AlterTable
38
- ALTER TABLE "assets" ADD COLUMN "title" TEXT,
39
- ADD COLUMN "description" TEXT,
40
- ADD COLUMN "tags" TEXT[] DEFAULT ARRAY[]::TEXT[];
41
-
42
- -- ── POST-ASSERTIONS (no row lost; every pre-existing row reads back empty) ──
43
- -- This is AC-1's second half, asserted against the rows the target database
44
- -- actually holds rather than against a fixture's.
45
- DO $$
46
- DECLARE
47
- before_n bigint;
48
- after_n bigint;
49
- written bigint;
50
- BEGIN
51
- SELECT n INTO before_n FROM "_6092_asset_census";
52
- SELECT count(*) INTO after_n FROM "assets";
53
- IF before_n <> after_n THEN
54
- RAISE EXCEPTION
55
- '#6092 post-assertion: asset count changed across a purely additive migration (% -> %)',
56
- before_n, after_n;
57
- END IF;
58
-
59
- -- Adding the columns must not itself author metadata for anyone. Rows gain a
60
- -- title, a description or a tag later, one at a time, from the lightbox.
61
- SELECT count(*) INTO written FROM "assets"
62
- WHERE "title" IS NOT NULL
63
- OR "description" IS NOT NULL
64
- OR "tags" IS DISTINCT FROM ARRAY[]::TEXT[];
65
- IF written <> 0 THEN
66
- RAISE EXCEPTION
67
- '#6092 post-assertion: % pre-existing asset row(s) came out of the migration with metadata already set',
68
- written;
69
- END IF;
70
- END $$;