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.
- package/LICENSE +201 -0
- package/README.md +39 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +80 -0
- package/dist/copy.d.ts +8 -0
- package/dist/copy.js +109 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +10 -0
- package/dist/lib/pro-callout.d.ts +12 -0
- package/dist/lib/pro-callout.js +20 -0
- package/dist/parse-args.d.ts +13 -0
- package/dist/parse-args.js +81 -0
- package/dist/programmatic.d.ts +49 -0
- package/dist/programmatic.js +89 -0
- package/dist/substitute.d.ts +31 -0
- package/dist/substitute.js +45 -0
- package/dist/validate.d.ts +8 -0
- package/dist/validate.js +70 -0
- package/package.json +47 -0
- package/templates/.claude/.gitkeep +0 -0
- package/templates/.claude/agents/web.md +80 -0
- package/templates/.claude/rules/architecture.md +62 -0
- package/templates/.claude/rules/preserve-existing-style.md +51 -0
- package/templates/.claude/skills/README.md +43 -0
- package/templates/.claude/skills/add-schema/SKILL.md +270 -0
- package/templates/.claude/skills/add-schema/references/conflict-handling.md +200 -0
- package/templates/.claude/skills/add-schema/references/file-finding.md +123 -0
- package/templates/.claude/skills/add-schema/references/schema-types.md +131 -0
- package/templates/.claude/skills/audit-site/SKILL.md +213 -0
- package/templates/.claude/skills/audit-site/references/common-errors.md +113 -0
- package/templates/.claude/skills/audit-site/references/findings-glossary.md +138 -0
- package/templates/.claude/skills/audit-site/references/severity-levels.md +114 -0
- package/templates/.claude/skills/provision-config/SKILL.md +243 -0
- package/templates/.claude/skills/provision-config/references/env-vars-template.md +184 -0
- package/templates/.claude/skills/provision-config/references/runbook-template.md +248 -0
- package/templates/.claude/skills/provision-config/references/vercel-json-template.md +98 -0
- package/templates/.claude/skills/scaffold-auth/SKILL.md +261 -0
- package/templates/.claude/skills/scaffold-auth/references/env-vars.md +91 -0
- package/templates/.claude/skills/scaffold-auth/references/oauth-app-setup.md +171 -0
- package/templates/.claude/skills/scaffold-commerce/SKILL.md +310 -0
- package/templates/.claude/skills/scaffold-commerce/references/lookup-keys-template.md +71 -0
- package/templates/.claude/skills/scaffold-commerce/references/marketplace-brand-pages.md +83 -0
- package/templates/.claude/skills/scaffold-commerce/templates/marketplace-cta-route.tsx.tmpl +72 -0
- package/templates/.claude/skills/scaffold-page/SKILL.md +243 -0
- package/templates/.claude/skills/scaffold-page/references/page-types.md +169 -0
- package/templates/.claude/skills/scaffold-page/templates/content.mdx.tmpl +28 -0
- package/templates/.claude/skills/scaffold-page/templates/route.tsx.tmpl +28 -0
- package/templates/.claude/skills/suggest-site-pages/SKILL.md +242 -0
- package/templates/.claude/skills/suggest-site-pages/references/categories.md +287 -0
- package/templates/.env.example +205 -0
- package/templates/.gitkeep +2 -0
- package/templates/CLAUDE.md +142 -0
- package/templates/CONVENTIONS.md +222 -0
- package/templates/README.md +110 -0
- package/templates/apps/api/.env.example +40 -0
- package/templates/apps/api/CLAUDE.md +63 -0
- package/templates/apps/api/api/index.ts +144 -0
- package/templates/apps/api/jest.config.cjs +74 -0
- package/templates/apps/api/package.json +54 -0
- package/templates/apps/api/src/__tests__/factories/content-fixture.ts +138 -0
- package/templates/apps/api/src/__tests__/factories/index.ts +70 -0
- package/templates/apps/api/src/__tests__/factories/lead-fixture.ts +82 -0
- package/templates/apps/api/src/__tests__/index.test.ts +118 -0
- package/templates/apps/api/src/__tests__/server.test.ts +207 -0
- package/templates/apps/api/src/__tests__/services/enrichment-shim.test.ts +126 -0
- package/templates/apps/api/src/__tests__/setup.ts +24 -0
- package/templates/apps/api/src/cli.ts +30 -0
- package/templates/apps/api/src/config/__tests__/index.test.ts +97 -0
- package/templates/apps/api/src/config/index.ts +56 -0
- package/templates/apps/api/src/index.ts +32 -0
- package/templates/apps/api/src/lib/__mocks__/prisma-client.js +15 -0
- package/templates/apps/api/src/lib/__mocks__/prisma.ts +45 -0
- package/templates/apps/api/src/lib/__tests__/content-adapter.test.ts +178 -0
- package/templates/apps/api/src/lib/__tests__/error-serializer.test.ts +100 -0
- package/templates/apps/api/src/lib/__tests__/errors.test.ts +94 -0
- package/templates/apps/api/src/lib/__tests__/file-fallback.test.ts +144 -0
- package/templates/apps/api/src/lib/__tests__/fixtures/HomePage/home.mdx +8 -0
- package/templates/apps/api/src/lib/__tests__/lead-capture-store.test.ts +227 -0
- package/templates/apps/api/src/lib/__tests__/outbound-http.test.ts +125 -0
- package/templates/apps/api/src/lib/__tests__/prisma.test.ts +165 -0
- package/templates/apps/api/src/lib/__tests__/require-paid-tier.test.ts +129 -0
- package/templates/apps/api/src/lib/__tests__/stripe.test.ts +74 -0
- package/templates/apps/api/src/lib/content-adapter.ts +86 -0
- package/templates/apps/api/src/lib/error-serializer.ts +77 -0
- package/templates/apps/api/src/lib/errors.ts +95 -0
- package/templates/apps/api/src/lib/file-fallback.ts +87 -0
- package/templates/apps/api/src/lib/lead-capture-store.ts +110 -0
- package/templates/apps/api/src/lib/locales.ts +201 -0
- package/templates/apps/api/src/lib/outbound-http.ts +122 -0
- package/templates/apps/api/src/lib/prisma.ts +21 -0
- package/templates/apps/api/src/lib/require-paid-tier.ts +53 -0
- package/templates/apps/api/src/lib/stripe.ts +30 -0
- package/templates/apps/api/src/lib/webhook-idempotency.ts +92 -0
- package/templates/apps/api/src/middleware/__tests__/adversarial/bearer-token-format.test.ts +111 -0
- package/templates/apps/api/src/middleware/__tests__/adversarial/cookie-or-bearer-precedence.test.ts +172 -0
- package/templates/apps/api/src/middleware/__tests__/adversarial/csrf-bearer-skip.test.ts +119 -0
- package/templates/apps/api/src/middleware/__tests__/adversarial/csrf-cookie-path.test.ts +138 -0
- package/templates/apps/api/src/middleware/__tests__/adversarial/session-fixation.test.ts +149 -0
- package/templates/apps/api/src/middleware/__tests__/adversarial/session-timeout.test.ts +139 -0
- package/templates/apps/api/src/middleware/__tests__/auth.bearer-path.test.ts +175 -0
- package/templates/apps/api/src/middleware/__tests__/auth.both-present-precedence.test.ts +76 -0
- package/templates/apps/api/src/middleware/__tests__/auth.cookie-path.test.ts +153 -0
- package/templates/apps/api/src/middleware/__tests__/auth.neither-present.test.ts +72 -0
- package/templates/apps/api/src/middleware/__tests__/rate-limit.test.ts +292 -0
- package/templates/apps/api/src/middleware/auth.ts +246 -0
- package/templates/apps/api/src/middleware/rate-limit.ts +132 -0
- package/templates/apps/api/src/openapi/__tests__/openapi.test.ts +129 -0
- package/templates/apps/api/src/openapi/index.ts +12 -0
- package/templates/apps/api/src/openapi/spec.ts +408 -0
- package/templates/apps/api/src/routes/auth/__tests__/auth-tokens.functional.test.ts +193 -0
- package/templates/apps/api/src/routes/auth/__tests__/auth-user.functional.test.ts +201 -0
- package/templates/apps/api/src/routes/auth/__tests__/tokens.test.ts +294 -0
- package/templates/apps/api/src/routes/auth/__tests__/user.test.ts +486 -0
- package/templates/apps/api/src/routes/auth/tokens.ts +199 -0
- package/templates/apps/api/src/routes/auth/user.ts +244 -0
- package/templates/apps/api/src/routes/checkout/__tests__/sessions.test.ts +588 -0
- package/templates/apps/api/src/routes/checkout/index.ts +13 -0
- package/templates/apps/api/src/routes/checkout/sessions.ts +185 -0
- package/templates/apps/api/src/routes/content/__tests__/create.test.ts +239 -0
- package/templates/apps/api/src/routes/content/__tests__/delete.test.ts +201 -0
- package/templates/apps/api/src/routes/content/__tests__/get-page.test.ts +141 -0
- package/templates/apps/api/src/routes/content/__tests__/list-pages.test.ts +122 -0
- package/templates/apps/api/src/routes/content/__tests__/list-types.test.ts +44 -0
- package/templates/apps/api/src/routes/content/__tests__/locale.test.ts +118 -0
- package/templates/apps/api/src/routes/content/__tests__/rate-limit.test.ts +51 -0
- package/templates/apps/api/src/routes/content/__tests__/update.test.ts +252 -0
- package/templates/apps/api/src/routes/content/create.ts +114 -0
- package/templates/apps/api/src/routes/content/delete.ts +81 -0
- package/templates/apps/api/src/routes/content/get-page.ts +98 -0
- package/templates/apps/api/src/routes/content/index.ts +32 -0
- package/templates/apps/api/src/routes/content/list-pages.ts +83 -0
- package/templates/apps/api/src/routes/content/list-types.ts +19 -0
- package/templates/apps/api/src/routes/content/rate-limit.ts +13 -0
- package/templates/apps/api/src/routes/content/slug.ts +9 -0
- package/templates/apps/api/src/routes/content/update.ts +111 -0
- package/templates/apps/api/src/routes/leads/__tests__/index.test.ts +415 -0
- package/templates/apps/api/src/routes/leads/__tests__/track.test.ts +165 -0
- package/templates/apps/api/src/routes/leads/index.ts +130 -0
- package/templates/apps/api/src/routes/test/auth/__tests__/session.test.ts +296 -0
- package/templates/apps/api/src/routes/test/auth/session.ts +141 -0
- package/templates/apps/api/src/routes/webhooks/README.md +57 -0
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-idempotency.test.ts +247 -0
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-rate-limit.test.ts +198 -0
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe.test.ts +633 -0
- package/templates/apps/api/src/routes/webhooks/index.ts +41 -0
- package/templates/apps/api/src/routes/webhooks/stripe.ts +253 -0
- package/templates/apps/api/src/server.ts +157 -0
- package/templates/apps/api/src/services/__tests__/lead-routing.test.ts +395 -0
- package/templates/apps/api/src/services/enrichment-shim.ts +53 -0
- package/templates/apps/api/src/services/lead-routing.ts +338 -0
- package/templates/apps/api/tsconfig.json +34 -0
- package/templates/apps/api/vercel.json +17 -0
- package/templates/apps/mcp/.env.example +52 -0
- package/templates/apps/mcp/CLAUDE.md +84 -0
- package/templates/apps/mcp/__tests__/abuse/daily-cap.test.ts +52 -0
- package/templates/apps/mcp/__tests__/abuse/email-validator.test.ts +46 -0
- package/templates/apps/mcp/__tests__/abuse/honeypot.test.ts +36 -0
- package/templates/apps/mcp/__tests__/abuse/user-agent-deny.test.ts +54 -0
- package/templates/apps/mcp/__tests__/aeo-cli-parity.test.ts +110 -0
- package/templates/apps/mcp/__tests__/audit-single-page.test.ts +213 -0
- package/templates/apps/mcp/__tests__/audit.test.ts +217 -0
- package/templates/apps/mcp/__tests__/catalog-drift.test.ts +52 -0
- package/templates/apps/mcp/__tests__/create_page.test.ts +201 -0
- package/templates/apps/mcp/__tests__/delete_page.test.ts +176 -0
- package/templates/apps/mcp/__tests__/get_business_hours.test.ts +82 -0
- package/templates/apps/mcp/__tests__/get_faq.test.ts +80 -0
- package/templates/apps/mcp/__tests__/get_locations.test.ts +65 -0
- package/templates/apps/mcp/__tests__/get_offerings.test.ts +90 -0
- package/templates/apps/mcp/__tests__/get_pricing.test.ts +80 -0
- package/templates/apps/mcp/__tests__/get_site_info.test.ts +81 -0
- package/templates/apps/mcp/__tests__/http-transport.test.ts +323 -0
- package/templates/apps/mcp/__tests__/lib/errors.test.ts +75 -0
- package/templates/apps/mcp/__tests__/lib/require-paid-tier.test.ts +75 -0
- package/templates/apps/mcp/__tests__/list_pages.test.ts +112 -0
- package/templates/apps/mcp/__tests__/locale.test.ts +135 -0
- package/templates/apps/mcp/__tests__/parity.test.ts +205 -0
- package/templates/apps/mcp/__tests__/purchase-disabled.test.ts +34 -0
- package/templates/apps/mcp/__tests__/read_content.test.ts +153 -0
- package/templates/apps/mcp/__tests__/request_callback.test.ts +163 -0
- package/templates/apps/mcp/__tests__/search_content.test.ts +153 -0
- package/templates/apps/mcp/__tests__/server.test.ts +115 -0
- package/templates/apps/mcp/__tests__/submit_lead.test.ts +165 -0
- package/templates/apps/mcp/__tests__/subscribe_newsletter.test.ts +161 -0
- package/templates/apps/mcp/__tests__/tools/purchase.test.ts +227 -0
- package/templates/apps/mcp/__tests__/tools/scaffold.test.ts +237 -0
- package/templates/apps/mcp/__tests__/update_page.test.ts +195 -0
- package/templates/apps/mcp/jest.config.cjs +82 -0
- package/templates/apps/mcp/package.json +37 -0
- package/templates/apps/mcp/src/abuse/daily-cap.ts +47 -0
- package/templates/apps/mcp/src/abuse/email-validator.ts +25 -0
- package/templates/apps/mcp/src/abuse/honeypot.ts +21 -0
- package/templates/apps/mcp/src/abuse/index.ts +111 -0
- package/templates/apps/mcp/src/abuse/user-agent-deny.ts +58 -0
- package/templates/apps/mcp/src/http-transport.ts +303 -0
- package/templates/apps/mcp/src/index.ts +67 -0
- package/templates/apps/mcp/src/lib/audit-single-page.ts +194 -0
- package/templates/apps/mcp/src/lib/errors.ts +61 -0
- package/templates/apps/mcp/src/lib/locales.ts +171 -0
- package/templates/apps/mcp/src/lib/require-paid-tier.ts +44 -0
- package/templates/apps/mcp/src/lib/resolve-locale.ts +30 -0
- package/templates/apps/mcp/src/server.ts +139 -0
- package/templates/apps/mcp/src/tools/audit.ts +103 -0
- package/templates/apps/mcp/src/tools/capture_lead.ts +52 -0
- package/templates/apps/mcp/src/tools/create_page.ts +95 -0
- package/templates/apps/mcp/src/tools/delete_page.ts +73 -0
- package/templates/apps/mcp/src/tools/get_business_hours.ts +66 -0
- package/templates/apps/mcp/src/tools/get_faq.ts +69 -0
- package/templates/apps/mcp/src/tools/get_locations.ts +85 -0
- package/templates/apps/mcp/src/tools/get_offerings.ts +66 -0
- package/templates/apps/mcp/src/tools/get_pricing.ts +74 -0
- package/templates/apps/mcp/src/tools/get_site_info.ts +84 -0
- package/templates/apps/mcp/src/tools/index.ts +125 -0
- package/templates/apps/mcp/src/tools/list_pages.ts +72 -0
- package/templates/apps/mcp/src/tools/purchase.ts +89 -0
- package/templates/apps/mcp/src/tools/read_content.ts +61 -0
- package/templates/apps/mcp/src/tools/request_callback.ts +51 -0
- package/templates/apps/mcp/src/tools/scaffold.ts +119 -0
- package/templates/apps/mcp/src/tools/search_content.ts +59 -0
- package/templates/apps/mcp/src/tools/subscribe_newsletter.ts +47 -0
- package/templates/apps/mcp/src/tools/update_page.ts +91 -0
- package/templates/apps/mcp/tsconfig.json +19 -0
- package/templates/apps/web/.env.example +47 -0
- package/templates/apps/web/CLAUDE.md +81 -0
- package/templates/apps/web/__tests__/auth/adversarial/cookie-attributes.test.ts +94 -0
- package/templates/apps/web/__tests__/auth/adversarial/oauth-state-parameter.test.ts +75 -0
- package/templates/apps/web/__tests__/auth/adversarial/redirect-uri-allowlist.test.ts +82 -0
- package/templates/apps/web/__tests__/auth/env-helpers.test.ts +168 -0
- package/templates/apps/web/__tests__/authority-list-routes.test.tsx +208 -0
- package/templates/apps/web/__tests__/better-stack.test.ts +66 -0
- package/templates/apps/web/__tests__/blog-dir-resolution.test.ts +87 -0
- package/templates/apps/web/__tests__/blog-source-populated.test.ts +130 -0
- package/templates/apps/web/__tests__/data-testid-coverage.test.tsx +60 -0
- package/templates/apps/web/__tests__/google-analytics.test.tsx +104 -0
- package/templates/apps/web/__tests__/i18n/middleware.test.ts +119 -0
- package/templates/apps/web/__tests__/i18n/routing.test.ts +114 -0
- package/templates/apps/web/__tests__/i18n/translations.test.ts +191 -0
- package/templates/apps/web/__tests__/json-ld.test.ts +98 -0
- package/templates/apps/web/__tests__/knowledge-events-routes.test.tsx +580 -0
- package/templates/apps/web/__tests__/layout-stealth.test.ts +39 -0
- package/templates/apps/web/__tests__/lighthouse-fixtures/improvement-image-shrink.tsx +103 -0
- package/templates/apps/web/__tests__/lighthouse-fixtures/override-fixture.md +114 -0
- package/templates/apps/web/__tests__/lighthouse-fixtures/regression-bloat.tsx +94 -0
- package/templates/apps/web/__tests__/page.test.tsx +230 -0
- package/templates/apps/web/__tests__/products-services-phase1.test.tsx +321 -0
- package/templates/apps/web/__tests__/projects-routes.test.tsx +392 -0
- package/templates/apps/web/__tests__/resources-downloads-integrations-phase2.test.tsx +475 -0
- package/templates/apps/web/__tests__/routes/ai-plugin-json.test.ts +53 -0
- package/templates/apps/web/__tests__/routes/blog-route.test.tsx +191 -0
- package/templates/apps/web/__tests__/routes/llms-txt.test.ts +123 -0
- package/templates/apps/web/__tests__/routes/robots-txt.test.ts +52 -0
- package/templates/apps/web/__tests__/routes/sitemap-xml.test.ts +78 -0
- package/templates/apps/web/__tests__/routes/well-known-mcp.test.ts +203 -0
- package/templates/apps/web/__tests__/section-routes.test.tsx +693 -0
- package/templates/apps/web/__tests__/security-headers.test.ts +201 -0
- package/templates/apps/web/__tests__/sentry-config.test.ts +116 -0
- package/templates/apps/web/__tests__/setup.ts +82 -0
- package/templates/apps/web/__tests__/sitemap-locales.test.ts +415 -0
- package/templates/apps/web/__tests__/standalone-informational-routes.test.tsx +844 -0
- package/templates/apps/web/app/.well-known/ai-plugin.json/route.ts +81 -0
- package/templates/apps/web/app/.well-known/mcp.json/build-manifest.ts +110 -0
- package/templates/apps/web/app/.well-known/mcp.json/route.ts +58 -0
- package/templates/apps/web/app/[locale]/__tests__/layout.test.tsx +120 -0
- package/templates/apps/web/app/[locale]/__tests__/page-renderer-migration.test.tsx +202 -0
- package/templates/apps/web/app/[locale]/about/page.tsx +31 -0
- package/templates/apps/web/app/[locale]/blog/[[...slug]]/page.tsx +173 -0
- package/templates/apps/web/app/[locale]/careers/[slug]/page.tsx +45 -0
- package/templates/apps/web/app/[locale]/careers/__tests__/page-renderer-migration.test.tsx +117 -0
- package/templates/apps/web/app/[locale]/careers/page.tsx +25 -0
- package/templates/apps/web/app/[locale]/case-studies/[slug]/page.tsx +44 -0
- package/templates/apps/web/app/[locale]/case-studies/__tests__/page-renderer-migration.test.tsx +113 -0
- package/templates/apps/web/app/[locale]/case-studies/page.tsx +25 -0
- package/templates/apps/web/app/[locale]/clients/__tests__/page-renderer-migration.test.tsx +63 -0
- package/templates/apps/web/app/[locale]/clients/page.tsx +27 -0
- package/templates/apps/web/app/[locale]/contact/ContactForm.tsx +130 -0
- package/templates/apps/web/app/[locale]/contact/__tests__/contact.actions.test.ts +152 -0
- package/templates/apps/web/app/[locale]/contact/__tests__/page-renderer-migration.test.tsx +92 -0
- package/templates/apps/web/app/[locale]/contact/contact.actions.ts +79 -0
- package/templates/apps/web/app/[locale]/contact/error.tsx +24 -0
- package/templates/apps/web/app/[locale]/contact/page.tsx +38 -0
- package/templates/apps/web/app/[locale]/courses/[slug]/page.tsx +34 -0
- package/templates/apps/web/app/[locale]/courses/__tests__/page-renderer-migration.test.tsx +119 -0
- package/templates/apps/web/app/[locale]/courses/page.tsx +25 -0
- package/templates/apps/web/app/[locale]/dev/purchase/__tests__/actions.test.ts +160 -0
- package/templates/apps/web/app/[locale]/dev/purchase/error.tsx +25 -0
- package/templates/apps/web/app/[locale]/dev/purchase/page.tsx +117 -0
- package/templates/apps/web/app/[locale]/dev/purchase/purchase.actions.ts +58 -0
- package/templates/apps/web/app/[locale]/docs/[[...slug]]/page.tsx +118 -0
- package/templates/apps/web/app/[locale]/downloads/__tests__/page-renderer-migration.test.tsx +72 -0
- package/templates/apps/web/app/[locale]/downloads/page.tsx +25 -0
- package/templates/apps/web/app/[locale]/events/[slug]/page.tsx +47 -0
- package/templates/apps/web/app/[locale]/events/__tests__/page-renderer-migration.test.tsx +130 -0
- package/templates/apps/web/app/[locale]/events/page.tsx +25 -0
- package/templates/apps/web/app/[locale]/faq/page.tsx +36 -0
- package/templates/apps/web/app/[locale]/how-to/[slug]/page.tsx +34 -0
- package/templates/apps/web/app/[locale]/how-to/__tests__/page-renderer-migration.test.tsx +78 -0
- package/templates/apps/web/app/[locale]/how-to/page.tsx +40 -0
- package/templates/apps/web/app/[locale]/integrations/[slug]/page.tsx +43 -0
- package/templates/apps/web/app/[locale]/integrations/__tests__/page-renderer-migration.test.tsx +129 -0
- package/templates/apps/web/app/[locale]/integrations/page.tsx +25 -0
- package/templates/apps/web/app/[locale]/launch-service/page.tsx +31 -0
- package/templates/apps/web/app/[locale]/layout.tsx +241 -0
- package/templates/apps/web/app/[locale]/page.tsx +41 -0
- package/templates/apps/web/app/[locale]/partners/[slug]/page.tsx +44 -0
- package/templates/apps/web/app/[locale]/partners/__tests__/page-renderer-migration.test.tsx +113 -0
- package/templates/apps/web/app/[locale]/partners/page.tsx +25 -0
- package/templates/apps/web/app/[locale]/products/[slug]/page.tsx +43 -0
- package/templates/apps/web/app/[locale]/products/__tests__/page-renderer-migration.test.tsx +129 -0
- package/templates/apps/web/app/[locale]/products/page.tsx +25 -0
- package/templates/apps/web/app/[locale]/projects/[slug]/page.tsx +39 -0
- package/templates/apps/web/app/[locale]/projects/__tests__/page-renderer-migration.test.tsx +138 -0
- package/templates/apps/web/app/[locale]/projects/page.tsx +30 -0
- package/templates/apps/web/app/[locale]/resources/[slug]/page.tsx +51 -0
- package/templates/apps/web/app/[locale]/resources/__tests__/page-renderer-migration.test.tsx +117 -0
- package/templates/apps/web/app/[locale]/resources/page.tsx +27 -0
- package/templates/apps/web/app/[locale]/services/[slug]/page.tsx +43 -0
- package/templates/apps/web/app/[locale]/services/__tests__/page-renderer-migration.test.tsx +129 -0
- package/templates/apps/web/app/[locale]/services/page.tsx +25 -0
- package/templates/apps/web/app/[locale]/software/[slug]/page.tsx +34 -0
- package/templates/apps/web/app/[locale]/software/__tests__/page-renderer-migration.test.tsx +81 -0
- package/templates/apps/web/app/[locale]/software/page.tsx +39 -0
- package/templates/apps/web/app/[locale]/tech-articles/[slug]/page.tsx +34 -0
- package/templates/apps/web/app/[locale]/tech-articles/__tests__/page-renderer-migration.test.tsx +82 -0
- package/templates/apps/web/app/[locale]/tech-articles/page.tsx +39 -0
- package/templates/apps/web/app/[locale]/testimonials/__tests__/page-renderer-migration.test.tsx +63 -0
- package/templates/apps/web/app/[locale]/testimonials/page.tsx +27 -0
- package/templates/apps/web/app/[locale]/use-cases/__tests__/page-renderer-migration.test.tsx +63 -0
- package/templates/apps/web/app/[locale]/use-cases/page.tsx +27 -0
- package/templates/apps/web/app/[locale]/whitepapers/[slug]/page.tsx +34 -0
- package/templates/apps/web/app/[locale]/whitepapers/__tests__/page-renderer-migration.test.tsx +82 -0
- package/templates/apps/web/app/[locale]/whitepapers/page.tsx +39 -0
- package/templates/apps/web/app/__tests__/error-boundaries.test.tsx +152 -0
- package/templates/apps/web/app/api/auth/[...all]/route.ts +16 -0
- package/templates/apps/web/app/error-fallback.tsx +75 -0
- package/templates/apps/web/app/error.tsx +23 -0
- package/templates/apps/web/app/layout.tsx +18 -0
- package/templates/apps/web/app/llms.txt/route.ts +101 -0
- package/templates/apps/web/app/not-found.tsx +48 -0
- package/templates/apps/web/app/og/__tests__/route.test.ts +164 -0
- package/templates/apps/web/app/og/route.tsx +135 -0
- package/templates/apps/web/app/robots.txt/route.ts +36 -0
- package/templates/apps/web/app/sitemap.xml/route.ts +146 -0
- package/templates/apps/web/auth.ts +141 -0
- package/templates/apps/web/components/ThemeToggle.tsx +60 -0
- package/templates/apps/web/components/google-analytics.tsx +34 -0
- package/templates/apps/web/content/en/blog/index.mdx +15 -0
- package/templates/apps/web/content/en/blog/launching-ailk.mdx +20 -0
- package/templates/apps/web/content/en/docs/getting-started.mdx +30 -0
- package/templates/apps/web/i18n/request.ts +36 -0
- package/templates/apps/web/jest.config.cjs +100 -0
- package/templates/apps/web/lib/__mocks__/next-mdx-remote-rsc.js +12 -0
- package/templates/apps/web/lib/__mocks__/source-server.js +31 -0
- package/templates/apps/web/lib/__tests__/og.test.ts +65 -0
- package/templates/apps/web/lib/auth-env.ts +66 -0
- package/templates/apps/web/lib/blog-list-data.ts +95 -0
- package/templates/apps/web/lib/blog-post-data.ts +79 -0
- package/templates/apps/web/lib/nav-config.ts +13 -0
- package/templates/apps/web/lib/observability/better-stack.ts +27 -0
- package/templates/apps/web/lib/og.ts +23 -0
- package/templates/apps/web/lib/prisma-for-auth.ts +34 -0
- package/templates/apps/web/lib/source.ts +34 -0
- package/templates/apps/web/messages/en.json +131 -0
- package/templates/apps/web/middleware.ts +80 -0
- package/templates/apps/web/next.config.mjs +167 -0
- package/templates/apps/web/package.json +62 -0
- package/templates/apps/web/public/.well-known/security.txt +17 -0
- package/templates/apps/web/public/android-chrome-192x192.png +0 -0
- package/templates/apps/web/public/android-chrome-512x512.png +0 -0
- package/templates/apps/web/public/apple-touch-icon.png +0 -0
- package/templates/apps/web/public/favicon-16x16.png +0 -0
- package/templates/apps/web/public/favicon-32x32.png +0 -0
- package/templates/apps/web/public/favicon.ico +0 -0
- package/templates/apps/web/public/favicon.svg +4 -0
- package/templates/apps/web/public/logo-dark.svg +21 -0
- package/templates/apps/web/public/logo-light.svg +21 -0
- package/templates/apps/web/public/logomark-dark.svg +4 -0
- package/templates/apps/web/public/logomark-light.svg +4 -0
- package/templates/apps/web/public/og-default.png +0 -0
- package/templates/apps/web/public/site.webmanifest +19 -0
- package/templates/apps/web/scripts/assert-content-bundled.ts +55 -0
- package/templates/apps/web/security-headers.config.ts +132 -0
- package/templates/apps/web/sentry.client.config.ts +27 -0
- package/templates/apps/web/sentry.edge.config.ts +15 -0
- package/templates/apps/web/sentry.server.config.ts +20 -0
- package/templates/apps/web/source.config.ts +78 -0
- package/templates/apps/web/src/components/SiteNav.tsx +21 -0
- package/templates/apps/web/src/lib/routes.ts +37 -0
- package/templates/apps/web/tsconfig.json +35 -0
- package/templates/apps/web/types/messages.d.ts +19 -0
- package/templates/content/.gitkeep +0 -0
- package/templates/content/CLAUDE.md +85 -0
- package/templates/content/_site.mdx +38 -0
- package/templates/content/ar/HomePage/home.mdx +123 -0
- package/templates/content/ar/_site.mdx +35 -0
- package/templates/content/de/_site.mdx +29 -0
- package/templates/content/en/.gitkeep +0 -0
- package/templates/content/en/AboutPage/about.mdx +19 -0
- package/templates/content/en/AboutPage/about.schema.json +82 -0
- package/templates/content/en/BookCall/book-call.mdx +19 -0
- package/templates/content/en/BookCall/book-call.schema.json +121 -0
- package/templates/content/en/BreadcrumbList/site-breadcrumbs.mdx +20 -0
- package/templates/content/en/CareersList/careers.mdx +24 -0
- package/templates/content/en/CaseStudiesList/case-studies.mdx +22 -0
- package/templates/content/en/CaseStudiesList/showcase.mdx +8 -0
- package/templates/content/en/CaseStudy/ailk-aeo-rollout.mdx +32 -0
- package/templates/content/en/CaseStudy/schema-builder-migration.mdx +41 -0
- package/templates/content/en/ClientsList/clients.mdx +38 -0
- package/templates/content/en/ContactPage/contact.mdx +19 -0
- package/templates/content/en/ContactPage/contact.schema.json +100 -0
- package/templates/content/en/ContactPoint/primary.mdx +14 -0
- package/templates/content/en/Course/aeo-fundamentals.mdx +37 -0
- package/templates/content/en/Course/schema-builder-workshop.mdx +62 -0
- package/templates/content/en/CoursesList/courses.mdx +22 -0
- package/templates/content/en/DownloadsList/downloads.mdx +22 -0
- package/templates/content/en/Event/aeo-office-hours-may-2026.mdx +39 -0
- package/templates/content/en/Event/ailk-launch-day-2026.mdx +35 -0
- package/templates/content/en/EventsList/events.mdx +26 -0
- package/templates/content/en/FAQPage/faq.mdx +420 -0
- package/templates/content/en/FAQPage/faq.schema.json +231 -0
- package/templates/content/en/GlossaryList/glossary.mdx +19 -0
- package/templates/content/en/GlossaryList/glossary.schema.json +300 -0
- package/templates/content/en/HomePage/home.mdx +312 -0
- package/templates/content/en/HomePage/home.schema.json +88 -0
- package/templates/content/en/HomePage/launch-service.mdx +475 -0
- package/templates/content/en/HomePage/launch-service.schema.json +138 -0
- package/templates/content/en/HowTo/add-mdx-content.mdx +38 -0
- package/templates/content/en/HowTo/configure-aeo-scoring.mdx +35 -0
- package/templates/content/en/HowTo/set-up-json-ld.mdx +36 -0
- package/templates/content/en/Integration/github-actions.mdx +31 -0
- package/templates/content/en/Integration/openai-api.mdx +26 -0
- package/templates/content/en/Integration/vercel.mdx +32 -0
- package/templates/content/en/IntegrationsList/integrations.mdx +22 -0
- package/templates/content/en/JobPosting/content-strategist.mdx +46 -0
- package/templates/content/en/JobPosting/developer-advocate.mdx +47 -0
- package/templates/content/en/JobPosting/senior-fullstack-engineer.mdx +57 -0
- package/templates/content/en/LandingPage/aeo-audit.mdx +19 -0
- package/templates/content/en/LandingPage/aeo-audit.schema.json +92 -0
- package/templates/content/en/LandingPage/agency-waitlist.mdx +340 -0
- package/templates/content/en/LandingPage/agency-waitlist.schema.json +152 -0
- package/templates/content/en/LandingPage/developers.mdx +19 -0
- package/templates/content/en/LandingPage/developers.schema.json +109 -0
- package/templates/content/en/LandingPage/for-agencies.mdx +390 -0
- package/templates/content/en/LandingPage/for-agencies.schema.json +107 -0
- package/templates/content/en/LandingPage/for-ai-search-agencies.mdx +417 -0
- package/templates/content/en/LandingPage/for-ai-search-agencies.schema.json +105 -0
- package/templates/content/en/LandingPage/for-businesses.mdx +19 -0
- package/templates/content/en/LandingPage/for-businesses.schema.json +96 -0
- package/templates/content/en/LandingPage/platform.mdx +369 -0
- package/templates/content/en/LandingPage/platform.schema.json +166 -0
- package/templates/content/en/LandingPage/vs-ai-website-builders.mdx +19 -0
- package/templates/content/en/LandingPage/vs-ai-website-builders.schema.json +102 -0
- package/templates/content/en/LandingPage/vs-wordpress.mdx +19 -0
- package/templates/content/en/LandingPage/vs-wordpress.schema.json +53 -0
- package/templates/content/en/NewsletterSignup/newsletter.mdx +236 -0
- package/templates/content/en/NewsletterSignup/newsletter.schema.json +91 -0
- package/templates/content/en/Organization/site-owner.mdx +16 -0
- package/templates/content/en/Partner/prisma.mdx +31 -0
- package/templates/content/en/Partner/supabase.mdx +30 -0
- package/templates/content/en/Partner/vercel.mdx +28 -0
- package/templates/content/en/PartnersList/partners.mdx +22 -0
- package/templates/content/en/Person/founder.mdx +18 -0
- package/templates/content/en/Pricing/pricing.mdx +538 -0
- package/templates/content/en/Pricing/pricing.schema.json +209 -0
- package/templates/content/en/PrivacyPage/privacy.mdx +165 -0
- package/templates/content/en/PrivacyPage/privacy.schema.json +64 -0
- package/templates/content/en/Product/ailk.mdx +19 -0
- package/templates/content/en/Product/ailk.schema.json +94 -0
- package/templates/content/en/Product/api-launch-kit.mdx +26 -0
- package/templates/content/en/Product/launch-kit.mdx +28 -0
- package/templates/content/en/ProductsList/products.mdx +26 -0
- package/templates/content/en/Project/ailk-phase-2.mdx +54 -0
- package/templates/content/en/ProjectsList/projects.mdx +25 -0
- package/templates/content/en/ResourceDetail/aeo-scoring-guide.mdx +27 -0
- package/templates/content/en/ResourceDetail/content-model-whitepaper.mdx +28 -0
- package/templates/content/en/ResourceDetail/schema-org-quick-reference.mdx +39 -0
- package/templates/content/en/ResourcesHub/resources.mdx +22 -0
- package/templates/content/en/Service/consulting.mdx +22 -0
- package/templates/content/en/Service/implementation.mdx +30 -0
- package/templates/content/en/Service/launch-service.mdx +232 -0
- package/templates/content/en/Service/launch.mdx +228 -0
- package/templates/content/en/ServicesList/services.mdx +84 -0
- package/templates/content/en/SoftwareProduct/ailk-aeo.mdx +44 -0
- package/templates/content/en/SoftwareProduct/ailk-content-adapters.mdx +47 -0
- package/templates/content/en/SoftwareProduct/ailk-schema.mdx +49 -0
- package/templates/content/en/TeamList/team.mdx +63 -0
- package/templates/content/en/TeamMember/founder.mdx +72 -0
- package/templates/content/en/TermsPage/terms.mdx +19 -0
- package/templates/content/en/TermsPage/terms.schema.json +99 -0
- package/templates/content/en/TestimonialsList/testimonials.mdx +44 -0
- package/templates/content/en/UseCasesList/use-cases.mdx +30 -0
- package/templates/content/en/Whitepaper/ax-first-product-development.mdx +27 -0
- package/templates/content/en/Whitepaper/open-core-commercial-strategy.mdx +27 -0
- package/templates/content/en/Whitepaper/structured-data-for-answer-engines.mdx +31 -0
- package/templates/content/en-XA/AboutPage/about.mdx +8 -0
- package/templates/content/en-XA/FAQPage/faq.mdx +8 -0
- package/templates/content/en-XA/HomePage/home.mdx +8 -0
- package/templates/content/es/_site.mdx +30 -0
- package/templates/content/fr/_site.mdx +30 -0
- package/templates/content/ja/_site.mdx +30 -0
- package/templates/content/pt-BR/AboutPage/about.mdx +8 -0
- package/templates/content/pt-BR/FAQPage/faq.mdx +8 -0
- package/templates/content/pt-BR/HomePage/home.mdx +23 -0
- package/templates/database/CHANGELOG.md +5 -0
- package/templates/database/README.md +234 -0
- package/templates/database/__tests__/user-cascade.test.ts +125 -0
- package/templates/database/auth/.gitkeep +0 -0
- package/templates/database/config/.gitkeep +0 -0
- package/templates/database/content/.gitkeep +0 -0
- package/templates/database/inbox/.gitkeep +0 -0
- package/templates/database/inbox/README.md +3 -0
- package/templates/database/inbox/__tests__/schema.test.ts +40 -0
- package/templates/database/inbox/schema.prisma +52 -0
- package/templates/database/jest.config.cjs +29 -0
- package/templates/database/migrations/20260508000000_add_inbox_namespace/migration.sql +328 -0
- package/templates/database/migrations/20260513000000_better_auth_migration/migration.sql +100 -0
- package/templates/database/migrations/20260515000000_add_user_billing_fields/migration.sql +28 -0
- package/templates/database/migrations/20260516000000_add_user_tier_care_plan_seat/migration.sql +25 -0
- package/templates/database/migrations/20260518000000_add_telemetry_records/migration.sql +42 -0
- package/templates/database/migrations/20260525000000_theme_wiring/migration.sql +67 -0
- package/templates/database/migrations/20260710000000_retire_commercial_tier/migration.sql +21 -0
- package/templates/database/migrations/migration_lock.toml +3 -0
- package/templates/database/ops/.gitkeep +0 -0
- package/templates/database/package.json +45 -0
- package/templates/database/prisma.config.ts +20 -0
- package/templates/database/schema.prisma +487 -0
- package/templates/database/scripts/db-generate-locked.sh +80 -0
- package/templates/database/seed-test.ts +85 -0
- package/templates/database/tsconfig.build.json +16 -0
- package/templates/database/tsconfig.json +9 -0
- package/templates/package.json +125 -0
- package/templates/pnpm-workspace.yaml +6 -0
- package/templates/project.yaml +59 -0
- package/templates/tsconfig.base.json +18 -0
- 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");
|