create-ailk 0.2.0 → 0.4.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 (292) hide show
  1. package/component-catalog.md +50 -53
  2. package/dist/cli.js +19 -9
  3. package/dist/lib/apply-module-patches.d.ts +47 -0
  4. package/dist/lib/apply-module-patches.js +370 -0
  5. package/dist/lib/extract-module-bundle.d.ts +51 -3
  6. package/dist/lib/extract-module-bundle.js +327 -28
  7. package/dist/lib/fetch-module.d.ts +3 -38
  8. package/dist/lib/fetch-module.js +26 -8
  9. package/dist/lib/fetch-template.d.ts +20 -0
  10. package/dist/lib/fetch-template.js +129 -0
  11. package/dist/lib/module-license-gate.d.ts +10 -0
  12. package/dist/lib/module-license-gate.js +13 -4
  13. package/dist/lib/paid-paths.d.ts +16 -0
  14. package/dist/lib/paid-paths.js +90 -0
  15. package/dist/module-architecture.d.ts +197 -23
  16. package/dist/module-architecture.js +820 -25
  17. package/dist/parse-args.d.ts +9 -2
  18. package/dist/parse-args.js +46 -1
  19. package/dist/programmatic.d.ts +28 -2
  20. package/dist/programmatic.js +115 -8
  21. package/dist/surfaces.d.ts +12 -36
  22. package/dist/surfaces.js +77 -5
  23. package/dist/sync-routes.js +31 -1
  24. package/dist/template-manifest.d.ts +92 -0
  25. package/dist/template-manifest.js +168 -0
  26. package/dist/template-names.d.ts +41 -0
  27. package/dist/template-names.js +44 -0
  28. package/package.json +3 -2
  29. package/site-templates/marketing-site-free/ailk-template.json +8 -0
  30. package/site-templates/marketing-site-free/content/en/Pricing/pricing.mdx +103 -0
  31. package/site-templates/marketing-site-free/content/en/PrivacyPage/privacy.mdx +79 -0
  32. package/site-templates/marketing-site-free/content/en/TermsPage/terms.mdx +80 -0
  33. package/site-templates/marketing-site-free/provenance.json +4 -0
  34. package/templates/.claude/agents/web.md +2 -3
  35. package/templates/.claude/rules/architecture.md +5 -5
  36. package/templates/.claude/skills/README.md +2 -1
  37. package/templates/.env.example +21 -9
  38. package/templates/CONVENTIONS.md +6 -7
  39. package/templates/apps/api/.env.example +9 -0
  40. package/templates/apps/api/CLAUDE.md +33 -5
  41. package/templates/apps/api/package.json +0 -1
  42. package/templates/apps/api/src/__tests__/cors.test.ts +195 -0
  43. package/templates/apps/api/src/__tests__/module-exclusion.test.ts +60 -2
  44. package/templates/apps/api/src/__tests__/vercel-handler.test.ts +159 -0
  45. package/templates/apps/api/src/__tests__/workspace-module-registration.test.ts +166 -0
  46. package/templates/apps/api/src/config/__tests__/modules.test.ts +76 -0
  47. package/templates/apps/api/src/config/index.ts +19 -0
  48. package/templates/apps/api/src/config/modules.ts +12 -14
  49. package/templates/apps/api/src/lib/__mocks__/prisma.ts +3 -0
  50. package/templates/apps/api/src/lib/__tests__/slice-load.test.ts +89 -0
  51. package/templates/apps/api/src/lib/slice-load.ts +90 -0
  52. package/templates/apps/api/src/openapi/__tests__/openapi.test.ts +52 -32
  53. package/templates/apps/api/src/openapi/__tests__/spec-identity.test.ts +182 -0
  54. package/templates/apps/api/src/openapi/__tests__/surface-drift.test.ts +293 -0
  55. package/templates/apps/api/src/openapi/index.ts +9 -3
  56. package/templates/apps/api/src/openapi/spec.ts +505 -65
  57. package/templates/apps/api/src/openapi/surface-drift.ts +195 -0
  58. package/templates/apps/api/src/routes/content/__tests__/create.test.ts +14 -0
  59. package/templates/apps/api/src/routes/content/__tests__/delete.test.ts +14 -0
  60. package/templates/apps/api/src/routes/content/__tests__/update.test.ts +14 -0
  61. package/templates/apps/api/src/routes/content/index.ts +38 -11
  62. package/templates/apps/api/src/routes/project-listings/__tests__/configured-application.test.ts +17 -0
  63. package/templates/apps/api/src/routes/project-listings/__tests__/drafts.test.ts +17 -0
  64. package/templates/apps/api/src/routes/project-listings/__tests__/founder-identity.test.ts +796 -0
  65. package/templates/apps/api/src/routes/project-listings/__tests__/me.test.ts +10 -0
  66. package/templates/apps/api/src/routes/project-listings/__tests__/public.test.ts +38 -0
  67. package/templates/apps/api/src/routes/project-listings/__tests__/resume-email.test.ts +814 -0
  68. package/templates/apps/api/src/routes/project-listings/__tests__/site-answers.test.ts +10 -0
  69. package/templates/apps/api/src/routes/project-listings/__tests__/site-key.test.ts +24 -0
  70. package/templates/apps/api/src/routes/project-listings/__tests__/structured-address.test.ts +17 -0
  71. package/templates/apps/api/src/routes/project-listings/index.ts +37 -10
  72. package/templates/apps/api/src/routes/project-listings/me.ts +10 -0
  73. package/templates/apps/api/src/routes/project-listings/patch-draft.ts +5 -0
  74. package/templates/apps/api/src/routes/project-listings/public.ts +5 -0
  75. package/templates/apps/api/src/routes/project-listings/respond.ts +11 -0
  76. package/templates/apps/api/src/routes/project-listings/resume-token.ts +5 -0
  77. package/templates/apps/api/src/routes/project-listings/start.ts +30 -0
  78. package/templates/apps/api/src/routes/project-listings/submit.ts +5 -0
  79. package/templates/apps/api/src/routes/project-listings/verify-email.ts +150 -0
  80. package/templates/apps/api/src/server.ts +504 -137
  81. package/templates/apps/api/src/services/deliverable-fulfillment.ts +10 -0
  82. package/templates/apps/api/src/services/listing-config.ts +58 -0
  83. package/templates/apps/api/src/services/project-listing-resume-email.ts +326 -0
  84. package/templates/apps/api/src/services/project-listings.ts +229 -4
  85. package/templates/apps/api/src/vercel-handler.ts +60 -26
  86. package/templates/apps/mcp/.env.example +8 -0
  87. package/templates/apps/mcp/CLAUDE.md +2 -2
  88. package/templates/apps/mcp/__tests__/catalog-drift.test.ts +21 -0
  89. package/templates/apps/mcp/__tests__/config/modules.test.ts +78 -0
  90. package/templates/apps/mcp/__tests__/module-exclusion.test.ts +1 -1
  91. package/templates/apps/mcp/src/config/modules.ts +14 -13
  92. package/templates/apps/mcp/src/server.ts +8 -4
  93. package/templates/apps/mcp/src/tools/index.ts +7 -22
  94. package/templates/apps/web/.env.example +15 -0
  95. package/templates/apps/web/app/[locale]/(authed)/{waitlist/__tests__ → __tests__}/gate.test.tsx +4 -4
  96. package/templates/apps/web/app/[locale]/flows/[slug]/FlowStepperClient.tsx +2 -1
  97. package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/FlowStepperClient.permalink.test.tsx +2 -1
  98. package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/FlowStepperClient.test.tsx +2 -1
  99. package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/flow.actions.test.ts +1 -0
  100. package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/two-route-tool.test.tsx +1 -0
  101. package/templates/apps/web/app/[locale]/flows/[slug]/flow.actions.ts +2 -1
  102. package/templates/apps/web/app/[locale]/flows/[slug]/page.tsx +1 -0
  103. package/templates/apps/web/app/[locale]/flows/[slug]/start/page.tsx +1 -0
  104. package/templates/apps/web/app/[locale]/pricing/page.tsx +40 -0
  105. package/templates/apps/web/app/[locale]/privacy/page.tsx +40 -0
  106. package/templates/apps/web/app/[locale]/terms/page.tsx +40 -0
  107. package/templates/apps/web/app/llms.txt/route.ts +12 -9
  108. package/templates/apps/web/jest.config.cjs +19 -13
  109. package/templates/apps/web/lib/__tests__/server-api.test.ts +61 -0
  110. package/templates/apps/web/lib/server-api.ts +28 -12
  111. package/templates/apps/web/messages/en.json +58 -0
  112. package/templates/apps/web/next.config.mjs +1 -3
  113. package/templates/apps/web/package.json +0 -6
  114. package/templates/apps/web/public/android-chrome-192x192.png +0 -0
  115. package/templates/apps/web/public/android-chrome-512x512.png +0 -0
  116. package/templates/apps/web/public/apple-touch-icon.png +0 -0
  117. package/templates/apps/web/public/favicon-16x16.png +0 -0
  118. package/templates/apps/web/public/favicon-32x32.png +0 -0
  119. package/templates/apps/web/public/favicon.ico +0 -0
  120. package/templates/apps/web/public/favicon.svg +6 -3
  121. package/templates/apps/web/public/lockup-horizontal.svg +4 -0
  122. package/templates/apps/web/public/logomark.svg +4 -0
  123. package/templates/apps/web/public/site.webmanifest +2 -2
  124. package/templates/apps/web/public/wordmark.svg +4 -0
  125. package/templates/database/CHANGELOG.md +47 -0
  126. package/templates/database/inbox/schema.prisma +67 -0
  127. package/templates/database/migrations/20260914120000_listing_founder_identity/migration.sql +123 -0
  128. package/templates/database/package.json +1 -1
  129. package/templates/package.json +1 -1
  130. package/templates/.claude/skills/scaffold-commerce/SKILL.md +0 -807
  131. package/templates/.claude/skills/scaffold-commerce/references/lookup-keys-template.md +0 -71
  132. package/templates/.claude/skills/scaffold-commerce/references/marketplace-brand-pages.md +0 -83
  133. package/templates/.claude/skills/scaffold-commerce/templates/checkout-route.template.ts +0 -370
  134. package/templates/.claude/skills/scaffold-commerce/templates/invoice-route.template.ts +0 -376
  135. package/templates/.claude/skills/scaffold-commerce/templates/marketplace-cta-route.tsx.tmpl +0 -72
  136. package/templates/.claude/skills/scaffold-commerce/templates/payment-link-route.template.ts +0 -471
  137. package/templates/.claude/skills/scaffold-commerce/templates/portal-route.template.ts +0 -365
  138. package/templates/.claude/skills/scaffold-commerce/templates/stripe-config.template.ts +0 -60
  139. package/templates/.claude/skills/scaffold-commerce/templates/subscription-route.template.ts +0 -446
  140. package/templates/apps/api/src/__tests__/server.test.ts +0 -253
  141. package/templates/apps/api/src/bin/deliverable-resend.ts +0 -144
  142. package/templates/apps/api/src/bin/deliverable-upload.ts +0 -114
  143. package/templates/apps/api/src/bin/followup-sweep.ts +0 -44
  144. package/templates/apps/api/src/bin/listing-csv-sweep.ts +0 -46
  145. package/templates/apps/api/src/bin/seed-presets.ts +0 -58
  146. package/templates/apps/api/src/bin/seed-waitlist-experiments.ts +0 -104
  147. package/templates/apps/api/src/bin/session-retention-sweep.ts +0 -46
  148. package/templates/apps/api/src/lib/__tests__/stripe.test.ts +0 -74
  149. package/templates/apps/api/src/lib/stripe.ts +0 -52
  150. package/templates/apps/api/src/lib/tenant-db.ts +0 -225
  151. package/templates/apps/api/src/lib/ws-token.ts +0 -91
  152. package/templates/apps/api/src/middleware/tenant.ts +0 -99
  153. package/templates/apps/api/src/routes/billing/__tests__/portal.test.ts +0 -450
  154. package/templates/apps/api/src/routes/billing/__tests__/read.test.ts +0 -262
  155. package/templates/apps/api/src/routes/billing/__tests__/usage.test.ts +0 -436
  156. package/templates/apps/api/src/routes/billing/index.ts +0 -36
  157. package/templates/apps/api/src/routes/billing/portal.ts +0 -182
  158. package/templates/apps/api/src/routes/billing/read.ts +0 -75
  159. package/templates/apps/api/src/routes/billing/usage.ts +0 -153
  160. package/templates/apps/api/src/routes/checkout/__tests__/sessions.test.ts +0 -687
  161. package/templates/apps/api/src/routes/checkout/index.ts +0 -13
  162. package/templates/apps/api/src/routes/checkout/sessions.ts +0 -197
  163. package/templates/apps/api/src/routes/deliverables/__tests__/index.test.ts +0 -393
  164. package/templates/apps/api/src/routes/deliverables/index.ts +0 -200
  165. package/templates/apps/api/src/routes/flow-checkouts/__tests__/index.test.ts +0 -443
  166. package/templates/apps/api/src/routes/flow-checkouts/index.ts +0 -82
  167. package/templates/apps/api/src/routes/flows/README.md +0 -147
  168. package/templates/apps/api/src/routes/flows/__tests__/index.test.ts +0 -752
  169. package/templates/apps/api/src/routes/flows/__tests__/recommender.test.ts +0 -671
  170. package/templates/apps/api/src/routes/flows/index.ts +0 -202
  171. package/templates/apps/api/src/routes/flows/recommender.ts +0 -443
  172. package/templates/apps/api/src/routes/project-listings/__tests__/copy-edit.test.ts +0 -815
  173. package/templates/apps/api/src/routes/project-listings/__tests__/me-route-precedence.test.ts +0 -221
  174. package/templates/apps/api/src/routes/project-listings/__tests__/tenant-isolation.test.ts +0 -566
  175. package/templates/apps/api/src/routes/project-listings/get.ts +0 -70
  176. package/templates/apps/api/src/routes/project-listings/list.ts +0 -47
  177. package/templates/apps/api/src/routes/project-listings/patch.ts +0 -136
  178. package/templates/apps/api/src/routes/schedule/__tests__/index.test.ts +0 -490
  179. package/templates/apps/api/src/routes/schedule/index.ts +0 -249
  180. package/templates/apps/api/src/routes/slack/__tests__/actions.test.ts +0 -385
  181. package/templates/apps/api/src/routes/slack/actions.ts +0 -177
  182. package/templates/apps/api/src/routes/slack/index.ts +0 -38
  183. package/templates/apps/api/src/routes/waitlist-experiments/__tests__/tenant-isolation.test.ts +0 -577
  184. package/templates/apps/api/src/routes/waitlist-experiments/comparison.ts +0 -78
  185. package/templates/apps/api/src/routes/waitlist-experiments/index.ts +0 -41
  186. package/templates/apps/api/src/routes/waitlist-experiments/list.ts +0 -64
  187. package/templates/apps/api/src/routes/waitlist-experiments/respond.ts +0 -42
  188. package/templates/apps/api/src/routes/waitlist-experiments/signup.ts +0 -84
  189. package/templates/apps/api/src/routes/waitlist-experiments/signups.ts +0 -119
  190. package/templates/apps/api/src/routes/waitlist-signups/__tests__/index.test.ts +0 -238
  191. package/templates/apps/api/src/routes/waitlist-signups/index.ts +0 -101
  192. package/templates/apps/api/src/routes/webhooks/README.md +0 -80
  193. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-flow-checkout.test.ts +0 -315
  194. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-idempotency.test.ts +0 -247
  195. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-org-billing.test.ts +0 -270
  196. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-rate-limit.test.ts +0 -198
  197. package/templates/apps/api/src/routes/webhooks/__tests__/stripe.test.ts +0 -633
  198. package/templates/apps/api/src/routes/webhooks/index.ts +0 -41
  199. package/templates/apps/api/src/routes/webhooks/stripe.ts +0 -481
  200. package/templates/apps/api/src/routes/workspaces/__tests__/config-tenant-isolation.test.ts +0 -356
  201. package/templates/apps/api/src/routes/workspaces/__tests__/tenant-isolation.test.ts +0 -671
  202. package/templates/apps/api/src/routes/workspaces/config.ts +0 -125
  203. package/templates/apps/api/src/routes/workspaces/index.ts +0 -194
  204. package/templates/apps/api/src/routes/workspaces/sessions.ts +0 -218
  205. package/templates/apps/api/src/services/__tests__/flow-aggregate.test.ts +0 -425
  206. package/templates/apps/api/src/services/__tests__/flow-engine.test.ts +0 -2840
  207. package/templates/apps/api/src/services/__tests__/lead-promotion.test.ts +0 -393
  208. package/templates/apps/api/src/services/__tests__/listing-csv-sweep.test.ts +0 -560
  209. package/templates/apps/api/src/services/__tests__/listing-promotion.test.ts +0 -684
  210. package/templates/apps/api/src/services/__tests__/playbook-compile.test.ts +0 -406
  211. package/templates/apps/api/src/services/__tests__/playbook-render.test.ts +0 -290
  212. package/templates/apps/api/src/services/__tests__/project-listing-decision.test.ts +0 -736
  213. package/templates/apps/api/src/services/__tests__/project-listing-flow.test.ts +0 -475
  214. package/templates/apps/api/src/services/__tests__/project-listing-issue.test.ts +0 -340
  215. package/templates/apps/api/src/services/__tests__/recommender-capture.test.ts +0 -983
  216. package/templates/apps/api/src/services/__tests__/tenant-context-cascade.test.ts +0 -71
  217. package/templates/apps/api/src/services/__tests__/tenant-context.test.ts +0 -379
  218. package/templates/apps/api/src/services/__tests__/usage-metering.test.ts +0 -768
  219. package/templates/apps/api/src/services/__tests__/waitlist-dashboard.test.ts +0 -1314
  220. package/templates/apps/api/src/services/__tests__/waitlist-experiments.test.ts +0 -341
  221. package/templates/apps/api/src/services/__tests__/waitlist-followup.test.ts +0 -567
  222. package/templates/apps/api/src/services/__tests__/waitlist-scoring.test.ts +0 -474
  223. package/templates/apps/api/src/services/__tests__/waitlist-signups.test.ts +0 -354
  224. package/templates/apps/api/src/services/flow-aggregate.ts +0 -232
  225. package/templates/apps/api/src/services/flow-checkouts.ts +0 -123
  226. package/templates/apps/api/src/services/flow-engine.ts +0 -1296
  227. package/templates/apps/api/src/services/lead-promotion.ts +0 -176
  228. package/templates/apps/api/src/services/listing-csv-sweep.ts +0 -455
  229. package/templates/apps/api/src/services/listing-promotion.ts +0 -342
  230. package/templates/apps/api/src/services/playbook-compile.ts +0 -398
  231. package/templates/apps/api/src/services/playbook-render.ts +0 -263
  232. package/templates/apps/api/src/services/project-listing-decision.ts +0 -510
  233. package/templates/apps/api/src/services/project-listing-flow.ts +0 -426
  234. package/templates/apps/api/src/services/project-listing-issue.ts +0 -251
  235. package/templates/apps/api/src/services/recommender-capture.ts +0 -835
  236. package/templates/apps/api/src/services/scheduling/cal-provider.ts +0 -392
  237. package/templates/apps/api/src/services/scheduling/index.ts +0 -63
  238. package/templates/apps/api/src/services/scheduling/types.ts +0 -88
  239. package/templates/apps/api/src/services/tenant-context.ts +0 -451
  240. package/templates/apps/api/src/services/usage-metering.ts +0 -699
  241. package/templates/apps/api/src/services/waitlist-dashboard.ts +0 -947
  242. package/templates/apps/api/src/services/waitlist-experiments.ts +0 -213
  243. package/templates/apps/api/src/services/waitlist-followup.ts +0 -486
  244. package/templates/apps/api/src/services/waitlist-scoring.ts +0 -166
  245. package/templates/apps/api/src/services/waitlist-signups.ts +0 -165
  246. package/templates/apps/mcp/__tests__/schedule_tools.test.ts +0 -242
  247. package/templates/apps/mcp/src/tools/create_booking.ts +0 -58
  248. package/templates/apps/mcp/src/tools/get_event_meta.ts +0 -55
  249. package/templates/apps/mcp/src/tools/get_flow.ts +0 -61
  250. package/templates/apps/mcp/src/tools/list_availability.ts +0 -67
  251. package/templates/apps/mcp/src/tools/submit_flow_step.ts +0 -83
  252. package/templates/apps/web/app/[locale]/(authed)/waitlist/[experimentId]/page.tsx +0 -309
  253. package/templates/apps/web/app/[locale]/(authed)/waitlist/[experimentId]/signups/[leadId]/page.tsx +0 -149
  254. package/templates/apps/web/app/[locale]/(authed)/waitlist/__tests__/comparison.test.tsx +0 -273
  255. package/templates/apps/web/app/[locale]/(authed)/waitlist/__tests__/list.test.tsx +0 -171
  256. package/templates/apps/web/app/[locale]/(authed)/waitlist/__tests__/signup.test.tsx +0 -179
  257. package/templates/apps/web/app/[locale]/(authed)/waitlist/components/ExperimentsTable.tsx +0 -116
  258. package/templates/apps/web/app/[locale]/(authed)/waitlist/components/OfferFunnelTable.tsx +0 -66
  259. package/templates/apps/web/app/[locale]/(authed)/waitlist/components/RollupTicker.tsx +0 -61
  260. package/templates/apps/web/app/[locale]/(authed)/waitlist/components/ScoreTrace.tsx +0 -114
  261. package/templates/apps/web/app/[locale]/(authed)/waitlist/components/SignupsTable.tsx +0 -139
  262. package/templates/apps/web/app/[locale]/(authed)/waitlist/components/WaitlistComparisonTabs.tsx +0 -85
  263. package/templates/apps/web/app/[locale]/(authed)/waitlist/components/status-badges.tsx +0 -67
  264. package/templates/apps/web/app/[locale]/(authed)/waitlist/page.tsx +0 -179
  265. package/templates/apps/web/app/[locale]/blog/[[...slug]]/page.tsx +0 -178
  266. package/templates/apps/web/app/[locale]/dev/purchase/__tests__/actions.test.ts +0 -160
  267. package/templates/apps/web/app/[locale]/dev/purchase/error.tsx +0 -25
  268. package/templates/apps/web/app/[locale]/dev/purchase/page.tsx +0 -117
  269. package/templates/apps/web/app/[locale]/dev/purchase/purchase.actions.ts +0 -58
  270. package/templates/apps/web/app/[locale]/docs/[[...slug]]/page.tsx +0 -119
  271. package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/checkout.actions.test.ts +0 -287
  272. package/templates/apps/web/app/[locale]/flows/[slug]/checkout.actions.ts +0 -254
  273. package/templates/apps/web/app/[locale]/flows/[slug]/results/[payload]/ResultsClient.tsx +0 -532
  274. package/templates/apps/web/app/[locale]/flows/[slug]/results/[payload]/ResultsEmailStep.tsx +0 -121
  275. package/templates/apps/web/app/[locale]/flows/[slug]/results/[payload]/__tests__/ResultsClient.checkout.test.tsx +0 -457
  276. package/templates/apps/web/app/[locale]/flows/[slug]/results/[payload]/__tests__/page.test.tsx +0 -396
  277. package/templates/apps/web/app/[locale]/flows/[slug]/results/[payload]/page.tsx +0 -114
  278. package/templates/apps/web/app/[locale]/projects/apply/ListingApplicationClient.tsx +0 -110
  279. package/templates/apps/web/app/[locale]/projects/apply/__tests__/ListingApplicationClient.test.tsx +0 -96
  280. package/templates/apps/web/app/[locale]/schedule/__tests__/page.test.tsx +0 -117
  281. package/templates/apps/web/app/[locale]/schedule/confirmed/__tests__/page.test.tsx +0 -96
  282. package/templates/apps/web/app/[locale]/schedule/confirmed/page.tsx +0 -92
  283. package/templates/apps/web/app/[locale]/schedule/page.tsx +0 -82
  284. package/templates/apps/web/content/en/blog/README.txt +0 -25
  285. package/templates/apps/web/content/en/docs/index.mdx +0 -28
  286. package/templates/apps/web/lib/__mocks__/source-server.js +0 -31
  287. package/templates/apps/web/lib/blog-list-data.ts +0 -95
  288. package/templates/apps/web/lib/blog-post-data.ts +0 -79
  289. package/templates/apps/web/lib/source.ts +0 -34
  290. package/templates/apps/web/public/logomark-dark.svg +0 -4
  291. package/templates/apps/web/public/logomark-light.svg +0 -4
  292. package/templates/apps/web/source.config.ts +0 -78
