create-ailk 0.8.0 → 0.10.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 (238) hide show
  1. package/README.md +71 -3
  2. package/component-catalog.json +279 -45
  3. package/dist/add-module.d.ts +20 -0
  4. package/dist/add-module.js +43 -7
  5. package/dist/add-route.d.ts +56 -0
  6. package/dist/add-route.js +286 -0
  7. package/dist/apply-design-md.d.ts +7 -0
  8. package/dist/apply-design-md.js +50 -0
  9. package/dist/apply-design.d.ts +64 -0
  10. package/dist/apply-design.js +273 -0
  11. package/dist/claude-md.d.ts +111 -0
  12. package/dist/claude-md.js +334 -0
  13. package/dist/cli.js +104 -5
  14. package/dist/derive-architecture.js +41 -36
  15. package/dist/design-compile.d.ts +71 -0
  16. package/dist/design-compile.js +98 -0
  17. package/dist/design-package.d.ts +83 -0
  18. package/dist/design-package.js +468 -0
  19. package/dist/design-presets.d.ts +86 -0
  20. package/dist/design-presets.js +642 -0
  21. package/dist/design-scaffold.d.ts +76 -0
  22. package/dist/design-scaffold.js +220 -0
  23. package/dist/index.d.ts +2 -1
  24. package/dist/index.js +4 -1
  25. package/dist/legacy-nav-renderers.d.ts +45 -0
  26. package/dist/legacy-nav-renderers.js +545 -0
  27. package/dist/lib/auth-secret-file.d.ts +19 -0
  28. package/dist/lib/auth-secret-file.js +112 -0
  29. package/dist/lib/design-checks.d.ts +78 -0
  30. package/dist/lib/design-checks.js +174 -0
  31. package/dist/lib/license-key-files.d.ts +9 -0
  32. package/dist/lib/license-key-files.js +2 -2
  33. package/dist/lib/module-license-gate.d.ts +48 -32
  34. package/dist/lib/module-license-gate.js +117 -8
  35. package/dist/lib/render-verdict.d.ts +52 -0
  36. package/dist/lib/render-verdict.js +77 -0
  37. package/dist/lib/scaffold-render-sweep.d.ts +105 -0
  38. package/dist/lib/scaffold-render-sweep.js +236 -0
  39. package/dist/module-architecture.d.ts +19 -16
  40. package/dist/module-architecture.js +67 -23
  41. package/dist/parse-args.d.ts +12 -2
  42. package/dist/parse-args.js +74 -13
  43. package/dist/programmatic.d.ts +30 -6
  44. package/dist/programmatic.js +216 -19
  45. package/dist/site-chrome.d.ts +19 -9
  46. package/dist/site-chrome.js +23 -13
  47. package/dist/site-manifest.d.ts +25 -0
  48. package/dist/site-manifest.js +254 -0
  49. package/dist/site-roster.d.ts +41 -0
  50. package/dist/site-roster.js +141 -8
  51. package/dist/starter-grid.d.ts +16 -63
  52. package/dist/starter-grid.js +102 -84
  53. package/dist/surfaces.d.ts +41 -9
  54. package/dist/surfaces.js +200 -83
  55. package/dist/template-manifest.d.ts +30 -13
  56. package/dist/template-manifest.js +53 -28
  57. package/package.json +6 -3
  58. package/release-scope.json +25 -0
  59. package/site-templates/_base/content/en/UseCase/persona-1.mdx +7 -6
  60. package/site-templates/_base/content/en/UseCase/persona-2.mdx +7 -6
  61. package/site-templates/_base/content/en/UseCase/persona-3.mdx +7 -6
  62. package/site-templates/designs/minimalism/DESIGN.md +98 -6
  63. package/site-templates/designs/minimalism/sample/README.md +48 -0
  64. package/site-templates/{minimalism-site → designs/minimalism/sample}/content/en/HomePage/home.mdx +1 -1
  65. package/site-templates/designs/standard/DESIGN.md +98 -6
  66. package/site-templates/marketing-site/DESIGN.md +98 -6
  67. package/site-templates/marketing-site/TEMPLATE-MANIFEST.json +60 -27
  68. package/site-templates/marketing-site/TEMPLATE-MANIFEST.md +50 -30
  69. package/site-templates/marketing-site-free/DESIGN.md +98 -6
  70. package/site-templates/marketing-site-free/TEMPLATE-MANIFEST.json +60 -24
  71. package/site-templates/marketing-site-free/TEMPLATE-MANIFEST.md +44 -27
  72. package/site-templates/marketing-site-free/ailk-template.json +1 -1
  73. package/site-templates/saas-product/DESIGN.md +98 -6
  74. package/site-templates/shapes/local-business-service/TEMPLATE-MANIFEST.json +127 -18
  75. package/site-templates/shapes/local-business-service/TEMPLATE-MANIFEST.md +74 -20
  76. package/site-templates/shapes/local-business-service/ailk-template.json +1 -1
  77. package/site-templates/shapes/organization-service/TEMPLATE-MANIFEST.json +127 -18
  78. package/site-templates/shapes/organization-service/TEMPLATE-MANIFEST.md +74 -20
  79. package/site-templates/shapes/organization-service/ailk-template.json +1 -1
  80. package/site-templates/shapes/person-service/TEMPLATE-MANIFEST.json +127 -18
  81. package/site-templates/shapes/person-service/TEMPLATE-MANIFEST.md +75 -21
  82. package/site-templates/shapes/person-service/ailk-template.json +1 -1
  83. package/site-templates/shapes/person-service/content/en/AboutPage/about.mdx +1 -1
  84. package/site-templates/shapes/person-service/content/en/HomePage/home.mdx +2 -2
  85. package/site-templates/shapes/person-service/content/en/PortfolioList/portfolio.mdx +4 -2
  86. package/site-templates/shapes/person-service/content/en/ServicesList/services.mdx +1 -1
  87. package/templates/.claude/agents/web.md +10 -8
  88. package/templates/.claude/rules/architecture.md +17 -7
  89. package/templates/.claude/skills/README.md +3 -2
  90. package/templates/.claude/skills/add-auth/SKILL.md +142 -90
  91. package/templates/.claude/skills/add-auth/references/env-vars.md +32 -17
  92. package/templates/.claude/skills/add-auth/references/oauth-app-setup.md +17 -8
  93. package/templates/.claude/skills/add-page/SKILL.md +241 -238
  94. package/templates/.claude/skills/add-page/references/page-types.md +94 -86
  95. package/templates/.claude/skills/add-page/scripts/site-pages.mjs +87 -0
  96. package/templates/.claude/skills/add-page/templates/comparison-page.mdx.tmpl +99 -0
  97. package/templates/.claude/skills/add-page/templates/content.mdx.tmpl +8 -18
  98. package/templates/.claude/skills/add-page/templates/flow-landing-page.mdx.tmpl +43 -0
  99. package/templates/.claude/skills/add-page/templates/report-page.mdx.tmpl +52 -0
  100. package/templates/.claude/skills/add-page/templates/reports-list.mdx.tmpl +38 -0
  101. package/templates/.claude/skills/check-site/SKILL.md +51 -18
  102. package/templates/.claude/skills/check-site/references/common-errors.md +12 -9
  103. package/templates/.claude/skills/check-site/references/findings-glossary.md +4 -4
  104. package/templates/.claude/skills/check-site/references/severity-levels.md +3 -3
  105. package/templates/.claude/skills/fill-page/SKILL.md +26 -7
  106. package/templates/.claude/skills/fill-page/profiles/plumbing.yaml +1 -1
  107. package/templates/.claude/skills/setup-deploy/SKILL.md +75 -38
  108. package/templates/.claude/skills/update-page/SKILL.md +117 -0
  109. package/templates/.claude/skills/update-page/scripts/update-page.ts +640 -0
  110. package/templates/.claude/skills/update-page/templates/redirects.mjs.tmpl +31 -0
  111. package/templates/.claude/skills/upgrade-plan/SKILL.md +12 -8
  112. package/templates/.env.example +23 -2
  113. package/templates/.github/workflows/ci.yml +4 -0
  114. package/templates/.prettierignore +1 -0
  115. package/templates/CLAUDE.md +146 -103
  116. package/templates/DESIGN.md +98 -6
  117. package/templates/README.md +50 -38
  118. package/templates/apps/api/.env.example +2 -1
  119. package/templates/apps/api/src/__tests__/commerce-claim-registration.test.ts +2 -0
  120. package/templates/apps/api/src/__tests__/server.test.ts +116 -0
  121. package/templates/apps/api/src/lib/stripe.ts +9 -0
  122. package/templates/apps/api/src/middleware/__tests__/auth.optional-cookie.test.ts +140 -0
  123. package/templates/apps/api/src/middleware/auth.ts +54 -0
  124. package/templates/apps/api/src/routes/checkout/__tests__/session.test.ts +5 -2
  125. package/templates/apps/api/src/routes/checkout/__tests__/sessions.test.ts +628 -0
  126. package/templates/apps/api/src/routes/checkout/sessions.ts +222 -24
  127. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-flow-checkout.test.ts +1 -1
  128. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-org-billing.test.ts +5 -1
  129. package/templates/apps/api/src/routes/webhooks/__tests__/stripe.test.ts +521 -20
  130. package/templates/apps/api/src/routes/webhooks/stripe.ts +124 -32
  131. package/templates/apps/api/src/server.ts +28 -0
  132. package/templates/apps/api/src/services/__tests__/revalidation.test.ts +90 -15
  133. package/templates/apps/api/src/services/checkout-buyer.ts +72 -0
  134. package/templates/apps/api/src/services/revalidation.ts +60 -15
  135. package/templates/apps/mcp/__tests__/tools/create_project.test.ts +30 -24
  136. package/templates/apps/mcp/src/tools/purchase.ts +4 -2
  137. package/templates/apps/web/.env.example +13 -0
  138. package/templates/apps/web/CLAUDE.md +22 -28
  139. package/templates/apps/web/app/[locale]/(auth)/layout.tsx +1 -1
  140. package/templates/apps/web/app/[locale]/(authed)/leads/__tests__/page.test.tsx +24 -0
  141. package/templates/apps/web/app/[locale]/(authed)/leads/page.tsx +17 -6
  142. package/templates/apps/web/app/[locale]/[slug]/[detail]/__tests__/page.test.tsx +110 -0
  143. package/templates/apps/web/app/[locale]/[slug]/[detail]/page.tsx +60 -0
  144. package/templates/apps/web/app/[locale]/[slug]/page.tsx +1 -1
  145. package/templates/apps/web/app/[locale]/alternatives/__tests__/page.test.tsx +161 -0
  146. package/templates/apps/web/app/[locale]/alternatives/page.tsx +104 -0
  147. package/templates/apps/web/app/[locale]/{use-cases → for}/[slug]/page.tsx +4 -3
  148. package/templates/apps/web/app/[locale]/for/__tests__/page-renderer-migration.test.tsx +73 -0
  149. package/templates/apps/web/app/[locale]/{use-cases → for}/page.tsx +8 -7
  150. package/templates/apps/web/app/[locale]/glossary/page.tsx +1 -1
  151. package/templates/apps/web/app/[locale]/layout.tsx +35 -19
  152. package/templates/apps/web/app/[locale]/newsletter/page.tsx +1 -1
  153. package/templates/apps/web/app/[locale]/portfolio/[slug]/page.tsx +1 -1
  154. package/templates/apps/web/app/[locale]/portfolio/page.tsx +1 -1
  155. package/templates/apps/web/app/[locale]/vs/[slug]/__tests__/page.test.tsx +112 -0
  156. package/templates/apps/web/app/[locale]/vs/[slug]/page.tsx +70 -0
  157. package/templates/apps/web/app/api/revalidate/__tests__/route.test.ts +236 -44
  158. package/templates/apps/web/app/api/revalidate/route.ts +78 -36
  159. package/templates/apps/web/lib/__tests__/site-brand.test.ts +79 -0
  160. package/templates/apps/web/lib/__tests__/site-theme.test.ts +104 -11
  161. package/templates/apps/web/lib/__tests__/structured-data.test.tsx +21 -4
  162. package/templates/apps/web/lib/locale-guard.ts +18 -0
  163. package/templates/apps/web/lib/meet-placeholder.ts +5 -0
  164. package/templates/apps/web/lib/nav-config.ts +14 -13
  165. package/templates/apps/web/lib/site-brand.tsx +13 -9
  166. package/templates/apps/web/lib/site-logo.tsx +36 -0
  167. package/templates/apps/web/lib/site-theme.ts +46 -26
  168. package/templates/apps/web/messages/en.json +23 -9
  169. package/templates/apps/web/middleware.ts +28 -4
  170. package/templates/content/en/BookCall/book-a-call.mdx +80 -0
  171. package/templates/content/en/BookCall/onsite-estimate.mdx +56 -0
  172. package/templates/content/en/BookCall/onsite-service.mdx +56 -0
  173. package/templates/content/en/BookCall/start-project.mdx +56 -0
  174. package/templates/content/en/ContactPage/contact.mdx +40 -1
  175. package/templates/content/en/HomePage/home.mdx +2 -6
  176. package/templates/content/en/LandingPage/meet.mdx +59 -0
  177. package/templates/content/en/UseCasesList/{use-cases.mdx → for.mdx} +19 -18
  178. package/templates/database/CHANGELOG.md +7 -0
  179. package/templates/database/package.json +1 -1
  180. package/templates/package.json +4 -1
  181. package/templates/tools/check-claude-md.ts +128 -0
  182. package/versions.json +33 -33
  183. package/dist/modules/commerce/0.6.0.tar.gz +0 -0
  184. package/dist/modules/commerce/0.6.1.tar.gz +0 -0
  185. package/dist/modules/docs-blog/0.6.0.tar.gz +0 -0
  186. package/dist/modules/docs-blog/0.6.1.tar.gz +0 -0
  187. package/dist/modules/marketing-site/0.6.1.tar.gz +0 -0
  188. package/dist/modules/minimalism-site/0.6.1.tar.gz +0 -0
  189. package/dist/modules/multi-tenant/0.6.0.tar.gz +0 -0
  190. package/dist/modules/multi-tenant/0.6.1.tar.gz +0 -0
  191. package/dist/modules/saas-product/0.6.1.tar.gz +0 -0
  192. package/dist/modules/scheduling/0.6.0.tar.gz +0 -0
  193. package/dist/modules/scheduling/0.6.1.tar.gz +0 -0
  194. package/dist/modules/signal-collectors/0.6.0.tar.gz +0 -0
  195. package/dist/modules/signal-collectors/0.6.1.tar.gz +0 -0
  196. package/dist/modules/simple-service/0.6.1.tar.gz +0 -0
  197. package/dist/modules/workspace/0.6.0.tar.gz +0 -0
  198. package/dist/modules/workspace/0.6.1.tar.gz +0 -0
  199. package/site-templates/_base/content/en/BookCall/book-call.mdx +0 -52
  200. package/site-templates/minimalism-site/DESIGN.md +0 -162
  201. package/site-templates/minimalism-site/TEMPLATE-MANIFEST.json +0 -506
  202. package/site-templates/minimalism-site/TEMPLATE-MANIFEST.md +0 -458
  203. package/site-templates/minimalism-site/ailk-template.json +0 -23
  204. package/site-templates/minimalism-site/content/en/AboutPage/about.mdx +0 -110
  205. package/site-templates/minimalism-site/content/en/BookCall/book-call.mdx +0 -52
  206. package/site-templates/minimalism-site/content/en/ContactPage/contact.mdx +0 -34
  207. package/site-templates/minimalism-site/content/en/FAQPage/faq.mdx +0 -57
  208. package/site-templates/minimalism-site/content/en/LandingPage/referral.mdx +0 -77
  209. package/site-templates/minimalism-site/content/en/LandingPage/reports.mdx +0 -73
  210. package/site-templates/minimalism-site/content/en/PurchasePolicyPage/purchase-policy.mdx +0 -123
  211. package/site-templates/minimalism-site/content/en/ReportPage/annual-letter-2024.mdx +0 -52
  212. package/site-templates/minimalism-site/content/en/ReportPage/field-notes-2023.mdx +0 -52
  213. package/site-templates/minimalism-site/content/en/ReportPage/platform-shift-2025.mdx +0 -52
  214. package/site-templates/minimalism-site/content/en/ReportPage/state-of-the-market-2026.mdx +0 -52
  215. package/site-templates/minimalism-site/content/en/Service/first-engagement.mdx +0 -38
  216. package/site-templates/minimalism-site/content/en/Service/second-engagement.mdx +0 -38
  217. package/site-templates/minimalism-site/content/en/Service/third-engagement.mdx +0 -38
  218. package/site-templates/minimalism-site/content/en/ServicesList/services.mdx +0 -73
  219. package/site-templates/minimalism-site/flows/referral.flow.json +0 -71
  220. package/site-templates/minimalism-site/provenance.json +0 -4
  221. package/templates/.claude/skills/add-page/templates/route.tsx.tmpl +0 -28
  222. package/templates/.claude/skills/setup-deploy/references/env-vars-template.md +0 -175
  223. package/templates/apps/api/.ailk/inbox/2026-09-20T14-57-31.552Z-fallback-1789916251590-037e9005.json +0 -8
  224. package/templates/apps/api/.ailk/inbox/2026-09-20T14-57-33.840Z-fallback-1789916253842-b52659e9.json +0 -12
  225. package/templates/apps/api/.ailk/inbox/2026-09-20T14-57-33.844Z-fallback-1789916253845-6b266f8c.json +0 -12
  226. package/templates/apps/web/app/[locale]/book-a-call/page.tsx +0 -50
  227. package/templates/apps/web/app/[locale]/use-cases/__tests__/page-renderer-migration.test.tsx +0 -72
  228. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/avatar-placeholder-1.svg +0 -0
  229. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/avatar-placeholder-2.svg +0 -0
  230. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/avatar-placeholder-3.svg +0 -0
  231. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/avatar-placeholder-4.svg +0 -0
  232. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/avatar-placeholder-5.svg +0 -0
  233. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/avatar-placeholder-6.svg +0 -0
  234. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/hero-backdrop.svg +0 -0
  235. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/logo-placeholder-1.svg +0 -0
  236. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/logo-placeholder-2.svg +0 -0
  237. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/logo-placeholder-3.svg +0 -0
  238. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/wordmark-placeholder.svg +0 -0
