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,248 @@
|
|
|
1
|
+
# `RUNBOOK.md` Template
|
|
2
|
+
|
|
3
|
+
The `provision-config` skill emits this runbook at the consumer's
|
|
4
|
+
project root. It documents pre-deploy steps, the **critical**
|
|
5
|
+
leads-persistence caveat, and the three named upgrade paths.
|
|
6
|
+
|
|
7
|
+
The skill must verify all three named persistence-section headings
|
|
8
|
+
are present after emit (per SKILL.md Step 6 validation). If any is
|
|
9
|
+
missing, the skill has a bug.
|
|
10
|
+
|
|
11
|
+
## Template
|
|
12
|
+
|
|
13
|
+
```markdown
|
|
14
|
+
# RUNBOOK — Production Operations
|
|
15
|
+
|
|
16
|
+
This runbook is generated by the `provision-config` skill. It covers
|
|
17
|
+
what to do before and after deploying to Vercel, plus the
|
|
18
|
+
operational caveats AILK ships with.
|
|
19
|
+
|
|
20
|
+
If you re-run `provision-config`, new sections may be appended at
|
|
21
|
+
the end under "## Added by provision-config." Existing sections are
|
|
22
|
+
not modified by the skill.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Pre-deploy checklist
|
|
27
|
+
|
|
28
|
+
Before you click Deploy in Vercel:
|
|
29
|
+
|
|
30
|
+
- [ ] **Add a Vercel project** pointed at this repo
|
|
31
|
+
(`vercel link` from the CLI, or the dashboard).
|
|
32
|
+
- [ ] **Set environment variables** in Vercel's project dashboard
|
|
33
|
+
(Settings → Environment Variables). Use `.env.example` as the
|
|
34
|
+
contract — every variable listed there should have a value
|
|
35
|
+
set in Vercel before deploy.
|
|
36
|
+
- [ ] **Configure your custom domain** if you have one (Vercel
|
|
37
|
+
Project → Settings → Domains). Vercel handles TLS automatically.
|
|
38
|
+
- [ ] **Pick a leads-persistence backend** — see the three named
|
|
39
|
+
upgrade paths below. **Do not deploy without picking one** if
|
|
40
|
+
your site captures leads. AILK's default `leads.jsonl`
|
|
41
|
+
fallback does not persist on Vercel's ephemeral filesystem.
|
|
42
|
+
- [ ] **Register production OAuth callbacks** if you used
|
|
43
|
+
`scaffold-auth` and activated Google or GitHub. Each provider
|
|
44
|
+
needs the prod callback URL added to its OAuth app settings.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Operations — leads.jsonl persistence
|
|
49
|
+
|
|
50
|
+
> **Critical:** AILK's default lead-capture writes to
|
|
51
|
+
> `apps/api/leads.jsonl`. On Vercel's ephemeral filesystem, this
|
|
52
|
+
> file **does not persist** across cold starts. Leads captured
|
|
53
|
+
> during one container's lifetime are lost when that container
|
|
54
|
+
> shuts down.
|
|
55
|
+
|
|
56
|
+
You **must** pick a persistence backend before going live or you
|
|
57
|
+
will lose leads. Pick one of the three sections below based on
|
|
58
|
+
your situation:
|
|
59
|
+
|
|
60
|
+
- Cheapest fix, drop-in, native Vercel — **Vercel KV**
|
|
61
|
+
- One provider for db + auth + storage — **Supabase**
|
|
62
|
+
- Already have Postgres elsewhere — **Postgres via `@working-theory/database`**
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## Persistence upgrade — Vercel KV
|
|
67
|
+
|
|
68
|
+
**When to pick:** you want the cheapest fix, no new infra, and
|
|
69
|
+
you're already on Vercel. Vercel KV is Redis-compatible key-value
|
|
70
|
+
storage, native to the Vercel dashboard.
|
|
71
|
+
|
|
72
|
+
**Setup:**
|
|
73
|
+
|
|
74
|
+
1. Vercel Dashboard → Storage → Create Database → KV.
|
|
75
|
+
2. Connect to your project. Vercel auto-populates
|
|
76
|
+
`KV_REST_API_URL` and `KV_REST_API_TOKEN` in your project
|
|
77
|
+
environment.
|
|
78
|
+
3. Pull updated env vars locally: `vercel env pull`.
|
|
79
|
+
4. Switch the lead-capture writer in your code from JSONL to KV
|
|
80
|
+
(`@working-theory/api`'s lead-capture supports a KV adapter — see its
|
|
81
|
+
README for the wiring).
|
|
82
|
+
5. Redeploy.
|
|
83
|
+
|
|
84
|
+
**Trade-offs:** KV is fast and easy but has limits (storage
|
|
85
|
+
ceilings, access patterns). For >10K leads/month or rich querying,
|
|
86
|
+
graduate to Supabase or Postgres.
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## Persistence upgrade — Supabase
|
|
91
|
+
|
|
92
|
+
**When to pick:** you want one provider for database, auth, and
|
|
93
|
+
storage. You're not committed to NextAuth (Supabase has its own
|
|
94
|
+
auth), or you're fine running NextAuth + Supabase auth in parallel.
|
|
95
|
+
|
|
96
|
+
**Setup:**
|
|
97
|
+
|
|
98
|
+
1. Sign up at <https://supabase.com>.
|
|
99
|
+
2. Create a project.
|
|
100
|
+
3. Go to Settings → API. Copy:
|
|
101
|
+
- `Project URL` → `NEXT_PUBLIC_SUPABASE_URL`
|
|
102
|
+
- `anon public` key → `NEXT_PUBLIC_SUPABASE_ANON_KEY`
|
|
103
|
+
- `service_role` key → `SUPABASE_SERVICE_ROLE_KEY` (server-only)
|
|
104
|
+
4. Set those three env vars in Vercel project settings.
|
|
105
|
+
5. Run the AILK Supabase migration (see `@working-theory/database` Supabase
|
|
106
|
+
adapter README — the migration creates a `leads` table with the
|
|
107
|
+
AILK schema).
|
|
108
|
+
6. Switch the lead-capture writer to use the Supabase adapter.
|
|
109
|
+
7. Redeploy.
|
|
110
|
+
|
|
111
|
+
**Trade-offs:** Supabase is generous on free tier, scales well, and
|
|
112
|
+
its dashboard is excellent. The auth coexistence with NextAuth is
|
|
113
|
+
the only design wrinkle — most consumers either use NextAuth alone
|
|
114
|
+
(treating Supabase as just a Postgres host) or commit to Supabase
|
|
115
|
+
auth and remove NextAuth.
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## Persistence upgrade — Postgres via `@working-theory/database`
|
|
120
|
+
|
|
121
|
+
**When to pick:** you already have Postgres somewhere — Neon,
|
|
122
|
+
Railway, RDS, self-hosted, anywhere. You don't need a new provider
|
|
123
|
+
relationship.
|
|
124
|
+
|
|
125
|
+
**Setup:**
|
|
126
|
+
|
|
127
|
+
1. Get a Postgres connection string from your provider. Format:
|
|
128
|
+
`postgres://user:password@host:5432/dbname`.
|
|
129
|
+
2. Set `DATABASE_URL` in Vercel project settings.
|
|
130
|
+
3. Install `@working-theory/database`: `pnpm add @working-theory/database`.
|
|
131
|
+
4. Run the migration:
|
|
132
|
+
`pnpm --filter @working-theory/database run migrate:deploy` (or your
|
|
133
|
+
provider's equivalent).
|
|
134
|
+
5. The `@working-theory/database` package exposes a Prisma client tied to the
|
|
135
|
+
AILK schema; switch the lead-capture writer to use it.
|
|
136
|
+
6. Redeploy.
|
|
137
|
+
|
|
138
|
+
**Trade-offs:** most flexible, most setup. You manage the database
|
|
139
|
+
yourself (backups, connection pooling, scaling). For consumers who
|
|
140
|
+
already have Postgres in their stack, this is the natural fit.
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Custom domain + DNS
|
|
145
|
+
|
|
146
|
+
Vercel handles TLS automatically once a domain is added to your
|
|
147
|
+
project. Two paths:
|
|
148
|
+
|
|
149
|
+
- **Vercel-managed DNS** — let Vercel handle nameservers. Easiest;
|
|
150
|
+
Vercel Dashboard → Project → Settings → Domains → Add → "Manage
|
|
151
|
+
DNS Records."
|
|
152
|
+
- **External DNS** — add an A record (or CNAME for subdomains)
|
|
153
|
+
pointing at Vercel's IP, then add the domain to your project.
|
|
154
|
+
Vercel docs walk through it.
|
|
155
|
+
|
|
156
|
+
For email-sending domains (Resend, magic-link), you'll also need
|
|
157
|
+
to verify the sending domain in Resend's dashboard before
|
|
158
|
+
production magic-link emails will deliver. Resend Dashboard →
|
|
159
|
+
Domains → Add → DNS records → wait for verification.
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## Production callbacks for OAuth (if you used `scaffold-auth`)
|
|
164
|
+
|
|
165
|
+
If you activated Google or GitHub OAuth via `scaffold-auth` (#364),
|
|
166
|
+
those activations used dev callback URLs (`localhost:3000`). For
|
|
167
|
+
production, add the prod callback URLs to each OAuth app:
|
|
168
|
+
|
|
169
|
+
### Google
|
|
170
|
+
|
|
171
|
+
1. Open the Google Cloud Console OAuth client you created
|
|
172
|
+
(<https://console.cloud.google.com/apis/credentials>).
|
|
173
|
+
2. Under **Authorized redirect URIs**, add:
|
|
174
|
+
`https://<your-prod-domain>/api/auth/callback/google`
|
|
175
|
+
3. Save.
|
|
176
|
+
|
|
177
|
+
### GitHub
|
|
178
|
+
|
|
179
|
+
1. Open the GitHub OAuth App you created
|
|
180
|
+
(<https://github.com/settings/developers>).
|
|
181
|
+
2. Edit either:
|
|
182
|
+
- The same app's **Authorization callback URL** to add a second
|
|
183
|
+
line for prod (GitHub allows multiple).
|
|
184
|
+
- Or create a separate OAuth App for production.
|
|
185
|
+
3. Update the env vars in Vercel if you created a separate app.
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## When to redeploy
|
|
190
|
+
|
|
191
|
+
- After changing any `NEXT_PUBLIC_*` env var (those bake at build
|
|
192
|
+
time).
|
|
193
|
+
- After running database migrations (data shape changed).
|
|
194
|
+
- After updating `vercel.json` (deploy config changed).
|
|
195
|
+
|
|
196
|
+
You do **not** need to redeploy after:
|
|
197
|
+
|
|
198
|
+
- Adding a non-`NEXT_PUBLIC_*` env var in Vercel's dashboard
|
|
199
|
+
(server-side reads pick it up on next request).
|
|
200
|
+
- Editing MDX content in `content/` and pushing — Vercel rebuilds
|
|
201
|
+
on push.
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
## Troubleshooting
|
|
206
|
+
|
|
207
|
+
- **"My leads disappeared"** → you skipped the leads-persistence
|
|
208
|
+
upgrade. Pick one of Vercel KV / Supabase / Postgres above and
|
|
209
|
+
migrate the writer.
|
|
210
|
+
- **"OAuth login redirects to localhost in production"** → you
|
|
211
|
+
haven't added the production callback URL to the OAuth app
|
|
212
|
+
(see above).
|
|
213
|
+
- **"Magic-link emails aren't arriving in production"** → your
|
|
214
|
+
Resend sender domain isn't verified yet (Resend Dashboard →
|
|
215
|
+
Domains).
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
## Section headings the validation must find
|
|
221
|
+
|
|
222
|
+
After emit, the skill must grep for these three headings (verbatim
|
|
223
|
+
match). All three must be present:
|
|
224
|
+
|
|
225
|
+
- `## Persistence upgrade — Vercel KV`
|
|
226
|
+
- `## Persistence upgrade — Supabase`
|
|
227
|
+
- `## Persistence upgrade — Postgres via `@working-theory/database\``
|
|
228
|
+
|
|
229
|
+
If any is missing, the template was edited in a way that broke the
|
|
230
|
+
contract. Surface the failure to the consumer (not silent).
|
|
231
|
+
|
|
232
|
+
## Merge logic
|
|
233
|
+
|
|
234
|
+
If the consumer already has `RUNBOOK.md`, the skill (per SKILL.md
|
|
235
|
+
Step 3) offers merge / overwrite / skip. Merge logic:
|
|
236
|
+
|
|
237
|
+
1. Read the existing file.
|
|
238
|
+
2. Check whether each of the three named persistence section
|
|
239
|
+
headings is already present.
|
|
240
|
+
3. Headings already present → not modified.
|
|
241
|
+
4. Headings missing → append at the end of the existing file under:
|
|
242
|
+
```
|
|
243
|
+
## Added by provision-config
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
The pre-deploy checklist, custom-domain, and OAuth-prod-callbacks
|
|
247
|
+
sections are also appended if missing. Sections that are already
|
|
248
|
+
present (even with different content) are not modified.
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# `vercel.json` Template
|
|
2
|
+
|
|
3
|
+
The minimal viable Vercel config the `provision-config` skill emits.
|
|
4
|
+
Customization beyond this template is the consumer's responsibility —
|
|
5
|
+
the skill's job is to ship the consumer with a working baseline.
|
|
6
|
+
|
|
7
|
+
## Template
|
|
8
|
+
|
|
9
|
+
```json
|
|
10
|
+
{
|
|
11
|
+
"version": 2,
|
|
12
|
+
"framework": "nextjs",
|
|
13
|
+
"buildCommand": "pnpm build",
|
|
14
|
+
"installCommand": "pnpm install --frozen-lockfile",
|
|
15
|
+
"env": {}
|
|
16
|
+
}
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Field-by-field
|
|
20
|
+
|
|
21
|
+
### `version: 2`
|
|
22
|
+
|
|
23
|
+
Required. Vercel config schema version. Always `2` at v1.
|
|
24
|
+
|
|
25
|
+
### `framework: "nextjs"`
|
|
26
|
+
|
|
27
|
+
The skill assumes the consumer's `apps/web` is a Next.js app (the
|
|
28
|
+
AILK scaffold default). Other valid values exist in Vercel's docs
|
|
29
|
+
but the skill emits `nextjs` only. Consumers on bespoke setups can
|
|
30
|
+
overwrite the file post-emission.
|
|
31
|
+
|
|
32
|
+
### `buildCommand`
|
|
33
|
+
|
|
34
|
+
The default `pnpm build` works for single-app deploys (the AILK
|
|
35
|
+
scaffold's `apps/web` is the deploy target). For monorepo deploys
|
|
36
|
+
where the consumer wants Vercel to build the whole tree, suggest
|
|
37
|
+
the consumer change this to:
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
cd ../.. && pnpm install --frozen-lockfile && pnpm --filter ./apps/web build
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
The skill does NOT auto-detect monorepo vs single-app — the consumer
|
|
44
|
+
edits the field if their setup deviates. Surface the alternative as
|
|
45
|
+
a comment in the chat after emit, not in the JSON file (JSON has
|
|
46
|
+
no comments).
|
|
47
|
+
|
|
48
|
+
### `installCommand`
|
|
49
|
+
|
|
50
|
+
Default `pnpm install --frozen-lockfile`. Match the consumer's
|
|
51
|
+
package manager:
|
|
52
|
+
|
|
53
|
+
- pnpm — `pnpm install --frozen-lockfile`
|
|
54
|
+
- npm — `npm ci`
|
|
55
|
+
- yarn — `yarn install --frozen-lockfile`
|
|
56
|
+
|
|
57
|
+
The skill detects the package manager by checking for `pnpm-lock.yaml`,
|
|
58
|
+
`package-lock.json`, or `yarn.lock` at the project root. Default
|
|
59
|
+
to pnpm if none is found (AILK scaffold ships pnpm).
|
|
60
|
+
|
|
61
|
+
### `env: {}`
|
|
62
|
+
|
|
63
|
+
Empty by default. Vercel's project-level env-var dashboard is the
|
|
64
|
+
canonical place to set production values — `.env.example` is the
|
|
65
|
+
contract, the dashboard is the values.
|
|
66
|
+
|
|
67
|
+
If the consumer specifically asks for build-time env-var defaults
|
|
68
|
+
(e.g., `NODE_ENV: "production"`), the skill can populate the field.
|
|
69
|
+
But the default is empty.
|
|
70
|
+
|
|
71
|
+
## What this template intentionally omits
|
|
72
|
+
|
|
73
|
+
- **`routes`** — Next.js App Router handles routing; `vercel.json`
|
|
74
|
+
routing is for non-Next.js apps. AILK is Next.js.
|
|
75
|
+
- **`outputDirectory`** — Vercel auto-detects `.next` for Next.js.
|
|
76
|
+
- **`functions`** — per-function config is rarely needed for AILK's
|
|
77
|
+
shape. Consumers who need it (long-running cron, large payload
|
|
78
|
+
tolerances) edit post-emission.
|
|
79
|
+
- **`regions`** — Vercel's default multi-region routing is fine for
|
|
80
|
+
AILK at v1. Consumers with strict latency requirements add this
|
|
81
|
+
themselves.
|
|
82
|
+
- **`crons`** — AILK doesn't ship scheduled jobs. Consumer-added
|
|
83
|
+
crons go in post-emit edits.
|
|
84
|
+
|
|
85
|
+
The template is small on purpose. A 100-line `vercel.json` carries a
|
|
86
|
+
maintenance cost the consumer didn't ask for. Five fields is enough
|
|
87
|
+
to deploy.
|
|
88
|
+
|
|
89
|
+
## Validation after emit
|
|
90
|
+
|
|
91
|
+
After writing, the skill must:
|
|
92
|
+
|
|
93
|
+
1. Parse the file as JSON. If it fails to parse, the skill has a bug
|
|
94
|
+
(the template is hand-authored JSON; a parse failure means the
|
|
95
|
+
template was edited in a way that broke it).
|
|
96
|
+
2. Confirm the field count matches the template (5 fields). Extra
|
|
97
|
+
fields are fine if the consumer's existing file had more (in
|
|
98
|
+
merge mode, but `vercel.json` doesn't merge — see SKILL.md Step 3).
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: scaffold-auth
|
|
3
|
+
description: Activate auth providers (magic-link via Resend, Google OAuth, GitHub OAuth) on an AILK consumer site. Use when the user says "wire up auth", "add login", "set up sign-in", "I need users to log in", or asks how to enable any of magic-link / Google / GitHub auth on their AILK site. The skill writes env vars for whichever subset of providers the consumer activates and prints (plus saves) an OAuth-app-setup runbook. It does NOT modify `auth.config.ts` and does NOT emit any pages.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# scaffold-auth
|
|
7
|
+
|
|
8
|
+
Activate one or more auth providers on an AILK site by writing the env
|
|
9
|
+
vars NextAuth reads to detect them, plus a `RUNBOOK.md` that documents
|
|
10
|
+
the OAuth-app-creation steps for the consumer's records.
|
|
11
|
+
|
|
12
|
+
## When to use
|
|
13
|
+
|
|
14
|
+
The user has a working AILK site (post-`pnpm create ailk`) and wants
|
|
15
|
+
to gate routes behind sign-in, send magic-link emails, or accept
|
|
16
|
+
Google / GitHub OAuth. Phrases that should trigger this skill:
|
|
17
|
+
|
|
18
|
+
- "wire up auth" / "add login" / "set up sign-in"
|
|
19
|
+
- "I want users to log in"
|
|
20
|
+
- "enable Google sign-in" / "enable GitHub login"
|
|
21
|
+
- "set up magic-link auth"
|
|
22
|
+
- "add OAuth"
|
|
23
|
+
|
|
24
|
+
Skip this skill when:
|
|
25
|
+
|
|
26
|
+
- The user wants a `/login` or `/account` _page_ — those are pages, not
|
|
27
|
+
auth wiring. Use `scaffold-page` (#362) for that.
|
|
28
|
+
- The user is asking about a third-party provider that isn't in the
|
|
29
|
+
AILK locked set (Apple, Microsoft, Twitter, etc.). The locked set is
|
|
30
|
+
magic-link + Google + GitHub at v1; broader provider support is a
|
|
31
|
+
future PR. Acknowledge the request and stop.
|
|
32
|
+
- The user is in production and needs production callback URLs. v1
|
|
33
|
+
ships dev-mode callbacks (`http://localhost:3000`) only —
|
|
34
|
+
production callback setup is deferred to `provision-config` (#367)
|
|
35
|
+
or a future deploy skill. Note this and stop.
|
|
36
|
+
|
|
37
|
+
## What this skill does (and does not do)
|
|
38
|
+
|
|
39
|
+
**Does:**
|
|
40
|
+
|
|
41
|
+
- Reads `.env.local` to see which providers are already activated.
|
|
42
|
+
- Asks the consumer which of the three locked providers
|
|
43
|
+
(magic-link, Google, GitHub) they want to activate _this session_.
|
|
44
|
+
- For each picked provider, walks the consumer through
|
|
45
|
+
OAuth-app-creation (Google / GitHub) or Resend-key setup
|
|
46
|
+
(magic-link), then writes the resulting secrets to `.env.local`.
|
|
47
|
+
- Auto-detects whether `@working-theory/database` is installed with User /
|
|
48
|
+
Session models (Prisma adapter mode) or not (JWT-only mode), and
|
|
49
|
+
states which mode the site is in.
|
|
50
|
+
- Writes (or merges) a `RUNBOOK.md` in the consumer's repo root
|
|
51
|
+
with the same setup instructions the consumer just followed, so
|
|
52
|
+
they can refer back later or hand to a collaborator.
|
|
53
|
+
|
|
54
|
+
**Does not:**
|
|
55
|
+
|
|
56
|
+
- Modify `auth.config.ts`. The locked-set providers are env-var-driven
|
|
57
|
+
— present env vars activate the matching provider in
|
|
58
|
+
`auth.config.ts`'s `buildProviders()`. No code changes are needed.
|
|
59
|
+
- Create any new files under `app/`, `pages/`, or `content/`. The
|
|
60
|
+
emit is limited to `.env.local` writes and a `RUNBOOK.md` write.
|
|
61
|
+
- Set up production callback URLs. Dev-mode (`http://localhost:3000`)
|
|
62
|
+
only at v1.
|
|
63
|
+
- Add, remove, or modify any provider entry in `auth.config.ts`
|
|
64
|
+
outside of magic-link / Google / GitHub. Consumer-added providers
|
|
65
|
+
(e.g., Apple) are preserved as-is and never touched by this skill.
|
|
66
|
+
- Accept production OAuth credentials. If the consumer pastes a
|
|
67
|
+
production-looking secret, that's acceptable, but the runbook still
|
|
68
|
+
documents only the dev callback URL.
|
|
69
|
+
|
|
70
|
+
## The mechanic
|
|
71
|
+
|
|
72
|
+
### Step 1 — Show the menu
|
|
73
|
+
|
|
74
|
+
Greet the consumer and present the three locked providers, marking
|
|
75
|
+
which are already activated (env vars present in `.env.local`):
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
Which auth providers do you want to activate?
|
|
79
|
+
|
|
80
|
+
[ ] magic-link (passwordless email login via Resend)
|
|
81
|
+
[ ] Google OAuth
|
|
82
|
+
[ ] GitHub OAuth
|
|
83
|
+
|
|
84
|
+
You can pick any subset, including "none of the above" (in which case
|
|
85
|
+
this skill exits without writing anything). You can also re-run this
|
|
86
|
+
skill later to activate more providers — already-activated providers
|
|
87
|
+
will be skipped automatically.
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
If `.env.local` already has any of these activated, mark them:
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
[x] magic-link (already activated — AUTH_EMAIL_SERVER + AUTH_EMAIL_FROM are set)
|
|
94
|
+
[ ] Google OAuth
|
|
95
|
+
[ ] GitHub OAuth
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Wait for the consumer to pick a subset. Then, for each picked
|
|
99
|
+
provider, run the matching sub-flow.
|
|
100
|
+
|
|
101
|
+
### Step 2 — Run per-provider sub-flows
|
|
102
|
+
|
|
103
|
+
#### magic-link sub-flow
|
|
104
|
+
|
|
105
|
+
1. Tell the consumer: _"Magic-link uses Resend as the email provider
|
|
106
|
+
at AILK v1. Other email providers ship as additive future PRs.
|
|
107
|
+
You'll need a Resend API key (free tier is fine for development).
|
|
108
|
+
Get one at <https://resend.com/api-keys>."_
|
|
109
|
+
2. Wait for the consumer to paste the API key.
|
|
110
|
+
3. Ask for the `AUTH_EMAIL_FROM` address. This must be a verified
|
|
111
|
+
sender on the consumer's Resend account. For development it's
|
|
112
|
+
common to use `onboarding@resend.dev` (Resend's shared dev
|
|
113
|
+
sender). Mention that.
|
|
114
|
+
4. Construct `AUTH_EMAIL_SERVER` as
|
|
115
|
+
`smtp://resend:<API_KEY>@smtp.resend.com:465`.
|
|
116
|
+
5. Write to `.env.local`:
|
|
117
|
+
```
|
|
118
|
+
AUTH_EMAIL_SERVER=smtp://resend:re_...@smtp.resend.com:465
|
|
119
|
+
AUTH_EMAIL_FROM=onboarding@resend.dev
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
#### Google OAuth sub-flow
|
|
123
|
+
|
|
124
|
+
1. Tell the consumer the steps in chat AND queue the same content for
|
|
125
|
+
the runbook (see Step 3). Steps:
|
|
126
|
+
- Go to <https://console.cloud.google.com/apis/credentials>.
|
|
127
|
+
- Click **Create Credentials → OAuth client ID**. If prompted,
|
|
128
|
+
configure the OAuth consent screen first (**External** → fill
|
|
129
|
+
name, support email, developer contact email; scopes are
|
|
130
|
+
auto-populated by NextAuth).
|
|
131
|
+
- Application type: **Web application**.
|
|
132
|
+
- Name: anything (e.g., "AILK dev").
|
|
133
|
+
- **Authorized redirect URIs** — add exactly:
|
|
134
|
+
`http://localhost:3000/api/auth/callback/google`
|
|
135
|
+
- Click **Create**. Copy the **Client ID** and **Client secret**
|
|
136
|
+
from the dialog.
|
|
137
|
+
2. Wait for the consumer to paste both values.
|
|
138
|
+
3. Write to `.env.local`:
|
|
139
|
+
```
|
|
140
|
+
GOOGLE_CLIENT_ID=...
|
|
141
|
+
GOOGLE_CLIENT_SECRET=...
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
#### GitHub OAuth sub-flow
|
|
145
|
+
|
|
146
|
+
1. Tell the consumer the steps in chat AND queue the same content for
|
|
147
|
+
the runbook. Steps:
|
|
148
|
+
- Go to <https://github.com/settings/developers>.
|
|
149
|
+
- Click **New OAuth App**.
|
|
150
|
+
- Application name: anything (e.g., "AILK dev").
|
|
151
|
+
- Homepage URL: `http://localhost:3000`
|
|
152
|
+
- **Authorization callback URL** — add exactly:
|
|
153
|
+
`http://localhost:3000/api/auth/callback/github`
|
|
154
|
+
- Click **Register application**. Generate a new client secret.
|
|
155
|
+
Copy the **Client ID** and **Client secret**.
|
|
156
|
+
2. Wait for the consumer to paste both values.
|
|
157
|
+
3. Write to `.env.local`:
|
|
158
|
+
```
|
|
159
|
+
GITHUB_CLIENT_ID=...
|
|
160
|
+
GITHUB_CLIENT_SECRET=...
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Step 3 — Write the RUNBOOK
|
|
164
|
+
|
|
165
|
+
After all picked providers are activated, write
|
|
166
|
+
`RUNBOOK.md` (or merge into existing) at the consumer's repo root.
|
|
167
|
+
The runbook captures the OAuth-app-creation steps and Resend setup
|
|
168
|
+
the consumer just walked through, so they can hand it to a teammate
|
|
169
|
+
or refer back later.
|
|
170
|
+
|
|
171
|
+
Use `references/oauth-app-setup.md` as the template. Replace
|
|
172
|
+
`<provider>` headings as appropriate, and only include sections for
|
|
173
|
+
providers actually activated this session. If `RUNBOOK.md` already
|
|
174
|
+
exists with sections for already-activated providers, do not
|
|
175
|
+
duplicate — add only the new sections beneath any existing content.
|
|
176
|
+
|
|
177
|
+
### Step 4 — Detect the database adapter mode
|
|
178
|
+
|
|
179
|
+
Before printing the closing summary, check the consumer's setup:
|
|
180
|
+
|
|
181
|
+
- If `package.json` lists `@working-theory/database` as a dependency AND
|
|
182
|
+
`database/prisma/schema.prisma` defines `User` and `Session` models
|
|
183
|
+
→ **Prisma adapter mode**. Sessions persist across server restarts.
|
|
184
|
+
- Otherwise → **JWT-only mode**. Sessions are cookies, no database.
|
|
185
|
+
|
|
186
|
+
State the mode in the closing summary so the consumer is never
|
|
187
|
+
surprised:
|
|
188
|
+
|
|
189
|
+
> "Your site is running in **Prisma adapter mode** — sessions persist
|
|
190
|
+
> in the `User` and `Session` tables. Run `pnpm db:push` after this
|
|
191
|
+
> skill if you haven't applied the migration yet."
|
|
192
|
+
|
|
193
|
+
or
|
|
194
|
+
|
|
195
|
+
> "Your site is running in **JWT-only mode** — sessions are
|
|
196
|
+
> cookie-only and don't require a database. To switch to persistent
|
|
197
|
+
> sessions, install `@working-theory/database` and add the `User` / `Session`
|
|
198
|
+
> models from `database/prisma/schema.prisma`."
|
|
199
|
+
|
|
200
|
+
### Step 5 — Closing summary
|
|
201
|
+
|
|
202
|
+
Print:
|
|
203
|
+
|
|
204
|
+
- Which providers are now active (subset picked this session +
|
|
205
|
+
already-activated providers).
|
|
206
|
+
- The database adapter mode (Prisma or JWT).
|
|
207
|
+
- A reminder to set `AILK_AUTH_REQUIRED=1` in `.env.local` if they
|
|
208
|
+
want protected routes (default is auth-disabled / public).
|
|
209
|
+
- A pointer to `RUNBOOK.md` for future reference.
|
|
210
|
+
- A pointer to `provision-config` (#367) for production callback URL
|
|
211
|
+
setup when the consumer is ready to deploy.
|
|
212
|
+
|
|
213
|
+
## Re-invocation
|
|
214
|
+
|
|
215
|
+
The skill is idempotent. On a second run, the menu in Step 1 marks
|
|
216
|
+
already-activated providers with `[x]` (read from `.env.local`), and
|
|
217
|
+
the per-provider sub-flows skip those and only run for the new ones.
|
|
218
|
+
The closing summary lists everything, not just what changed this
|
|
219
|
+
session.
|
|
220
|
+
|
|
221
|
+
If the consumer wants to _change_ a previously-activated provider's
|
|
222
|
+
secrets (e.g., rotated their Google Client Secret), they should pick
|
|
223
|
+
that provider in the menu and the sub-flow will overwrite the
|
|
224
|
+
existing values in `.env.local`. Confirm before overwriting.
|
|
225
|
+
|
|
226
|
+
## Customization preservation
|
|
227
|
+
|
|
228
|
+
If `auth.config.ts` has been modified by the consumer to add a
|
|
229
|
+
third-party provider (e.g., Apple), this skill leaves that file
|
|
230
|
+
completely untouched. The skill never reads, edits, or even opens
|
|
231
|
+
`auth.config.ts`. Activation of the AILK locked set happens entirely
|
|
232
|
+
through env vars — `getActiveProviderIds()` in
|
|
233
|
+
`apps/web/lib/auth-env.ts` is what reads them at startup.
|
|
234
|
+
|
|
235
|
+
## What "activation" means under the hood
|
|
236
|
+
|
|
237
|
+
- **Provider list is computed at startup from env-var presence** in
|
|
238
|
+
`apps/web/auth.config.ts` → `buildProviders()`.
|
|
239
|
+
- A provider is included only when every required env var is set:
|
|
240
|
+
- `email` (magic-link): `AUTH_EMAIL_SERVER` + `AUTH_EMAIL_FROM`
|
|
241
|
+
- `google`: `GOOGLE_CLIENT_ID` + `GOOGLE_CLIENT_SECRET`
|
|
242
|
+
- `github`: `GITHUB_CLIENT_ID` + `GITHUB_CLIENT_SECRET`
|
|
243
|
+
- A site with zero auth env vars boots cleanly with no active
|
|
244
|
+
providers (`apps/web/lib/auth-env.ts` returns an empty array).
|
|
245
|
+
|
|
246
|
+
This means the skill's job is purely env-var wiring + documentation.
|
|
247
|
+
|
|
248
|
+
## References
|
|
249
|
+
|
|
250
|
+
- `references/oauth-app-setup.md` — RUNBOOK template the skill instantiates per session.
|
|
251
|
+
- `references/env-vars.md` — env-var contract (which vars activate which provider).
|
|
252
|
+
|
|
253
|
+
## Coordination
|
|
254
|
+
|
|
255
|
+
- **`scaffold-page` (#362)** — `/login` or `/account` pages. This skill
|
|
256
|
+
emits no pages.
|
|
257
|
+
- **`provision-config` (#367)** — production callback URL setup. v1
|
|
258
|
+
is dev-only.
|
|
259
|
+
- **`@working-theory/database`** — Prisma adapter detection. Install
|
|
260
|
+
`@working-theory/database` separately to upgrade from JWT-only to persistent
|
|
261
|
+
sessions.
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# Auth Env-Var Contract
|
|
2
|
+
|
|
3
|
+
Source of truth for which env vars activate which auth provider on
|
|
4
|
+
an AILK consumer site. Read by the `scaffold-auth` skill before
|
|
5
|
+
asking the consumer to paste secrets.
|
|
6
|
+
|
|
7
|
+
The activation logic lives in `apps/web/lib/auth-env.ts` →
|
|
8
|
+
`getActiveProviderIds()`. A provider is active **only when every
|
|
9
|
+
required var is set to a non-empty value**. Partial wiring (e.g.,
|
|
10
|
+
`GOOGLE_CLIENT_ID` set but `GOOGLE_CLIENT_SECRET` missing) is treated
|
|
11
|
+
as inactive — NextAuth never tries to construct that provider.
|
|
12
|
+
|
|
13
|
+
## Provider activation table
|
|
14
|
+
|
|
15
|
+
| Provider ID | Required env vars | Source |
|
|
16
|
+
| ----------- | -------------------------------------------- | ---------------------------- |
|
|
17
|
+
| `email` | `AUTH_EMAIL_SERVER` + `AUTH_EMAIL_FROM` | Magic-link (Resend at v1) |
|
|
18
|
+
| `google` | `GOOGLE_CLIENT_ID` + `GOOGLE_CLIENT_SECRET` | Google OAuth |
|
|
19
|
+
| `github` | `GITHUB_CLIENT_ID` + `GITHUB_CLIENT_SECRET` | GitHub OAuth |
|
|
20
|
+
|
|
21
|
+
## Auxiliary auth env vars
|
|
22
|
+
|
|
23
|
+
| Var | Default | Effect |
|
|
24
|
+
| ---------------------- | ------- | ------------------------------------------------------------------------------------- |
|
|
25
|
+
| `AILK_AUTH_REQUIRED` | unset | When `"1"` or `"true"`, the middleware redirects unauthenticated users to `/api/auth/signin` for protected routes. Default is auth-disabled / public, so a fresh scaffold boots without requiring any auth wiring. |
|
|
26
|
+
| `NEXTAUTH_URL` | unset | NextAuth uses this as the base URL when constructing callback URLs in production. Local dev defaults to `http://localhost:3000` so you can leave this unset for development. |
|
|
27
|
+
| `NEXTAUTH_SECRET` | unset | NextAuth uses this to sign JWT tokens. **Must** be set for production — generate with `openssl rand -base64 32`. Optional for `next dev` (auto-generated for local-only sessions). |
|
|
28
|
+
|
|
29
|
+
The skill writes none of these auxiliary vars on its own. It mentions
|
|
30
|
+
them in the closing summary so the consumer is aware:
|
|
31
|
+
|
|
32
|
+
- `AILK_AUTH_REQUIRED` is the consumer's call (skill always defaults
|
|
33
|
+
to leaving it unset).
|
|
34
|
+
- `NEXTAUTH_URL` and `NEXTAUTH_SECRET` are deferred to production-time
|
|
35
|
+
setup (`provision-config` (#367) or future deploy skill).
|
|
36
|
+
|
|
37
|
+
## Env-var formats — what valid values look like
|
|
38
|
+
|
|
39
|
+
### `AUTH_EMAIL_SERVER` (magic-link via Resend)
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
smtp://resend:<RESEND_API_KEY>@smtp.resend.com:465
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
The Resend API key starts with `re_`. The literal username is the
|
|
46
|
+
string `resend` (Resend's SMTP convention). Port 465 is implicit-TLS
|
|
47
|
+
SMTP.
|
|
48
|
+
|
|
49
|
+
### `AUTH_EMAIL_FROM` (magic-link via Resend)
|
|
50
|
+
|
|
51
|
+
A verified sender address on the consumer's Resend account. For
|
|
52
|
+
development, `onboarding@resend.dev` works without verification.
|
|
53
|
+
|
|
54
|
+
### `GOOGLE_CLIENT_ID` / `GITHUB_CLIENT_ID`
|
|
55
|
+
|
|
56
|
+
Public identifiers issued by Google / GitHub. Typically:
|
|
57
|
+
|
|
58
|
+
- Google: ends in `.apps.googleusercontent.com`
|
|
59
|
+
- GitHub: 20-character hex string
|
|
60
|
+
|
|
61
|
+
Either can be safely committed to a public template; production
|
|
62
|
+
secrets stay in `.env.local`.
|
|
63
|
+
|
|
64
|
+
### `GOOGLE_CLIENT_SECRET` / `GITHUB_CLIENT_SECRET`
|
|
65
|
+
|
|
66
|
+
Sensitive values. Treat as passwords. Never commit. The skill writes
|
|
67
|
+
these only to `.env.local` (which is in the consumer scaffold's
|
|
68
|
+
`.gitignore` by default).
|
|
69
|
+
|
|
70
|
+
## Detection of "already activated"
|
|
71
|
+
|
|
72
|
+
The skill's Step 1 menu marks providers as `[x]` when both required
|
|
73
|
+
vars are set in `.env.local`. The detection is presence-only — the
|
|
74
|
+
skill does not validate that the values actually work (no Google
|
|
75
|
+
API ping, no GitHub API ping, no test SMTP connection). A consumer
|
|
76
|
+
who pasted typos will get a runtime auth error from NextAuth on
|
|
77
|
+
their first sign-in attempt; the fix is to re-run the skill and
|
|
78
|
+
overwrite.
|
|
79
|
+
|
|
80
|
+
## Where these vars are read
|
|
81
|
+
|
|
82
|
+
- `apps/web/lib/auth-env.ts` — `getActiveProviderIds()` and
|
|
83
|
+
`isAuthRequired()`.
|
|
84
|
+
- `apps/web/auth.config.ts` — `buildProviders()` consumes the
|
|
85
|
+
active-provider list and constructs NextAuth provider objects with
|
|
86
|
+
the matching env vars.
|
|
87
|
+
- `apps/web/middleware.ts` — `isAuthRequired()` decides whether to
|
|
88
|
+
redirect unauthenticated users.
|
|
89
|
+
|
|
90
|
+
The skill never modifies any of those files. All activation is
|
|
91
|
+
env-var-driven.
|