create-ailk 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (533) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +39 -0
  3. package/dist/cli.d.ts +2 -0
  4. package/dist/cli.js +80 -0
  5. package/dist/copy.d.ts +8 -0
  6. package/dist/copy.js +109 -0
  7. package/dist/index.d.ts +10 -0
  8. package/dist/index.js +10 -0
  9. package/dist/lib/pro-callout.d.ts +12 -0
  10. package/dist/lib/pro-callout.js +20 -0
  11. package/dist/parse-args.d.ts +13 -0
  12. package/dist/parse-args.js +81 -0
  13. package/dist/programmatic.d.ts +49 -0
  14. package/dist/programmatic.js +89 -0
  15. package/dist/substitute.d.ts +31 -0
  16. package/dist/substitute.js +45 -0
  17. package/dist/validate.d.ts +8 -0
  18. package/dist/validate.js +70 -0
  19. package/package.json +47 -0
  20. package/templates/.claude/.gitkeep +0 -0
  21. package/templates/.claude/agents/web.md +80 -0
  22. package/templates/.claude/rules/architecture.md +62 -0
  23. package/templates/.claude/rules/preserve-existing-style.md +51 -0
  24. package/templates/.claude/skills/README.md +43 -0
  25. package/templates/.claude/skills/add-schema/SKILL.md +270 -0
  26. package/templates/.claude/skills/add-schema/references/conflict-handling.md +200 -0
  27. package/templates/.claude/skills/add-schema/references/file-finding.md +123 -0
  28. package/templates/.claude/skills/add-schema/references/schema-types.md +131 -0
  29. package/templates/.claude/skills/audit-site/SKILL.md +213 -0
  30. package/templates/.claude/skills/audit-site/references/common-errors.md +113 -0
  31. package/templates/.claude/skills/audit-site/references/findings-glossary.md +138 -0
  32. package/templates/.claude/skills/audit-site/references/severity-levels.md +114 -0
  33. package/templates/.claude/skills/provision-config/SKILL.md +243 -0
  34. package/templates/.claude/skills/provision-config/references/env-vars-template.md +184 -0
  35. package/templates/.claude/skills/provision-config/references/runbook-template.md +248 -0
  36. package/templates/.claude/skills/provision-config/references/vercel-json-template.md +98 -0
  37. package/templates/.claude/skills/scaffold-auth/SKILL.md +261 -0
  38. package/templates/.claude/skills/scaffold-auth/references/env-vars.md +91 -0
  39. package/templates/.claude/skills/scaffold-auth/references/oauth-app-setup.md +171 -0
  40. package/templates/.claude/skills/scaffold-commerce/SKILL.md +310 -0
  41. package/templates/.claude/skills/scaffold-commerce/references/lookup-keys-template.md +71 -0
  42. package/templates/.claude/skills/scaffold-commerce/references/marketplace-brand-pages.md +83 -0
  43. package/templates/.claude/skills/scaffold-commerce/templates/marketplace-cta-route.tsx.tmpl +72 -0
  44. package/templates/.claude/skills/scaffold-page/SKILL.md +243 -0
  45. package/templates/.claude/skills/scaffold-page/references/page-types.md +169 -0
  46. package/templates/.claude/skills/scaffold-page/templates/content.mdx.tmpl +28 -0
  47. package/templates/.claude/skills/scaffold-page/templates/route.tsx.tmpl +28 -0
  48. package/templates/.claude/skills/suggest-site-pages/SKILL.md +242 -0
  49. package/templates/.claude/skills/suggest-site-pages/references/categories.md +287 -0
  50. package/templates/.env.example +205 -0
  51. package/templates/.gitkeep +2 -0
  52. package/templates/CLAUDE.md +142 -0
  53. package/templates/CONVENTIONS.md +222 -0
  54. package/templates/README.md +110 -0
  55. package/templates/apps/api/.env.example +40 -0
  56. package/templates/apps/api/CLAUDE.md +63 -0
  57. package/templates/apps/api/api/index.ts +144 -0
  58. package/templates/apps/api/jest.config.cjs +74 -0
  59. package/templates/apps/api/package.json +54 -0
  60. package/templates/apps/api/src/__tests__/factories/content-fixture.ts +138 -0
  61. package/templates/apps/api/src/__tests__/factories/index.ts +70 -0
  62. package/templates/apps/api/src/__tests__/factories/lead-fixture.ts +82 -0
  63. package/templates/apps/api/src/__tests__/index.test.ts +118 -0
  64. package/templates/apps/api/src/__tests__/server.test.ts +207 -0
  65. package/templates/apps/api/src/__tests__/services/enrichment-shim.test.ts +126 -0
  66. package/templates/apps/api/src/__tests__/setup.ts +24 -0
  67. package/templates/apps/api/src/cli.ts +30 -0
  68. package/templates/apps/api/src/config/__tests__/index.test.ts +97 -0
  69. package/templates/apps/api/src/config/index.ts +56 -0
  70. package/templates/apps/api/src/index.ts +32 -0
  71. package/templates/apps/api/src/lib/__mocks__/prisma-client.js +15 -0
  72. package/templates/apps/api/src/lib/__mocks__/prisma.ts +45 -0
  73. package/templates/apps/api/src/lib/__tests__/content-adapter.test.ts +178 -0
  74. package/templates/apps/api/src/lib/__tests__/error-serializer.test.ts +100 -0
  75. package/templates/apps/api/src/lib/__tests__/errors.test.ts +94 -0
  76. package/templates/apps/api/src/lib/__tests__/file-fallback.test.ts +144 -0
  77. package/templates/apps/api/src/lib/__tests__/fixtures/HomePage/home.mdx +8 -0
  78. package/templates/apps/api/src/lib/__tests__/lead-capture-store.test.ts +227 -0
  79. package/templates/apps/api/src/lib/__tests__/outbound-http.test.ts +125 -0
  80. package/templates/apps/api/src/lib/__tests__/prisma.test.ts +165 -0
  81. package/templates/apps/api/src/lib/__tests__/require-paid-tier.test.ts +129 -0
  82. package/templates/apps/api/src/lib/__tests__/stripe.test.ts +74 -0
  83. package/templates/apps/api/src/lib/content-adapter.ts +86 -0
  84. package/templates/apps/api/src/lib/error-serializer.ts +77 -0
  85. package/templates/apps/api/src/lib/errors.ts +95 -0
  86. package/templates/apps/api/src/lib/file-fallback.ts +87 -0
  87. package/templates/apps/api/src/lib/lead-capture-store.ts +110 -0
  88. package/templates/apps/api/src/lib/locales.ts +201 -0
  89. package/templates/apps/api/src/lib/outbound-http.ts +122 -0
  90. package/templates/apps/api/src/lib/prisma.ts +21 -0
  91. package/templates/apps/api/src/lib/require-paid-tier.ts +53 -0
  92. package/templates/apps/api/src/lib/stripe.ts +30 -0
  93. package/templates/apps/api/src/lib/webhook-idempotency.ts +92 -0
  94. package/templates/apps/api/src/middleware/__tests__/adversarial/bearer-token-format.test.ts +111 -0
  95. package/templates/apps/api/src/middleware/__tests__/adversarial/cookie-or-bearer-precedence.test.ts +172 -0
  96. package/templates/apps/api/src/middleware/__tests__/adversarial/csrf-bearer-skip.test.ts +119 -0
  97. package/templates/apps/api/src/middleware/__tests__/adversarial/csrf-cookie-path.test.ts +138 -0
  98. package/templates/apps/api/src/middleware/__tests__/adversarial/session-fixation.test.ts +149 -0
  99. package/templates/apps/api/src/middleware/__tests__/adversarial/session-timeout.test.ts +139 -0
  100. package/templates/apps/api/src/middleware/__tests__/auth.bearer-path.test.ts +175 -0
  101. package/templates/apps/api/src/middleware/__tests__/auth.both-present-precedence.test.ts +76 -0
  102. package/templates/apps/api/src/middleware/__tests__/auth.cookie-path.test.ts +153 -0
  103. package/templates/apps/api/src/middleware/__tests__/auth.neither-present.test.ts +72 -0
  104. package/templates/apps/api/src/middleware/__tests__/rate-limit.test.ts +292 -0
  105. package/templates/apps/api/src/middleware/auth.ts +246 -0
  106. package/templates/apps/api/src/middleware/rate-limit.ts +132 -0
  107. package/templates/apps/api/src/openapi/__tests__/openapi.test.ts +129 -0
  108. package/templates/apps/api/src/openapi/index.ts +12 -0
  109. package/templates/apps/api/src/openapi/spec.ts +408 -0
  110. package/templates/apps/api/src/routes/auth/__tests__/auth-tokens.functional.test.ts +193 -0
  111. package/templates/apps/api/src/routes/auth/__tests__/auth-user.functional.test.ts +201 -0
  112. package/templates/apps/api/src/routes/auth/__tests__/tokens.test.ts +294 -0
  113. package/templates/apps/api/src/routes/auth/__tests__/user.test.ts +486 -0
  114. package/templates/apps/api/src/routes/auth/tokens.ts +199 -0
  115. package/templates/apps/api/src/routes/auth/user.ts +244 -0
  116. package/templates/apps/api/src/routes/checkout/__tests__/sessions.test.ts +588 -0
  117. package/templates/apps/api/src/routes/checkout/index.ts +13 -0
  118. package/templates/apps/api/src/routes/checkout/sessions.ts +185 -0
  119. package/templates/apps/api/src/routes/content/__tests__/create.test.ts +239 -0
  120. package/templates/apps/api/src/routes/content/__tests__/delete.test.ts +201 -0
  121. package/templates/apps/api/src/routes/content/__tests__/get-page.test.ts +141 -0
  122. package/templates/apps/api/src/routes/content/__tests__/list-pages.test.ts +122 -0
  123. package/templates/apps/api/src/routes/content/__tests__/list-types.test.ts +44 -0
  124. package/templates/apps/api/src/routes/content/__tests__/locale.test.ts +118 -0
  125. package/templates/apps/api/src/routes/content/__tests__/rate-limit.test.ts +51 -0
  126. package/templates/apps/api/src/routes/content/__tests__/update.test.ts +252 -0
  127. package/templates/apps/api/src/routes/content/create.ts +114 -0
  128. package/templates/apps/api/src/routes/content/delete.ts +81 -0
  129. package/templates/apps/api/src/routes/content/get-page.ts +98 -0
  130. package/templates/apps/api/src/routes/content/index.ts +32 -0
  131. package/templates/apps/api/src/routes/content/list-pages.ts +83 -0
  132. package/templates/apps/api/src/routes/content/list-types.ts +19 -0
  133. package/templates/apps/api/src/routes/content/rate-limit.ts +13 -0
  134. package/templates/apps/api/src/routes/content/slug.ts +9 -0
  135. package/templates/apps/api/src/routes/content/update.ts +111 -0
  136. package/templates/apps/api/src/routes/leads/__tests__/index.test.ts +415 -0
  137. package/templates/apps/api/src/routes/leads/__tests__/track.test.ts +165 -0
  138. package/templates/apps/api/src/routes/leads/index.ts +130 -0
  139. package/templates/apps/api/src/routes/test/auth/__tests__/session.test.ts +296 -0
  140. package/templates/apps/api/src/routes/test/auth/session.ts +141 -0
  141. package/templates/apps/api/src/routes/webhooks/README.md +57 -0
  142. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-idempotency.test.ts +247 -0
  143. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-rate-limit.test.ts +198 -0
  144. package/templates/apps/api/src/routes/webhooks/__tests__/stripe.test.ts +633 -0
  145. package/templates/apps/api/src/routes/webhooks/index.ts +41 -0
  146. package/templates/apps/api/src/routes/webhooks/stripe.ts +253 -0
  147. package/templates/apps/api/src/server.ts +157 -0
  148. package/templates/apps/api/src/services/__tests__/lead-routing.test.ts +395 -0
  149. package/templates/apps/api/src/services/enrichment-shim.ts +53 -0
  150. package/templates/apps/api/src/services/lead-routing.ts +338 -0
  151. package/templates/apps/api/tsconfig.json +34 -0
  152. package/templates/apps/api/vercel.json +17 -0
  153. package/templates/apps/mcp/.env.example +52 -0
  154. package/templates/apps/mcp/CLAUDE.md +84 -0
  155. package/templates/apps/mcp/__tests__/abuse/daily-cap.test.ts +52 -0
  156. package/templates/apps/mcp/__tests__/abuse/email-validator.test.ts +46 -0
  157. package/templates/apps/mcp/__tests__/abuse/honeypot.test.ts +36 -0
  158. package/templates/apps/mcp/__tests__/abuse/user-agent-deny.test.ts +54 -0
  159. package/templates/apps/mcp/__tests__/aeo-cli-parity.test.ts +110 -0
  160. package/templates/apps/mcp/__tests__/audit-single-page.test.ts +213 -0
  161. package/templates/apps/mcp/__tests__/audit.test.ts +217 -0
  162. package/templates/apps/mcp/__tests__/catalog-drift.test.ts +52 -0
  163. package/templates/apps/mcp/__tests__/create_page.test.ts +201 -0
  164. package/templates/apps/mcp/__tests__/delete_page.test.ts +176 -0
  165. package/templates/apps/mcp/__tests__/get_business_hours.test.ts +82 -0
  166. package/templates/apps/mcp/__tests__/get_faq.test.ts +80 -0
  167. package/templates/apps/mcp/__tests__/get_locations.test.ts +65 -0
  168. package/templates/apps/mcp/__tests__/get_offerings.test.ts +90 -0
  169. package/templates/apps/mcp/__tests__/get_pricing.test.ts +80 -0
  170. package/templates/apps/mcp/__tests__/get_site_info.test.ts +81 -0
  171. package/templates/apps/mcp/__tests__/http-transport.test.ts +323 -0
  172. package/templates/apps/mcp/__tests__/lib/errors.test.ts +75 -0
  173. package/templates/apps/mcp/__tests__/lib/require-paid-tier.test.ts +75 -0
  174. package/templates/apps/mcp/__tests__/list_pages.test.ts +112 -0
  175. package/templates/apps/mcp/__tests__/locale.test.ts +135 -0
  176. package/templates/apps/mcp/__tests__/parity.test.ts +205 -0
  177. package/templates/apps/mcp/__tests__/purchase-disabled.test.ts +34 -0
  178. package/templates/apps/mcp/__tests__/read_content.test.ts +153 -0
  179. package/templates/apps/mcp/__tests__/request_callback.test.ts +163 -0
  180. package/templates/apps/mcp/__tests__/search_content.test.ts +153 -0
  181. package/templates/apps/mcp/__tests__/server.test.ts +115 -0
  182. package/templates/apps/mcp/__tests__/submit_lead.test.ts +165 -0
  183. package/templates/apps/mcp/__tests__/subscribe_newsletter.test.ts +161 -0
  184. package/templates/apps/mcp/__tests__/tools/purchase.test.ts +227 -0
  185. package/templates/apps/mcp/__tests__/tools/scaffold.test.ts +237 -0
  186. package/templates/apps/mcp/__tests__/update_page.test.ts +195 -0
  187. package/templates/apps/mcp/jest.config.cjs +82 -0
  188. package/templates/apps/mcp/package.json +37 -0
  189. package/templates/apps/mcp/src/abuse/daily-cap.ts +47 -0
  190. package/templates/apps/mcp/src/abuse/email-validator.ts +25 -0
  191. package/templates/apps/mcp/src/abuse/honeypot.ts +21 -0
  192. package/templates/apps/mcp/src/abuse/index.ts +111 -0
  193. package/templates/apps/mcp/src/abuse/user-agent-deny.ts +58 -0
  194. package/templates/apps/mcp/src/http-transport.ts +303 -0
  195. package/templates/apps/mcp/src/index.ts +67 -0
  196. package/templates/apps/mcp/src/lib/audit-single-page.ts +194 -0
  197. package/templates/apps/mcp/src/lib/errors.ts +61 -0
  198. package/templates/apps/mcp/src/lib/locales.ts +171 -0
  199. package/templates/apps/mcp/src/lib/require-paid-tier.ts +44 -0
  200. package/templates/apps/mcp/src/lib/resolve-locale.ts +30 -0
  201. package/templates/apps/mcp/src/server.ts +139 -0
  202. package/templates/apps/mcp/src/tools/audit.ts +103 -0
  203. package/templates/apps/mcp/src/tools/capture_lead.ts +52 -0
  204. package/templates/apps/mcp/src/tools/create_page.ts +95 -0
  205. package/templates/apps/mcp/src/tools/delete_page.ts +73 -0
  206. package/templates/apps/mcp/src/tools/get_business_hours.ts +66 -0
  207. package/templates/apps/mcp/src/tools/get_faq.ts +69 -0
  208. package/templates/apps/mcp/src/tools/get_locations.ts +85 -0
  209. package/templates/apps/mcp/src/tools/get_offerings.ts +66 -0
  210. package/templates/apps/mcp/src/tools/get_pricing.ts +74 -0
  211. package/templates/apps/mcp/src/tools/get_site_info.ts +84 -0
  212. package/templates/apps/mcp/src/tools/index.ts +125 -0
  213. package/templates/apps/mcp/src/tools/list_pages.ts +72 -0
  214. package/templates/apps/mcp/src/tools/purchase.ts +89 -0
  215. package/templates/apps/mcp/src/tools/read_content.ts +61 -0
  216. package/templates/apps/mcp/src/tools/request_callback.ts +51 -0
  217. package/templates/apps/mcp/src/tools/scaffold.ts +119 -0
  218. package/templates/apps/mcp/src/tools/search_content.ts +59 -0
  219. package/templates/apps/mcp/src/tools/subscribe_newsletter.ts +47 -0
  220. package/templates/apps/mcp/src/tools/update_page.ts +91 -0
  221. package/templates/apps/mcp/tsconfig.json +19 -0
  222. package/templates/apps/web/.env.example +47 -0
  223. package/templates/apps/web/CLAUDE.md +81 -0
  224. package/templates/apps/web/__tests__/auth/adversarial/cookie-attributes.test.ts +94 -0
  225. package/templates/apps/web/__tests__/auth/adversarial/oauth-state-parameter.test.ts +75 -0
  226. package/templates/apps/web/__tests__/auth/adversarial/redirect-uri-allowlist.test.ts +82 -0
  227. package/templates/apps/web/__tests__/auth/env-helpers.test.ts +168 -0
  228. package/templates/apps/web/__tests__/authority-list-routes.test.tsx +208 -0
  229. package/templates/apps/web/__tests__/better-stack.test.ts +66 -0
  230. package/templates/apps/web/__tests__/blog-dir-resolution.test.ts +87 -0
  231. package/templates/apps/web/__tests__/blog-source-populated.test.ts +130 -0
  232. package/templates/apps/web/__tests__/data-testid-coverage.test.tsx +60 -0
  233. package/templates/apps/web/__tests__/google-analytics.test.tsx +104 -0
  234. package/templates/apps/web/__tests__/i18n/middleware.test.ts +119 -0
  235. package/templates/apps/web/__tests__/i18n/routing.test.ts +114 -0
  236. package/templates/apps/web/__tests__/i18n/translations.test.ts +191 -0
  237. package/templates/apps/web/__tests__/json-ld.test.ts +98 -0
  238. package/templates/apps/web/__tests__/knowledge-events-routes.test.tsx +580 -0
  239. package/templates/apps/web/__tests__/layout-stealth.test.ts +39 -0
  240. package/templates/apps/web/__tests__/lighthouse-fixtures/improvement-image-shrink.tsx +103 -0
  241. package/templates/apps/web/__tests__/lighthouse-fixtures/override-fixture.md +114 -0
  242. package/templates/apps/web/__tests__/lighthouse-fixtures/regression-bloat.tsx +94 -0
  243. package/templates/apps/web/__tests__/page.test.tsx +230 -0
  244. package/templates/apps/web/__tests__/products-services-phase1.test.tsx +321 -0
  245. package/templates/apps/web/__tests__/projects-routes.test.tsx +392 -0
  246. package/templates/apps/web/__tests__/resources-downloads-integrations-phase2.test.tsx +475 -0
  247. package/templates/apps/web/__tests__/routes/ai-plugin-json.test.ts +53 -0
  248. package/templates/apps/web/__tests__/routes/blog-route.test.tsx +191 -0
  249. package/templates/apps/web/__tests__/routes/llms-txt.test.ts +123 -0
  250. package/templates/apps/web/__tests__/routes/robots-txt.test.ts +52 -0
  251. package/templates/apps/web/__tests__/routes/sitemap-xml.test.ts +78 -0
  252. package/templates/apps/web/__tests__/routes/well-known-mcp.test.ts +203 -0
  253. package/templates/apps/web/__tests__/section-routes.test.tsx +693 -0
  254. package/templates/apps/web/__tests__/security-headers.test.ts +201 -0
  255. package/templates/apps/web/__tests__/sentry-config.test.ts +116 -0
  256. package/templates/apps/web/__tests__/setup.ts +82 -0
  257. package/templates/apps/web/__tests__/sitemap-locales.test.ts +415 -0
  258. package/templates/apps/web/__tests__/standalone-informational-routes.test.tsx +844 -0
  259. package/templates/apps/web/app/.well-known/ai-plugin.json/route.ts +81 -0
  260. package/templates/apps/web/app/.well-known/mcp.json/build-manifest.ts +110 -0
  261. package/templates/apps/web/app/.well-known/mcp.json/route.ts +58 -0
  262. package/templates/apps/web/app/[locale]/__tests__/layout.test.tsx +120 -0
  263. package/templates/apps/web/app/[locale]/__tests__/page-renderer-migration.test.tsx +202 -0
  264. package/templates/apps/web/app/[locale]/about/page.tsx +31 -0
  265. package/templates/apps/web/app/[locale]/blog/[[...slug]]/page.tsx +173 -0
  266. package/templates/apps/web/app/[locale]/careers/[slug]/page.tsx +45 -0
  267. package/templates/apps/web/app/[locale]/careers/__tests__/page-renderer-migration.test.tsx +117 -0
  268. package/templates/apps/web/app/[locale]/careers/page.tsx +25 -0
  269. package/templates/apps/web/app/[locale]/case-studies/[slug]/page.tsx +44 -0
  270. package/templates/apps/web/app/[locale]/case-studies/__tests__/page-renderer-migration.test.tsx +113 -0
  271. package/templates/apps/web/app/[locale]/case-studies/page.tsx +25 -0
  272. package/templates/apps/web/app/[locale]/clients/__tests__/page-renderer-migration.test.tsx +63 -0
  273. package/templates/apps/web/app/[locale]/clients/page.tsx +27 -0
  274. package/templates/apps/web/app/[locale]/contact/ContactForm.tsx +130 -0
  275. package/templates/apps/web/app/[locale]/contact/__tests__/contact.actions.test.ts +152 -0
  276. package/templates/apps/web/app/[locale]/contact/__tests__/page-renderer-migration.test.tsx +92 -0
  277. package/templates/apps/web/app/[locale]/contact/contact.actions.ts +79 -0
  278. package/templates/apps/web/app/[locale]/contact/error.tsx +24 -0
  279. package/templates/apps/web/app/[locale]/contact/page.tsx +38 -0
  280. package/templates/apps/web/app/[locale]/courses/[slug]/page.tsx +34 -0
  281. package/templates/apps/web/app/[locale]/courses/__tests__/page-renderer-migration.test.tsx +119 -0
  282. package/templates/apps/web/app/[locale]/courses/page.tsx +25 -0
  283. package/templates/apps/web/app/[locale]/dev/purchase/__tests__/actions.test.ts +160 -0
  284. package/templates/apps/web/app/[locale]/dev/purchase/error.tsx +25 -0
  285. package/templates/apps/web/app/[locale]/dev/purchase/page.tsx +117 -0
  286. package/templates/apps/web/app/[locale]/dev/purchase/purchase.actions.ts +58 -0
  287. package/templates/apps/web/app/[locale]/docs/[[...slug]]/page.tsx +118 -0
  288. package/templates/apps/web/app/[locale]/downloads/__tests__/page-renderer-migration.test.tsx +72 -0
  289. package/templates/apps/web/app/[locale]/downloads/page.tsx +25 -0
  290. package/templates/apps/web/app/[locale]/events/[slug]/page.tsx +47 -0
  291. package/templates/apps/web/app/[locale]/events/__tests__/page-renderer-migration.test.tsx +130 -0
  292. package/templates/apps/web/app/[locale]/events/page.tsx +25 -0
  293. package/templates/apps/web/app/[locale]/faq/page.tsx +36 -0
  294. package/templates/apps/web/app/[locale]/how-to/[slug]/page.tsx +34 -0
  295. package/templates/apps/web/app/[locale]/how-to/__tests__/page-renderer-migration.test.tsx +78 -0
  296. package/templates/apps/web/app/[locale]/how-to/page.tsx +40 -0
  297. package/templates/apps/web/app/[locale]/integrations/[slug]/page.tsx +43 -0
  298. package/templates/apps/web/app/[locale]/integrations/__tests__/page-renderer-migration.test.tsx +129 -0
  299. package/templates/apps/web/app/[locale]/integrations/page.tsx +25 -0
  300. package/templates/apps/web/app/[locale]/launch-service/page.tsx +31 -0
  301. package/templates/apps/web/app/[locale]/layout.tsx +241 -0
  302. package/templates/apps/web/app/[locale]/page.tsx +41 -0
  303. package/templates/apps/web/app/[locale]/partners/[slug]/page.tsx +44 -0
  304. package/templates/apps/web/app/[locale]/partners/__tests__/page-renderer-migration.test.tsx +113 -0
  305. package/templates/apps/web/app/[locale]/partners/page.tsx +25 -0
  306. package/templates/apps/web/app/[locale]/products/[slug]/page.tsx +43 -0
  307. package/templates/apps/web/app/[locale]/products/__tests__/page-renderer-migration.test.tsx +129 -0
  308. package/templates/apps/web/app/[locale]/products/page.tsx +25 -0
  309. package/templates/apps/web/app/[locale]/projects/[slug]/page.tsx +39 -0
  310. package/templates/apps/web/app/[locale]/projects/__tests__/page-renderer-migration.test.tsx +138 -0
  311. package/templates/apps/web/app/[locale]/projects/page.tsx +30 -0
  312. package/templates/apps/web/app/[locale]/resources/[slug]/page.tsx +51 -0
  313. package/templates/apps/web/app/[locale]/resources/__tests__/page-renderer-migration.test.tsx +117 -0
  314. package/templates/apps/web/app/[locale]/resources/page.tsx +27 -0
  315. package/templates/apps/web/app/[locale]/services/[slug]/page.tsx +43 -0
  316. package/templates/apps/web/app/[locale]/services/__tests__/page-renderer-migration.test.tsx +129 -0
  317. package/templates/apps/web/app/[locale]/services/page.tsx +25 -0
  318. package/templates/apps/web/app/[locale]/software/[slug]/page.tsx +34 -0
  319. package/templates/apps/web/app/[locale]/software/__tests__/page-renderer-migration.test.tsx +81 -0
  320. package/templates/apps/web/app/[locale]/software/page.tsx +39 -0
  321. package/templates/apps/web/app/[locale]/tech-articles/[slug]/page.tsx +34 -0
  322. package/templates/apps/web/app/[locale]/tech-articles/__tests__/page-renderer-migration.test.tsx +82 -0
  323. package/templates/apps/web/app/[locale]/tech-articles/page.tsx +39 -0
  324. package/templates/apps/web/app/[locale]/testimonials/__tests__/page-renderer-migration.test.tsx +63 -0
  325. package/templates/apps/web/app/[locale]/testimonials/page.tsx +27 -0
  326. package/templates/apps/web/app/[locale]/use-cases/__tests__/page-renderer-migration.test.tsx +63 -0
  327. package/templates/apps/web/app/[locale]/use-cases/page.tsx +27 -0
  328. package/templates/apps/web/app/[locale]/whitepapers/[slug]/page.tsx +34 -0
  329. package/templates/apps/web/app/[locale]/whitepapers/__tests__/page-renderer-migration.test.tsx +82 -0
  330. package/templates/apps/web/app/[locale]/whitepapers/page.tsx +39 -0
  331. package/templates/apps/web/app/__tests__/error-boundaries.test.tsx +152 -0
  332. package/templates/apps/web/app/api/auth/[...all]/route.ts +16 -0
  333. package/templates/apps/web/app/error-fallback.tsx +75 -0
  334. package/templates/apps/web/app/error.tsx +23 -0
  335. package/templates/apps/web/app/layout.tsx +18 -0
  336. package/templates/apps/web/app/llms.txt/route.ts +101 -0
  337. package/templates/apps/web/app/not-found.tsx +48 -0
  338. package/templates/apps/web/app/og/__tests__/route.test.ts +164 -0
  339. package/templates/apps/web/app/og/route.tsx +135 -0
  340. package/templates/apps/web/app/robots.txt/route.ts +36 -0
  341. package/templates/apps/web/app/sitemap.xml/route.ts +146 -0
  342. package/templates/apps/web/auth.ts +141 -0
  343. package/templates/apps/web/components/ThemeToggle.tsx +60 -0
  344. package/templates/apps/web/components/google-analytics.tsx +34 -0
  345. package/templates/apps/web/content/en/blog/index.mdx +15 -0
  346. package/templates/apps/web/content/en/blog/launching-ailk.mdx +20 -0
  347. package/templates/apps/web/content/en/docs/getting-started.mdx +30 -0
  348. package/templates/apps/web/i18n/request.ts +36 -0
  349. package/templates/apps/web/jest.config.cjs +100 -0
  350. package/templates/apps/web/lib/__mocks__/next-mdx-remote-rsc.js +12 -0
  351. package/templates/apps/web/lib/__mocks__/source-server.js +31 -0
  352. package/templates/apps/web/lib/__tests__/og.test.ts +65 -0
  353. package/templates/apps/web/lib/auth-env.ts +66 -0
  354. package/templates/apps/web/lib/blog-list-data.ts +95 -0
  355. package/templates/apps/web/lib/blog-post-data.ts +79 -0
  356. package/templates/apps/web/lib/nav-config.ts +13 -0
  357. package/templates/apps/web/lib/observability/better-stack.ts +27 -0
  358. package/templates/apps/web/lib/og.ts +23 -0
  359. package/templates/apps/web/lib/prisma-for-auth.ts +34 -0
  360. package/templates/apps/web/lib/source.ts +34 -0
  361. package/templates/apps/web/messages/en.json +131 -0
  362. package/templates/apps/web/middleware.ts +80 -0
  363. package/templates/apps/web/next.config.mjs +167 -0
  364. package/templates/apps/web/package.json +62 -0
  365. package/templates/apps/web/public/.well-known/security.txt +17 -0
  366. package/templates/apps/web/public/android-chrome-192x192.png +0 -0
  367. package/templates/apps/web/public/android-chrome-512x512.png +0 -0
  368. package/templates/apps/web/public/apple-touch-icon.png +0 -0
  369. package/templates/apps/web/public/favicon-16x16.png +0 -0
  370. package/templates/apps/web/public/favicon-32x32.png +0 -0
  371. package/templates/apps/web/public/favicon.ico +0 -0
  372. package/templates/apps/web/public/favicon.svg +4 -0
  373. package/templates/apps/web/public/logo-dark.svg +21 -0
  374. package/templates/apps/web/public/logo-light.svg +21 -0
  375. package/templates/apps/web/public/logomark-dark.svg +4 -0
  376. package/templates/apps/web/public/logomark-light.svg +4 -0
  377. package/templates/apps/web/public/og-default.png +0 -0
  378. package/templates/apps/web/public/site.webmanifest +19 -0
  379. package/templates/apps/web/scripts/assert-content-bundled.ts +55 -0
  380. package/templates/apps/web/security-headers.config.ts +132 -0
  381. package/templates/apps/web/sentry.client.config.ts +27 -0
  382. package/templates/apps/web/sentry.edge.config.ts +15 -0
  383. package/templates/apps/web/sentry.server.config.ts +20 -0
  384. package/templates/apps/web/source.config.ts +78 -0
  385. package/templates/apps/web/src/components/SiteNav.tsx +21 -0
  386. package/templates/apps/web/src/lib/routes.ts +37 -0
  387. package/templates/apps/web/tsconfig.json +35 -0
  388. package/templates/apps/web/types/messages.d.ts +19 -0
  389. package/templates/content/.gitkeep +0 -0
  390. package/templates/content/CLAUDE.md +85 -0
  391. package/templates/content/_site.mdx +38 -0
  392. package/templates/content/ar/HomePage/home.mdx +123 -0
  393. package/templates/content/ar/_site.mdx +35 -0
  394. package/templates/content/de/_site.mdx +29 -0
  395. package/templates/content/en/.gitkeep +0 -0
  396. package/templates/content/en/AboutPage/about.mdx +19 -0
  397. package/templates/content/en/AboutPage/about.schema.json +82 -0
  398. package/templates/content/en/BookCall/book-call.mdx +19 -0
  399. package/templates/content/en/BookCall/book-call.schema.json +121 -0
  400. package/templates/content/en/BreadcrumbList/site-breadcrumbs.mdx +20 -0
  401. package/templates/content/en/CareersList/careers.mdx +24 -0
  402. package/templates/content/en/CaseStudiesList/case-studies.mdx +22 -0
  403. package/templates/content/en/CaseStudiesList/showcase.mdx +8 -0
  404. package/templates/content/en/CaseStudy/ailk-aeo-rollout.mdx +32 -0
  405. package/templates/content/en/CaseStudy/schema-builder-migration.mdx +41 -0
  406. package/templates/content/en/ClientsList/clients.mdx +38 -0
  407. package/templates/content/en/ContactPage/contact.mdx +19 -0
  408. package/templates/content/en/ContactPage/contact.schema.json +100 -0
  409. package/templates/content/en/ContactPoint/primary.mdx +14 -0
  410. package/templates/content/en/Course/aeo-fundamentals.mdx +37 -0
  411. package/templates/content/en/Course/schema-builder-workshop.mdx +62 -0
  412. package/templates/content/en/CoursesList/courses.mdx +22 -0
  413. package/templates/content/en/DownloadsList/downloads.mdx +22 -0
  414. package/templates/content/en/Event/aeo-office-hours-may-2026.mdx +39 -0
  415. package/templates/content/en/Event/ailk-launch-day-2026.mdx +35 -0
  416. package/templates/content/en/EventsList/events.mdx +26 -0
  417. package/templates/content/en/FAQPage/faq.mdx +420 -0
  418. package/templates/content/en/FAQPage/faq.schema.json +231 -0
  419. package/templates/content/en/GlossaryList/glossary.mdx +19 -0
  420. package/templates/content/en/GlossaryList/glossary.schema.json +300 -0
  421. package/templates/content/en/HomePage/home.mdx +312 -0
  422. package/templates/content/en/HomePage/home.schema.json +88 -0
  423. package/templates/content/en/HomePage/launch-service.mdx +475 -0
  424. package/templates/content/en/HomePage/launch-service.schema.json +138 -0
  425. package/templates/content/en/HowTo/add-mdx-content.mdx +38 -0
  426. package/templates/content/en/HowTo/configure-aeo-scoring.mdx +35 -0
  427. package/templates/content/en/HowTo/set-up-json-ld.mdx +36 -0
  428. package/templates/content/en/Integration/github-actions.mdx +31 -0
  429. package/templates/content/en/Integration/openai-api.mdx +26 -0
  430. package/templates/content/en/Integration/vercel.mdx +32 -0
  431. package/templates/content/en/IntegrationsList/integrations.mdx +22 -0
  432. package/templates/content/en/JobPosting/content-strategist.mdx +46 -0
  433. package/templates/content/en/JobPosting/developer-advocate.mdx +47 -0
  434. package/templates/content/en/JobPosting/senior-fullstack-engineer.mdx +57 -0
  435. package/templates/content/en/LandingPage/aeo-audit.mdx +19 -0
  436. package/templates/content/en/LandingPage/aeo-audit.schema.json +92 -0
  437. package/templates/content/en/LandingPage/agency-waitlist.mdx +340 -0
  438. package/templates/content/en/LandingPage/agency-waitlist.schema.json +152 -0
  439. package/templates/content/en/LandingPage/developers.mdx +19 -0
  440. package/templates/content/en/LandingPage/developers.schema.json +109 -0
  441. package/templates/content/en/LandingPage/for-agencies.mdx +390 -0
  442. package/templates/content/en/LandingPage/for-agencies.schema.json +107 -0
  443. package/templates/content/en/LandingPage/for-ai-search-agencies.mdx +417 -0
  444. package/templates/content/en/LandingPage/for-ai-search-agencies.schema.json +105 -0
  445. package/templates/content/en/LandingPage/for-businesses.mdx +19 -0
  446. package/templates/content/en/LandingPage/for-businesses.schema.json +96 -0
  447. package/templates/content/en/LandingPage/platform.mdx +369 -0
  448. package/templates/content/en/LandingPage/platform.schema.json +166 -0
  449. package/templates/content/en/LandingPage/vs-ai-website-builders.mdx +19 -0
  450. package/templates/content/en/LandingPage/vs-ai-website-builders.schema.json +102 -0
  451. package/templates/content/en/LandingPage/vs-wordpress.mdx +19 -0
  452. package/templates/content/en/LandingPage/vs-wordpress.schema.json +53 -0
  453. package/templates/content/en/NewsletterSignup/newsletter.mdx +236 -0
  454. package/templates/content/en/NewsletterSignup/newsletter.schema.json +91 -0
  455. package/templates/content/en/Organization/site-owner.mdx +16 -0
  456. package/templates/content/en/Partner/prisma.mdx +31 -0
  457. package/templates/content/en/Partner/supabase.mdx +30 -0
  458. package/templates/content/en/Partner/vercel.mdx +28 -0
  459. package/templates/content/en/PartnersList/partners.mdx +22 -0
  460. package/templates/content/en/Person/founder.mdx +18 -0
  461. package/templates/content/en/Pricing/pricing.mdx +538 -0
  462. package/templates/content/en/Pricing/pricing.schema.json +209 -0
  463. package/templates/content/en/PrivacyPage/privacy.mdx +165 -0
  464. package/templates/content/en/PrivacyPage/privacy.schema.json +64 -0
  465. package/templates/content/en/Product/ailk.mdx +19 -0
  466. package/templates/content/en/Product/ailk.schema.json +94 -0
  467. package/templates/content/en/Product/api-launch-kit.mdx +26 -0
  468. package/templates/content/en/Product/launch-kit.mdx +28 -0
  469. package/templates/content/en/ProductsList/products.mdx +26 -0
  470. package/templates/content/en/Project/ailk-phase-2.mdx +54 -0
  471. package/templates/content/en/ProjectsList/projects.mdx +25 -0
  472. package/templates/content/en/ResourceDetail/aeo-scoring-guide.mdx +27 -0
  473. package/templates/content/en/ResourceDetail/content-model-whitepaper.mdx +28 -0
  474. package/templates/content/en/ResourceDetail/schema-org-quick-reference.mdx +39 -0
  475. package/templates/content/en/ResourcesHub/resources.mdx +22 -0
  476. package/templates/content/en/Service/consulting.mdx +22 -0
  477. package/templates/content/en/Service/implementation.mdx +30 -0
  478. package/templates/content/en/Service/launch-service.mdx +232 -0
  479. package/templates/content/en/Service/launch.mdx +228 -0
  480. package/templates/content/en/ServicesList/services.mdx +84 -0
  481. package/templates/content/en/SoftwareProduct/ailk-aeo.mdx +44 -0
  482. package/templates/content/en/SoftwareProduct/ailk-content-adapters.mdx +47 -0
  483. package/templates/content/en/SoftwareProduct/ailk-schema.mdx +49 -0
  484. package/templates/content/en/TeamList/team.mdx +63 -0
  485. package/templates/content/en/TeamMember/founder.mdx +72 -0
  486. package/templates/content/en/TermsPage/terms.mdx +19 -0
  487. package/templates/content/en/TermsPage/terms.schema.json +99 -0
  488. package/templates/content/en/TestimonialsList/testimonials.mdx +44 -0
  489. package/templates/content/en/UseCasesList/use-cases.mdx +30 -0
  490. package/templates/content/en/Whitepaper/ax-first-product-development.mdx +27 -0
  491. package/templates/content/en/Whitepaper/open-core-commercial-strategy.mdx +27 -0
  492. package/templates/content/en/Whitepaper/structured-data-for-answer-engines.mdx +31 -0
  493. package/templates/content/en-XA/AboutPage/about.mdx +8 -0
  494. package/templates/content/en-XA/FAQPage/faq.mdx +8 -0
  495. package/templates/content/en-XA/HomePage/home.mdx +8 -0
  496. package/templates/content/es/_site.mdx +30 -0
  497. package/templates/content/fr/_site.mdx +30 -0
  498. package/templates/content/ja/_site.mdx +30 -0
  499. package/templates/content/pt-BR/AboutPage/about.mdx +8 -0
  500. package/templates/content/pt-BR/FAQPage/faq.mdx +8 -0
  501. package/templates/content/pt-BR/HomePage/home.mdx +23 -0
  502. package/templates/database/CHANGELOG.md +5 -0
  503. package/templates/database/README.md +234 -0
  504. package/templates/database/__tests__/user-cascade.test.ts +125 -0
  505. package/templates/database/auth/.gitkeep +0 -0
  506. package/templates/database/config/.gitkeep +0 -0
  507. package/templates/database/content/.gitkeep +0 -0
  508. package/templates/database/inbox/.gitkeep +0 -0
  509. package/templates/database/inbox/README.md +3 -0
  510. package/templates/database/inbox/__tests__/schema.test.ts +40 -0
  511. package/templates/database/inbox/schema.prisma +52 -0
  512. package/templates/database/jest.config.cjs +29 -0
  513. package/templates/database/migrations/20260508000000_add_inbox_namespace/migration.sql +328 -0
  514. package/templates/database/migrations/20260513000000_better_auth_migration/migration.sql +100 -0
  515. package/templates/database/migrations/20260515000000_add_user_billing_fields/migration.sql +28 -0
  516. package/templates/database/migrations/20260516000000_add_user_tier_care_plan_seat/migration.sql +25 -0
  517. package/templates/database/migrations/20260518000000_add_telemetry_records/migration.sql +42 -0
  518. package/templates/database/migrations/20260525000000_theme_wiring/migration.sql +67 -0
  519. package/templates/database/migrations/20260710000000_retire_commercial_tier/migration.sql +21 -0
  520. package/templates/database/migrations/migration_lock.toml +3 -0
  521. package/templates/database/ops/.gitkeep +0 -0
  522. package/templates/database/package.json +45 -0
  523. package/templates/database/prisma.config.ts +20 -0
  524. package/templates/database/schema.prisma +487 -0
  525. package/templates/database/scripts/db-generate-locked.sh +80 -0
  526. package/templates/database/seed-test.ts +85 -0
  527. package/templates/database/tsconfig.build.json +16 -0
  528. package/templates/database/tsconfig.json +9 -0
  529. package/templates/package.json +125 -0
  530. package/templates/pnpm-workspace.yaml +6 -0
  531. package/templates/project.yaml +59 -0
  532. package/templates/tsconfig.base.json +18 -0
  533. package/templates/tsconfig.json +45 -0