@@ -1,68 +1,95 @@
1
1
  ---
2
2
  name: add-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.
3
+ description: Activate the site's sign-in providers (email-and-password, 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 email / Google / GitHub sign-in 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 `apps/web/auth.ts` and does NOT emit any pages.
4
4
  ---
5
5
 
6
6
  # add-auth
7
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.
8
+ Activate one or more sign-in providers on an AILK site by writing the
9
+ env vars `getActiveProviderIds()` (`apps/web/lib/auth-env.ts`) reads
10
+ to detect them, plus a `RUNBOOK.md` that documents the OAuth-app-creation
11
+ steps for the consumer's records.
12
+
13
+ The site's auth library is **Better Auth**, configured in
14
+ `apps/web/auth.ts` and mounted at `apps/web/app/api/auth/[...all]/route.ts`.
11
15
 
12
16
  ## When to use
13
17
 
14
18
  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:
19
+ to gate routes behind sign-in or accept email, Google or GitHub
20
+ sign-in. Phrases that should trigger this skill:
17
21
 
18
22
  - "wire up auth" / "add login" / "set up sign-in"
19
23
  - "I want users to log in"
20
24
  - "enable Google sign-in" / "enable GitHub login"
21
- - "set up magic-link auth"
25
+ - "set up email login" / "set up magic-link auth"
22
26
  - "add OAuth"