@@ -0,0 +1,92 @@
1
+ import { type PageRosterRow } from "./module-architecture.js";
2
+ import type { ModuleName } from "./parse-args.js";
3
+ /**
4
+ * One site template: its fixed module list and the page rows it brings itself.
5
+ *
6
+ * THERE IS NO `tier`, `level` OR `price` MEMBER, and there never is one
7
+ * (parent § D4). Delivery tier is DERIVED from `requires` — by the client via
8
+ * `templateDelivery` below, and by the issuer via `TIER_SPECS` (#5480) — so
9
+ * declaring it here would be a second authority for a fact the module list
10
+ * already settles. The type, not a convention, is what makes adding one a
11
+ * compile error: a convention is a thing someone must remember.
12
+ *
13
+ * There is likewise no optional-module member (parent § D12). A template's
14
+ * level must be readable from ONE fixed list; a soft list would make the same
15
+ * template Free or Pro depending on the key.
16
+ */
17
+ export interface TemplateManifest {
18
+ /** Template name. Equals this manifest's `TEMPLATE_MANIFESTS` key. */
19
+ name: string;
20
+ /**
21
+ * The modules whose PAGES this template's roster uses (parent § D15) — not
22
+ * the modules its level bundles. Typed against `ModuleName`, so an
23
+ * unrecognized name fails type-check rather than a runtime validation.
24
+ */
25
+ requires: readonly ModuleName[];
26
+ /** Base rows, before any module's contribution is merged. */
27
+ roster: readonly PageRosterRow[];
28
+ /** Bundle-relative source → scaffold-relative destination. */
29
+ installMap?: Record<string, string>;
30
+ }
31
+ /** Thrown on an undeclared template name or a route claimed twice. Mirrors `SurfaceError`'s shape. */
32
+ export declare class TemplateError extends Error {
33
+ constructor(message: string);
34
+ }
35
+ /**
36
+ * The three settled templates and their fixed `requires` lists — settled by
37
+ * Sam, 2026-09-14 (parent § D12). The plain name is the Pro one: it is the
38
+ * flagship and the demo.
39
+ *
40
+ * `workspace` appears in none of them. It is a Pro module, but an authed app
41
+ * surface contributing no PUBLIC page to a marketing site, and `requires`
42
+ * names what the roster uses (parent § D15). A Pro key unlocks it regardless
43
+ * of any template. `ModuleName` could not express it in any case —
44
+ * `RECOGNIZED_MODULES` is the six names and `workspace` is not among them.
45
+ *
46
+ * `commerce` is likewise in none of them: it is a per-site add-on available at
47
+ * any level, so a template for it would contradict the offering model and
48
+ * multiply the set combinatorially (parent § D13). It still contributes rows
49
+ * to whichever template takes it, through `mergeRoster` below.
50
+ */
51
+ export declare const TEMPLATE_MANIFESTS: Record<string, TemplateManifest>;
52
+ /** Look up a declared template. @throws TemplateError on an undeclared name. */
53
+ export declare function resolveTemplate(name: string): TemplateManifest;
54
+ /**
55
+ * Compose a template's roster: its base rows, then each taken module's
56
+ * contributed rows in `normalizeModules` order (parent § D7).
57
+ *
58
+ * `normalizeModules` is REUSED rather than re-sorted here. It already returns
59
+ * the unique set ordered by `RECOGNIZED_MODULES`, and `scaffold()` already
60
+ * calls it — a second sort at this call site would be a second ordering
61
+ * authority that could drift from the one `deriveArchitecture` depends on.
62
+ * That also makes the merge a pure function of the module SET: the same set in
63
+ * any argument order returns identical rows.
64
+ *
65
+ * The merge is pure and writes nothing. Staging a contributed row's seed
66
+ * content is the bundle producer's job (`build-module-bundles.mjs`, #5481);
67
+ * doing it here would put a filesystem dependency in a function three sibling
68
+ * units import for its return value.
69
+ *
70
+ * @param modules the modules this scaffold takes. A template's `requires` are
71
+ * taken by definition — a required module whose bundle cannot be had refuses
72
+ * the install outright (parent § D17, #5481) rather than merging short.
73
+ * @throws TemplateError when two sources claim one route (parent § D8). Both
74
+ * the base roster and every contribution are compile-time known, so the
75
+ * collision is caught by a test before a bundle exists — never resolved at
76
+ * runtime by a base-wins or module-wins precedence rule, either of which
77
+ * silently produces a site missing a page someone declared.
78
+ */
79
+ export declare function mergeRoster(manifest: TemplateManifest, modules: readonly string[]): PageRosterRow[];
80
+ /**
81
+ * Whether a template installs on the keyless path or needs a verified
82
+ * `AILK_LICENSE_KEY` — derived from `requires`, never declared (parent § D3).
83
+ *
84
+ * The derivation goes through the existing `classifyModules` rather than a
85
+ * second list of paid names, which would drift. This is deliberately the
86
+ * CLIENT half of a two-derivation split: the issuer derives the commercial
87
+ * LEVEL from the same `requires` via `TIER_SPECS` (#5480). One shared
88
+ * derivation would force this package to import
89
+ * `@working-theory/license-manifest` — a `restricted` package — breaking
90
+ * `pnpm install` for every Free consumer, not merely gating the paid path.
91
+ */
92
+ export declare function templateDelivery(manifest: TemplateManifest): "free" | "paid";
@@ -0,0 +1,168 @@
1
+ /**
2
+ * Site-template registry, and the roster merge that composes a template with
3
+ * the modules it takes (spec 5478, unit A of the site-templates mechanism;
4
+ * design record docs/specs/5462-site-templates-module-bundles-spec.md).
5
+ *
6
+ * A site template is DATA AND CONTENT, NOT CODE: a page roster, seed content
7
+ * and config — never a `page.tsx` (parent § D16). This file declares what a
8
+ * template IS. It declares no delivery channel, reads no licence, and touches
9
+ * no disk: the `--template` flag, the bundle fetch and the landing order are
10
+ * #5481's, and `GET /v1/templates/:name/:version` is #5480's.
11
+ *
12
+ * A CODE registry, not per-template JSON (parent § D2): in TypeScript,
13
+ * `requires` is checked against `RECOGNIZED_MODULES` at compile time, and this
14
+ * package already twice records that a fixed template FILE is the drift a
15
+ * registry removes.
16
+ */
17
+ import { classifyModules } from "./lib/module-tier.js";
18
+ import { MODULE_SLICES, normalizeModules, } from "./module-architecture.js";
19
+ /** Thrown on an undeclared template name or a route claimed twice. Mirrors `SurfaceError`'s shape. */
20
+ export class TemplateError extends Error {
21
+ constructor(message) {
22
+ super(message);
23
+ this.name = "TemplateError";
24
+ }
25
+ }
26
+ /**
27
+ * `/pricing`, `/privacy` and `/terms` — the three module-less rows every
28
+ * declared template brings itself.
29
+ *
30
+ * Module-less by construction (parent § D16): no module owns these surfaces,
31
+ * their route files live in `apps/web` and are snapshotted into the starter
32
+ * like every other route, and a template enables them by NAMING them in its
33
+ * roster. Registering the three as `GATEABLE_SURFACES` entries is #5479's; the
34
+ * rows are declared here because the roster is what a template is.
35
+ */
36
+ const TEMPLATE_BASE_ROSTER = [
37
+ { route: "/pricing", content: ["content/en/Pricing/pricing.mdx"] },
38
+ { route: "/privacy", content: ["content/en/PrivacyPage/privacy.mdx"] },
39
+ { route: "/terms", content: ["content/en/TermsPage/terms.mdx"] },
40
+ ];
41
+ /**
42
+ * The three settled templates and their fixed `requires` lists — settled by
43
+ * Sam, 2026-09-14 (parent § D12). The plain name is the Pro one: it is the
44
+ * flagship and the demo.
45
+ *
46
+ * `workspace` appears in none of them. It is a Pro module, but an authed app
47
+ * surface contributing no PUBLIC page to a marketing site, and `requires`
48
+ * names what the roster uses (parent § D15). A Pro key unlocks it regardless
49
+ * of any template. `ModuleName` could not express it in any case —
50
+ * `RECOGNIZED_MODULES` is the six names and `workspace` is not among them.
51
+ *
52
+ * `commerce` is likewise in none of them: it is a per-site add-on available at
53
+ * any level, so a template for it would contradict the offering model and
54
+ * multiply the set combinatorially (parent § D13). It still contributes rows
55
+ * to whichever template takes it, through `mergeRoster` below.
56
+ */
57
+ export const TEMPLATE_MANIFESTS = {
58
+ /**
59
+ * The Free template, and the mechanism's own proof (parent § D11): it
60
+ * requires only `marketing`, so the keyless merge path is exercised by a
61
+ * template we ship anyway rather than by a throwaway fixture.
62
+ */
63
+ "marketing-site-free": {
64
+ name: "marketing-site-free",
65
+ requires: ["marketing"],
66
+ roster: TEMPLATE_BASE_ROSTER,
67
+ },
68
+ /**
69
+ * The Pro flagship. Its module list is OFFERINGS § 4 offering 3's tiers line
70
+ * — "docs, scheduling and flows modules" — where "flows" is
71
+ * `signal-collectors` (`MODULE_SURFACES` maps it to `["flows"]`).
72
+ */
73
+ "marketing-site": {
74
+ name: "marketing-site",
75
+ requires: ["marketing", "docs-blog", "scheduling", "signal-collectors"],
76
+ roster: TEMPLATE_BASE_ROSTER,
77
+ },
78
+ /**
79
+ * Pro Plus — the Pro list plus `multi-tenant`, which is correctly in the
80
+ * list because it DOES contribute pages (the org and workspace surfaces).
81
+ * Its `pageContributions` is nonetheless unset today, deferred to its own
82
+ * instance, so this template's merged roster carries the same contributed
83
+ * rows as `marketing-site`'s and no more. That is a module which has
84
+ * declared no rows yet — visible in the diff — not a merge that dropped
85
+ * declared rows.
86
+ */
87
+ "saas-product": {
88
+ name: "saas-product",
89
+ requires: [
90
+ "marketing",
91
+ "docs-blog",
92
+ "scheduling",
93
+ "signal-collectors",
94
+ "multi-tenant",
95
+ ],
96
+ roster: TEMPLATE_BASE_ROSTER,
97
+ },
98
+ };
99
+ /** Look up a declared template. @throws TemplateError on an undeclared name. */
100
+ export function resolveTemplate(name) {
101
+ const manifest = TEMPLATE_MANIFESTS[name];
102
+ if (!manifest) {
103
+ throw new TemplateError(`unknown template "${name}". Declared: ${Object.keys(TEMPLATE_MANIFESTS).join(", ")}`);
104
+ }
105
+ return manifest;
106
+ }
107
+ /**
108
+ * Compose a template's roster: its base rows, then each taken module's
109
+ * contributed rows in `normalizeModules` order (parent § D7).
110
+ *
111
+ * `normalizeModules` is REUSED rather than re-sorted here. It already returns
112
+ * the unique set ordered by `RECOGNIZED_MODULES`, and `scaffold()` already
113
+ * calls it — a second sort at this call site would be a second ordering
114
+ * authority that could drift from the one `deriveArchitecture` depends on.
115
+ * That also makes the merge a pure function of the module SET: the same set in
116
+ * any argument order returns identical rows.
117
+ *
118
+ * The merge is pure and writes nothing. Staging a contributed row's seed
119
+ * content is the bundle producer's job (`build-module-bundles.mjs`, #5481);
120
+ * doing it here would put a filesystem dependency in a function three sibling
121
+ * units import for its return value.
122
+ *
123
+ * @param modules the modules this scaffold takes. A template's `requires` are
124
+ * taken by definition — a required module whose bundle cannot be had refuses
125
+ * the install outright (parent § D17, #5481) rather than merging short.
126
+ * @throws TemplateError when two sources claim one route (parent § D8). Both
127
+ * the base roster and every contribution are compile-time known, so the
128
+ * collision is caught by a test before a bundle exists — never resolved at
129
+ * runtime by a base-wins or module-wins precedence rule, either of which
130
+ * silently produces a site missing a page someone declared.
131
+ */
132
+ export function mergeRoster(manifest, modules) {
133
+ const merged = [];
134
+ /** route → the source that claimed it, for the collision message. */
135
+ const claimedBy = new Map();
136
+ const take = (rows, source) => {
137
+ for (const row of rows) {
138
+ const owner = claimedBy.get(row.route);
139
+ if (owner !== undefined) {
140
+ throw new TemplateError(`route "${row.route}" is claimed by both ${owner} and ${source}`);
141
+ }
142
+ claimedBy.set(row.route, source);
143
+ merged.push(row);
144
+ }
145
+ };
146
+ take(manifest.roster, `template "${manifest.name}"`);
147
+ for (const module of normalizeModules([...modules])) {
148
+ take(MODULE_SLICES[module].pageContributions ?? [], `module "${module}"`);
149
+ }
150
+ return merged;
151
+ }
152
+ /**
153
+ * Whether a template installs on the keyless path or needs a verified
154
+ * `AILK_LICENSE_KEY` — derived from `requires`, never declared (parent § D3).
155
+ *
156
+ * The derivation goes through the existing `classifyModules` rather than a
157
+ * second list of paid names, which would drift. This is deliberately the
158
+ * CLIENT half of a two-derivation split: the issuer derives the commercial
159
+ * LEVEL from the same `requires` via `TIER_SPECS` (#5480). One shared
160
+ * derivation would force this package to import
161
+ * `@working-theory/license-manifest` — a `restricted` package — breaking
162
+ * `pnpm install` for every Free consumer, not merely gating the paid path.
163
+ */
164
+ export function templateDelivery(manifest) {
165
+ return classifyModules([...manifest.requires]).paid.length > 0
166
+ ? "paid"
167
+ : "free";
168
+ }
@@ -0,0 +1,41 @@
1
+ /**
2
+ * The `--template` flag's vocabulary, and nothing else.
3
+ *
4
+ * WHY THIS FILE EXISTS, measured rather than assumed. Spec 5481 § 3 DD1 has
5
+ * `parse-args.ts` validate `--template` against `TEMPLATE_MANIFESTS` through a
6
+ * runtime import, on the grounds that the registry's own dependency on
7
+ * `parse-args.ts` (for `ModuleName`) is `import type` and so erases at
8
+ * compile. That is true of the DIRECT edge and false of the graph:
9
+ * `template-manifest.ts` imports `lib/module-tier.js` and
10
+ * `module-architecture.js` as RUNTIME values, and BOTH of those import
11
+ * `RECOGNIZED_MODULES` — a runtime value — back from `parse-args.ts`.
12
+ * `module-tier.ts` then reads it at MODULE SCOPE to derive `PAID_MODULES`.
13
+ * So `parse-args.ts` importing the registry closes a runtime cycle whose
14
+ * first read lands in the temporal dead zone:
15
+ *
16
+ * ReferenceError: Cannot access 'RECOGNIZED_MODULES' before initialization
17
+ *
18
+ * — reproduced against the built `dist/` while implementing this unit, not
19
+ * theorised. `surfaces.ts`'s header warns about exactly this relationship
20
+ * ("Deliberately imports nothing from `parse-args.ts`: that module imports
21
+ * THIS one … so a back-import would close a cycle"), and `surfaces.ts` is the
22
+ * precedent this file follows: the flag's vocabulary lives in a module the
23
+ * parser can import because it imports nothing at all.
24
+ *
25
+ * THE REGISTRY IS STILL `template-manifest.ts` (parent record D2). This file
26
+ * declares NAMES; that one declares what a template IS — `requires`, the
27
+ * roster, the `installMap`, the free-vs-paid derivation — and it stays the
28
+ * single place a template is defined. The two cannot drift: the names here
29
+ * are asserted equal to `Object.keys(TEMPLATE_MANIFESTS)` by
30
+ * `__tests__/template-scaffold.test.ts`, so adding a template without listing
31
+ * it here (or the reverse) fails the suite rather than shipping a flag that
32
+ * accepts a name the registry does not know.
33
+ *
34
+ * Rejected: lazifying `module-tier.ts`'s `PAID_MODULES` to break the cycle at
35
+ * its source. It is the correct structural fix and it is not this unit's to
36
+ * make — `module-tier.ts` is a READ row in spec 5481 § 4, and `PAID_MODULES`
37
+ * is consumed as a plain array across the package.
38
+ */
39
+ /** The declared site templates, in `TEMPLATE_MANIFESTS` declaration order. */
40
+ export declare const RECOGNIZED_TEMPLATES: readonly ["marketing-site-free", "marketing-site", "saas-product"];
41
+ export type TemplateName = (typeof RECOGNIZED_TEMPLATES)[number];
@@ -0,0 +1,44 @@
1
+ /**
2
+ * The `--template` flag's vocabulary, and nothing else.
3
+ *
4
+ * WHY THIS FILE EXISTS, measured rather than assumed. Spec 5481 § 3 DD1 has
5
+ * `parse-args.ts` validate `--template` against `TEMPLATE_MANIFESTS` through a
6
+ * runtime import, on the grounds that the registry's own dependency on
7
+ * `parse-args.ts` (for `ModuleName`) is `import type` and so erases at
8
+ * compile. That is true of the DIRECT edge and false of the graph:
9
+ * `template-manifest.ts` imports `lib/module-tier.js` and
10
+ * `module-architecture.js` as RUNTIME values, and BOTH of those import
11
+ * `RECOGNIZED_MODULES` — a runtime value — back from `parse-args.ts`.
12
+ * `module-tier.ts` then reads it at MODULE SCOPE to derive `PAID_MODULES`.
13
+ * So `parse-args.ts` importing the registry closes a runtime cycle whose
14
+ * first read lands in the temporal dead zone:
15
+ *
16
+ * ReferenceError: Cannot access 'RECOGNIZED_MODULES' before initialization
17
+ *
18
+ * — reproduced against the built `dist/` while implementing this unit, not
19
+ * theorised. `surfaces.ts`'s header warns about exactly this relationship
20
+ * ("Deliberately imports nothing from `parse-args.ts`: that module imports
21
+ * THIS one … so a back-import would close a cycle"), and `surfaces.ts` is the
22
+ * precedent this file follows: the flag's vocabulary lives in a module the
23
+ * parser can import because it imports nothing at all.
24
+ *
25
+ * THE REGISTRY IS STILL `template-manifest.ts` (parent record D2). This file
26
+ * declares NAMES; that one declares what a template IS — `requires`, the
27
+ * roster, the `installMap`, the free-vs-paid derivation — and it stays the
28
+ * single place a template is defined. The two cannot drift: the names here
29
+ * are asserted equal to `Object.keys(TEMPLATE_MANIFESTS)` by
30
+ * `__tests__/template-scaffold.test.ts`, so adding a template without listing
31
+ * it here (or the reverse) fails the suite rather than shipping a flag that
32
+ * accepts a name the registry does not know.
33
+ *
34
+ * Rejected: lazifying `module-tier.ts`'s `PAID_MODULES` to break the cycle at
35
+ * its source. It is the correct structural fix and it is not this unit's to
36
+ * make — `module-tier.ts` is a READ row in spec 5481 § 4, and `PAID_MODULES`
37
+ * is consumed as a plain array across the package.
38
+ */
39
+ /** The declared site templates, in `TEMPLATE_MANIFESTS` declaration order. */
40
+ export const RECOGNIZED_TEMPLATES = [
41
+ "marketing-site-free",
42
+ "marketing-site",
43
+ "saas-product",
44
+ ];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-ailk",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "Scaffolder for AI Launch Kit — `pnpm create ailk@latest <dir>` produces a starter repo consuming @working-theory/* from npm (per ADR 0007).",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -11,6 +11,7 @@
11
11
  "files": [
12
12
  "dist",
13
13
  "templates",
14
+ "site-templates",
14
15
  "component-catalog.md",
15
16
  "README.md",
16
17
  "LICENSE"
@@ -47,7 +48,7 @@
47
48
  "test": "tsc -b && node scripts/build-templates.mjs && jest",
48
49
  "test:watch": "jest --watch",
49
50
  "test:coverage": "jest --coverage",
50
- "build-templates": "node scripts/build-templates.mjs",
51
+ "build-templates": "tsc -b && node scripts/build-templates.mjs",
51
52
  "build-catalog": "node scripts/build-component-catalog.mjs",
52
53
  "check-catalog": "node scripts/build-component-catalog.mjs --check"
53
54
  }
@@ -0,0 +1,8 @@
1
+ {
2
+ "name": "marketing-site-free",
3
+ "requires": ["marketing"],
4
+ "installMap": {
5
+ "provenance.json": ".ailk-template.json"
6
+ },
7
+ "postInstall": "Template marketing-site-free installed. Its seed content for /pricing, /privacy and /terms is in content/en/ - replace the placeholder copy before you launch."
8
+ }
@@ -0,0 +1,103 @@
1
+ ---
2
+ type: "Pricing"
3
+ slug: "pricing"
4
+ title: "Pricing"
5
+ description: "Replace this with one sentence naming how Your Company charges — the unit, the range, and what moves the number. It is the description answer engines quote."
6
+ sections:
7
+ [
8
+ {
9
+ "id": "hero",
10
+ "type": "hero",
11
+ "data":
12
+ {
13
+ "headline": "Pricing",
14
+ "subheadline": "Replace this with the one thing a buyer most needs to know about what they will pay.",
15
+ },
16
+ },
17
+ {
18
+ "id": "plans",
19
+ "type": "pricing",
20
+ "data":
21
+ {
22
+ "headline": "Replace these plans with your own",
23
+ "description": "Three placeholder plans. Rename them, set real prices, and list what each one actually includes. Delete any plan you do not offer — an empty tier is worse than one fewer.",
24
+ "plans":
25
+ [
26
+ {
27
+ "name": "Plan one",
28
+ "description": "Replace this with who this plan is for.",
29
+ "price": { "custom": "Your price" },
30
+ "features":
31
+ [
32
+ "Replace this line with something the plan includes.",
33
+ "One line per included thing.",
34
+ "Name the limit, not just the feature.",
35
+ ],
36
+ "cta": { "label": "Get in touch", "href": "/contact" },
37
+ },
38
+ {
39
+ "name": "Plan two",
40
+ "description": "Replace this with who this plan is for.",
41
+ "price": { "custom": "Your price" },
42
+ "features":
43
+ [
44
+ "Everything in plan one.",
45
+ "Replace this line with what the step up buys.",
46
+ "Say the number when there is one.",
47
+ ],
48
+ "cta": { "label": "Get in touch", "href": "/contact" },
49
+ "highlighted": true,
50
+ },
51
+ {
52
+ "name": "Plan three",
53
+ "description": "Replace this with who this plan is for.",
54
+ "price": { "custom": "Let's talk" },
55
+ "features":
56
+ [
57
+ "Everything in plan two.",
58
+ "Replace this line with the work you quote per engagement.",
59
+ "Scope, not adjectives.",
60
+ ],
61
+ "cta":
62
+ {
63
+ "label": "Book a call",
64
+ "href": "/contact",
65
+ "variant": "outline",
66
+ },
67
+ },
68
+ ],
69
+ },
70
+ },
71
+ {
72
+ "id": "pricing-faq",
73
+ "type": "faq",
74
+ "data":
75
+ {
76
+ "headline": "Pricing questions",
77
+ "items":
78
+ [
79
+ {
80
+ "question": "Replace this with the pricing question you are actually asked.",
81
+ "answer": "Answer it in the first sentence, with the number in it. A pricing answer that opens with context is the one buyers stop reading.",
82
+ },
83
+ {
84
+ "question": "What happens when the scope changes?",
85
+ "answer": "Replace this with how you handle a change in scope — who decides, how it is priced, and when the new price starts. Say it plainly here and you will not have to say it awkwardly later.",
86
+ },
87
+ ],
88
+ },
89
+ },
90
+ {
91
+ "id": "cta",
92
+ "type": "cta",
93
+ "data":
94
+ {
95
+ "headline": "Not sure which plan fits?",
96
+ "description": "Replace this with an invitation to the conversation you actually want to have.",
97
+ "primaryCta": { "label": "Get in touch", "href": "/contact" },
98
+ },
99
+ },
100
+ ]
101
+ ---
102
+
103
+ {/* Rendered from frontmatter `sections[]`. Seed content — replace the plan names, prices and features above with your own before you launch. */}
@@ -0,0 +1,79 @@
1
+ ---
2
+ type: "PrivacyPage"
3
+ slug: "privacy"
4
+ title: "Privacy Policy"
5
+ description: "Placeholder privacy policy for Your Company. Replace every section with a policy that describes what your site actually collects before you launch."
6
+ sections:
7
+ [
8
+ {
9
+ "id": "privacy-document",
10
+ "type": "document-chassis",
11
+ "data":
12
+ {
13
+ "eyebrow": "PLACEHOLDER — REPLACE BEFORE LAUNCH",
14
+ "headline": "Privacy Policy",
15
+ "backHref": "/",
16
+ "backLabel": "Back home",
17
+ "navGroupLabel": "Contents",
18
+ "sections":
19
+ [
20
+ {
21
+ "id": "placeholder-notice",
22
+ "heading": "This is placeholder text",
23
+ "blocks":
24
+ [
25
+ {
26
+ "kind": "paragraph",
27
+ "text": "This page is starter content that shipped with your site. It is not a privacy policy, it makes no commitment on behalf of Your Company, and it is not legal advice. Replace every section below with a policy that describes what your site actually collects, and have someone qualified read it before you publish.",
28
+ },
29
+ {
30
+ "kind": "paragraph",
31
+ "text": "Until you do, leave this notice in place so nobody mistakes the page for a finished policy.",
32
+ },
33
+ ],
34
+ },
35
+ {
36
+ "id": "what-to-write-here",
37
+ "heading": "What belongs on this page",
38
+ "blocks":
39
+ [
40
+ {
41
+ "kind": "paragraph",
42
+ "text": "A privacy policy answers a short list of questions. Write each answer in plain language, and write it about the site you actually run — not about the site you plan to run.",
43
+ },
44
+ {
45
+ "kind": "list",
46
+ "listStyle": "number",
47
+ "items":
48
+ [
49
+ "Who operates this site, and how to reach them.",
50
+ "What the site collects — forms you publish, server logs, analytics.",
51
+ "Why you collect each thing, and what you do with it.",
52
+ "Which third parties process it on your behalf.",
53
+ "How long you keep it, and how someone asks for a copy or a deletion.",
54
+ ],
55
+ },
56
+ ],
57
+ },
58
+ {
59
+ "id": "contact",
60
+ "heading": "How to reach us",
61
+ "blocks":
62
+ [
63
+ {
64
+ "kind": "paragraph",
65
+ "text": "Replace this with the address you actually monitor — for example privacy@example.com — and say how quickly someone can expect a reply. A published address nobody watches is worse than no address.",
66
+ },
67
+ {
68
+ "kind": "paragraph",
69
+ "text": "Replace this with the date you last updated the policy, and say how you will announce future changes.",
70
+ },
71
+ ],
72
+ },
73
+ ],
74
+ },
75
+ },
76
+ ]
77
+ ---
78
+
79
+ {/* Rendered from frontmatter `sections[]`. Placeholder seed content — this is not a privacy policy and not legal advice. Replace every section before you launch. */}
@@ -0,0 +1,80 @@
1
+ ---
2
+ type: "TermsPage"
3
+ slug: "terms"
4
+ title: "Terms of Service"
5
+ description: "Placeholder terms of service for Your Company. Replace every section with terms that describe what you actually offer before you launch."
6
+ sections:
7
+ [
8
+ {
9
+ "id": "terms-document",
10
+ "type": "document-chassis",
11
+ "data":
12
+ {
13
+ "eyebrow": "PLACEHOLDER — REPLACE BEFORE LAUNCH",
14
+ "headline": "Terms of Service",
15
+ "backHref": "/",
16
+ "backLabel": "Back home",
17
+ "navGroupLabel": "Contents",
18
+ "sections":
19
+ [
20
+ {
21
+ "id": "placeholder-notice",
22
+ "heading": "This is placeholder text",
23
+ "blocks":
24
+ [
25
+ {
26
+ "kind": "paragraph",
27
+ "text": "This page is starter content that shipped with your site. It is not a contract, it binds nobody, and it is not legal advice. Replace every section below with terms that match what Your Company actually offers, and have someone qualified read them before you publish.",
28
+ },
29
+ {
30
+ "kind": "paragraph",
31
+ "text": "Until you do, leave this notice in place so nobody mistakes the page for finished terms.",
32
+ },
33
+ ],
34
+ },
35
+ {
36
+ "id": "what-to-write-here",
37
+ "heading": "What belongs on this page",
38
+ "blocks":
39
+ [
40
+ {
41
+ "kind": "paragraph",
42
+ "text": "Terms of service set out who is offering what, on what conditions. Write each part about the thing you actually sell, and keep the sentences short enough that a customer can follow them.",
43
+ },
44
+ {
45
+ "kind": "list",
46
+ "listStyle": "number",
47
+ "items":
48
+ [
49
+ "Who provides the service, and which legal entity stands behind it.",
50
+ "What the service is, and what it is not.",
51
+ "What a customer may and may not do with it.",
52
+ "How payment, renewal and cancellation work, if you charge.",
53
+ "Which warranties you give, and which you do not.",
54
+ "Which law governs the agreement, and how you will announce changes.",
55
+ ],
56
+ },
57
+ ],
58
+ },
59
+ {
60
+ "id": "contact",
61
+ "heading": "Questions about these terms",
62
+ "blocks":
63
+ [
64
+ {
65
+ "kind": "paragraph",
66
+ "text": "Replace this with the address you actually monitor — for example hello@example.com — so a customer with a question about the terms has somewhere to send it.",
67
+ },
68
+ {
69
+ "kind": "paragraph",
70
+ "text": "Replace this with the date these terms last changed, and say what happens when they change again.",
71
+ },
72
+ ],
73
+ },
74
+ ],
75
+ },
76
+ },
77
+ ]
78
+ ---
79
+
80
+ {/* Rendered from frontmatter `sections[]`. Placeholder seed content — these are not terms of service and not legal advice. Replace every section before you launch. */}
@@ -0,0 +1,4 @@
1
+ {
2
+ "template": "marketing-site-free",
3
+ "requires": ["marketing"]
4
+ }
@@ -72,9 +72,8 @@ Run `pnpm preflight` before opening a PR.
72
72
  speak to the API via `@working-theory/api-client`.
73
73
  - Importing `@working-theory/database` — `apps/web` does not touch the DB;
74
74
  route through `apps/api`.
75
- - Importing `stripe`, `resend`, `@react-email/*` directly — wrap
76
- through `@working-theory/stripe-client` or `@working-theory/email`, server-side via
77
- `apps/api`.
75
+ - Importing `resend`, `@react-email/*` directly — wrap through
76
+ `@working-theory/email`, server-side via `apps/api`.
78
77
  - Adding a `utils.ts`, `helpers.ts`, `common.ts`, or `misc.ts` file
79
78
  — use a descriptive name.
80
79
  - Reformatting unrelated lines. Diff is the contract.