create-ailk 0.8.0 → 0.9.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 (211) hide show
  1. package/README.md +68 -0
  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 +92 -4
  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 +19 -9
  34. package/dist/lib/module-license-gate.js +19 -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 +64 -21
  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 +206 -17
  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 +32 -16
  52. package/dist/starter-grid.js +129 -33
  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 +49 -24
  57. package/package.json +5 -4
  58. package/site-templates/_base/content/en/UseCase/persona-1.mdx +7 -6
  59. package/site-templates/_base/content/en/UseCase/persona-2.mdx +7 -6
  60. package/site-templates/_base/content/en/UseCase/persona-3.mdx +7 -6
  61. package/site-templates/{minimalism-site/TEMPLATE-MANIFEST.json → aliases/minimalism-site.TEMPLATE-MANIFEST.json} +72 -40
  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/designs/standard/DESIGN.md +98 -6
  65. package/site-templates/marketing-site/DESIGN.md +98 -6
  66. package/site-templates/marketing-site/TEMPLATE-MANIFEST.json +60 -27
  67. package/site-templates/marketing-site/TEMPLATE-MANIFEST.md +50 -30
  68. package/site-templates/marketing-site-free/DESIGN.md +98 -6
  69. package/site-templates/marketing-site-free/TEMPLATE-MANIFEST.json +60 -24
  70. package/site-templates/marketing-site-free/TEMPLATE-MANIFEST.md +44 -27
  71. package/site-templates/marketing-site-free/ailk-template.json +1 -1
  72. package/site-templates/saas-product/DESIGN.md +98 -6
  73. package/site-templates/shapes/local-business-service/TEMPLATE-MANIFEST.json +127 -18
  74. package/site-templates/shapes/local-business-service/TEMPLATE-MANIFEST.md +74 -20
  75. package/site-templates/shapes/local-business-service/ailk-template.json +1 -1
  76. package/site-templates/shapes/organization-service/TEMPLATE-MANIFEST.json +127 -18
  77. package/site-templates/shapes/organization-service/TEMPLATE-MANIFEST.md +74 -20
  78. package/site-templates/shapes/organization-service/ailk-template.json +1 -1
  79. package/site-templates/shapes/person-service/TEMPLATE-MANIFEST.json +127 -18
  80. package/site-templates/shapes/person-service/TEMPLATE-MANIFEST.md +75 -21
  81. package/site-templates/shapes/person-service/ailk-template.json +1 -1
  82. package/site-templates/shapes/person-service/content/en/AboutPage/about.mdx +1 -1
  83. package/site-templates/shapes/person-service/content/en/HomePage/home.mdx +2 -2
  84. package/site-templates/shapes/person-service/content/en/PortfolioList/portfolio.mdx +4 -2
  85. package/site-templates/shapes/person-service/content/en/ServicesList/services.mdx +1 -1
  86. package/templates/.claude/rules/architecture.md +7 -0
  87. package/templates/.claude/skills/README.md +3 -2
  88. package/templates/.claude/skills/add-auth/references/env-vars.md +22 -15
  89. package/templates/.claude/skills/add-auth/references/oauth-app-setup.md +3 -2
  90. package/templates/.claude/skills/add-page/SKILL.md +241 -238
  91. package/templates/.claude/skills/add-page/references/page-types.md +85 -76
  92. package/templates/.claude/skills/add-page/scripts/site-pages.mjs +87 -0
  93. package/templates/.claude/skills/add-page/templates/comparison-page.mdx.tmpl +99 -0
  94. package/templates/.claude/skills/add-page/templates/content.mdx.tmpl +8 -18
  95. package/templates/.claude/skills/add-page/templates/flow-landing-page.mdx.tmpl +43 -0
  96. package/templates/.claude/skills/add-page/templates/report-page.mdx.tmpl +52 -0
  97. package/templates/.claude/skills/add-page/templates/reports-list.mdx.tmpl +38 -0
  98. package/templates/.claude/skills/check-site/SKILL.md +23 -0
  99. package/templates/.claude/skills/fill-page/SKILL.md +26 -7
  100. package/templates/.claude/skills/fill-page/profiles/plumbing.yaml +1 -1
  101. package/templates/.claude/skills/setup-deploy/references/env-vars-template.md +28 -11
  102. package/templates/.claude/skills/update-page/SKILL.md +117 -0
  103. package/templates/.claude/skills/update-page/scripts/update-page.ts +640 -0
  104. package/templates/.claude/skills/update-page/templates/redirects.mjs.tmpl +31 -0
  105. package/templates/.claude/skills/upgrade-plan/SKILL.md +12 -8
  106. package/templates/.github/workflows/ci.yml +4 -0
  107. package/templates/.prettierignore +1 -0
  108. package/templates/CLAUDE.md +146 -103
  109. package/templates/DESIGN.md +98 -6
  110. package/templates/README.md +50 -38
  111. package/templates/apps/api/.env.example +2 -1
  112. package/templates/apps/api/src/__tests__/commerce-claim-registration.test.ts +2 -0
  113. package/templates/apps/api/src/__tests__/server.test.ts +116 -0
  114. package/templates/apps/api/src/lib/stripe.ts +9 -0
  115. package/templates/apps/api/src/middleware/__tests__/auth.optional-cookie.test.ts +140 -0
  116. package/templates/apps/api/src/middleware/auth.ts +54 -0
  117. package/templates/apps/api/src/routes/checkout/__tests__/session.test.ts +5 -2
  118. package/templates/apps/api/src/routes/checkout/__tests__/sessions.test.ts +628 -0
  119. package/templates/apps/api/src/routes/checkout/sessions.ts +222 -24
  120. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-flow-checkout.test.ts +1 -1
  121. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-org-billing.test.ts +5 -1
  122. package/templates/apps/api/src/routes/webhooks/__tests__/stripe.test.ts +521 -20
  123. package/templates/apps/api/src/routes/webhooks/stripe.ts +124 -32
  124. package/templates/apps/api/src/server.ts +28 -0
  125. package/templates/apps/api/src/services/__tests__/revalidation.test.ts +90 -15
  126. package/templates/apps/api/src/services/checkout-buyer.ts +72 -0
  127. package/templates/apps/api/src/services/revalidation.ts +60 -15
  128. package/templates/apps/mcp/__tests__/tools/create_project.test.ts +30 -24
  129. package/templates/apps/mcp/src/tools/purchase.ts +4 -2
  130. package/templates/apps/web/.env.example +13 -0
  131. package/templates/apps/web/CLAUDE.md +22 -28
  132. package/templates/apps/web/app/[locale]/(auth)/layout.tsx +1 -1
  133. package/templates/apps/web/app/[locale]/(authed)/leads/__tests__/page.test.tsx +24 -0
  134. package/templates/apps/web/app/[locale]/(authed)/leads/page.tsx +17 -6
  135. package/templates/apps/web/app/[locale]/[slug]/[detail]/__tests__/page.test.tsx +110 -0
  136. package/templates/apps/web/app/[locale]/[slug]/[detail]/page.tsx +60 -0
  137. package/templates/apps/web/app/[locale]/[slug]/page.tsx +1 -1
  138. package/templates/apps/web/app/[locale]/alternatives/__tests__/page.test.tsx +161 -0
  139. package/templates/apps/web/app/[locale]/alternatives/page.tsx +104 -0
  140. package/templates/apps/web/app/[locale]/{use-cases → for}/[slug]/page.tsx +4 -3
  141. package/templates/apps/web/app/[locale]/for/__tests__/page-renderer-migration.test.tsx +73 -0
  142. package/templates/apps/web/app/[locale]/{use-cases → for}/page.tsx +8 -7
  143. package/templates/apps/web/app/[locale]/glossary/page.tsx +1 -1
  144. package/templates/apps/web/app/[locale]/layout.tsx +35 -19
  145. package/templates/apps/web/app/[locale]/newsletter/page.tsx +1 -1
  146. package/templates/apps/web/app/[locale]/portfolio/[slug]/page.tsx +1 -1
  147. package/templates/apps/web/app/[locale]/portfolio/page.tsx +1 -1
  148. package/templates/apps/web/app/[locale]/vs/[slug]/__tests__/page.test.tsx +112 -0
  149. package/templates/apps/web/app/[locale]/vs/[slug]/page.tsx +70 -0
  150. package/templates/apps/web/app/api/revalidate/__tests__/route.test.ts +236 -44
  151. package/templates/apps/web/app/api/revalidate/route.ts +78 -36
  152. package/templates/apps/web/lib/__tests__/site-brand.test.ts +79 -0
  153. package/templates/apps/web/lib/__tests__/site-theme.test.ts +104 -11
  154. package/templates/apps/web/lib/__tests__/structured-data.test.tsx +21 -4
  155. package/templates/apps/web/lib/locale-guard.ts +18 -0
  156. package/templates/apps/web/lib/meet-placeholder.ts +5 -0
  157. package/templates/apps/web/lib/nav-config.ts +14 -13
  158. package/templates/apps/web/lib/site-brand.tsx +13 -9
  159. package/templates/apps/web/lib/site-logo.tsx +36 -0
  160. package/templates/apps/web/lib/site-theme.ts +46 -26
  161. package/templates/apps/web/messages/en.json +23 -9
  162. package/templates/apps/web/middleware.ts +28 -4
  163. package/templates/content/en/BookCall/book-a-call.mdx +80 -0
  164. package/templates/content/en/BookCall/onsite-estimate.mdx +56 -0
  165. package/templates/content/en/BookCall/onsite-service.mdx +56 -0
  166. package/templates/content/en/BookCall/start-project.mdx +56 -0
  167. package/templates/content/en/ContactPage/contact.mdx +40 -1
  168. package/templates/content/en/HomePage/home.mdx +2 -6
  169. package/templates/content/en/LandingPage/meet.mdx +59 -0
  170. package/templates/content/en/UseCasesList/{use-cases.mdx → for.mdx} +19 -18
  171. package/templates/database/CHANGELOG.md +7 -0
  172. package/templates/database/package.json +1 -1
  173. package/templates/package.json +2 -1
  174. package/templates/tools/check-claude-md.ts +128 -0
  175. package/versions.json +33 -33
  176. package/site-templates/_base/content/en/BookCall/book-call.mdx +0 -52
  177. package/site-templates/minimalism-site/DESIGN.md +0 -162
  178. package/site-templates/minimalism-site/TEMPLATE-MANIFEST.md +0 -458
  179. package/site-templates/minimalism-site/ailk-template.json +0 -23
  180. package/site-templates/minimalism-site/content/en/AboutPage/about.mdx +0 -110
  181. package/site-templates/minimalism-site/content/en/BookCall/book-call.mdx +0 -52
  182. package/site-templates/minimalism-site/content/en/ContactPage/contact.mdx +0 -34
  183. package/site-templates/minimalism-site/content/en/FAQPage/faq.mdx +0 -57
  184. package/site-templates/minimalism-site/content/en/LandingPage/referral.mdx +0 -77
  185. package/site-templates/minimalism-site/content/en/LandingPage/reports.mdx +0 -73
  186. package/site-templates/minimalism-site/content/en/PurchasePolicyPage/purchase-policy.mdx +0 -123
  187. package/site-templates/minimalism-site/content/en/ReportPage/annual-letter-2024.mdx +0 -52
  188. package/site-templates/minimalism-site/content/en/ReportPage/field-notes-2023.mdx +0 -52
  189. package/site-templates/minimalism-site/content/en/ReportPage/platform-shift-2025.mdx +0 -52
  190. package/site-templates/minimalism-site/content/en/ReportPage/state-of-the-market-2026.mdx +0 -52
  191. package/site-templates/minimalism-site/content/en/Service/first-engagement.mdx +0 -38
  192. package/site-templates/minimalism-site/content/en/Service/second-engagement.mdx +0 -38
  193. package/site-templates/minimalism-site/content/en/Service/third-engagement.mdx +0 -38
  194. package/site-templates/minimalism-site/content/en/ServicesList/services.mdx +0 -73
  195. package/site-templates/minimalism-site/flows/referral.flow.json +0 -71
  196. package/site-templates/minimalism-site/provenance.json +0 -4
  197. package/templates/.claude/skills/add-page/templates/route.tsx.tmpl +0 -28
  198. package/templates/apps/web/app/[locale]/book-a-call/page.tsx +0 -50
  199. package/templates/apps/web/app/[locale]/use-cases/__tests__/page-renderer-migration.test.tsx +0 -72
  200. /package/site-templates/{minimalism-site → designs/minimalism/sample}/content/en/HomePage/home.mdx +0 -0
  201. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/avatar-placeholder-1.svg +0 -0
  202. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/avatar-placeholder-2.svg +0 -0
  203. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/avatar-placeholder-3.svg +0 -0
  204. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/avatar-placeholder-4.svg +0 -0
  205. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/avatar-placeholder-5.svg +0 -0
  206. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/avatar-placeholder-6.svg +0 -0
  207. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/hero-backdrop.svg +0 -0
  208. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/logo-placeholder-1.svg +0 -0
  209. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/logo-placeholder-2.svg +0 -0
  210. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/logo-placeholder-3.svg +0 -0
  211. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/wordmark-placeholder.svg +0 -0