23
27
 
28
+ A magic link is not wired: Better Auth core ships no magic-link
29
+ provider, so the `email` provider id switches on email-and-password
30
+ sign-in instead. Say so when the consumer asks for a magic link, and
31
+ offer `email` on those terms.
32
+
24
33
  Skip this skill when:
25
34
 
26
- - The user wants a `/login` or `/account` _page_ — those are pages, not
27
- auth wiring. Use `add-page` 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.
35
+ - The user wants a new page. The site already ships its sign-in and
36
+ sign-up pages (`apps/web/app/[locale]/(auth)/`), which list whichever
37
+ providers are active. Any other page is `add-page`'s job.
38
+ - The user is asking about a third-party provider outside the three
39
+ provider ids below (Apple, Microsoft, Twitter, etc.). Adding one is a
40
+ code change to `apps/web/auth.ts`, not env wiring. Acknowledge the
41
+ request and stop.
32
42
  - The user is in production and needs production callback URLs. v1
33
43
  ships dev-mode callbacks (`http://localhost:3000`) only —
34
44
  production callback setup is deferred to `setup-deploy`
35
45
  or a future deploy skill. Note this and stop.
36
46
 
47
+ ## The provider ids
48
+
49
+ `getActiveProviderIds()` in `apps/web/lib/auth-env.ts` returns a
50
+ provider id only when every one of its env vars is set to a non-empty
51
+ value:
52
+
53
+ | Provider id | Env vars | What it switches on |
54
+ | ----------- | ------------------------------------------- | --------------------------------------------------------------- |
55
+ | `email` | `AUTH_EMAIL_SERVER` + `AUTH_EMAIL_FROM` | Email-and-password sign-in (Better Auth's `emailAndPassword`) |
56
+ | `google` | `GOOGLE_CLIENT_ID` + `GOOGLE_CLIENT_SECRET` | Google OAuth (Better Auth's `socialProviders.google`) |
57
+ | `github` | `GITHUB_CLIENT_ID` + `GITHUB_CLIENT_SECRET` | GitHub OAuth (Better Auth's `socialProviders.github`) |
58
+
59
+ `references/env-vars.md` is the full contract, including the auxiliary
60
+ vars (`BETTER_AUTH_URL`, `BETTER_AUTH_SECRET`, `AILK_AUTH_REQUIRED`,
61
+ `AILK_AUTH_SIGNUP_OPEN`, `AILK_AUTH_PASSWORD_RESET`,
62
+ `AUTH_EMAIL_WEBHOOK_SECRET`).
63
+
37
64
  ## What this skill does (and does not do)
38
65
 
39
66
  **Does:**
40
67
 
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_.
68
+ - Reads `.env.local` to see which provider ids are already active.
69
+ - Asks the consumer which of the three provider ids (`email`,
70
+ `google`, `github`) they want to activate _this session_.
44
71
  - 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.
72
+ OAuth-app creation (`google` / `github`) or the Resend sender setup
73
+ (`email`), then writes the resulting values to `.env.local`.
74
+ - Checks that sign-in has a database to write to. Better Auth always
75
+ runs its Prisma adapter with database sessions, so sign-in needs
76
+ `DATABASE_URL` and the auth tables in place.
50
77
  - Writes (or merges) a `RUNBOOK.md` in the consumer's repo root
51
78
  with the same setup instructions the consumer just followed, so
52
79
  they can refer back later or hand to a collaborator.
53
80
 
54
81
  **Does not:**
55
82
 
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.
83
+ - Modify `apps/web/auth.ts`. The three provider ids are env-var-driven
84
+ — `apps/web/auth.ts` reads `getActiveProviderIds()` at startup and
85
+ builds only the providers it returns. No code changes are needed.
59
86
  - Create any new files under `app/`, `pages/`, or `content/`. The
60
87
  emit is limited to `.env.local` writes and a `RUNBOOK.md` write.
61
88
  - Set up production callback URLs. Dev-mode (`http://localhost:3000`)
62
89
  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.
90
+ - Add, remove, or modify any provider in `apps/web/auth.ts`. A
91
+ provider the consumer added there by hand (e.g., Apple) is preserved
92
+ as-is and never touched by this skill.
66
93
  - Accept production OAuth credentials. If the consumer pastes a
67
94
  production-looking secret, that's acceptable, but the runbook still
68
95
  documents only the dev callback URL.
@@ -71,28 +98,28 @@ Skip this skill when:
71
98
 
72
99
  ### Step 1 — Show the menu
73
100
 
74
- Greet the consumer and present the three locked providers, marking
75
- which are already activated (env vars present in `.env.local`):
101
+ Greet the consumer and present the three provider ids, marking
102
+ which are already active (env vars present in `.env.local`):
76
103
 
77
104
  ```
78
- Which auth providers do you want to activate?
105
+ Which sign-in providers do you want to activate?
79
106
 
80
- [ ] magic-link (passwordless email login via Resend)
81
- [ ] Google OAuth
82
- [ ] GitHub OAuth
107
+ [ ] email (email-and-password sign-in)
108
+ [ ] google (Google OAuth)
109
+ [ ] github (GitHub OAuth)
83
110
 
84
111
  You can pick any subset, including "none of the above" (in which case
85
112
  this skill exits without writing anything). You can also re-run this
86
- skill later to activate more providers — already-activated providers
113
+ skill later to activate more providers — already-active providers
87
114
  will be skipped automatically.
88
115
  ```
89
116
 
90
- If `.env.local` already has any of these activated, mark them:
117
+ If `.env.local` already has any of these active, mark them:
91
118
 
92
119
  ```
93
- [x] magic-link (already activated — AUTH_EMAIL_SERVER + AUTH_EMAIL_FROM are set)
94
- [ ] Google OAuth
95
- [ ] GitHub OAuth
120
+ [x] email (already active — AUTH_EMAIL_SERVER + AUTH_EMAIL_FROM are set)
121
+ [ ] google (Google OAuth)
122
+ [ ] github (GitHub OAuth)
96
123
  ```
97
124
 
98
125
  Wait for the consumer to pick a subset. Then, for each picked
@@ -100,12 +127,13 @@ provider, run the matching sub-flow.
100
127
 
101
128
  ### Step 2 — Run per-provider sub-flows
102
129
 
103
- #### magic-link sub-flow
130
+ #### `email` sub-flow
104
131
 
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>."_
132
+ 1. Tell the consumer: _"The `email` provider turns on
133
+ email-and-password sign-in. It switches on when `AUTH_EMAIL_SERVER`
134
+ and `AUTH_EMAIL_FROM` are both set. You'll need a Resend API key
135
+ (free tier is fine for development). Get one at
136
+ <https://resend.com/api-keys>."_
109
137
  2. Wait for the consumer to paste the API key.
110
138
  3. Ask for the `AUTH_EMAIL_FROM` address. This must be a verified
111
139
  sender on the consumer's Resend account. For development it's
@@ -118,16 +146,33 @@ provider, run the matching sub-flow.
118
146
  AUTH_EMAIL_SERVER=smtp://resend:re_...@smtp.resend.com:465
119
147
  AUTH_EMAIL_FROM=onboarding@resend.dev
120
148
  ```
121
-
122
- #### Google OAuth sub-flow
149
+ 6. Tell the consumer who actually sends the mail. `apps/web` sends
150
+ none: `AUTH_EMAIL_SERVER` is read for its presence only, and
151
+ `apps/web/lib/auth-email.ts` relays each auth email (verification,
152
+ password reset) to `apps/api`, which sends it with `RESEND_API_KEY`
153
+ from `AUTH_EMAIL_FROM`. For that mail to go out, `RESEND_API_KEY`
154
+ and `AUTH_EMAIL_FROM` must be set for `apps/api`, and
155
+ `AUTH_EMAIL_WEBHOOK_SECRET` (any long random string, the same value)
156
+ for both apps. Password reset — and the verification mail with it —
157
+ is off until `AILK_AUTH_PASSWORD_RESET=1`, and also needs
158
+ `BETTER_AUTH_URL` and `BETTER_AUTH_SECRET` (`resetSendConfigured()`
159
+ in `apps/web/lib/auth-env.ts`).
160
+ 7. Tell the consumer that public sign-up stays closed until they set
161
+ `AILK_AUTH_SIGNUP_OPEN=1` (read by `isSignUpOpen()` in
162
+ `apps/web/lib/auth-env.ts`). With sign-up closed and `email` the only
163
+ provider, nobody can create the first account — so either open
164
+ sign-up long enough to create it, or activate `google` or `github`
165
+ as well. Ask which they want; leave the flag unset otherwise.
166
+
167
+ #### `google` sub-flow
123
168
 
124
169
  1. Tell the consumer the steps in chat AND queue the same content for
125
170
  the runbook (see Step 3). Steps:
126
171
  - Go to <https://console.cloud.google.com/apis/credentials>.
127
172
  - Click **Create Credentials → OAuth client ID**. If prompted,
128
173
  configure the OAuth consent screen first (**External** → fill
129
- name, support email, developer contact email; scopes are
130
- auto-populated by NextAuth).
174
+ name, support email, developer contact email; Better Auth
175
+ requests the scopes at runtime, so leave the scope list empty).
131
176
  - Application type: **Web application**.
132
177
  - Name: anything (e.g., "AILK dev").
133
178
  - **Authorized redirect URIs** — add exactly:
@@ -141,7 +186,7 @@ provider, run the matching sub-flow.
141
186
  GOOGLE_CLIENT_SECRET=...
142
187
  ```
143
188
 
144
- #### GitHub OAuth sub-flow
189
+ #### `github` sub-flow
145
190
 
146
191
  1. Tell the consumer the steps in chat AND queue the same content for
147
192
  the runbook. Steps:
@@ -171,49 +216,56 @@ or refer back later.
171
216
  Use `references/oauth-app-setup.md` as the template. Replace
172
217
  `<provider>` headings as appropriate, and only include sections for
173
218
  providers actually activated this session. If `RUNBOOK.md` already
174
- exists with sections for already-activated providers, do not
219
+ exists with sections for already-active providers, do not
175
220
  duplicate — add only the new sections beneath any existing content.
176
221
 
177
- ### Step 4 — Detect the database adapter mode
222
+ ### Step 4 — Check the database
178
223
 
179
- Before printing the closing summary, check the consumer's setup:
224
+ Sign-in always reads and writes the database: `apps/web/auth.ts`
225
+ runs Better Auth's Prisma adapter, and sessions are rows, not
226
+ cookie-only tokens. There is no database-free mode. Before printing
227
+ the closing summary, check:
180
228
 
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.
229
+ - `DATABASE_URL` (and `DATABASE_URL_NON_POOLED`, which the migrations
230
+ use) is set in `.env.local`. If it is not, sign-in will fail on its
231
+ first request — point the consumer at the `setup-database` skill,
232
+ which sets both and creates the tables.
233
+ - The auth tables exist. The Prisma schema is `database/schema.prisma`
234
+ (Prisma reads the whole `database/` folder; the `User`, `Session`,
235
+ `Account` and `Verification` models are in `database/auth/schema.prisma`).
236
+ If the consumer has not applied the migrations yet, they run
237
+ `pnpm db:migrate:deploy`.
185
238
 
186
- State the mode in the closing summary so the consumer is never
239
+ State what you found in the closing summary so the consumer is never
187
240
  surprised:
188
241
 
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."
242
+ > "Sign-in stores its users and sessions in your database (the
243
+ > `User` and `Session` tables). Run `pnpm db:migrate:deploy` if you
244
+ > haven't applied the migrations yet."
192
245
 
193
- or
246
+ or, when `DATABASE_URL` is unset:
194
247
 
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`."
248
+ > "Sign-in needs a database and none is configured yet. Run the
249
+ > `setup-database` skill before you try to sign in."
199
250
 
200
251
  ### Step 5 — Closing summary
201
252
 
202
253
  Print:
203
254
 
204
- - Which providers are now active (subset picked this session +
205
- already-activated providers).
206
- - The database adapter mode (Prisma or JWT).
255
+ - Which provider ids are now active (subset picked this session +
256
+ already-active providers).
257
+ - What Step 4 found about the database.
207
258
  - A reminder to set `AILK_AUTH_REQUIRED=1` in `.env.local` if they
208
259
  want protected routes (default is auth-disabled / public).
209
260
  - A pointer to `RUNBOOK.md` for future reference.
210
- - A pointer to `setup-deploy` for production callback URL
211
- setup when the consumer is ready to deploy.
261
+ - A pointer to `setup-deploy` for production callback URLs and
262
+ `BETTER_AUTH_URL` / `BETTER_AUTH_SECRET` when the consumer is ready
263
+ to deploy — a production deploy fails without `BETTER_AUTH_SECRET`.
212
264
 
213
265
  ## Re-invocation
214
266
 
215
267
  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
268
+ already-active providers with `[x]` (read from `.env.local`), and
217
269
  the per-provider sub-flows skip those and only run for the new ones.
218
270
  The closing summary lists everything, not just what changed this
219
271
  session.
@@ -225,37 +277,37 @@ existing values in `.env.local`. Confirm before overwriting.
225
277
 
226
278
  ## Customization preservation
227
279
 
228
- If `auth.config.ts` has been modified by the consumer to add a
280
+ If `apps/web/auth.ts` has been modified by the consumer to add a
229
281
  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.
282
+ completely untouched. The skill never edits `apps/web/auth.ts`.
283
+ Activation of the three provider ids happens entirely through env
284
+ vars — `getActiveProviderIds()` in `apps/web/lib/auth-env.ts` is what
285
+ reads them at startup.
234
286
 
235
287
  ## What "activation" means under the hood
236
288
 
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`
289
+ - **The provider list is computed at startup from env-var presence**
290
+ by `getActiveProviderIds()` in `apps/web/lib/auth-env.ts`.
291
+ - `apps/web/auth.ts` consumes that list: `google` and `github` become
292
+ Better Auth `socialProviders` entries built from their env vars, and
293
+ `email` switches `emailAndPassword` on.
294
+ - A provider id is returned only when every one of its env vars is set
295
+ (the table under § The provider ids).
243
296
  - A site with zero auth env vars boots cleanly with no active
244
- providers (`apps/web/lib/auth-env.ts` returns an empty array).
297
+ providers (`getActiveProviderIds()` returns an empty array).
245
298
 
246
299
  This means the skill's job is purely env-var wiring + documentation.
247
300
 
248
301
  ## References
249
302
 
250
303
  - `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).
304
+ - `references/env-vars.md` — env-var contract (which vars activate which provider id).
252
305
 
253
306
  ## Coordination
254
307
 
255
- - **`add-page`** — `/login` or `/account` pages. This skill
256
- emits no pages.
257
- - **`setup-deploy`** — 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.
308
+ - **`add-page`** — any new page. This skill emits no pages; the
309
+ sign-in and sign-up pages already ship.
310
+ - **`setup-database`** — `DATABASE_URL` and the tables sign-in
311
+ needs.
312
+ - **`setup-deploy`** — production callback URLs and the production
313
+ auth env vars. v1 of this skill is dev-only.
@@ -8,35 +8,51 @@ The activation logic lives in `apps/web/lib/auth-env.ts` →
8
8
  `getActiveProviderIds()`. A provider is active **only when every
9
9
  required var is set to a non-empty value**. Partial wiring (e.g.,
10
10
  `GOOGLE_CLIENT_ID` set but `GOOGLE_CLIENT_SECRET` missing) is treated
11
- as inactive — NextAuth never tries to construct that provider.
11
+ as inactive — `apps/web/auth.ts` never constructs that provider.
12
+
13
+ The site's auth library is **Better Auth** (`apps/web/auth.ts`,
14
+ `betterAuth({ secret, baseURL, socialProviders, … })`).
12
15
 
13
16
  ## Provider activation table
14
17
 
15
18
  | Provider ID | Required env vars | Source |
16
19
  | ----------- | -------------------------------------------- | ---------------------------- |
17
- | `email` | `AUTH_EMAIL_SERVER` + `AUTH_EMAIL_FROM` | Magic-link (Resend at v1) |
20
+ | `email` | `AUTH_EMAIL_SERVER` + `AUTH_EMAIL_FROM` | Email sign-in (Resend)¹ |
18
21
  | `google` | `GOOGLE_CLIENT_ID` + `GOOGLE_CLIENT_SECRET` | Google OAuth |
19
22
  | `github` | `GITHUB_CLIENT_ID` + `GITHUB_CLIENT_SECRET` | GitHub OAuth |
20
23
 
24
+ ¹ Better Auth core ships no magic-link provider, so `email` is an
25
+ env-presence signal: it switches on the password method
26
+ (`emailAndPassword`) in `apps/web/auth.ts`, not a wired magic link.
27
+
21
28
  ## Auxiliary auth env vars
22
29
 
23
30
  | Var | Default | Effect |
24
31
  | ---------------------- | ------- | ------------------------------------------------------------------------------------- |
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
32
+ | `AILK_AUTH_REQUIRED` | unset | Read by `isAuthRequired()` in `apps/web/lib/auth-env.ts` (`"1"` or `"true"`). Default is auth-disabled / public, so a fresh scaffold boots without requiring any auth wiring. |
33
+ | `BETTER_AUTH_URL` | unset | The site's public origin (e.g. `https://your-domain.com`). Better Auth builds OAuth callback URLs on it and it is the one trusted origin; unset, Better Auth derives both from each request. Set it in production. Local dev can leave it unset. |
34
+ | `BETTER_AUTH_SECRET` | unset | Signs session cookies and email-verification tokens. **Required in production** — `apps/web/auth.ts` throws when it is unset there, rather than fall back to the development secret published in the source. Generate with `openssl rand -base64 32`. Optional for `next dev`. |
35
+ | `AILK_AUTH_SIGNUP_OPEN` | unset | Read by `isSignUpOpen()` in `apps/web/lib/auth-env.ts` (`"1"` or `"true"`). Unset, public sign-up is closed: with `email` active, the password form signs existing accounts in but creates none. |
36
+ | `AILK_AUTH_PASSWORD_RESET` | unset | Read by `isResetAvailable()` (`"1"` or `"true"`). Password reset also needs `BETTER_AUTH_URL`, `BETTER_AUTH_SECRET` and `AUTH_EMAIL_WEBHOOK_SECRET` (`resetSendConfigured()`). |
37
+ | `AUTH_EMAIL_WEBHOOK_SECRET` | unset | Signs the auth-mail relay from `apps/web` to `apps/api`, which sends with `RESEND_API_KEY` from `AUTH_EMAIL_FROM`. Set the same value for both apps; unset, no auth mail is sent. |
38
+
39
+ The skill writes none of these auxiliary vars unasked. It mentions
30
40
  them in the closing summary so the consumer is aware:
31
41
 
32
42
  - `AILK_AUTH_REQUIRED` is the consumer's call (skill always defaults
33
43
  to leaving it unset).
34
- - `NEXTAUTH_URL` and `NEXTAUTH_SECRET` are deferred to production-time
35
- setup (`setup-deploy` or future deploy skill).
44
+ - `AILK_AUTH_SIGNUP_OPEN` is the consumer's call too; the skill asks
45
+ when `email` is active, because with sign-up closed and no OAuth
46
+ provider nobody can create the first account.
47
+ - `AILK_AUTH_PASSWORD_RESET` and `AUTH_EMAIL_WEBHOOK_SECRET` are the
48
+ auth-mail setup the `email` sub-flow describes.
49
+ - `BETTER_AUTH_URL` and `BETTER_AUTH_SECRET` are deferred to
50
+ production-time setup (`setup-deploy`), and a production deploy
51
+ fails without `BETTER_AUTH_SECRET`.
36
52
 
37
53
  ## Env-var formats — what valid values look like
38
54
 
39
- ### `AUTH_EMAIL_SERVER` (magic-link via Resend)
55
+ ### `AUTH_EMAIL_SERVER` (email sign-in via Resend)
40
56
 
41
57
  ```
42
58
  smtp://resend:<RESEND_API_KEY>@smtp.resend.com:465
@@ -46,7 +62,7 @@ The Resend API key starts with `re_`. The literal username is the
46
62
  string `resend` (Resend's SMTP convention). Port 465 is implicit-TLS
47
63
  SMTP.
48
64
 
49
- ### `AUTH_EMAIL_FROM` (magic-link via Resend)
65
+ ### `AUTH_EMAIL_FROM` (email sign-in via Resend)
50
66
 
51
67
  A verified sender address on the consumer's Resend account. For
52
68
  development, `onboarding@resend.dev` works without verification.
@@ -73,7 +89,7 @@ The skill's Step 1 menu marks providers as `[x]` when both required
73
89
  vars are set in `.env.local`. The detection is presence-only — the
74
90
  skill does not validate that the values actually work (no Google
75
91
  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
92
+ who pasted typos will get a runtime auth error from Better Auth on
77
93
  their first sign-in attempt; the fix is to re-run the skill and
78
94
  overwrite.
79
95
 
@@ -81,11 +97,10 @@ overwrite.
81
97
 
82
98
  - `apps/web/lib/auth-env.ts` — `getActiveProviderIds()` and
83
99
  `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.
100
+ - `apps/web/auth.ts` — `buildSocialProviders()` consumes the
101
+ active-provider list and builds Better Auth's `socialProviders`
102
+ from the matching env vars; `resolveSecret()` reads
103
+ `BETTER_AUTH_SECRET`, and `baseURL` is `BETTER_AUTH_URL`.
89
104
 
90
105
  The skill never modifies any of those files. All activation is
91
106
  env-var-driven.
@@ -1,4 +1,4 @@
1
- # OAuth + Magic-Link Setup — RUNBOOK Template
1
+ # OAuth + Email Sign-In Setup — RUNBOOK Template
2
2
 
3
3
  The `add-auth` skill writes (or merges into) `RUNBOOK.md` at the
4
4
  consumer's repo root using the per-provider sections below. Only the
@@ -10,13 +10,13 @@ sections appear in the final runbook.
10
10
 
11
11
  ---
12
12
 
13
- ## Provider section: magic-link (Resend)
13
+ ## Provider section: email (Resend)
14
14
 
15
15
  ```markdown
16
- ## Auth — magic-link (Resend)
16
+ ## Auth — email sign-in (Resend)
17
17
 
18
- Magic-link sign-in uses Resend as the email provider. Activation is
19
- keyed off two env vars in `.env.local`:
18
+ Email-and-password sign-in is activated when both env vars are present
19
+ in `.env.local`:
20
20
 
21
21
  - `AUTH_EMAIL_SERVER` — `smtp://resend:<API_KEY>@smtp.resend.com:465`
22
22
  - `AUTH_EMAIL_FROM` — verified sender address on your Resend account
@@ -30,6 +30,14 @@ keyed off two env vars in `.env.local`:
30
30
  Resend's shared dev sender and works without verification. For
31
31
  production, verify your own sending domain in the Resend dashboard.
32
32
 
33
+ `AUTH_EMAIL_SERVER` is read for its presence only. The auth mail
34
+ (verification, password reset) is sent by `apps/api` with
35
+ `RESEND_API_KEY` from `AUTH_EMAIL_FROM`, so set both for the API, and
36
+ set `AUTH_EMAIL_WEBHOOK_SECRET` to the same random value for both apps.
37
+
38
+ Public sign-up stays closed until you set `AILK_AUTH_SIGNUP_OPEN=1` in
39
+ `.env.local`.
40
+
33
41
  ### `.env.local` entries
34
42
 
35
43
  \`\`\`
@@ -62,7 +70,7 @@ Google sign-in is activated when both env vars are present in
62
70
  2. If you haven't yet, configure the OAuth consent screen:
63
71
  - User type: **External** (unless you're inside a Workspace org).
64
72
  - Fill in app name, support email, and developer contact email.
65
- - Scopes are auto-populated by NextAuth at runtime — leave the
73
+ - Scopes are requested by Better Auth at runtime — leave the
66
74
  consent screen scope list empty.
67
75
  3. Click **Create Credentials → OAuth client ID**.
68
76
  4. Application type: **Web application**.
@@ -152,13 +160,14 @@ The Client ID stays the same.
152
160
 
153
161
  | Provider | Env vars | Active |
154
162
  | ----------- | ------------------------------------------------- | ------ |
155
- | magic-link | `AUTH_EMAIL_SERVER` + `AUTH_EMAIL_FROM` | <fill> |
163
+ | email | `AUTH_EMAIL_SERVER` + `AUTH_EMAIL_FROM` | <fill> |
156
164
  | Google | `GOOGLE_CLIENT_ID` + `GOOGLE_CLIENT_SECRET` | <fill> |
157
165
  | GitHub | `GITHUB_CLIENT_ID` + `GITHUB_CLIENT_SECRET` | <fill> |
158
166
 
159
167
  A provider is **active** when both required env vars are set in
160
168
  `.env.local`. The provider list is computed at server startup from env
161
- vars only — there are no `auth.config.ts` edits to make.
169
+ vars only (`getActiveProviderIds()` in `apps/web/lib/auth-env.ts`) — there
170
+ are no `apps/web/auth.ts` edits to make.
162
171
 
163
172
  To require sign-in for protected routes, set in `.env.local`:
164
173