@@ -0,0 +1,125 @@
1
+ /**
2
+ * @file user-cascade.test.ts
3
+ *
4
+ * Schema-shape verification for the User cascade contract (#587 spec §3
5
+ * "Database schema" + AC #9: "Deleting a User cascades to all five custom
6
+ * relations").
7
+ *
8
+ * Approach: read `database/schema.prisma` as text and assert that each of the
9
+ * five User-relation foreign keys declares `onDelete: Cascade`. We deliberately
10
+ * avoid live Postgres in this test:
11
+ *
12
+ * - The repo's existing pattern (database/inbox/__tests__/schema.test.ts)
13
+ * validates model presence at the generated-client level only.
14
+ * - A real cascade integration test runs in the `apps/api Route Tests
15
+ * (Postgres)` non-required workflow, which spins up Postgres + applies the
16
+ * migration generated by `pnpm db:migrate`.
17
+ * - The schema-text assertion catches the regression class that matters
18
+ * most: accidental loss of the `onDelete: Cascade` directive during the
19
+ * Better Auth migration. Once the schema declares cascade, Prisma + the
20
+ * generated migration are responsible for enforcing it at runtime.
21
+ *
22
+ * If a future contributor proposes a real-DB cascade test, they should add it
23
+ * under `apps/api Route Tests (Postgres)` rather than here so the workspace's
24
+ * Jest run stays DB-free.
25
+ */
26
+
27
+ import { readFileSync } from "node:fs";
28
+ import { resolve } from "node:path";
29
+
30
+ const SCHEMA_PATH = resolve(__dirname, "..", "schema.prisma");
31
+
32
+ /**
33
+ * `relationField` is the field name on User that points at each related
34
+ * model. It's intentionally not always the lowercased model name — the schema
35
+ * uses `oauthAuthorizations` (lowercase `oauth-`) but the model itself is
36
+ * `OAuthAuthorization` (Pascal `OAuth-`). Listing it explicitly is more
37
+ * readable than a regex with multiple optional casings.
38
+ */
39
+ const CUSTOM_RELATIONS: Array<{
40
+ model: string;
41
+ relationField: string;
42
+ description: string;
43
+ }> = [
44
+ { model: "ApiToken", relationField: "apiTokens", description: "API tokens (Bearer auth)" },
45
+ { model: "RefreshToken", relationField: "refreshTokens", description: "Mobile session refresh tokens" },
46
+ {
47
+ model: "OAuthAuthorization",
48
+ relationField: "oauthAuthorizations",
49
+ description: "OAuth grants to ChatGPT/Slack/etc",
50
+ },
51
+ { model: "PushToken", relationField: "pushTokens", description: "Mobile / web push subscription tokens" },
52
+ { model: "UserData", relationField: "userData", description: "Customer key-value preferences" },
53
+ ];
54
+
55
+ const BETTER_AUTH_RELATIONS: Array<{ model: string }> = [
56
+ { model: "Session" },
57
+ { model: "Account" },
58
+ ];
59
+
60
+ describe("User cascade — schema-shape contract (#587)", () => {
61
+ const schema = readFileSync(SCHEMA_PATH, "utf-8");
62
+
63
+ it.each(CUSTOM_RELATIONS)(
64
+ "$model FK to User declares onDelete: Cascade ($description)",
65
+ ({ model }) => {
66
+ // Find the model block, then check the User @relation line within it
67
+ // carries onDelete: Cascade.
68
+ const modelRegex = new RegExp(`model ${model} \\{([\\s\\S]*?)^}`, "m");
69
+ const match = modelRegex.exec(schema);
70
+ expect(match).not.toBeNull();
71
+ const body = match![1];
72
+ // The relation line referencing User.id MUST contain onDelete: Cascade.
73
+ const relationLine = body
74
+ .split("\n")
75
+ .find(
76
+ (line) =>
77
+ /@relation\s*\(/.test(line) && /references:\s*\[id\]/.test(line),
78
+ );
79
+ expect(relationLine).toBeDefined();
80
+ expect(relationLine).toMatch(/onDelete:\s*Cascade/);
81
+ },
82
+ );
83
+
84
+ it.each(BETTER_AUTH_RELATIONS)(
85
+ "$model FK to User declares onDelete: Cascade (Better Auth surface)",
86
+ ({ model }) => {
87
+ const modelRegex = new RegExp(`model ${model} \\{([\\s\\S]*?)^}`, "m");
88
+ const match = modelRegex.exec(schema);
89
+ expect(match).not.toBeNull();
90
+ const body = match![1];
91
+ const relationLine = body
92
+ .split("\n")
93
+ .find(
94
+ (line) =>
95
+ /@relation\s*\(/.test(line) && /references:\s*\[id\]/.test(line),
96
+ );
97
+ expect(relationLine).toBeDefined();
98
+ expect(relationLine).toMatch(/onDelete:\s*Cascade/);
99
+ },
100
+ );
101
+
102
+ it("User model still declares every required custom relation back-reference", () => {
103
+ const userRegex = /model User \{([\s\S]*?)^}/m;
104
+ const match = userRegex.exec(schema);
105
+ expect(match).not.toBeNull();
106
+ const body = match![1];
107
+ for (const { model, relationField } of CUSTOM_RELATIONS) {
108
+ // The User model must reference each related model (plural array or
109
+ // optional singular). Catches accidental relation drops during schema
110
+ // refactors.
111
+ const typePattern = new RegExp(`\\b${model}(\\[\\]|\\?)?\\b`);
112
+ expect(body).toMatch(typePattern);
113
+ // And the matching back-reference field name must be present.
114
+ const fieldPattern = new RegExp(`\\b${relationField}\\b`);
115
+ expect(body).toMatch(fieldPattern);
116
+ }
117
+ });
118
+
119
+ it("Better Auth replaces three NextAuth tables (Authenticator was never present)", () => {
120
+ expect(schema).not.toMatch(/model VerificationToken/);
121
+ expect(schema).toMatch(/model Verification\b/);
122
+ expect(schema).toMatch(/model Session\b/);
123
+ expect(schema).toMatch(/model Account\b/);
124
+ });
125
+ });
File without changes
File without changes
File without changes
File without changes
@@ -0,0 +1,3 @@
1
+ # inbox namespace
2
+
3
+ The `inbox` namespace owns lead and relationship data: anonymous leads submitted via MCP tools or API routes, newsletter subscribers, and callback requests. All three models use `siteId` as a plain string identifier — there is no foreign-key relationship to auth-namespace models per [ADR 0009](../../docs/adr/0009-database-namespace-separation.md) D2. When a feature needs "leads with their owning user's name," that assembly happens in `apps/api/src/services/` (the D3 service-layer exemption), never via a Prisma `@relation` crossing the namespace boundary.
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Smoke tests for the inbox namespace schema (issue #214 — B1).
3
+ *
4
+ * Model presence is checked against the generator-emitted per-model files
5
+ * rather than via PrismaClient instantiation: the v7 `prisma-client`
6
+ * generator's client.ts uses `import.meta.url`, which the CommonJS Jest
7
+ * runtime can't load.
8
+ */
9
+
10
+ import { spawnSync } from "node:child_process";
11
+ import { existsSync } from "node:fs";
12
+ import { resolve } from "node:path";
13
+
14
+ const REPO_ROOT = resolve(__dirname, "..", "..", "..");
15
+ const MODELS_DIR = resolve(__dirname, "..", "..", "generated", "client", "models");
16
+
17
+ describe("inbox namespace — Prisma client model presence", () => {
18
+ it("emits Lead model file", () => {
19
+ expect(existsSync(resolve(MODELS_DIR, "Lead.ts"))).toBe(true);
20
+ });
21
+
22
+ it("emits Subscriber model file", () => {
23
+ expect(existsSync(resolve(MODELS_DIR, "Subscriber.ts"))).toBe(true);
24
+ });
25
+
26
+ it("emits Callback model file", () => {
27
+ expect(existsSync(resolve(MODELS_DIR, "Callback.ts"))).toBe(true);
28
+ });
29
+ });
30
+
31
+ describe("inbox namespace — architecture lint", () => {
32
+ it("namespace lint exits 0 (no cross-namespace violations)", () => {
33
+ const result = spawnSync(
34
+ "pnpm",
35
+ ["exec", "tsx", "tools/lint-architecture.ts"],
36
+ { cwd: REPO_ROOT, encoding: "utf-8" },
37
+ );
38
+ expect(result.status).toBe(0);
39
+ });
40
+ });
@@ -0,0 +1,52 @@
1
+ // inbox namespace — Lead, Subscriber, Callback
2
+ //
3
+ // Backs the Phase B anonymous-write MCP tools (submit_lead, subscribe_newsletter,
4
+ // request_callback) and their corresponding POST routes (B6).
5
+ //
6
+ // Per ADR 0009 D2: no @relation directives cross namespace boundaries.
7
+ // siteId is a plain String identifier — no FK to auth/users.
8
+ //
9
+ // Generator + datasource blocks live in database/schema.prisma (the root schema
10
+ // file). This file holds only model definitions for the inbox namespace.
11
+
12
+ /// Lead — anonymous lead submission (Phase B submit_lead tool / B6 route)
13
+ model Lead {
14
+ id String @id @default(cuid())
15
+ siteId String @map("site_id")
16
+ source String
17
+ email String
18
+ payload Json
19
+ createdAt DateTime @default(now()) @map("created_at")
20
+
21
+ @@index([siteId])
22
+ @@index([createdAt])
23
+ @@map("leads")
24
+ }
25
+
26
+ /// Subscriber — newsletter subscription (Phase B subscribe_newsletter tool / B6 route)
27
+ model Subscriber {
28
+ id String @id @default(cuid())
29
+ siteId String @map("site_id")
30
+ email String
31
+ source String
32
+ createdAt DateTime @default(now()) @map("created_at")
33
+
34
+ @@unique([siteId, email])
35
+ @@index([siteId])
36
+ @@map("subscribers")
37
+ }
38
+
39
+ /// Callback — callback request (Phase B request_callback tool / B6 route)
40
+ model Callback {
41
+ id String @id @default(cuid())
42
+ siteId String @map("site_id")
43
+ name String
44
+ phone String
45
+ preferredTime String? @map("preferred_time")
46
+ payload Json
47
+ createdAt DateTime @default(now()) @map("created_at")
48
+
49
+ @@index([siteId])
50
+ @@index([createdAt])
51
+ @@map("callbacks")
52
+ }
@@ -0,0 +1,29 @@
1
+ module.exports = {
2
+ preset: "ts-jest",
3
+ testEnvironment: "node",
4
+ roots: ["<rootDir>"],
5
+ testMatch: ["**/__tests__/**/*.test.ts"],
6
+ testPathIgnorePatterns: ["/node_modules/", "/generated/"],
7
+ moduleFileExtensions: ["ts", "js", "json"],
8
+ moduleNameMapper: {
9
+ "^(\\.{1,2}/.*)\\.js$": "$1",
10
+ },
11
+ transform: {
12
+ "^.+\\.tsx?$": [
13
+ "ts-jest",
14
+ {
15
+ tsconfig: {
16
+ target: "ES2020",
17
+ module: "commonjs",
18
+ lib: ["ES2020"],
19
+ declaration: false,
20
+ strict: true,
21
+ esModuleInterop: true,
22
+ skipLibCheck: true,
23
+ ignoreDeprecations: '6.0',
24
+ types: ["node", "jest"],
25
+ },
26
+ },
27
+ ],
28
+ },
29
+ };
@@ -0,0 +1,328 @@
1
+ -- CreateSchema
2
+ CREATE SCHEMA IF NOT EXISTS "public";
3
+
4
+ -- CreateTable
5
+ CREATE TABLE "users" (
6
+ "id" TEXT NOT NULL,
7
+ "email" TEXT NOT NULL,
8
+ "name" TEXT,
9
+ "image" TEXT,
10
+ "email_verified" TIMESTAMP(3),
11
+ "role" TEXT NOT NULL DEFAULT 'user',
12
+ "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
13
+ "updated_at" TIMESTAMP(3) NOT NULL,
14
+
15
+ CONSTRAINT "users_pkey" PRIMARY KEY ("id")
16
+ );
17
+
18
+ -- CreateTable
19
+ CREATE TABLE "accounts" (
20
+ "id" TEXT NOT NULL,
21
+ "user_id" TEXT NOT NULL,
22
+ "type" TEXT NOT NULL,
23
+ "provider" TEXT NOT NULL,
24
+ "provider_account_id" TEXT NOT NULL,
25
+ "refresh_token" TEXT,
26
+ "access_token" TEXT,
27
+ "expires_at" INTEGER,
28
+ "token_type" TEXT,
29
+ "scope" TEXT,
30
+ "id_token" TEXT,
31
+ "session_state" TEXT,
32
+
33
+ CONSTRAINT "accounts_pkey" PRIMARY KEY ("id")
34
+ );
35
+
36
+ -- CreateTable
37
+ CREATE TABLE "sessions" (
38
+ "id" TEXT NOT NULL,
39
+ "session_token" TEXT NOT NULL,
40
+ "user_id" TEXT NOT NULL,
41
+ "expires" TIMESTAMP(3) NOT NULL,
42
+
43
+ CONSTRAINT "sessions_pkey" PRIMARY KEY ("id")
44
+ );
45
+
46
+ -- CreateTable
47
+ CREATE TABLE "verification_tokens" (
48
+ "identifier" TEXT NOT NULL,
49
+ "token" TEXT NOT NULL,
50
+ "expires" TIMESTAMP(3) NOT NULL
51
+ );
52
+
53
+ -- CreateTable
54
+ CREATE TABLE "api_tokens" (
55
+ "id" TEXT NOT NULL,
56
+ "user_id" TEXT NOT NULL,
57
+ "name" TEXT NOT NULL,
58
+ "token" TEXT NOT NULL,
59
+ "token_prefix" TEXT NOT NULL,
60
+ "client_type" TEXT NOT NULL DEFAULT 'api',
61
+ "device_info" TEXT,
62
+ "scopes" TEXT[] DEFAULT ARRAY[]::TEXT[],
63
+ "expires_at" TIMESTAMP(3),
64
+ "last_used_at" TIMESTAMP(3),
65
+ "last_used_ip" TEXT,
66
+ "revoked_at" TIMESTAMP(3),
67
+ "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
68
+
69
+ CONSTRAINT "api_tokens_pkey" PRIMARY KEY ("id")
70
+ );
71
+
72
+ -- CreateTable
73
+ CREATE TABLE "refresh_tokens" (
74
+ "id" TEXT NOT NULL,
75
+ "user_id" TEXT NOT NULL,
76
+ "api_token_id" TEXT NOT NULL,
77
+ "token" TEXT NOT NULL,
78
+ "expires_at" TIMESTAMP(3) NOT NULL,
79
+ "used_at" TIMESTAMP(3),
80
+ "revoked_at" TIMESTAMP(3),
81
+ "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
82
+
83
+ CONSTRAINT "refresh_tokens_pkey" PRIMARY KEY ("id")
84
+ );
85
+
86
+ -- CreateTable
87
+ CREATE TABLE "oauth_clients" (
88
+ "id" TEXT NOT NULL,
89
+ "name" TEXT NOT NULL,
90
+ "description" TEXT,
91
+ "logo_url" TEXT,
92
+ "client_id" TEXT NOT NULL,
93
+ "client_secret" TEXT NOT NULL,
94
+ "redirect_uris" TEXT[],
95
+ "scopes" TEXT[] DEFAULT ARRAY[]::TEXT[],
96
+ "enabled" BOOLEAN NOT NULL DEFAULT true,
97
+ "trusted" BOOLEAN NOT NULL DEFAULT false,
98
+ "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
99
+ "updated_at" TIMESTAMP(3) NOT NULL,
100
+
101
+ CONSTRAINT "oauth_clients_pkey" PRIMARY KEY ("id")
102
+ );
103
+
104
+ -- CreateTable
105
+ CREATE TABLE "oauth_authorizations" (
106
+ "id" TEXT NOT NULL,
107
+ "user_id" TEXT NOT NULL,
108
+ "client_id" TEXT NOT NULL,
109
+ "scopes" TEXT[],
110
+ "access_token" TEXT NOT NULL,
111
+ "refresh_token" TEXT,
112
+ "expires_at" TIMESTAMP(3) NOT NULL,
113
+ "revoked_at" TIMESTAMP(3),
114
+ "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
115
+ "updated_at" TIMESTAMP(3) NOT NULL,
116
+
117
+ CONSTRAINT "oauth_authorizations_pkey" PRIMARY KEY ("id")
118
+ );
119
+
120
+ -- CreateTable
121
+ CREATE TABLE "push_tokens" (
122
+ "id" TEXT NOT NULL,
123
+ "user_id" TEXT NOT NULL,
124
+ "token" TEXT NOT NULL,
125
+ "platform" TEXT NOT NULL,
126
+ "device_id" TEXT,
127
+ "device_name" TEXT,
128
+ "app_version" TEXT,
129
+ "enabled" BOOLEAN NOT NULL DEFAULT true,
130
+ "failed_at" TIMESTAMP(3),
131
+ "fail_count" INTEGER NOT NULL DEFAULT 0,
132
+ "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
133
+ "updated_at" TIMESTAMP(3) NOT NULL,
134
+
135
+ CONSTRAINT "push_tokens_pkey" PRIMARY KEY ("id")
136
+ );
137
+
138
+ -- CreateTable
139
+ CREATE TABLE "user_data" (
140
+ "id" TEXT NOT NULL,
141
+ "user_id" TEXT NOT NULL,
142
+ "key" TEXT NOT NULL,
143
+ "value" JSONB NOT NULL,
144
+ "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
145
+ "updated_at" TIMESTAMP(3) NOT NULL,
146
+
147
+ CONSTRAINT "user_data_pkey" PRIMARY KEY ("id")
148
+ );
149
+
150
+ -- CreateTable
151
+ CREATE TABLE "site_settings" (
152
+ "id" TEXT NOT NULL,
153
+ "key" TEXT NOT NULL,
154
+ "value" JSONB NOT NULL,
155
+ "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
156
+ "updated_at" TIMESTAMP(3) NOT NULL,
157
+
158
+ CONSTRAINT "site_settings_pkey" PRIMARY KEY ("id")
159
+ );
160
+
161
+ -- CreateTable
162
+ CREATE TABLE "leads" (
163
+ "id" TEXT NOT NULL,
164
+ "site_id" TEXT NOT NULL,
165
+ "source" TEXT NOT NULL,
166
+ "email" TEXT NOT NULL,
167
+ "payload" JSONB NOT NULL,
168
+ "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
169
+
170
+ CONSTRAINT "leads_pkey" PRIMARY KEY ("id")
171
+ );
172
+
173
+ -- CreateTable
174
+ CREATE TABLE "subscribers" (
175
+ "id" TEXT NOT NULL,
176
+ "site_id" TEXT NOT NULL,
177
+ "email" TEXT NOT NULL,
178
+ "source" TEXT NOT NULL,
179
+ "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
180
+
181
+ CONSTRAINT "subscribers_pkey" PRIMARY KEY ("id")
182
+ );
183
+
184
+ -- CreateTable
185
+ CREATE TABLE "callbacks" (
186
+ "id" TEXT NOT NULL,
187
+ "site_id" TEXT NOT NULL,
188
+ "name" TEXT NOT NULL,
189
+ "phone" TEXT NOT NULL,
190
+ "preferred_time" TEXT,
191
+ "payload" JSONB NOT NULL,
192
+ "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
193
+
194
+ CONSTRAINT "callbacks_pkey" PRIMARY KEY ("id")
195
+ );
196
+
197
+ -- CreateIndex
198
+ CREATE UNIQUE INDEX "users_email_key" ON "users"("email");
199
+
200
+ -- CreateIndex
201
+ CREATE INDEX "accounts_user_id_idx" ON "accounts"("user_id");
202
+
203
+ -- CreateIndex
204
+ CREATE UNIQUE INDEX "accounts_provider_provider_account_id_key" ON "accounts"("provider", "provider_account_id");
205
+
206
+ -- CreateIndex
207
+ CREATE UNIQUE INDEX "sessions_session_token_key" ON "sessions"("session_token");
208
+
209
+ -- CreateIndex
210
+ CREATE INDEX "sessions_user_id_idx" ON "sessions"("user_id");
211
+
212
+ -- CreateIndex
213
+ CREATE UNIQUE INDEX "verification_tokens_token_key" ON "verification_tokens"("token");
214
+
215
+ -- CreateIndex
216
+ CREATE UNIQUE INDEX "verification_tokens_identifier_token_key" ON "verification_tokens"("identifier", "token");
217
+
218
+ -- CreateIndex
219
+ CREATE UNIQUE INDEX "api_tokens_token_key" ON "api_tokens"("token");
220
+
221
+ -- CreateIndex
222
+ CREATE INDEX "api_tokens_user_id_idx" ON "api_tokens"("user_id");
223
+
224
+ -- CreateIndex
225
+ CREATE INDEX "api_tokens_token_idx" ON "api_tokens"("token");
226
+
227
+ -- CreateIndex
228
+ CREATE INDEX "api_tokens_token_prefix_idx" ON "api_tokens"("token_prefix");
229
+
230
+ -- CreateIndex
231
+ CREATE UNIQUE INDEX "refresh_tokens_token_key" ON "refresh_tokens"("token");
232
+
233
+ -- CreateIndex
234
+ CREATE INDEX "refresh_tokens_user_id_idx" ON "refresh_tokens"("user_id");
235
+
236
+ -- CreateIndex
237
+ CREATE INDEX "refresh_tokens_api_token_id_idx" ON "refresh_tokens"("api_token_id");
238
+
239
+ -- CreateIndex
240
+ CREATE INDEX "refresh_tokens_token_idx" ON "refresh_tokens"("token");
241
+
242
+ -- CreateIndex
243
+ CREATE UNIQUE INDEX "oauth_clients_client_id_key" ON "oauth_clients"("client_id");
244
+
245
+ -- CreateIndex
246
+ CREATE UNIQUE INDEX "oauth_authorizations_access_token_key" ON "oauth_authorizations"("access_token");
247
+
248
+ -- CreateIndex
249
+ CREATE UNIQUE INDEX "oauth_authorizations_refresh_token_key" ON "oauth_authorizations"("refresh_token");
250
+
251
+ -- CreateIndex
252
+ CREATE INDEX "oauth_authorizations_user_id_idx" ON "oauth_authorizations"("user_id");
253
+
254
+ -- CreateIndex
255
+ CREATE INDEX "oauth_authorizations_client_id_idx" ON "oauth_authorizations"("client_id");
256
+
257
+ -- CreateIndex
258
+ CREATE INDEX "oauth_authorizations_access_token_idx" ON "oauth_authorizations"("access_token");
259
+
260
+ -- CreateIndex
261
+ CREATE UNIQUE INDEX "oauth_authorizations_user_id_client_id_key" ON "oauth_authorizations"("user_id", "client_id");
262
+
263
+ -- CreateIndex
264
+ CREATE UNIQUE INDEX "push_tokens_token_key" ON "push_tokens"("token");
265
+
266
+ -- CreateIndex
267
+ CREATE INDEX "push_tokens_user_id_idx" ON "push_tokens"("user_id");
268
+
269
+ -- CreateIndex
270
+ CREATE INDEX "push_tokens_platform_idx" ON "push_tokens"("platform");
271
+
272
+ -- CreateIndex
273
+ CREATE INDEX "user_data_user_id_idx" ON "user_data"("user_id");
274
+
275
+ -- CreateIndex
276
+ CREATE INDEX "user_data_key_idx" ON "user_data"("key");
277
+
278
+ -- CreateIndex
279
+ CREATE UNIQUE INDEX "user_data_user_id_key_key" ON "user_data"("user_id", "key");
280
+
281
+ -- CreateIndex
282
+ CREATE UNIQUE INDEX "site_settings_key_key" ON "site_settings"("key");
283
+
284
+ -- CreateIndex
285
+ CREATE INDEX "leads_site_id_idx" ON "leads"("site_id");
286
+
287
+ -- CreateIndex
288
+ CREATE INDEX "leads_created_at_idx" ON "leads"("created_at");
289
+
290
+ -- CreateIndex
291
+ CREATE INDEX "subscribers_site_id_idx" ON "subscribers"("site_id");
292
+
293
+ -- CreateIndex
294
+ CREATE UNIQUE INDEX "subscribers_site_id_email_key" ON "subscribers"("site_id", "email");
295
+
296
+ -- CreateIndex
297
+ CREATE INDEX "callbacks_site_id_idx" ON "callbacks"("site_id");
298
+
299
+ -- CreateIndex
300
+ CREATE INDEX "callbacks_created_at_idx" ON "callbacks"("created_at");
301
+
302
+ -- AddForeignKey
303
+ ALTER TABLE "accounts" ADD CONSTRAINT "accounts_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
304
+
305
+ -- AddForeignKey
306
+ ALTER TABLE "sessions" ADD CONSTRAINT "sessions_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
307
+
308
+ -- AddForeignKey
309
+ ALTER TABLE "api_tokens" ADD CONSTRAINT "api_tokens_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
310
+
311
+ -- AddForeignKey
312
+ ALTER TABLE "refresh_tokens" ADD CONSTRAINT "refresh_tokens_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
313
+
314
+ -- AddForeignKey
315
+ ALTER TABLE "refresh_tokens" ADD CONSTRAINT "refresh_tokens_api_token_id_fkey" FOREIGN KEY ("api_token_id") REFERENCES "api_tokens"("id") ON DELETE CASCADE ON UPDATE CASCADE;
316
+
317
+ -- AddForeignKey
318
+ ALTER TABLE "oauth_authorizations" ADD CONSTRAINT "oauth_authorizations_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
319
+
320
+ -- AddForeignKey
321
+ ALTER TABLE "oauth_authorizations" ADD CONSTRAINT "oauth_authorizations_client_id_fkey" FOREIGN KEY ("client_id") REFERENCES "oauth_clients"("id") ON DELETE CASCADE ON UPDATE CASCADE;
322
+
323
+ -- AddForeignKey
324
+ ALTER TABLE "push_tokens" ADD CONSTRAINT "push_tokens_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
325
+
326
+ -- AddForeignKey
327
+ ALTER TABLE "user_data" ADD CONSTRAINT "user_data_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
328
+
@@ -0,0 +1,100 @@
1
+ -- Better Auth migration (#587)
2
+ --
3
+ -- Drops the three NextAuth tables (accounts, sessions, verification_tokens)
4
+ -- and recreates accounts + sessions with the Better Auth column shape, plus a
5
+ -- new `verifications` table for Better Auth's email/magic-link surface.
6
+ --
7
+ -- The User table changes `email_verified` from a nullable timestamp to a
8
+ -- boolean. Pre-OSS posture: existing dev rows are sacrificed.
9
+ --
10
+ -- The five custom User relations (ApiToken, RefreshToken, OAuthAuthorization,
11
+ -- PushToken, UserData) are unaffected — their FKs to users.id and ON DELETE
12
+ -- CASCADE semantics remain identical.
13
+
14
+ -- DropForeignKey
15
+ ALTER TABLE "accounts" DROP CONSTRAINT "accounts_user_id_fkey";
16
+
17
+ -- DropForeignKey
18
+ ALTER TABLE "sessions" DROP CONSTRAINT "sessions_user_id_fkey";
19
+
20
+ -- DropTable
21
+ DROP TABLE "accounts";
22
+
23
+ -- DropTable
24
+ DROP TABLE "sessions";
25
+
26
+ -- DropTable
27
+ DROP TABLE "verification_tokens";
28
+
29
+ -- AlterTable: switch users.email_verified from timestamp? to boolean
30
+ ALTER TABLE "users" DROP COLUMN "email_verified";
31
+ ALTER TABLE "users" ADD COLUMN "email_verified" BOOLEAN NOT NULL DEFAULT false;
32
+
33
+ -- CreateTable: Better Auth sessions
34
+ CREATE TABLE "sessions" (
35
+ "id" TEXT NOT NULL,
36
+ "expires_at" TIMESTAMP(3) NOT NULL,
37
+ "token" TEXT NOT NULL,
38
+ "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
39
+ "updated_at" TIMESTAMP(3) NOT NULL,
40
+ "ip_address" TEXT,
41
+ "user_agent" TEXT,
42
+ "user_id" TEXT NOT NULL,
43
+
44
+ CONSTRAINT "sessions_pkey" PRIMARY KEY ("id")
45
+ );
46
+
47
+ -- CreateIndex
48
+ CREATE UNIQUE INDEX "sessions_token_key" ON "sessions"("token");
49
+
50
+ -- CreateIndex
51
+ CREATE INDEX "sessions_user_id_idx" ON "sessions"("user_id");
52
+
53
+ -- CreateIndex
54
+ CREATE INDEX "sessions_token_idx" ON "sessions"("token");
55
+
56
+ -- AddForeignKey
57
+ ALTER TABLE "sessions" ADD CONSTRAINT "sessions_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
58
+
59
+ -- CreateTable: Better Auth accounts
60
+ CREATE TABLE "accounts" (
61
+ "id" TEXT NOT NULL,
62
+ "account_id" TEXT NOT NULL,
63
+ "provider_id" TEXT NOT NULL,
64
+ "user_id" TEXT NOT NULL,
65
+ "access_token" TEXT,
66
+ "refresh_token" TEXT,
67
+ "id_token" TEXT,
68
+ "access_token_expires_at" TIMESTAMP(3),
69
+ "refresh_token_expires_at" TIMESTAMP(3),
70
+ "scope" TEXT,
71
+ "password" TEXT,
72
+ "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
73
+ "updated_at" TIMESTAMP(3) NOT NULL,
74
+
75
+ CONSTRAINT "accounts_pkey" PRIMARY KEY ("id")
76
+ );
77
+
78
+ -- CreateIndex
79
+ CREATE UNIQUE INDEX "accounts_provider_id_account_id_key" ON "accounts"("provider_id", "account_id");
80
+
81
+ -- CreateIndex
82
+ CREATE INDEX "accounts_user_id_idx" ON "accounts"("user_id");
83
+
84
+ -- AddForeignKey
85
+ ALTER TABLE "accounts" ADD CONSTRAINT "accounts_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
86
+
87
+ -- CreateTable: Better Auth verifications
88
+ CREATE TABLE "verifications" (
89
+ "id" TEXT NOT NULL,
90
+ "identifier" TEXT NOT NULL,
91
+ "value" TEXT NOT NULL,
92
+ "expires_at" TIMESTAMP(3) NOT NULL,
93
+ "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
94
+ "updated_at" TIMESTAMP(3) NOT NULL,
95
+
96
+ CONSTRAINT "verifications_pkey" PRIMARY KEY ("id")
97
+ );
98
+
99
+ -- CreateIndex
100
+ CREATE INDEX "verifications_identifier_idx" ON "verifications"("identifier");