@@ -4,7 +4,7 @@
4
4
  "categories": ["consulting"],
5
5
  "shape": "person-service",
6
6
  "design": "standard",
7
- "generatedHash": "21c12a9cd50e661a56ca51d56b33a4750a8aae92a13ebd1127f7530eb7cb0d72",
7
+ "generatedHash": "a763acef14c0c36649ad99dd4a4fea566ebdf64257bddb2f553ab8823349c309",
8
8
  "layout": {
9
9
  "nav": "full",
10
10
  "footer": "columns",
@@ -111,6 +111,61 @@
111
111
  "chrome": "on",
112
112
  "sections": []
113
113
  },
114
+ {
115
+ "route": "/for",
116
+ "kind": "page",
117
+ "pageType": "UseCasesList",
118
+ "schema": "UseCasesList",
119
+ "shell": "MarketingShell",
120
+ "chrome": "on",
121
+ "sections": [
122
+ {
123
+ "type": "hero",
124
+ "component": "Hero"
125
+ },
126
+ {
127
+ "type": "items",
128
+ "component": "Items",
129
+ "options": {
130
+ "columns": 3
131
+ }
132
+ },
133
+ {
134
+ "type": "logoCloud",
135
+ "component": "LogoCloud",
136
+ "options": {
137
+ "layout": "inline"
138
+ }
139
+ },
140
+ {
141
+ "type": "testimonials",
142
+ "component": "Testimonials"
143
+ },
144
+ {
145
+ "type": "cta",
146
+ "component": "CTA"
147
+ },
148
+ {
149
+ "type": "faq",
150
+ "component": "FAQ"
151
+ }
152
+ ]
153
+ },
154
+ {
155
+ "route": "/for/[slug]",
156
+ "kind": "page",
157
+ "contentDir": "content/en/UseCase",
158
+ "seeds": [
159
+ "content/en/UseCase/persona-1.mdx",
160
+ "content/en/UseCase/persona-2.mdx",
161
+ "content/en/UseCase/persona-3.mdx"
162
+ ],
163
+ "pageType": "UseCase",
164
+ "schema": "UseCase",
165
+ "shell": "MarketingShell",
166
+ "chrome": "on",
167
+ "sections": []
168
+ },
114
169
  {
115
170
  "route": "/about",
116
171
  "kind": "page",
@@ -143,6 +198,13 @@
143
198
  {
144
199
  "type": "hero",
145
200
  "component": "Hero"
201
+ },
202
+ {
203
+ "type": "items",
204
+ "component": "Items",
205
+ "options": {
206
+ "columns": 2
207
+ }
146
208
  }
147
209
  ]
