create-ailk 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (533) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +39 -0
  3. package/dist/cli.d.ts +2 -0
  4. package/dist/cli.js +80 -0
  5. package/dist/copy.d.ts +8 -0
  6. package/dist/copy.js +109 -0
  7. package/dist/index.d.ts +10 -0
  8. package/dist/index.js +10 -0
  9. package/dist/lib/pro-callout.d.ts +12 -0
  10. package/dist/lib/pro-callout.js +20 -0
  11. package/dist/parse-args.d.ts +13 -0
  12. package/dist/parse-args.js +81 -0
  13. package/dist/programmatic.d.ts +49 -0
  14. package/dist/programmatic.js +89 -0
  15. package/dist/substitute.d.ts +31 -0
  16. package/dist/substitute.js +45 -0
  17. package/dist/validate.d.ts +8 -0
  18. package/dist/validate.js +70 -0
  19. package/package.json +47 -0
  20. package/templates/.claude/.gitkeep +0 -0
  21. package/templates/.claude/agents/web.md +80 -0
  22. package/templates/.claude/rules/architecture.md +62 -0
  23. package/templates/.claude/rules/preserve-existing-style.md +51 -0
  24. package/templates/.claude/skills/README.md +43 -0
  25. package/templates/.claude/skills/add-schema/SKILL.md +270 -0
  26. package/templates/.claude/skills/add-schema/references/conflict-handling.md +200 -0
  27. package/templates/.claude/skills/add-schema/references/file-finding.md +123 -0
  28. package/templates/.claude/skills/add-schema/references/schema-types.md +131 -0
  29. package/templates/.claude/skills/audit-site/SKILL.md +213 -0
  30. package/templates/.claude/skills/audit-site/references/common-errors.md +113 -0
  31. package/templates/.claude/skills/audit-site/references/findings-glossary.md +138 -0
  32. package/templates/.claude/skills/audit-site/references/severity-levels.md +114 -0
  33. package/templates/.claude/skills/provision-config/SKILL.md +243 -0
  34. package/templates/.claude/skills/provision-config/references/env-vars-template.md +184 -0
  35. package/templates/.claude/skills/provision-config/references/runbook-template.md +248 -0
  36. package/templates/.claude/skills/provision-config/references/vercel-json-template.md +98 -0
  37. package/templates/.claude/skills/scaffold-auth/SKILL.md +261 -0
  38. package/templates/.claude/skills/scaffold-auth/references/env-vars.md +91 -0
  39. package/templates/.claude/skills/scaffold-auth/references/oauth-app-setup.md +171 -0
  40. package/templates/.claude/skills/scaffold-commerce/SKILL.md +310 -0
  41. package/templates/.claude/skills/scaffold-commerce/references/lookup-keys-template.md +71 -0
  42. package/templates/.claude/skills/scaffold-commerce/references/marketplace-brand-pages.md +83 -0
  43. package/templates/.claude/skills/scaffold-commerce/templates/marketplace-cta-route.tsx.tmpl +72 -0
  44. package/templates/.claude/skills/scaffold-page/SKILL.md +243 -0
  45. package/templates/.claude/skills/scaffold-page/references/page-types.md +169 -0
  46. package/templates/.claude/skills/scaffold-page/templates/content.mdx.tmpl +28 -0
  47. package/templates/.claude/skills/scaffold-page/templates/route.tsx.tmpl +28 -0
  48. package/templates/.claude/skills/suggest-site-pages/SKILL.md +242 -0
  49. package/templates/.claude/skills/suggest-site-pages/references/categories.md +287 -0
  50. package/templates/.env.example +205 -0
  51. package/templates/.gitkeep +2 -0
  52. package/templates/CLAUDE.md +142 -0
  53. package/templates/CONVENTIONS.md +222 -0
  54. package/templates/README.md +110 -0
  55. package/templates/apps/api/.env.example +40 -0
  56. package/templates/apps/api/CLAUDE.md +63 -0
  57. package/templates/apps/api/api/index.ts +144 -0
  58. package/templates/apps/api/jest.config.cjs +74 -0
  59. package/templates/apps/api/package.json +54 -0
  60. package/templates/apps/api/src/__tests__/factories/content-fixture.ts +138 -0
  61. package/templates/apps/api/src/__tests__/factories/index.ts +70 -0
  62. package/templates/apps/api/src/__tests__/factories/lead-fixture.ts +82 -0
  63. package/templates/apps/api/src/__tests__/index.test.ts +118 -0
  64. package/templates/apps/api/src/__tests__/server.test.ts +207 -0
  65. package/templates/apps/api/src/__tests__/services/enrichment-shim.test.ts +126 -0
  66. package/templates/apps/api/src/__tests__/setup.ts +24 -0
  67. package/templates/apps/api/src/cli.ts +30 -0
  68. package/templates/apps/api/src/config/__tests__/index.test.ts +97 -0
  69. package/templates/apps/api/src/config/index.ts +56 -0
  70. package/templates/apps/api/src/index.ts +32 -0
  71. package/templates/apps/api/src/lib/__mocks__/prisma-client.js +15 -0
  72. package/templates/apps/api/src/lib/__mocks__/prisma.ts +45 -0
  73. package/templates/apps/api/src/lib/__tests__/content-adapter.test.ts +178 -0
  74. package/templates/apps/api/src/lib/__tests__/error-serializer.test.ts +100 -0
  75. package/templates/apps/api/src/lib/__tests__/errors.test.ts +94 -0
  76. package/templates/apps/api/src/lib/__tests__/file-fallback.test.ts +144 -0
  77. package/templates/apps/api/src/lib/__tests__/fixtures/HomePage/home.mdx +8 -0
  78. package/templates/apps/api/src/lib/__tests__/lead-capture-store.test.ts +227 -0
  79. package/templates/apps/api/src/lib/__tests__/outbound-http.test.ts +125 -0
  80. package/templates/apps/api/src/lib/__tests__/prisma.test.ts +165 -0
  81. package/templates/apps/api/src/lib/__tests__/require-paid-tier.test.ts +129 -0
  82. package/templates/apps/api/src/lib/__tests__/stripe.test.ts +74 -0
  83. package/templates/apps/api/src/lib/content-adapter.ts +86 -0
  84. package/templates/apps/api/src/lib/error-serializer.ts +77 -0
  85. package/templates/apps/api/src/lib/errors.ts +95 -0
  86. package/templates/apps/api/src/lib/file-fallback.ts +87 -0
  87. package/templates/apps/api/src/lib/lead-capture-store.ts +110 -0
  88. package/templates/apps/api/src/lib/locales.ts +201 -0
  89. package/templates/apps/api/src/lib/outbound-http.ts +122 -0
  90. package/templates/apps/api/src/lib/prisma.ts +21 -0
  91. package/templates/apps/api/src/lib/require-paid-tier.ts +53 -0
  92. package/templates/apps/api/src/lib/stripe.ts +30 -0
  93. package/templates/apps/api/src/lib/webhook-idempotency.ts +92 -0
  94. package/templates/apps/api/src/middleware/__tests__/adversarial/bearer-token-format.test.ts +111 -0
  95. package/templates/apps/api/src/middleware/__tests__/adversarial/cookie-or-bearer-precedence.test.ts +172 -0
  96. package/templates/apps/api/src/middleware/__tests__/adversarial/csrf-bearer-skip.test.ts +119 -0
  97. package/templates/apps/api/src/middleware/__tests__/adversarial/csrf-cookie-path.test.ts +138 -0
  98. package/templates/apps/api/src/middleware/__tests__/adversarial/session-fixation.test.ts +149 -0
  99. package/templates/apps/api/src/middleware/__tests__/adversarial/session-timeout.test.ts +139 -0
  100. package/templates/apps/api/src/middleware/__tests__/auth.bearer-path.test.ts +175 -0
  101. package/templates/apps/api/src/middleware/__tests__/auth.both-present-precedence.test.ts +76 -0
  102. package/templates/apps/api/src/middleware/__tests__/auth.cookie-path.test.ts +153 -0
  103. package/templates/apps/api/src/middleware/__tests__/auth.neither-present.test.ts +72 -0
  104. package/templates/apps/api/src/middleware/__tests__/rate-limit.test.ts +292 -0
  105. package/templates/apps/api/src/middleware/auth.ts +246 -0
  106. package/templates/apps/api/src/middleware/rate-limit.ts +132 -0
  107. package/templates/apps/api/src/openapi/__tests__/openapi.test.ts +129 -0
  108. package/templates/apps/api/src/openapi/index.ts +12 -0
  109. package/templates/apps/api/src/openapi/spec.ts +408 -0
  110. package/templates/apps/api/src/routes/auth/__tests__/auth-tokens.functional.test.ts +193 -0
  111. package/templates/apps/api/src/routes/auth/__tests__/auth-user.functional.test.ts +201 -0
  112. package/templates/apps/api/src/routes/auth/__tests__/tokens.test.ts +294 -0
  113. package/templates/apps/api/src/routes/auth/__tests__/user.test.ts +486 -0
  114. package/templates/apps/api/src/routes/auth/tokens.ts +199 -0
  115. package/templates/apps/api/src/routes/auth/user.ts +244 -0
  116. package/templates/apps/api/src/routes/checkout/__tests__/sessions.test.ts +588 -0
  117. package/templates/apps/api/src/routes/checkout/index.ts +13 -0
  118. package/templates/apps/api/src/routes/checkout/sessions.ts +185 -0
  119. package/templates/apps/api/src/routes/content/__tests__/create.test.ts +239 -0
  120. package/templates/apps/api/src/routes/content/__tests__/delete.test.ts +201 -0
  121. package/templates/apps/api/src/routes/content/__tests__/get-page.test.ts +141 -0
  122. package/templates/apps/api/src/routes/content/__tests__/list-pages.test.ts +122 -0
  123. package/templates/apps/api/src/routes/content/__tests__/list-types.test.ts +44 -0
  124. package/templates/apps/api/src/routes/content/__tests__/locale.test.ts +118 -0
  125. package/templates/apps/api/src/routes/content/__tests__/rate-limit.test.ts +51 -0
  126. package/templates/apps/api/src/routes/content/__tests__/update.test.ts +252 -0
  127. package/templates/apps/api/src/routes/content/create.ts +114 -0
  128. package/templates/apps/api/src/routes/content/delete.ts +81 -0
  129. package/templates/apps/api/src/routes/content/get-page.ts +98 -0
  130. package/templates/apps/api/src/routes/content/index.ts +32 -0
  131. package/templates/apps/api/src/routes/content/list-pages.ts +83 -0
  132. package/templates/apps/api/src/routes/content/list-types.ts +19 -0
  133. package/templates/apps/api/src/routes/content/rate-limit.ts +13 -0
  134. package/templates/apps/api/src/routes/content/slug.ts +9 -0
  135. package/templates/apps/api/src/routes/content/update.ts +111 -0
  136. package/templates/apps/api/src/routes/leads/__tests__/index.test.ts +415 -0
  137. package/templates/apps/api/src/routes/leads/__tests__/track.test.ts +165 -0
  138. package/templates/apps/api/src/routes/leads/index.ts +130 -0
  139. package/templates/apps/api/src/routes/test/auth/__tests__/session.test.ts +296 -0
  140. package/templates/apps/api/src/routes/test/auth/session.ts +141 -0
  141. package/templates/apps/api/src/routes/webhooks/README.md +57 -0
  142. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-idempotency.test.ts +247 -0
  143. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-rate-limit.test.ts +198 -0
  144. package/templates/apps/api/src/routes/webhooks/__tests__/stripe.test.ts +633 -0
  145. package/templates/apps/api/src/routes/webhooks/index.ts +41 -0
  146. package/templates/apps/api/src/routes/webhooks/stripe.ts +253 -0
  147. package/templates/apps/api/src/server.ts +157 -0
  148. package/templates/apps/api/src/services/__tests__/lead-routing.test.ts +395 -0
  149. package/templates/apps/api/src/services/enrichment-shim.ts +53 -0
  150. package/templates/apps/api/src/services/lead-routing.ts +338 -0
  151. package/templates/apps/api/tsconfig.json +34 -0
  152. package/templates/apps/api/vercel.json +17 -0
  153. package/templates/apps/mcp/.env.example +52 -0
  154. package/templates/apps/mcp/CLAUDE.md +84 -0
  155. package/templates/apps/mcp/__tests__/abuse/daily-cap.test.ts +52 -0
  156. package/templates/apps/mcp/__tests__/abuse/email-validator.test.ts +46 -0
  157. package/templates/apps/mcp/__tests__/abuse/honeypot.test.ts +36 -0
  158. package/templates/apps/mcp/__tests__/abuse/user-agent-deny.test.ts +54 -0
  159. package/templates/apps/mcp/__tests__/aeo-cli-parity.test.ts +110 -0
  160. package/templates/apps/mcp/__tests__/audit-single-page.test.ts +213 -0
  161. package/templates/apps/mcp/__tests__/audit.test.ts +217 -0
  162. package/templates/apps/mcp/__tests__/catalog-drift.test.ts +52 -0
  163. package/templates/apps/mcp/__tests__/create_page.test.ts +201 -0
  164. package/templates/apps/mcp/__tests__/delete_page.test.ts +176 -0
  165. package/templates/apps/mcp/__tests__/get_business_hours.test.ts +82 -0
  166. package/templates/apps/mcp/__tests__/get_faq.test.ts +80 -0
  167. package/templates/apps/mcp/__tests__/get_locations.test.ts +65 -0
  168. package/templates/apps/mcp/__tests__/get_offerings.test.ts +90 -0
  169. package/templates/apps/mcp/__tests__/get_pricing.test.ts +80 -0
  170. package/templates/apps/mcp/__tests__/get_site_info.test.ts +81 -0
  171. package/templates/apps/mcp/__tests__/http-transport.test.ts +323 -0
  172. package/templates/apps/mcp/__tests__/lib/errors.test.ts +75 -0
  173. package/templates/apps/mcp/__tests__/lib/require-paid-tier.test.ts +75 -0
  174. package/templates/apps/mcp/__tests__/list_pages.test.ts +112 -0
  175. package/templates/apps/mcp/__tests__/locale.test.ts +135 -0
  176. package/templates/apps/mcp/__tests__/parity.test.ts +205 -0
  177. package/templates/apps/mcp/__tests__/purchase-disabled.test.ts +34 -0
  178. package/templates/apps/mcp/__tests__/read_content.test.ts +153 -0
  179. package/templates/apps/mcp/__tests__/request_callback.test.ts +163 -0
  180. package/templates/apps/mcp/__tests__/search_content.test.ts +153 -0
  181. package/templates/apps/mcp/__tests__/server.test.ts +115 -0
  182. package/templates/apps/mcp/__tests__/submit_lead.test.ts +165 -0
  183. package/templates/apps/mcp/__tests__/subscribe_newsletter.test.ts +161 -0
  184. package/templates/apps/mcp/__tests__/tools/purchase.test.ts +227 -0
  185. package/templates/apps/mcp/__tests__/tools/scaffold.test.ts +237 -0
  186. package/templates/apps/mcp/__tests__/update_page.test.ts +195 -0
  187. package/templates/apps/mcp/jest.config.cjs +82 -0
  188. package/templates/apps/mcp/package.json +37 -0
  189. package/templates/apps/mcp/src/abuse/daily-cap.ts +47 -0
  190. package/templates/apps/mcp/src/abuse/email-validator.ts +25 -0
  191. package/templates/apps/mcp/src/abuse/honeypot.ts +21 -0
  192. package/templates/apps/mcp/src/abuse/index.ts +111 -0
  193. package/templates/apps/mcp/src/abuse/user-agent-deny.ts +58 -0
  194. package/templates/apps/mcp/src/http-transport.ts +303 -0
  195. package/templates/apps/mcp/src/index.ts +67 -0
  196. package/templates/apps/mcp/src/lib/audit-single-page.ts +194 -0
  197. package/templates/apps/mcp/src/lib/errors.ts +61 -0
  198. package/templates/apps/mcp/src/lib/locales.ts +171 -0
  199. package/templates/apps/mcp/src/lib/require-paid-tier.ts +44 -0
  200. package/templates/apps/mcp/src/lib/resolve-locale.ts +30 -0
  201. package/templates/apps/mcp/src/server.ts +139 -0
  202. package/templates/apps/mcp/src/tools/audit.ts +103 -0
  203. package/templates/apps/mcp/src/tools/capture_lead.ts +52 -0
  204. package/templates/apps/mcp/src/tools/create_page.ts +95 -0
  205. package/templates/apps/mcp/src/tools/delete_page.ts +73 -0
  206. package/templates/apps/mcp/src/tools/get_business_hours.ts +66 -0
  207. package/templates/apps/mcp/src/tools/get_faq.ts +69 -0
  208. package/templates/apps/mcp/src/tools/get_locations.ts +85 -0
  209. package/templates/apps/mcp/src/tools/get_offerings.ts +66 -0
  210. package/templates/apps/mcp/src/tools/get_pricing.ts +74 -0
  211. package/templates/apps/mcp/src/tools/get_site_info.ts +84 -0
  212. package/templates/apps/mcp/src/tools/index.ts +125 -0
  213. package/templates/apps/mcp/src/tools/list_pages.ts +72 -0
  214. package/templates/apps/mcp/src/tools/purchase.ts +89 -0
  215. package/templates/apps/mcp/src/tools/read_content.ts +61 -0
  216. package/templates/apps/mcp/src/tools/request_callback.ts +51 -0
  217. package/templates/apps/mcp/src/tools/scaffold.ts +119 -0
  218. package/templates/apps/mcp/src/tools/search_content.ts +59 -0
  219. package/templates/apps/mcp/src/tools/subscribe_newsletter.ts +47 -0
  220. package/templates/apps/mcp/src/tools/update_page.ts +91 -0
  221. package/templates/apps/mcp/tsconfig.json +19 -0
  222. package/templates/apps/web/.env.example +47 -0
  223. package/templates/apps/web/CLAUDE.md +81 -0
  224. package/templates/apps/web/__tests__/auth/adversarial/cookie-attributes.test.ts +94 -0
  225. package/templates/apps/web/__tests__/auth/adversarial/oauth-state-parameter.test.ts +75 -0
  226. package/templates/apps/web/__tests__/auth/adversarial/redirect-uri-allowlist.test.ts +82 -0
  227. package/templates/apps/web/__tests__/auth/env-helpers.test.ts +168 -0
  228. package/templates/apps/web/__tests__/authority-list-routes.test.tsx +208 -0
  229. package/templates/apps/web/__tests__/better-stack.test.ts +66 -0
  230. package/templates/apps/web/__tests__/blog-dir-resolution.test.ts +87 -0
  231. package/templates/apps/web/__tests__/blog-source-populated.test.ts +130 -0
  232. package/templates/apps/web/__tests__/data-testid-coverage.test.tsx +60 -0
  233. package/templates/apps/web/__tests__/google-analytics.test.tsx +104 -0
  234. package/templates/apps/web/__tests__/i18n/middleware.test.ts +119 -0
  235. package/templates/apps/web/__tests__/i18n/routing.test.ts +114 -0
  236. package/templates/apps/web/__tests__/i18n/translations.test.ts +191 -0
  237. package/templates/apps/web/__tests__/json-ld.test.ts +98 -0
  238. package/templates/apps/web/__tests__/knowledge-events-routes.test.tsx +580 -0
  239. package/templates/apps/web/__tests__/layout-stealth.test.ts +39 -0
  240. package/templates/apps/web/__tests__/lighthouse-fixtures/improvement-image-shrink.tsx +103 -0
  241. package/templates/apps/web/__tests__/lighthouse-fixtures/override-fixture.md +114 -0
  242. package/templates/apps/web/__tests__/lighthouse-fixtures/regression-bloat.tsx +94 -0
  243. package/templates/apps/web/__tests__/page.test.tsx +230 -0
  244. package/templates/apps/web/__tests__/products-services-phase1.test.tsx +321 -0
  245. package/templates/apps/web/__tests__/projects-routes.test.tsx +392 -0
  246. package/templates/apps/web/__tests__/resources-downloads-integrations-phase2.test.tsx +475 -0
  247. package/templates/apps/web/__tests__/routes/ai-plugin-json.test.ts +53 -0
  248. package/templates/apps/web/__tests__/routes/blog-route.test.tsx +191 -0
  249. package/templates/apps/web/__tests__/routes/llms-txt.test.ts +123 -0
  250. package/templates/apps/web/__tests__/routes/robots-txt.test.ts +52 -0
  251. package/templates/apps/web/__tests__/routes/sitemap-xml.test.ts +78 -0
  252. package/templates/apps/web/__tests__/routes/well-known-mcp.test.ts +203 -0
  253. package/templates/apps/web/__tests__/section-routes.test.tsx +693 -0
  254. package/templates/apps/web/__tests__/security-headers.test.ts +201 -0
  255. package/templates/apps/web/__tests__/sentry-config.test.ts +116 -0
  256. package/templates/apps/web/__tests__/setup.ts +82 -0
  257. package/templates/apps/web/__tests__/sitemap-locales.test.ts +415 -0
  258. package/templates/apps/web/__tests__/standalone-informational-routes.test.tsx +844 -0
  259. package/templates/apps/web/app/.well-known/ai-plugin.json/route.ts +81 -0
  260. package/templates/apps/web/app/.well-known/mcp.json/build-manifest.ts +110 -0
  261. package/templates/apps/web/app/.well-known/mcp.json/route.ts +58 -0
  262. package/templates/apps/web/app/[locale]/__tests__/layout.test.tsx +120 -0
  263. package/templates/apps/web/app/[locale]/__tests__/page-renderer-migration.test.tsx +202 -0
  264. package/templates/apps/web/app/[locale]/about/page.tsx +31 -0
  265. package/templates/apps/web/app/[locale]/blog/[[...slug]]/page.tsx +173 -0
  266. package/templates/apps/web/app/[locale]/careers/[slug]/page.tsx +45 -0
  267. package/templates/apps/web/app/[locale]/careers/__tests__/page-renderer-migration.test.tsx +117 -0
  268. package/templates/apps/web/app/[locale]/careers/page.tsx +25 -0
  269. package/templates/apps/web/app/[locale]/case-studies/[slug]/page.tsx +44 -0
  270. package/templates/apps/web/app/[locale]/case-studies/__tests__/page-renderer-migration.test.tsx +113 -0
  271. package/templates/apps/web/app/[locale]/case-studies/page.tsx +25 -0
  272. package/templates/apps/web/app/[locale]/clients/__tests__/page-renderer-migration.test.tsx +63 -0
  273. package/templates/apps/web/app/[locale]/clients/page.tsx +27 -0
  274. package/templates/apps/web/app/[locale]/contact/ContactForm.tsx +130 -0
  275. package/templates/apps/web/app/[locale]/contact/__tests__/contact.actions.test.ts +152 -0
  276. package/templates/apps/web/app/[locale]/contact/__tests__/page-renderer-migration.test.tsx +92 -0
  277. package/templates/apps/web/app/[locale]/contact/contact.actions.ts +79 -0
  278. package/templates/apps/web/app/[locale]/contact/error.tsx +24 -0
  279. package/templates/apps/web/app/[locale]/contact/page.tsx +38 -0
  280. package/templates/apps/web/app/[locale]/courses/[slug]/page.tsx +34 -0
  281. package/templates/apps/web/app/[locale]/courses/__tests__/page-renderer-migration.test.tsx +119 -0
  282. package/templates/apps/web/app/[locale]/courses/page.tsx +25 -0
  283. package/templates/apps/web/app/[locale]/dev/purchase/__tests__/actions.test.ts +160 -0
  284. package/templates/apps/web/app/[locale]/dev/purchase/error.tsx +25 -0
  285. package/templates/apps/web/app/[locale]/dev/purchase/page.tsx +117 -0
  286. package/templates/apps/web/app/[locale]/dev/purchase/purchase.actions.ts +58 -0
  287. package/templates/apps/web/app/[locale]/docs/[[...slug]]/page.tsx +118 -0
  288. package/templates/apps/web/app/[locale]/downloads/__tests__/page-renderer-migration.test.tsx +72 -0
  289. package/templates/apps/web/app/[locale]/downloads/page.tsx +25 -0
  290. package/templates/apps/web/app/[locale]/events/[slug]/page.tsx +47 -0
  291. package/templates/apps/web/app/[locale]/events/__tests__/page-renderer-migration.test.tsx +130 -0
  292. package/templates/apps/web/app/[locale]/events/page.tsx +25 -0
  293. package/templates/apps/web/app/[locale]/faq/page.tsx +36 -0
  294. package/templates/apps/web/app/[locale]/how-to/[slug]/page.tsx +34 -0
  295. package/templates/apps/web/app/[locale]/how-to/__tests__/page-renderer-migration.test.tsx +78 -0
  296. package/templates/apps/web/app/[locale]/how-to/page.tsx +40 -0
  297. package/templates/apps/web/app/[locale]/integrations/[slug]/page.tsx +43 -0
  298. package/templates/apps/web/app/[locale]/integrations/__tests__/page-renderer-migration.test.tsx +129 -0
  299. package/templates/apps/web/app/[locale]/integrations/page.tsx +25 -0
  300. package/templates/apps/web/app/[locale]/launch-service/page.tsx +31 -0
  301. package/templates/apps/web/app/[locale]/layout.tsx +241 -0
  302. package/templates/apps/web/app/[locale]/page.tsx +41 -0
  303. package/templates/apps/web/app/[locale]/partners/[slug]/page.tsx +44 -0
  304. package/templates/apps/web/app/[locale]/partners/__tests__/page-renderer-migration.test.tsx +113 -0
  305. package/templates/apps/web/app/[locale]/partners/page.tsx +25 -0
  306. package/templates/apps/web/app/[locale]/products/[slug]/page.tsx +43 -0
  307. package/templates/apps/web/app/[locale]/products/__tests__/page-renderer-migration.test.tsx +129 -0
  308. package/templates/apps/web/app/[locale]/products/page.tsx +25 -0
  309. package/templates/apps/web/app/[locale]/projects/[slug]/page.tsx +39 -0
  310. package/templates/apps/web/app/[locale]/projects/__tests__/page-renderer-migration.test.tsx +138 -0
  311. package/templates/apps/web/app/[locale]/projects/page.tsx +30 -0
  312. package/templates/apps/web/app/[locale]/resources/[slug]/page.tsx +51 -0
  313. package/templates/apps/web/app/[locale]/resources/__tests__/page-renderer-migration.test.tsx +117 -0
  314. package/templates/apps/web/app/[locale]/resources/page.tsx +27 -0
  315. package/templates/apps/web/app/[locale]/services/[slug]/page.tsx +43 -0
  316. package/templates/apps/web/app/[locale]/services/__tests__/page-renderer-migration.test.tsx +129 -0
  317. package/templates/apps/web/app/[locale]/services/page.tsx +25 -0
  318. package/templates/apps/web/app/[locale]/software/[slug]/page.tsx +34 -0
  319. package/templates/apps/web/app/[locale]/software/__tests__/page-renderer-migration.test.tsx +81 -0
  320. package/templates/apps/web/app/[locale]/software/page.tsx +39 -0
  321. package/templates/apps/web/app/[locale]/tech-articles/[slug]/page.tsx +34 -0
  322. package/templates/apps/web/app/[locale]/tech-articles/__tests__/page-renderer-migration.test.tsx +82 -0
  323. package/templates/apps/web/app/[locale]/tech-articles/page.tsx +39 -0
  324. package/templates/apps/web/app/[locale]/testimonials/__tests__/page-renderer-migration.test.tsx +63 -0
  325. package/templates/apps/web/app/[locale]/testimonials/page.tsx +27 -0
  326. package/templates/apps/web/app/[locale]/use-cases/__tests__/page-renderer-migration.test.tsx +63 -0
  327. package/templates/apps/web/app/[locale]/use-cases/page.tsx +27 -0
  328. package/templates/apps/web/app/[locale]/whitepapers/[slug]/page.tsx +34 -0
  329. package/templates/apps/web/app/[locale]/whitepapers/__tests__/page-renderer-migration.test.tsx +82 -0
  330. package/templates/apps/web/app/[locale]/whitepapers/page.tsx +39 -0
  331. package/templates/apps/web/app/__tests__/error-boundaries.test.tsx +152 -0
  332. package/templates/apps/web/app/api/auth/[...all]/route.ts +16 -0
  333. package/templates/apps/web/app/error-fallback.tsx +75 -0
  334. package/templates/apps/web/app/error.tsx +23 -0
  335. package/templates/apps/web/app/layout.tsx +18 -0
  336. package/templates/apps/web/app/llms.txt/route.ts +101 -0
  337. package/templates/apps/web/app/not-found.tsx +48 -0
  338. package/templates/apps/web/app/og/__tests__/route.test.ts +164 -0
  339. package/templates/apps/web/app/og/route.tsx +135 -0
  340. package/templates/apps/web/app/robots.txt/route.ts +36 -0
  341. package/templates/apps/web/app/sitemap.xml/route.ts +146 -0
  342. package/templates/apps/web/auth.ts +141 -0
  343. package/templates/apps/web/components/ThemeToggle.tsx +60 -0
  344. package/templates/apps/web/components/google-analytics.tsx +34 -0
  345. package/templates/apps/web/content/en/blog/index.mdx +15 -0
  346. package/templates/apps/web/content/en/blog/launching-ailk.mdx +20 -0
  347. package/templates/apps/web/content/en/docs/getting-started.mdx +30 -0
  348. package/templates/apps/web/i18n/request.ts +36 -0
  349. package/templates/apps/web/jest.config.cjs +100 -0
  350. package/templates/apps/web/lib/__mocks__/next-mdx-remote-rsc.js +12 -0
  351. package/templates/apps/web/lib/__mocks__/source-server.js +31 -0
  352. package/templates/apps/web/lib/__tests__/og.test.ts +65 -0
  353. package/templates/apps/web/lib/auth-env.ts +66 -0
  354. package/templates/apps/web/lib/blog-list-data.ts +95 -0
  355. package/templates/apps/web/lib/blog-post-data.ts +79 -0
  356. package/templates/apps/web/lib/nav-config.ts +13 -0
  357. package/templates/apps/web/lib/observability/better-stack.ts +27 -0
  358. package/templates/apps/web/lib/og.ts +23 -0
  359. package/templates/apps/web/lib/prisma-for-auth.ts +34 -0
  360. package/templates/apps/web/lib/source.ts +34 -0
  361. package/templates/apps/web/messages/en.json +131 -0
  362. package/templates/apps/web/middleware.ts +80 -0
  363. package/templates/apps/web/next.config.mjs +167 -0
  364. package/templates/apps/web/package.json +62 -0
  365. package/templates/apps/web/public/.well-known/security.txt +17 -0
  366. package/templates/apps/web/public/android-chrome-192x192.png +0 -0
  367. package/templates/apps/web/public/android-chrome-512x512.png +0 -0
  368. package/templates/apps/web/public/apple-touch-icon.png +0 -0
  369. package/templates/apps/web/public/favicon-16x16.png +0 -0
  370. package/templates/apps/web/public/favicon-32x32.png +0 -0
  371. package/templates/apps/web/public/favicon.ico +0 -0
  372. package/templates/apps/web/public/favicon.svg +4 -0
  373. package/templates/apps/web/public/logo-dark.svg +21 -0
  374. package/templates/apps/web/public/logo-light.svg +21 -0
  375. package/templates/apps/web/public/logomark-dark.svg +4 -0
  376. package/templates/apps/web/public/logomark-light.svg +4 -0
  377. package/templates/apps/web/public/og-default.png +0 -0
  378. package/templates/apps/web/public/site.webmanifest +19 -0
  379. package/templates/apps/web/scripts/assert-content-bundled.ts +55 -0
  380. package/templates/apps/web/security-headers.config.ts +132 -0
  381. package/templates/apps/web/sentry.client.config.ts +27 -0
  382. package/templates/apps/web/sentry.edge.config.ts +15 -0
  383. package/templates/apps/web/sentry.server.config.ts +20 -0
  384. package/templates/apps/web/source.config.ts +78 -0
  385. package/templates/apps/web/src/components/SiteNav.tsx +21 -0
  386. package/templates/apps/web/src/lib/routes.ts +37 -0
  387. package/templates/apps/web/tsconfig.json +35 -0
  388. package/templates/apps/web/types/messages.d.ts +19 -0
  389. package/templates/content/.gitkeep +0 -0
  390. package/templates/content/CLAUDE.md +85 -0
  391. package/templates/content/_site.mdx +38 -0
  392. package/templates/content/ar/HomePage/home.mdx +123 -0
  393. package/templates/content/ar/_site.mdx +35 -0
  394. package/templates/content/de/_site.mdx +29 -0
  395. package/templates/content/en/.gitkeep +0 -0
  396. package/templates/content/en/AboutPage/about.mdx +19 -0
  397. package/templates/content/en/AboutPage/about.schema.json +82 -0
  398. package/templates/content/en/BookCall/book-call.mdx +19 -0
  399. package/templates/content/en/BookCall/book-call.schema.json +121 -0
  400. package/templates/content/en/BreadcrumbList/site-breadcrumbs.mdx +20 -0
  401. package/templates/content/en/CareersList/careers.mdx +24 -0
  402. package/templates/content/en/CaseStudiesList/case-studies.mdx +22 -0
  403. package/templates/content/en/CaseStudiesList/showcase.mdx +8 -0
  404. package/templates/content/en/CaseStudy/ailk-aeo-rollout.mdx +32 -0
  405. package/templates/content/en/CaseStudy/schema-builder-migration.mdx +41 -0
  406. package/templates/content/en/ClientsList/clients.mdx +38 -0
  407. package/templates/content/en/ContactPage/contact.mdx +19 -0
  408. package/templates/content/en/ContactPage/contact.schema.json +100 -0
  409. package/templates/content/en/ContactPoint/primary.mdx +14 -0
  410. package/templates/content/en/Course/aeo-fundamentals.mdx +37 -0
  411. package/templates/content/en/Course/schema-builder-workshop.mdx +62 -0
  412. package/templates/content/en/CoursesList/courses.mdx +22 -0
  413. package/templates/content/en/DownloadsList/downloads.mdx +22 -0
  414. package/templates/content/en/Event/aeo-office-hours-may-2026.mdx +39 -0
  415. package/templates/content/en/Event/ailk-launch-day-2026.mdx +35 -0
  416. package/templates/content/en/EventsList/events.mdx +26 -0
  417. package/templates/content/en/FAQPage/faq.mdx +420 -0
  418. package/templates/content/en/FAQPage/faq.schema.json +231 -0
  419. package/templates/content/en/GlossaryList/glossary.mdx +19 -0
  420. package/templates/content/en/GlossaryList/glossary.schema.json +300 -0
  421. package/templates/content/en/HomePage/home.mdx +312 -0
  422. package/templates/content/en/HomePage/home.schema.json +88 -0
  423. package/templates/content/en/HomePage/launch-service.mdx +475 -0
  424. package/templates/content/en/HomePage/launch-service.schema.json +138 -0
  425. package/templates/content/en/HowTo/add-mdx-content.mdx +38 -0
  426. package/templates/content/en/HowTo/configure-aeo-scoring.mdx +35 -0
  427. package/templates/content/en/HowTo/set-up-json-ld.mdx +36 -0
  428. package/templates/content/en/Integration/github-actions.mdx +31 -0
  429. package/templates/content/en/Integration/openai-api.mdx +26 -0
  430. package/templates/content/en/Integration/vercel.mdx +32 -0
  431. package/templates/content/en/IntegrationsList/integrations.mdx +22 -0
  432. package/templates/content/en/JobPosting/content-strategist.mdx +46 -0
  433. package/templates/content/en/JobPosting/developer-advocate.mdx +47 -0
  434. package/templates/content/en/JobPosting/senior-fullstack-engineer.mdx +57 -0
  435. package/templates/content/en/LandingPage/aeo-audit.mdx +19 -0
  436. package/templates/content/en/LandingPage/aeo-audit.schema.json +92 -0
  437. package/templates/content/en/LandingPage/agency-waitlist.mdx +340 -0
  438. package/templates/content/en/LandingPage/agency-waitlist.schema.json +152 -0
  439. package/templates/content/en/LandingPage/developers.mdx +19 -0
  440. package/templates/content/en/LandingPage/developers.schema.json +109 -0
  441. package/templates/content/en/LandingPage/for-agencies.mdx +390 -0
  442. package/templates/content/en/LandingPage/for-agencies.schema.json +107 -0
  443. package/templates/content/en/LandingPage/for-ai-search-agencies.mdx +417 -0
  444. package/templates/content/en/LandingPage/for-ai-search-agencies.schema.json +105 -0
  445. package/templates/content/en/LandingPage/for-businesses.mdx +19 -0
  446. package/templates/content/en/LandingPage/for-businesses.schema.json +96 -0
  447. package/templates/content/en/LandingPage/platform.mdx +369 -0
  448. package/templates/content/en/LandingPage/platform.schema.json +166 -0
  449. package/templates/content/en/LandingPage/vs-ai-website-builders.mdx +19 -0
  450. package/templates/content/en/LandingPage/vs-ai-website-builders.schema.json +102 -0
  451. package/templates/content/en/LandingPage/vs-wordpress.mdx +19 -0
  452. package/templates/content/en/LandingPage/vs-wordpress.schema.json +53 -0
  453. package/templates/content/en/NewsletterSignup/newsletter.mdx +236 -0
  454. package/templates/content/en/NewsletterSignup/newsletter.schema.json +91 -0
  455. package/templates/content/en/Organization/site-owner.mdx +16 -0
  456. package/templates/content/en/Partner/prisma.mdx +31 -0
  457. package/templates/content/en/Partner/supabase.mdx +30 -0
  458. package/templates/content/en/Partner/vercel.mdx +28 -0
  459. package/templates/content/en/PartnersList/partners.mdx +22 -0
  460. package/templates/content/en/Person/founder.mdx +18 -0
  461. package/templates/content/en/Pricing/pricing.mdx +538 -0
  462. package/templates/content/en/Pricing/pricing.schema.json +209 -0
  463. package/templates/content/en/PrivacyPage/privacy.mdx +165 -0
  464. package/templates/content/en/PrivacyPage/privacy.schema.json +64 -0
  465. package/templates/content/en/Product/ailk.mdx +19 -0
  466. package/templates/content/en/Product/ailk.schema.json +94 -0
  467. package/templates/content/en/Product/api-launch-kit.mdx +26 -0
  468. package/templates/content/en/Product/launch-kit.mdx +28 -0
  469. package/templates/content/en/ProductsList/products.mdx +26 -0
  470. package/templates/content/en/Project/ailk-phase-2.mdx +54 -0
  471. package/templates/content/en/ProjectsList/projects.mdx +25 -0
  472. package/templates/content/en/ResourceDetail/aeo-scoring-guide.mdx +27 -0
  473. package/templates/content/en/ResourceDetail/content-model-whitepaper.mdx +28 -0
  474. package/templates/content/en/ResourceDetail/schema-org-quick-reference.mdx +39 -0
  475. package/templates/content/en/ResourcesHub/resources.mdx +22 -0
  476. package/templates/content/en/Service/consulting.mdx +22 -0
  477. package/templates/content/en/Service/implementation.mdx +30 -0
  478. package/templates/content/en/Service/launch-service.mdx +232 -0
  479. package/templates/content/en/Service/launch.mdx +228 -0
  480. package/templates/content/en/ServicesList/services.mdx +84 -0
  481. package/templates/content/en/SoftwareProduct/ailk-aeo.mdx +44 -0
  482. package/templates/content/en/SoftwareProduct/ailk-content-adapters.mdx +47 -0
  483. package/templates/content/en/SoftwareProduct/ailk-schema.mdx +49 -0
  484. package/templates/content/en/TeamList/team.mdx +63 -0
  485. package/templates/content/en/TeamMember/founder.mdx +72 -0
  486. package/templates/content/en/TermsPage/terms.mdx +19 -0
  487. package/templates/content/en/TermsPage/terms.schema.json +99 -0
  488. package/templates/content/en/TestimonialsList/testimonials.mdx +44 -0
  489. package/templates/content/en/UseCasesList/use-cases.mdx +30 -0
  490. package/templates/content/en/Whitepaper/ax-first-product-development.mdx +27 -0
  491. package/templates/content/en/Whitepaper/open-core-commercial-strategy.mdx +27 -0
  492. package/templates/content/en/Whitepaper/structured-data-for-answer-engines.mdx +31 -0
  493. package/templates/content/en-XA/AboutPage/about.mdx +8 -0
  494. package/templates/content/en-XA/FAQPage/faq.mdx +8 -0
  495. package/templates/content/en-XA/HomePage/home.mdx +8 -0
  496. package/templates/content/es/_site.mdx +30 -0
  497. package/templates/content/fr/_site.mdx +30 -0
  498. package/templates/content/ja/_site.mdx +30 -0
  499. package/templates/content/pt-BR/AboutPage/about.mdx +8 -0
  500. package/templates/content/pt-BR/FAQPage/faq.mdx +8 -0
  501. package/templates/content/pt-BR/HomePage/home.mdx +23 -0
  502. package/templates/database/CHANGELOG.md +5 -0
  503. package/templates/database/README.md +234 -0
  504. package/templates/database/__tests__/user-cascade.test.ts +125 -0
  505. package/templates/database/auth/.gitkeep +0 -0
  506. package/templates/database/config/.gitkeep +0 -0
  507. package/templates/database/content/.gitkeep +0 -0
  508. package/templates/database/inbox/.gitkeep +0 -0
  509. package/templates/database/inbox/README.md +3 -0
  510. package/templates/database/inbox/__tests__/schema.test.ts +40 -0
  511. package/templates/database/inbox/schema.prisma +52 -0
  512. package/templates/database/jest.config.cjs +29 -0
  513. package/templates/database/migrations/20260508000000_add_inbox_namespace/migration.sql +328 -0
  514. package/templates/database/migrations/20260513000000_better_auth_migration/migration.sql +100 -0
  515. package/templates/database/migrations/20260515000000_add_user_billing_fields/migration.sql +28 -0
  516. package/templates/database/migrations/20260516000000_add_user_tier_care_plan_seat/migration.sql +25 -0
  517. package/templates/database/migrations/20260518000000_add_telemetry_records/migration.sql +42 -0
  518. package/templates/database/migrations/20260525000000_theme_wiring/migration.sql +67 -0
  519. package/templates/database/migrations/20260710000000_retire_commercial_tier/migration.sql +21 -0
  520. package/templates/database/migrations/migration_lock.toml +3 -0
  521. package/templates/database/ops/.gitkeep +0 -0
  522. package/templates/database/package.json +45 -0
  523. package/templates/database/prisma.config.ts +20 -0
  524. package/templates/database/schema.prisma +487 -0
  525. package/templates/database/scripts/db-generate-locked.sh +80 -0
  526. package/templates/database/seed-test.ts +85 -0
  527. package/templates/database/tsconfig.build.json +16 -0
  528. package/templates/database/tsconfig.json +9 -0
  529. package/templates/package.json +125 -0
  530. package/templates/pnpm-workspace.yaml +6 -0
  531. package/templates/project.yaml +59 -0
  532. package/templates/tsconfig.base.json +18 -0
  533. package/templates/tsconfig.json +45 -0
@@ -0,0 +1,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.