148
210
  },
@@ -208,25 +270,22 @@
208
270
  ]
209
271
  },
210
272
  {
211
- "route": "/book-a-call",
212
- "kind": "page",
213
- "pageType": "BookCall",
214
- "schema": "BookCall",
273
+ "route": "/sign-in",
274
+ "kind": "route",
275
+ "pageType": null,
276
+ "schema": null,
215
277
  "shell": "MarketingShell",
216
278
  "chrome": "on",
217
- "sections": [
218
- {
219
- "type": "hero",
220
- "component": "Hero"
221
- },
222
- {
223
- "type": "items",
224
- "component": "Items",
225
- "options": {
226
- "columns": 3
227
- }
228
- }
229
- ]
279
+ "sections": []
280
+ },
281
+ {
282
+ "route": "/sign-up",
283
+ "kind": "route",
284
+ "pageType": null,
285
+ "schema": null,
286
+ "shell": "MarketingShell",
287
+ "chrome": "on",
288
+ "sections": []
230
289
  },
231
290
  {
232
291
  "route": "/purchase-policy",
@@ -311,6 +370,56 @@
311
370
  }
312
371
  ]
313
372
  },
373
+ {
374
+ "route": "/meet",
375
+ "kind": "page",
376
+ "pageType": "LandingPage",
377
+ "schema": "WebPage",
378
+ "shell": "MarketingShell",
379
+ "chrome": "on",
380
+ "sections": [
381
+ {
382
+ "type": "hero",
383
+ "component": "Hero"
384
+ },
385
+ {
386
+ "type": "items",
387
+ "component": "Items",
388
+ "options": {
389
+ "columns": 2
390
+ }
391
+ }
392
+ ]
393
+ },
394
+ {
395
+ "route": "/meet/[slug]",
396
+ "kind": "page",
397
+ "pageType": "BookCall",
398
+ "schema": "BookCall",
399
+ "shell": "MarketingShell",
400
+ "chrome": "on",
401
+ "sections": [
402
+ {
403
+ "type": "hero",
404
+ "component": "Hero"
405
+ },
406
+ {
407
+ "type": "cta",
408
+ "component": "CTA"
409
+ },
410
+ {
411
+ "type": "items",
412
+ "component": "Items",
413
+ "options": {
414
+ "columns": 3
415
+ }
416
+ },
417
+ {
418
+ "type": "content-block",
419
+ "component": "ContentBlock"
420
+ }
421
+ ]
422
+ },
314
423
  {
315
424
  "route": "/portfolio",
316
425
  "kind": "page",
@@ -96,6 +96,28 @@ One `page=<route>` region per roster row, generated from the seed file the compo
96
96
  _Detail route over `content/en/Service/` — 3 seed pages: `first-engagement.mdx`, `second-engagement.mdx`, `third-engagement.mdx`._
97
97
  <!-- generated:end -->
98
98
 
99
+ `/for` (the persona hub — every shape carries the family now, #6878 D7):
100
+
101
+ <!-- generated:begin page=/for -->
102
+
103
+ | # | Section | Component | Copy (first line) |
104
+ | --- | -------------------------------------------------------- | -------------- | ----------------------------------------------------------------- |
105
+ | 1 | `hero` (eyebrow "Customers" · 2 CTAs) | `Hero` | {Customers: who your product or service is for} |
106
+ | 2 | `items` (columns=3 · items ×3) | `Items` | {The jobs customers hire your product or service to do} |
107
+ | 3 | `logoCloud` (layout=inline · logos ×6) | `LogoCloud` | Don’t just take our word for it |
108
+ | 4 | `testimonials` (quote · items ×1) | `Testimonials` | {A customer quote, in their own words, about the result they got} |
109
+ | 5 | `cta` (box · checklist ×3 · 2 CTAs · closingLine) | `CTA` | {Switch to your product or service in time amount or less} |
110
+ | 6 | `faq` (accordion · items ×5 · 1 CTA · initialOpen first) | `FAQ` | FAQs |
111
+
112
+ <!-- generated:end -->
113
+
114
+ `/for/[slug]`:
115
+
116
+ <!-- generated:begin page=/for/[slug] -->
117
+
118
+ _Detail route over `content/en/UseCase/` — 3 seed pages: `persona-1.mdx`, `persona-2.mdx`, `persona-3.mdx`._
119
+ <!-- generated:end -->
120
+
99
121
  `/about`:
100
122
 
101
123
  <!-- generated:begin page=/about -->
@@ -111,9 +133,10 @@ _Detail route over `content/en/Service/` — 3 seed pages: `first-engagement.mdx
111
133
 
112
134
  <!-- generated:begin page=/contact -->
113
135
 
114
- | # | Section | Component | Copy (first line) |
115
- | --- | --------------------------------------------------------- | --------- | ------------------------------------- |
116
- | 1 | `hero` (split · eyebrow "Contact" · checklist ×3 · 1 CTA) | `Hero` | Get every message in your email, free |
136
+ | # | Section | Component | Copy (first line) |
137
+ | --- | --------------------------------------------------------- | --------- | ----------------------------------------- |
138
+ | 1 | `hero` (split · eyebrow "Contact" · checklist ×3 · 1 CTA) | `Hero` | Get every message in your email, free |
139
+ | 2 | `items` (tiles · columns=2 · items ×4) | `Items` | {Add appointment scheduling to your site} |
117
140
 
118
141
  <!-- generated:end -->
119
142
 
@@ -129,7 +152,7 @@ _Detail route over `content/en/Service/` — 3 seed pages: `first-engagement.mdx
129
152
 
130
153
  <!-- generated:end -->
131
154
 
132
- `/glossary`, `/newsletter`, `/book-a-call` (base-layer seeds every starter carries, #6658 D5 — `/newsletter` is this tree's own byte copy of the Free newsletter, D4/D9):
155
+ `/glossary`, `/newsletter` (base-layer seeds every starter carries, #6658 D5 — `/newsletter` is this tree's own byte copy of the Free newsletter, D4/D9), plus the always-copied overlay's `/meet` hub and `/meet/[slug]` BookCall detail seeds (#6897 D3-D5):
133
156
 
134
157
  <!-- generated:begin page=/glossary -->
135
158
 
@@ -149,15 +172,38 @@ _Detail route over `content/en/Service/` — 3 seed pages: `first-engagement.mdx
149
172
 
150
173
  <!-- generated:end -->
151
174
 
152
- <!-- generated:begin page=/book-a-call -->
175
+ <!-- generated:begin page=/meet -->
153
176
 
154
- | # | Section | Component | Copy (first line) |
155
- | --- | -------------------------------------- | --------- | ------------------------------------------ |
156
- | 1 | `hero` (eyebrow "Book a call" · 1 CTA) | `Hero` | {Book a call: what a visitor gets from it} |
157
- | 2 | `items` (columns=3 · items ×3) | `Items` | What happens on the call? |
177
+ | # | Section | Component | Copy (first line) |
178
+ | --- | -------------------------------------- | --------- | --------------------- |
179
+ | 1 | `hero` (eyebrow "Meet") | `Hero` | {Book a time with us} |
180
+ | 2 | `items` (tiles · columns=2 · items ×4) | `Items` | |
158
181
 
159
182
  <!-- generated:end -->
160
183
 
184
+ <!-- generated:begin page=/meet/[slug] -->
185
+
186
+ | # | Section | Component | Copy (first line) |
187
+ | --- | -------------------------------------- | -------------- | ------------------------------------------------ |
188
+ | 1 | `hero` (eyebrow "Book a Call" · 1 CTA) | `Hero` | Book a Call |
189
+ | 2 | `cta` (box · 1 CTA) | `CTA` | {What booking a call would do for your visitors} |
190
+ | 3 | `items` (columns=3 · items ×3) | `Items` | What happens on the call? |
191
+ | 4 | `content-block` (1 CTA) | `ContentBlock` | |
192
+
193
+ <!-- generated:end -->
194
+
195
+ `/sign-in`, `/sign-up` (code routes — the `SignInCard` island and the sign-up form inside the locale layout, whose header links both; listed so the manifest is a complete install record, #6797):
196
+
197
+ <!-- generated:begin page=/sign-in -->
198
+
199
+ _Code route — no content, no sections._
200
+ <!-- generated:end -->
201
+
202
+ <!-- generated:begin page=/sign-up -->
203
+
204
+ _Code route — no content, no sections._
205
+ <!-- generated:end -->
206
+
161
207
  `/purchase-policy` (this tree's own service-shape override — cancellation and refunds, D4):
162
208
 
163
209
  <!-- generated:begin page=/purchase-policy -->
@@ -199,7 +245,7 @@ _Detail route over `content/en/Service/` — 3 seed pages: `first-engagement.mdx
199
245
 
200
246
  <!-- generated:end -->
201
247
 
202
- `/portfolio` (this tree's own override of the `_base` seed — re-voiced for one person, both CTAs `/book-a-call` and `/contact`, D4):
248
+ `/portfolio` (this tree's own override of the `_base` seed — re-voiced for one person, both CTAs `/meet/book-a-call` and `/contact`, D4):
203
249
 
204
250
  <!-- generated:begin page=/portfolio -->
205
251
 
@@ -230,19 +276,21 @@ The standard page set for this shape (`derive-roster.py --shape person-service -
230
276
  | `ProjectsList` · `Project` | the portfolio pair (`/portfolio`) is the proof of past work; `/projects` is the paid signal-collectors sample listing |
231
277
  | `Pricing` | a consultant sells named engagements, each priced on its own `Service` page or quoted on a call — not a pricing table |
232
278
  | `CaseStudiesList` · `CaseStudy` · `TestimonialsList` · `ClientsList` | proof pages need real clients (#6658's reason for Free, unchanged); the portfolio pages carry placeholder before/after proof |
233
- | `UseCasesList` · `UseCase` | each `Service` page names who it is for; the `_base` persona seeds are product copy that links `/pricing` |
234
279
  | `EventsList` · `Event` · `DownloadsList` | a placeholder starter has no events or downloads |
235
280
  | `ResourcesHub` · `ResourceDetail` · `HowTo` · `Whitepaper` | the Resources content system is the goal-driven default a site grows into, not a starter page |
236
281
 
237
282
  **Rows added:**
238
283
 
239
- | Row added | Reason |
240
- | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
241
- | `PurchasePolicyPage` | every shape carries one purchase policy with its shape's sections — service: cancellation and refunds (#6646 D3, contract R2.3) |
242
- | `PortfolioList` · `PortfolioItem` | the portfolio pair belongs to every shape's standard roster (operator, 2026-09-25; roadmap § 4) |
243
- | `BlogList` | every Free scaffold's nav links `/blog` unconditionally (`renderNavConfig`, operator ruling 2026-09-23); the Free teaser serves it, as on organization-product (#6753 D3) |
284
+ | Row added | Reason |
285
+ | --------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
286
+ | `PurchasePolicyPage` | every shape carries one purchase policy with its shape's sections — service: cancellation and refunds (#6646 D3, contract R2.3) |
287
+ | `PortfolioList` · `PortfolioItem` | the portfolio pair belongs to every shape's standard roster (operator, 2026-09-25; roadmap § 4) |
288
+ | `BlogList` | every Free scaffold's nav links `/blog` unconditionally (`renderNavConfig`, operator ruling 2026-09-23); the Free teaser serves it, as on organization-product (#6753 D3) |
289
+ | `LandingPage` | the Free `/meet` meeting-types hub is a LandingPage seed, the same generic `[slug]` route serves it through (#6897 D3); the four `/meet/[slug]` BookCall detail seeds ride the `BookCall` type already in the standard roster |
290
+
291
+ `|S − D| = 13` and `|R| = 18`.
244
292
 
245
- `|S − D| = 11` and `|R| = 15`.
293
+ `/sign-in` and `/sign-up` are also rostered (#6797) — code routes (`kind: route`) with no page type, so they sit outside this set equation: the locale layout's header links both, and the roster of record lists every page the scaffold serves.
246
294
 
247
295
  ## 4. Roster, as the registry declares it
248
296
 
@@ -260,16 +308,21 @@ person-service:
260
308
  - { route: "/", kind: page, content: ["content/en/HomePage/home.mdx"] }
261
309
  - { route: "/services", kind: page, content: ["content/en/ServicesList/services.mdx"] }
262
310
  - { route: "/services/[slug]", kind: page, contentDir: "content/en/Service" }
311
+ - { route: "/for", kind: page, content: ["content/en/UseCasesList/for.mdx"] }
312
+ - { route: "/for/[slug]", kind: page, contentDir: "content/en/UseCase" }
263
313
  - { route: "/about", kind: page, content: ["content/en/AboutPage/about.mdx"] }
264
314
  - { route: "/contact", kind: page, content: ["content/en/ContactPage/contact.mdx"] }
265
315
  - { route: "/faq", kind: page, content: ["content/en/FAQPage/faq.mdx"] }
266
316
  - { route: "/glossary", kind: page, content: ["content/en/GlossaryList/glossary.mdx"] }
267
317
  - { route: "/newsletter", kind: page, content: ["content/en/NewsletterSignup/newsletter.mdx"] }
268
- - { route: "/book-a-call", kind: page, content: ["content/en/BookCall/book-call.mdx"] }
318
+ - { route: "/sign-in", kind: route }
319
+ - { route: "/sign-up", kind: route }
269
320
  - { route: "/purchase-policy", kind: page, content: ["content/en/PurchasePolicyPage/purchase-policy.mdx"] }
270
321
  - { route: "/privacy", kind: page, content: ["content/en/PrivacyPage/privacy.mdx"] }
271
322
  - { route: "/terms", kind: page, content: ["content/en/TermsPage/terms.mdx"] }
272
323
  - { route: "/blog", kind: page, content: ["content/en/BlogList/blog.mdx"] }
324
+ - { route: "/meet", kind: page, content: ["content/en/LandingPage/meet.mdx"] }
325
+ - { route: "/meet/[slug]", kind: page, content: ["content/en/BookCall/book-a-call.mdx", "content/en/BookCall/onsite-estimate.mdx", "content/en/BookCall/start-project.mdx", "content/en/BookCall/onsite-service.mdx"] }
273
326
  - { route: "/portfolio", kind: page, content: ["content/en/PortfolioList/portfolio.mdx"] }
274
327
  - { route: "/portfolio/[slug]", kind: page, contentDir: "content/en/PortfolioItem" }
275
328
  ```
@@ -280,11 +333,12 @@ By source:
280
333
 
281
334
  ```
282
335
  starter: / · /services · /services/<slug> · /about · /contact · /faq
283
- /glossary · /newsletter · /book-a-call · /purchase-policy
284
- /privacy · /terms · /blog · /portfolio · /portfolio/<slug>
336
+ /glossary · /newsletter · /sign-in · /sign-up
337
+ /purchase-policy · /privacy · /terms · /blog · /meet · /meet/<slug>
338
+ /portfolio · /portfolio/<slug>
285
339
  ```
286
340
 
287
- Every row is module-less: `requires` is `[marketing]` alone, so `mergeRoster` contributes nothing beyond this tree's own fifteen rows.
341
+ Every row is module-less: `requires` is `[marketing]` alone, so `mergeRoster` contributes nothing beyond this tree's own seventeen rows.
288
342
 
289
343
  ## 5. Component inventory
290
344
 
@@ -6,5 +6,5 @@
6
6
  "provenance.json": ".ailk-template.json",
7
7
  "TEMPLATE-MANIFEST.json": ".ailk-site-manifest.json"
8
8
  },
9
- "postInstall": "Starter person-service installed. Its /faq, /contact and /blog seed pages came with the always-copied overlay; /glossary, /newsletter, /book-a-call, /privacy and /terms with the base layer it extends (content/en/). This tree's own /, /about, /services (+ three engagements), /purchase-policy and /portfolio pages are its own compositions, written for one person. Every line of copy is a placeholder — replace it before you launch."
9
+ "postInstall": "Starter person-service installed. Its /faq, /contact, /blog, /meet and its four /meet/<slug> seed pages came with the always-copied overlay; /glossary, /newsletter, /privacy and /terms with the base layer it extends (content/en/). This tree's own /, /about, /services (+ three engagements), /purchase-policy and /portfolio pages are its own compositions, written for one person. Every line of copy is a placeholder \u2014 replace it before you launch."
10
10
  }
@@ -24,7 +24,7 @@ sections:
24
24
  {
25
25
  "variant": "minimal",
26
26
  "headline": "Work with me",
27
- "primaryCta": { "label": "Book a call", "href": "/book-a-call" },
27
+ "primaryCta": { "label": "Book a call", "href": "/meet/book-a-call" },
28
28
  "secondaryCta":
29
29
  {
30
30
  "label": "Get in touch",
@@ -14,7 +14,7 @@ sections:
14
14
  "eyebrow": "{Your Name}",
15
15
  "headline": "{One line on the outcome you deliver for clients}",
16
16
  "subheadline": "{One line on who you work with and what makes working with you different.}",
17
- "primaryCta": { "label": "Book a call", "href": "/book-a-call" },
17
+ "primaryCta": { "label": "Book a call", "href": "/meet/book-a-call" },
18
18
  "secondaryCta":
19
19
  {
20
20
  "label": "Get in touch",
@@ -82,7 +82,7 @@ sections:
82
82
  "variant": "minimal",
83
83
  "headline": "Ready to talk about your project?",
84
84
  "description": "{One line inviting the reader to start the conversation.}",
85
- "primaryCta": { "label": "Book a call", "href": "/book-a-call" },
85
+ "primaryCta": { "label": "Book a call", "href": "/meet/book-a-call" },
86
86
  "secondaryCta":
87
87
  {
88
88
  "label": "Get in touch",
@@ -20,7 +20,8 @@ sections:
20
20
  "subheadline": "{Two or three sentences on why the comparison is the honest proof — what the before cost the client, what the after changed, and how a reader can check it.}",
21
21
  "subtitleSize": "lead",
22
22
  "ctaSize": "xl",
23
- "primaryCta": { "label": "{Book a call}", "href": "/book-a-call" },
23
+ "primaryCta":
24
+ { "label": "{Book a call}", "href": "/meet/book-a-call" },
24
25
  "secondaryCta": { "label": "{Get in touch}", "href": "/contact" },
25
26
  },
26
27
  },
@@ -126,7 +127,8 @@ sections:
126
127
  "variant": "beam",
127
128
  "headline": "{Is your project the before or the after?}",
128
129
  "description": "{One line offering the reader the same comparison for their own project.}",
129
- "primaryCta": { "label": "{Book a call}", "href": "/book-a-call" },
130
+ "primaryCta":
131
+ { "label": "{Book a call}", "href": "/meet/book-a-call" },
130
132
  "secondaryCta": { "label": "{Get in touch}", "href": "/contact" },
131
133
  "chips":
132
134
  [
@@ -63,7 +63,7 @@ sections:
63
63
  "variant": "minimal",
64
64
  "headline": "Not sure which one?",
65
65
  "description": "{One line inviting the reader to ask instead of guessing.}",
66
- "primaryCta": { "label": "Book a call", "href": "/book-a-call" },
66
+ "primaryCta": { "label": "Book a call", "href": "/meet/book-a-call" },
67
67
  },
68
68
  },
69
69
  ]
@@ -61,6 +61,13 @@ These never appear in source code:
61
61
  and future prefixes included, by being absent from the list rather than
62
62
  by being named on a ban-list. Live keys live in your deployment
63
63
  platform's secrets store, never in source files or `.env`.
64
+ `@working-theory/stripe-client` does export one opt-in,
65
+ `admitLiveRestrictedKey()`: a server process that calls it once at
66
+ startup lets `getStripeClient()` accept a restricted live key
67
+ (`rk_live_`) — never `sk_live_` or `pk_live_`. Nothing in this site
68
+ calls it, so the default refusal stands; calling it is a deliberate
69
+ go-live decision, and `assertSandboxKey()` stays sandbox-only even
70
+ then.
64
71
  - Direct vendor SDK imports outside the wrapper packages
65
72
  (`import 'resend'` outside `@working-theory/email`, etc.).
66
73
  - Hardcoded production database URLs in committed files.
@@ -4,14 +4,15 @@ Skills are reusable Claude Code workflows scoped to this project. Each
4
4
  lives in its own subdirectory with a `SKILL.md` describing when to use
5
5
  it and how it works.
6
6
 
7
- The seven skills below ship with this project. Claude Code discovers
7
+ The eight skills below ship with this project. Claude Code discovers
8
8
  them automatically at session start — nothing to install or enable.
9
9
 
10
10
  ## Available skills
11
11
 
12
12
  | Skill | Purpose |
13
13
  | -------------- | -------------------------------------------------------------------------------------------------------------- |
14
- | `add-page` | Generate a new page: App Router route + MDX content stub + typed JSON-LD, in one confirm-before-write pass. Also documents the `schema:` frontmatter override for adding supplementary structured data to a page that already exists. |
14
+ | `add-page` | Add a page this site can serve — its content file, structured data and nav link — adding a missing route with `create-ailk add-route` first. Also documents the `schema:` frontmatter override for any page. |
15
+ | `update-page` | Rename a page — give it a new URL and/or a new title — in one plan-then-confirm pass: its content files, its own route folder, exact internal links and the manifest row move together, and the old URL gets a permanent redirect. |
15
16
  | `add-auth` | Activate auth providers — magic-link via Resend, Google OAuth, GitHub OAuth. |
16
17
  | `setup-deploy` | Emit deploy configuration — `vercel.json`, `.env.example`, and `RUNBOOK.md` — for a Vercel deploy. Asks where leads go (email or a database) and warns when neither is set. |
17
18
  | `setup-database` | Take the site from no database to a working lead inbox: provision Postgres, create the tables, pin the owner, and verify one test message lands in `/leads`. |
@@ -8,35 +8,43 @@ 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). |
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`. |
28
35
 
29
36
  The skill writes none of these auxiliary vars on its own. It mentions
30
37
  them in the closing summary so the consumer is aware:
31
38
 
32
39
  - `AILK_AUTH_REQUIRED` is the consumer's call (skill always defaults
33
40
  to leaving it unset).
34
- - `NEXTAUTH_URL` and `NEXTAUTH_SECRET` are deferred to production-time
35
- setup (`setup-deploy` or future deploy skill).
41
+ - `BETTER_AUTH_URL` and `BETTER_AUTH_SECRET` are deferred to
42
+ production-time setup (`setup-deploy`), and a production deploy
43
+ fails without `BETTER_AUTH_SECRET`.
36
44
 
37
45
  ## Env-var formats — what valid values look like
38
46
 
39
- ### `AUTH_EMAIL_SERVER` (magic-link via Resend)
47
+ ### `AUTH_EMAIL_SERVER` (email sign-in via Resend)
40
48
 
41
49
  ```
42
50
  smtp://resend:<RESEND_API_KEY>@smtp.resend.com:465
@@ -46,7 +54,7 @@ The Resend API key starts with `re_`. The literal username is the
46
54
  string `resend` (Resend's SMTP convention). Port 465 is implicit-TLS
47
55
  SMTP.
48
56
 
49
- ### `AUTH_EMAIL_FROM` (magic-link via Resend)
57
+ ### `AUTH_EMAIL_FROM` (email sign-in via Resend)
50
58
 
51
59
  A verified sender address on the consumer's Resend account. For
52
60
  development, `onboarding@resend.dev` works without verification.
@@ -73,7 +81,7 @@ The skill's Step 1 menu marks providers as `[x]` when both required
73
81
  vars are set in `.env.local`. The detection is presence-only — the
74
82
  skill does not validate that the values actually work (no Google
75
83
  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
84
+ who pasted typos will get a runtime auth error from Better Auth on
77
85
  their first sign-in attempt; the fix is to re-run the skill and
78
86
  overwrite.
79
87
 
@@ -81,11 +89,10 @@ overwrite.
81
89
 
82
90
  - `apps/web/lib/auth-env.ts` — `getActiveProviderIds()` and
83
91
  `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.
92
+ - `apps/web/auth.ts` — `buildSocialProviders()` consumes the
93
+ active-provider list and builds Better Auth's `socialProviders`
94
+ from the matching env vars; `resolveSecret()` reads
95
+ `BETTER_AUTH_SECRET`, and `baseURL` is `BETTER_AUTH_URL`.
89
96
 
90
97
  The skill never modifies any of those files. All activation is
91
98
  env-var-driven.
@@ -62,7 +62,7 @@ Google sign-in is activated when both env vars are present in
62
62
  2. If you haven't yet, configure the OAuth consent screen:
63
63
  - User type: **External** (unless you're inside a Workspace org).
64
64
  - Fill in app name, support email, and developer contact email.
65
- - Scopes are auto-populated by NextAuth at runtime — leave the
65
+ - Scopes are requested by Better Auth at runtime — leave the
66
66
  consent screen scope list empty.
67
67
  3. Click **Create Credentials → OAuth client ID**.
68
68
  4. Application type: **Web application**.
@@ -158,7 +158,8 @@ The Client ID stays the same.
158
158
 
159
159
  A provider is **active** when both required env vars are set in
160
160
  `.env.local`. The provider list is computed at server startup from env
161
- vars only — there are no `auth.config.ts` edits to make.
161
+ vars only (`getActiveProviderIds()` in `apps/web/lib/auth-env.ts`) — there
162
+ are no `apps/web/auth.ts` edits to make.
162
163
 
163
164
  To require sign-in for protected routes, set in `.env.local`:
164
165