create-ailk 0.21.0 → 0.23.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 (342) hide show
  1. package/component-catalog.json +186 -8
  2. package/component-catalog.md +9 -7
  3. package/dist/add-module.js +20 -14
  4. package/dist/add-route.d.ts +55 -1
  5. package/dist/add-route.js +294 -12
  6. package/dist/cli.js +27 -10
  7. package/dist/derive-architecture.d.ts +12 -3
  8. package/dist/derive-architecture.js +20 -8
  9. package/dist/design-package.js +7 -2
  10. package/dist/lib/design-checks.js +4 -2
  11. package/dist/lib/env-catalog.js +5 -5
  12. package/dist/lib/npm-auth.d.ts +9 -0
  13. package/dist/lib/npm-auth.js +48 -0
  14. package/dist/lib/scaffold-render-sweep.d.ts +3 -2
  15. package/dist/lib/scaffold-render-sweep.js +5 -8
  16. package/dist/module-architecture.js +99 -9
  17. package/dist/paid-sections.d.ts +21 -2
  18. package/dist/paid-sections.js +69 -7
  19. package/dist/programmatic.js +19 -5
  20. package/dist/seed-flows.d.ts +4 -1
  21. package/dist/seed-flows.js +50 -4
  22. package/dist/site-chrome.d.ts +8 -0
  23. package/dist/site-chrome.js +17 -1
  24. package/dist/spoke-checkout.d.ts +65 -41
  25. package/dist/spoke-checkout.js +208 -430
  26. package/dist/starter-grid.d.ts +0 -3
  27. package/dist/starter-grid.js +24 -14
  28. package/dist/surfaces.js +52 -26
  29. package/dist/sync-routes.d.ts +38 -1
  30. package/dist/sync-routes.js +187 -13
  31. package/dist/template-record.d.ts +4 -3
  32. package/dist/template-record.js +8 -4
  33. package/dist/topology.js +25 -1
  34. package/dist/update.js +15 -0
  35. package/package.json +3 -3
  36. package/site-templates/_base/content/en/NewsletterSignup/newsletter.mdx +4 -49
  37. package/site-templates/_base/content/en/Pricing/pricing.mdx +3 -21
  38. package/site-templates/designs/minimalism/DESIGN.md +1 -1
  39. package/site-templates/marketing-site/TEMPLATE-MANIFEST.json +23 -20
  40. package/site-templates/marketing-site/TEMPLATE-MANIFEST.md +28 -14
  41. package/site-templates/marketing-site-free/TEMPLATE-MANIFEST.json +15 -39
  42. package/site-templates/marketing-site-free/TEMPLATE-MANIFEST.md +38 -34
  43. package/site-templates/marketing-site-free/content/en/NewsletterSignup/newsletter.mdx +6 -43
  44. package/site-templates/shapes/local-business-service/TEMPLATE-MANIFEST.json +14 -31
  45. package/site-templates/shapes/local-business-service/TEMPLATE-MANIFEST.md +26 -25
  46. package/site-templates/shapes/local-business-service/content/en/NewsletterSignup/newsletter.mdx +6 -43
  47. package/site-templates/shapes/organization-service/TEMPLATE-MANIFEST.json +14 -31
  48. package/site-templates/shapes/organization-service/TEMPLATE-MANIFEST.md +26 -25
  49. package/site-templates/shapes/organization-service/content/en/NewsletterSignup/newsletter.mdx +6 -43
  50. package/site-templates/shapes/person-service/TEMPLATE-MANIFEST.json +14 -31
  51. package/site-templates/shapes/person-service/TEMPLATE-MANIFEST.md +26 -25
  52. package/site-templates/shapes/person-service/content/en/NewsletterSignup/newsletter.mdx +6 -43
  53. package/templates/.env.example +9 -7
  54. package/templates/.github/workflows/ci.yml +13 -0
  55. package/templates/README.md +1 -0
  56. package/templates/_gitignore +4 -0
  57. package/templates/apps/api/.env.example +27 -0
  58. package/templates/apps/api/CLAUDE.md +87 -17
  59. package/templates/apps/api/package.json +1 -0
  60. package/templates/apps/api/src/__tests__/factories/in-memory-prisma.ts +2 -0
  61. package/templates/apps/api/src/bin/stripe-connections-rekey.ts +45 -0
  62. package/templates/apps/api/src/config/__tests__/stripe-connection-key.test.ts +185 -0
  63. package/templates/apps/api/src/config/index.ts +109 -0
  64. package/templates/apps/api/src/lib/__mocks__/prisma.ts +3 -0
  65. package/templates/apps/api/src/lib/__tests__/consent-store.test.ts +19 -0
  66. package/templates/apps/api/src/lib/__tests__/flow-completion-store.test.ts +149 -0
  67. package/templates/apps/api/src/lib/__tests__/flow-rename-race.db.test.ts +116 -0
  68. package/templates/apps/api/src/lib/consent-store.ts +28 -0
  69. package/templates/apps/api/src/lib/error-serializer.ts +74 -7
  70. package/templates/apps/api/src/lib/flow-completion-store.ts +136 -0
  71. package/templates/apps/api/src/lib/hub-sign-in-store.ts +38 -2
  72. package/templates/apps/api/src/lib/proposal-paid-store.ts +21 -4
  73. package/templates/apps/api/src/lib/stripe.ts +74 -4
  74. package/templates/apps/api/src/lib/webhook-idempotency.ts +66 -2
  75. package/templates/apps/api/src/middleware/__tests__/auth.hub-session-path.test.ts +14 -3
  76. package/templates/apps/api/src/middleware/__tests__/rate-limit.test.ts +218 -0
  77. package/templates/apps/api/src/middleware/__tests__/write-budget.test.ts +174 -0
  78. package/templates/apps/api/src/middleware/auth.ts +13 -6
  79. package/templates/apps/api/src/middleware/rate-limit.ts +226 -4
  80. package/templates/apps/api/src/openapi/spec.ts +33 -3
  81. package/templates/apps/api/src/routes/auth/__tests__/hub-sign-in.test.ts +49 -0
  82. package/templates/apps/api/src/routes/auth/hub-sign-in.ts +41 -0
  83. package/templates/apps/api/src/routes/billing/plan-checkout.ts +325 -0
  84. package/templates/apps/api/src/routes/checkout/__tests__/live-key.test.ts +11 -0
  85. package/templates/apps/api/src/routes/checkout/__tests__/offerings-authorization.test.ts +1300 -0
  86. package/templates/apps/api/src/routes/checkout/__tests__/session.test.ts +11 -0
  87. package/templates/apps/api/src/routes/checkout/__tests__/sessions.test.ts +49 -0
  88. package/templates/apps/api/src/routes/checkout/session.ts +57 -25
  89. package/templates/apps/api/src/routes/checkout/sessions.ts +232 -82
  90. package/templates/apps/api/src/routes/consent/__tests__/account.test.ts +386 -0
  91. package/templates/apps/api/src/routes/consent/__tests__/sign-up-rate-limit.test.ts +160 -0
  92. package/templates/apps/api/src/routes/consent/account.ts +268 -0
  93. package/templates/apps/api/src/routes/consent/index.ts +15 -7
  94. package/templates/apps/api/src/routes/content/__tests__/get-page.test.ts +36 -0
  95. package/templates/apps/api/src/routes/content/__tests__/offerings.test.ts +731 -0
  96. package/templates/apps/api/src/routes/content/__tests__/pricing.test.ts +753 -0
  97. package/templates/apps/api/src/routes/content/__tests__/shown-offerings.test.ts +762 -0
  98. package/templates/apps/api/src/routes/content/get-page.ts +4 -0
  99. package/templates/apps/api/src/routes/content/index.ts +16 -2
  100. package/templates/apps/api/src/routes/content/offerings.ts +184 -0
  101. package/templates/apps/api/src/routes/content/pricing.ts +176 -0
  102. package/templates/apps/api/src/routes/content/shown-offerings.ts +229 -0
  103. package/templates/apps/api/src/routes/leads/__tests__/magnet-completion.test.ts +515 -0
  104. package/templates/apps/api/src/routes/leads/index.ts +164 -7
  105. package/templates/apps/api/src/routes/webhooks/README.md +66 -0
  106. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-checkout-consent.test.ts +649 -0
  107. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-offerings.test.ts +814 -0
  108. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-org-billing.test.ts +80 -68
  109. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-site-filter.test.ts +5 -5
  110. package/templates/apps/api/src/routes/webhooks/__tests__/stripe.test.ts +8 -2
  111. package/templates/apps/api/src/routes/webhooks/index.ts +23 -0
  112. package/templates/apps/api/src/routes/webhooks/stripe-offerings.ts +384 -0
  113. package/templates/apps/api/src/routes/webhooks/stripe.ts +245 -36
  114. package/templates/apps/api/src/server.ts +163 -46
  115. package/templates/apps/api/src/services/__tests__/checkout-plan.test.ts +313 -0
  116. package/templates/apps/api/src/services/__tests__/deliverable-fulfillment.test.ts +51 -2
  117. package/templates/apps/api/src/services/__tests__/keyless-workspace-predicate.test.ts +234 -0
  118. package/templates/apps/api/src/services/__tests__/lead-routing.test.ts +1383 -133
  119. package/templates/apps/api/src/services/__tests__/magnet-completion.test.ts +389 -0
  120. package/templates/apps/api/src/services/__tests__/person.test.ts +232 -1
  121. package/templates/apps/api/src/services/__tests__/plan-offerings.test.ts +444 -0
  122. package/templates/apps/api/src/services/checkout-buyer.ts +100 -4
  123. package/templates/apps/api/src/services/consent.ts +95 -0
  124. package/templates/apps/api/src/services/deliverable-fulfillment.ts +13 -5
  125. package/templates/apps/api/src/services/entitlements.ts +157 -1
  126. package/templates/apps/api/src/services/lead-routing.ts +431 -47
  127. package/templates/apps/api/src/services/magnet-completion.ts +242 -0
  128. package/templates/apps/api/src/services/offerings/__tests__/catalog.test.ts +295 -0
  129. package/templates/apps/api/src/services/offerings/__tests__/checkout-session-record.test.ts +268 -0
  130. package/templates/apps/api/src/services/offerings/__tests__/connection.test.ts +868 -0
  131. package/templates/apps/api/src/services/offerings/__tests__/fixtures.ts +416 -0
  132. package/templates/apps/api/src/services/offerings/__tests__/org-products.test.ts +396 -0
  133. package/templates/apps/api/src/services/offerings/__tests__/readers.test.ts +681 -0
  134. package/templates/apps/api/src/services/offerings/__tests__/source.test.ts +231 -0
  135. package/templates/apps/api/src/services/offerings/catalog.ts +308 -0
  136. package/templates/apps/api/src/services/offerings/checkout-authorization.ts +385 -0
  137. package/templates/apps/api/src/services/offerings/checkout-session-record.ts +192 -0
  138. package/templates/apps/api/src/services/offerings/connection.ts +1003 -0
  139. package/templates/apps/api/src/services/offerings/index.ts +614 -0
  140. package/templates/apps/api/src/services/offerings/source.ts +140 -0
  141. package/templates/apps/api/src/services/offerings/store.ts +150 -0
  142. package/templates/apps/api/src/services/person.ts +164 -17
  143. package/templates/apps/api/src/services/plan-offerings.ts +125 -0
  144. package/templates/apps/api/src/services/public-site-resolver.ts +27 -15
  145. package/templates/apps/mcp/CLAUDE.md +22 -14
  146. package/templates/apps/mcp/__tests__/catalog-drift.test.ts +9 -4
  147. package/templates/apps/mcp/__tests__/get_offerings.test.ts +358 -0
  148. package/templates/apps/mcp/__tests__/get_pricing.test.ts +364 -0
  149. package/templates/apps/mcp/__tests__/http-transport.test.ts +4 -4
  150. package/templates/apps/mcp/__tests__/module-exclusion.test.ts +2 -2
  151. package/templates/apps/mcp/__tests__/server.test.ts +13 -11
  152. package/templates/apps/mcp/__tests__/start_purchase.test.ts +208 -12
  153. package/templates/apps/mcp/__tests__/tools/purchase.test.ts +11 -11
  154. package/templates/apps/mcp/src/lib/shown-offerings.ts +105 -0
  155. package/templates/apps/mcp/src/server.ts +5 -0
  156. package/templates/apps/mcp/src/tools/get_offerings.ts +47 -30
  157. package/templates/apps/mcp/src/tools/get_pricing.ts +40 -40
  158. package/templates/apps/mcp/src/tools/purchase.ts +30 -2
  159. package/templates/apps/mcp/src/workspace-server.ts +15 -0
  160. package/templates/apps/web/.env.example +24 -31
  161. package/templates/apps/web/CLAUDE.md +393 -9
  162. package/templates/apps/web/__tests__/__mocks__/next-intl-server.ts +6 -2
  163. package/templates/apps/web/app/[locale]/(auth)/__tests__/auth-pages.test.tsx +5 -4
  164. package/templates/apps/web/app/[locale]/(auth)/forgot-password/forgot-password-card.tsx +5 -1
  165. package/templates/apps/web/app/[locale]/(auth)/forgot-password/page.tsx +2 -0
  166. package/templates/apps/web/app/[locale]/(auth)/layout.tsx +3 -14
  167. package/templates/apps/web/app/[locale]/(auth)/reset-password/page.tsx +2 -0
  168. package/templates/apps/web/app/[locale]/(auth)/reset-password/reset-password-card.tsx +5 -1
  169. package/templates/apps/web/app/[locale]/(auth)/sign-in/__tests__/page.test.tsx +160 -8
  170. package/templates/apps/web/app/[locale]/(auth)/sign-in/__tests__/sign-in-card.test.tsx +12 -9
  171. package/templates/apps/web/app/[locale]/(auth)/sign-in/page.tsx +105 -2
  172. package/templates/apps/web/app/[locale]/(auth)/sign-in/sign-in-card.tsx +36 -3
  173. package/templates/apps/web/app/[locale]/(auth)/sign-in/sign-in-text.ts +47 -1
  174. package/templates/apps/web/app/[locale]/(auth)/sign-up/__tests__/sign-up-card.test.tsx +60 -22
  175. package/templates/apps/web/app/[locale]/(auth)/sign-up/page.tsx +16 -8
  176. package/templates/apps/web/app/[locale]/(auth)/sign-up/sign-up-card.tsx +85 -31
  177. package/templates/apps/web/app/[locale]/(auth)/use-auth-card-flow.ts +18 -4
  178. package/templates/apps/web/app/[locale]/(auth)/verify-email/page.tsx +3 -1
  179. package/templates/apps/web/app/[locale]/(authed)/__tests__/gate.test.tsx +7 -4
  180. package/templates/apps/web/app/[locale]/(authed)/account/__tests__/agreements-prompt.test.tsx +227 -207
  181. package/templates/apps/web/app/[locale]/(authed)/account/__tests__/layout-sign-out.test.tsx +17 -1
  182. package/templates/apps/web/app/[locale]/(authed)/account/__tests__/layout.test.tsx +143 -1
  183. package/templates/apps/web/app/[locale]/(authed)/account/__tests__/new-menu.test.tsx +4 -0
  184. package/templates/apps/web/app/[locale]/(authed)/account/__tests__/page.test.tsx +385 -89
  185. package/templates/apps/web/app/[locale]/(authed)/account/__tests__/popups.test.tsx +5 -0
  186. package/templates/apps/web/app/[locale]/(authed)/account/__tests__/privacy.test.tsx +44 -5
  187. package/templates/apps/web/app/[locale]/(authed)/account/account-frame.tsx +68 -34
  188. package/templates/apps/web/app/[locale]/(authed)/account/actions.ts +0 -8
  189. package/templates/apps/web/app/[locale]/(authed)/account/agreements-actions.ts +39 -151
  190. package/templates/apps/web/app/[locale]/(authed)/account/agreements-gate.ts +61 -0
  191. package/templates/apps/web/app/[locale]/(authed)/account/agreements-prompt.tsx +143 -140
  192. package/templates/apps/web/app/[locale]/(authed)/account/layout.tsx +40 -6
  193. package/templates/apps/web/app/[locale]/(authed)/account/page.tsx +68 -54
  194. package/templates/apps/web/app/[locale]/(authed)/account/privacy/page.tsx +5 -1
  195. package/templates/apps/web/app/[locale]/careers/[slug]/[action]/page.tsx +189 -0
  196. package/templates/apps/web/app/[locale]/careers/[slug]/apply.actions.ts +295 -0
  197. package/templates/apps/web/app/[locale]/careers/[slug]/job-application-form.ts +120 -0
  198. package/templates/apps/web/app/[locale]/careers/[slug]/page.tsx +23 -0
  199. package/templates/apps/web/app/[locale]/careers/__tests__/apply.actions.test.ts +319 -0
  200. package/templates/apps/web/app/[locale]/careers/__tests__/careers-hub.test.tsx +172 -0
  201. package/templates/apps/web/app/[locale]/careers/__tests__/careers-set.test.tsx +149 -0
  202. package/templates/apps/web/app/[locale]/careers/__tests__/job-application-form.test.ts +141 -0
  203. package/templates/apps/web/app/[locale]/careers/__tests__/job-apply-page.test.tsx +424 -0
  204. package/templates/apps/web/app/[locale]/careers/__tests__/page-renderer-migration.test.tsx +72 -11
  205. package/templates/apps/web/app/[locale]/careers/page.tsx +129 -5
  206. package/templates/apps/web/app/[locale]/case-studies/__tests__/page-renderer-migration.test.tsx +2 -2
  207. package/templates/apps/web/app/[locale]/checkout/__tests__/pages.test.tsx +139 -0
  208. package/templates/apps/web/app/[locale]/checkout/__tests__/thank-you-account.test.tsx +136 -0
  209. package/templates/apps/web/app/[locale]/checkout/thank-you/page.tsx +114 -0
  210. package/templates/apps/web/app/[locale]/checkout/unavailable/page.tsx +51 -0
  211. package/templates/apps/web/app/[locale]/clients/__tests__/page-renderer-migration.test.tsx +1 -1
  212. package/templates/apps/web/app/[locale]/contact/ConversationalIntakeWrapper.tsx +17 -1
  213. package/templates/apps/web/app/[locale]/contact/__tests__/ConversationalIntakeWrapper.test.tsx +79 -4
  214. package/templates/apps/web/app/[locale]/contact/__tests__/contact-magnet-page.test.tsx +160 -13
  215. package/templates/apps/web/app/[locale]/contact/__tests__/contact.actions.test.ts +466 -36
  216. package/templates/apps/web/app/[locale]/contact/__tests__/page-renderer-migration.test.tsx +7 -0
  217. package/templates/apps/web/app/[locale]/contact/contact.actions.ts +172 -57
  218. package/templates/apps/web/app/[locale]/contact/intake-script.ts +26 -0
  219. package/templates/apps/web/app/[locale]/contact/page.tsx +99 -60
  220. package/templates/apps/web/app/[locale]/courses/__tests__/page-renderer-migration.test.tsx +2 -2
  221. package/templates/apps/web/app/[locale]/events/__tests__/page-renderer-migration.test.tsx +2 -2
  222. package/templates/apps/web/app/[locale]/flows/[slug]/FlowStepperClient.tsx +341 -4
  223. package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/FlowStepperClient.count.test.tsx +43 -0
  224. package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/FlowStepperClient.deliverable.test.tsx +200 -0
  225. package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/FlowStepperClient.ending.test.tsx +197 -0
  226. package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/FlowStepperClient.invite.test.tsx +257 -0
  227. package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/account-invite.actions.test.ts +69 -0
  228. package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/magnet-page.test.tsx +430 -0
  229. package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/two-route-tool.test.tsx +21 -9
  230. package/templates/apps/web/app/[locale]/flows/[slug]/account-invite.actions.ts +35 -0
  231. package/templates/apps/web/app/[locale]/flows/[slug]/magnet-page.tsx +352 -0
  232. package/templates/apps/web/app/[locale]/flows/[slug]/page.tsx +12 -73
  233. package/templates/apps/web/app/[locale]/flows/[slug]/start/page.tsx +10 -31
  234. package/templates/apps/web/app/[locale]/for/__tests__/page-renderer-migration.test.tsx +1 -1
  235. package/templates/apps/web/app/[locale]/how-to/__tests__/page-renderer-migration.test.tsx +1 -1
  236. package/templates/apps/web/app/[locale]/integrations/__tests__/page-renderer-migration.test.tsx +2 -2
  237. package/templates/apps/web/app/[locale]/layout.tsx +55 -4
  238. package/templates/apps/web/app/[locale]/newsletter/__tests__/page.test.tsx +174 -104
  239. package/templates/apps/web/app/[locale]/newsletter/page.tsx +95 -58
  240. package/templates/apps/web/app/[locale]/page.tsx +13 -1
  241. package/templates/apps/web/app/[locale]/partners/__tests__/page-renderer-migration.test.tsx +2 -2
  242. package/templates/apps/web/app/[locale]/pricing/__tests__/__snapshots__/unconnected.test.tsx.snap +7 -0
  243. package/templates/apps/web/app/[locale]/pricing/__tests__/offerings.test.tsx +599 -0
  244. package/templates/apps/web/app/[locale]/pricing/__tests__/page.test.tsx +216 -0
  245. package/templates/apps/web/app/[locale]/pricing/__tests__/unconnected.test.tsx +236 -0
  246. package/templates/apps/web/app/[locale]/pricing/page.tsx +367 -6
  247. package/templates/apps/web/app/[locale]/products/__tests__/page-renderer-migration.test.tsx +2 -2
  248. package/templates/apps/web/app/[locale]/resources/__tests__/page-renderer-migration.test.tsx +2 -2
  249. package/templates/apps/web/app/[locale]/services/__tests__/page-renderer-migration.test.tsx +2 -2
  250. package/templates/apps/web/app/[locale]/software/__tests__/page-renderer-migration.test.tsx +1 -1
  251. package/templates/apps/web/app/[locale]/team/__tests__/team-routes.test.tsx +4 -1
  252. package/templates/apps/web/app/[locale]/tech-articles/__tests__/page-renderer-migration.test.tsx +1 -1
  253. package/templates/apps/web/app/[locale]/testimonials/__tests__/page-renderer-migration.test.tsx +1 -1
  254. package/templates/apps/web/app/[locale]/thanks/[slug]/AccountInviteLink.tsx +89 -0
  255. package/templates/apps/web/app/[locale]/thanks/[slug]/__tests__/AccountInviteLink.test.tsx +104 -0
  256. package/templates/apps/web/app/[locale]/thanks/[slug]/__tests__/page.test.tsx +38 -0
  257. package/templates/apps/web/app/[locale]/thanks/[slug]/page.tsx +9 -0
  258. package/templates/apps/web/app/[locale]/unsubscribe/__tests__/unsubscribe-rsc-boundary.test.tsx +17 -0
  259. package/templates/apps/web/app/[locale]/unsubscribe/__tests__/unsubscribe.test.tsx +62 -3
  260. package/templates/apps/web/app/[locale]/unsubscribe/page.tsx +70 -18
  261. package/templates/apps/web/app/[locale]/unsubscribe/unsubscribe-button.tsx +30 -9
  262. package/templates/apps/web/app/[locale]/whitepapers/__tests__/page-renderer-migration.test.tsx +1 -1
  263. package/templates/apps/web/app/api/auth/hub/authorize/__tests__/route.test.ts +114 -0
  264. package/templates/apps/web/app/api/auth/hub/authorize/route.ts +20 -3
  265. package/templates/apps/web/app/api/hub-session/__tests__/routes.test.ts +44 -1
  266. package/templates/apps/web/app/api/hub-session/sign-in/route.ts +22 -3
  267. package/templates/apps/web/app/api/offerings/checkout/[lookupKey]/route.ts +316 -0
  268. package/templates/apps/web/app/api/offerings/checkout/__tests__/route.test.ts +810 -0
  269. package/templates/apps/web/auth.ts +28 -2
  270. package/templates/apps/web/lib/__tests__/account-invite.test.ts +63 -0
  271. package/templates/apps/web/lib/__tests__/auth-routes.test.ts +27 -1
  272. package/templates/apps/web/lib/__tests__/consent-policies.test.ts +23 -0
  273. package/templates/apps/web/lib/__tests__/deck-page.test.ts +7 -1
  274. package/templates/apps/web/lib/__tests__/in-page-magnet.test.ts +265 -0
  275. package/templates/apps/web/lib/__tests__/magnet-routes.test.ts +57 -0
  276. package/templates/apps/web/lib/__tests__/newsletter.actions.test.ts +293 -0
  277. package/templates/apps/web/lib/__tests__/offerings-pricing.test.ts +601 -0
  278. package/templates/apps/web/lib/__tests__/structured-data.test.tsx +101 -25
  279. package/templates/apps/web/lib/account-invite.ts +37 -0
  280. package/templates/apps/web/lib/auth-routes.ts +36 -2
  281. package/templates/apps/web/lib/checkout-config.ts +16 -0
  282. package/templates/apps/web/lib/consent-policies.ts +22 -0
  283. package/templates/apps/web/lib/deck-page.ts +7 -0
  284. package/templates/apps/web/lib/deliverable-grant.ts +18 -0
  285. package/templates/apps/web/lib/hub-session/__tests__/sign-in-gate.test.tsx +111 -0
  286. package/templates/apps/web/lib/hub-session/sign-in-gate.tsx +88 -32
  287. package/templates/apps/web/lib/in-page-magnet.ts +416 -0
  288. package/templates/apps/web/lib/magnet-routes.ts +42 -0
  289. package/templates/apps/web/lib/modules.generated.ts +9 -0
  290. package/templates/apps/web/lib/newsletter.actions.ts +202 -0
  291. package/templates/apps/web/lib/offerings-pricing.ts +326 -0
  292. package/templates/apps/web/lib/posting-title.ts +17 -0
  293. package/templates/apps/web/lib/prisma-for-auth.ts +8 -0
  294. package/templates/apps/web/lib/sign-up-agreements.ts +449 -0
  295. package/templates/apps/web/lib/site-chrome.ts +2 -0
  296. package/templates/apps/web/lib/telemetry-scrub.ts +5 -1
  297. package/templates/apps/web/messages/en.json +71 -20
  298. package/templates/apps/web/middleware.ts +12 -2
  299. package/templates/apps/web/package.json +1 -0
  300. package/templates/apps/web/security-headers.config.ts +17 -0
  301. package/templates/apps/web/src/lib/__tests__/lead-write.test.ts +187 -0
  302. package/templates/apps/web/src/lib/__tests__/rate-limit.test.ts +67 -0
  303. package/templates/apps/web/src/lib/lead-write.ts +90 -0
  304. package/templates/apps/web/src/lib/rate-limit.ts +79 -0
  305. package/templates/content/en/BlogList/blog.mdx +4 -71
  306. package/templates/content/en/BookCall/book-a-call.mdx +1 -41
  307. package/templates/content/en/BookCall/onsite-estimate.mdx +1 -17
  308. package/templates/content/en/BookCall/onsite-service.mdx +1 -17
  309. package/templates/content/en/BookCall/start-project.mdx +1 -17
  310. package/templates/content/en/ContactPage/contact.mdx +6 -63
  311. package/templates/content/en/HomePage/home.mdx +3 -21
  312. package/templates/database/CHANGELOG.md +69 -0
  313. package/templates/database/__tests__/consent-source-checkout-migration.test.ts +79 -0
  314. package/templates/database/__tests__/flow-completion-migration.test.ts +115 -0
  315. package/templates/database/__tests__/flow-completion.db.test.ts +136 -0
  316. package/templates/database/__tests__/in-page-magnets-migration.test.ts +161 -0
  317. package/templates/database/__tests__/offerings-checkout-session.db.test.ts +270 -0
  318. package/templates/database/__tests__/offerings-migration.test.ts +197 -0
  319. package/templates/database/__tests__/offerings-shown-price-ids-migration.test.ts +86 -0
  320. package/templates/database/__tests__/offerings.db.test.ts +303 -0
  321. package/templates/database/__tests__/seed.test.ts +64 -1
  322. package/templates/database/auth/schema.prisma +4 -0
  323. package/templates/database/config/schema.prisma +91 -0
  324. package/templates/database/inbox/schema.prisma +17 -2
  325. package/templates/database/migrations/20261018120000_flow_completion/migration.sql +52 -0
  326. package/templates/database/migrations/20261019120000_consent_source_checkout/migration.sql +27 -0
  327. package/templates/database/migrations/20261020120000_offerings_data_model/migration.sql +146 -0
  328. package/templates/database/migrations/20261021120000_offerings_checkout_session/migration.sql +77 -0
  329. package/templates/database/migrations/20261022120000_in_page_magnets/migration.sql +45 -0
  330. package/templates/database/migrations/20261023120000_offerings_shown_price_ids/migration.sql +47 -0
  331. package/templates/database/migrations/20261024120000_organization_plan_checkout_session/migration.sql +16 -0
  332. package/templates/database/package.json +1 -1
  333. package/templates/database/seed.ts +62 -3
  334. package/versions.json +35 -35
  335. package/site-templates/marketing-site-free/content/en/Pricing/pricing.mdx +0 -199
  336. package/templates/apps/web/app/[locale]/(auth)/sign-up/sign-up.actions.ts +0 -125
  337. package/templates/apps/web/app/[locale]/downloads/__tests__/page-renderer-migration.test.tsx +0 -93
  338. package/templates/apps/web/app/[locale]/downloads/page.tsx +0 -37
  339. package/templates/apps/web/app/[locale]/newsletter/__tests__/newsletter.actions.test.ts +0 -139
  340. package/templates/apps/web/app/[locale]/newsletter/newsletter.actions.ts +0 -93
  341. package/templates/apps/web/lib/__tests__/meeting-slugs.test.ts +0 -120
  342. package/templates/apps/web/lib/meeting-slugs.ts +0 -63
@@ -1,8 +1,8 @@
1
1
  ---
2
2
  type: "NewsletterSignup"
3
3
  slug: "newsletter"
4
- title: "{Start a free newsletter with Substack}"
5
- description: "{Or upgrade to Pro to capture every subscriber and build your own marketing database.}"
4
+ title: "Get the newsletter"
5
+ description: "{One sentence on what this newsletter covers and who it is for}"
6
6
  schema:
7
7
  mainEntity:
8
8
  "@type": "Offer"
@@ -12,48 +12,11 @@ schema:
12
12
  sections:
13
13
  [
14
14
  {
15
- "id": "hero",
16
- "type": "hero",
17
- "data":
18
- {
19
- "eyebrow": "Newsletter",
20
- "headline": "{Start a free newsletter with Substack}",
21
- "subheadline": "{Or upgrade to Pro to capture every subscriber and build your own marketing database.}",
22
- "primaryCta":
23
- { "label": "{Connect Substack}", "href": "https://substack.com" },
24
- "secondaryCta":
25
- {
26
- "label": "{Upgrade to Pro}",
27
- "href": "https://ailaunchkit.ai/pricing",
28
- "variant": "outline",
29
- },
30
- },
31
- },
32
- {
33
- "id": "faq",
34
- "type": "faq",
35
- "data":
36
- {
37
- "headline": "FAQs",
38
- "presentation": "expanded",
39
- "items":
40
- [
41
- {
42
- "question": "{How often will I hear from you?}",
43
- "answer": "{Answer in one or two plain sentences}",
44
- },
45
- {
46
- "question": "{What will I get?}",
47
- "answer": "{Answer in one or two plain sentences}",
48
- },
49
- {
50
- "question": "{Can I unsubscribe?}",
51
- "answer": "{Answer in one or two plain sentences}",
52
- },
53
- ],
54
- },
15
+ "id": "signup",
16
+ "type": "contact-form",
17
+ "data": { "variant": "column", "fields": [] },
55
18
  },
56
19
  ]
57
20
  ---
58
21
 
59
- {/* Rendered from frontmatter `sections[]` by the /newsletter route. The Free template has no signup form: the hero points the owner to Substack, or to Pro for subscriber capture. The `schema:` Offer is the page's JSON-LD main entity — a free subscription. Placeholder copy — replace every {brace} with your own words before you launch. */}
22
+ {/* Rendered from frontmatter `sections[]` by the /newsletter route. The page's one signup surface is the workspace's Newsletter magnet: its heading, sentence, field, consent, button and ending all come from the magnet, mounted by the route in this section's slot. To change the signup, change the magnet in Admin → Magnets. The `schema:` Offer is the page's JSON-LD main entity — a free subscription. Replace every {brace} with your own words before you launch. */}
@@ -11,7 +11,7 @@
11
11
  ],
12
12
  "shape": "local-business-service",
13
13
  "design": "standard",
14
- "generatedHash": "b8ee2da3100d51dd191ed148dc6c9884394585064da8a27605414ea38dbe3fb0",
14
+ "generatedHash": "f9dc1b0efdca0ea907b523eccbd89d4e388d984671394280670af50d4d723190",
15
15
  "layout": {
16
16
  "nav": "full",
17
17
  "footer": "columns",
@@ -196,15 +196,8 @@
196
196
  "chrome": "on",
197
197
  "sections": [
198
198
  {
199
- "type": "hero",
200
- "component": "Hero"
201
- },
202
- {
203
- "type": "items",
204
- "component": "Items",
205
- "options": {
206
- "columns": 2
207
- }
199
+ "type": "contact-form",
200
+ "component": "ContactForm"
208
201
  }
209
202
  ]
210
203
  },
@@ -260,15 +253,20 @@
260
253
  "chrome": "on",
261
254
  "sections": [
262
255
  {
263
- "type": "hero",
264
- "component": "Hero"
265
- },
266
- {
267
- "type": "faq",
268
- "component": "FAQ"
256
+ "type": "contact-form",
257
+ "component": "ContactForm"
269
258
  }
270
259
  ]
271
260
  },
261
+ {
262
+ "route": "/unsubscribe",
263
+ "kind": "route",
264
+ "pageType": null,
265
+ "schema": null,
266
+ "shell": "MarketingShell",
267
+ "chrome": "on",
268
+ "sections": []
269
+ },
272
270
  {
273
271
  "route": "/sign-in",
274
272
  "kind": "route",
@@ -370,10 +368,6 @@
370
368
  "gapBelow": "tight"
371
369
  }
372
370
  },
373
- {
374
- "type": "blog-list",
375
- "component": "BlogList"
376
- },
377
371
  {
378
372
  "type": "logoCloud",
379
373
  "component": "LogoCloud",
@@ -420,17 +414,6 @@
420
414
  "type": "hero",
421
415
  "component": "Hero"
422
416
  },
423
- {
424
- "type": "cta",
425
- "component": "CTA"
426
- },
427
- {
428
- "type": "items",
429
- "component": "Items",
430
- "options": {
431
- "columns": 3
432
- }
433
- },
434
417
  {
435
418
  "type": "content-block",
436
419
  "component": "ContentBlock"
@@ -132,10 +132,9 @@ _Detail route over `content/en/UseCase/` — 3 seed pages: `persona-1.mdx`, `per
132
132
 
133
133
  <!-- generated:begin page=/contact -->
134
134
 
135
- | # | Section | Component | Copy (first line) |
136
- | --- | --------------------------------------------------------- | --------- | ----------------------------------------- |
137
- | 1 | `hero` (split · eyebrow "Contact" · checklist ×3 · 1 CTA) | `Hero` | Get every message in your email, free |
138
- | 2 | `items` (tiles · columns=2 · items ×4) | `Items` | {Add appointment scheduling to your site} |
135
+ | # | Section | Component | Copy (first line) |
136
+ | --- | ----------------------------------- | ------------- | ----------------- |
137
+ | 1 | `contact-form` (column · fields ×0) | `ContactForm` | |
139
138
 
140
139
  <!-- generated:end -->
141
140
 
@@ -164,13 +163,17 @@ _Detail route over `content/en/UseCase/` — 3 seed pages: `persona-1.mdx`, `per
164
163
 
165
164
  <!-- generated:begin page=/newsletter -->
166
165
 
167
- | # | Section | Component | Copy (first line) |
168
- | --- | -------------------------------------- | --------- | --------------------------------------- |
169
- | 1 | `hero` (eyebrow "Newsletter" · 2 CTAs) | `Hero` | {Start a free newsletter with Substack} |
170
- | 2 | `faq` (expanded · items ×3) | `FAQ` | FAQs |
166
+ | # | Section | Component | Copy (first line) |
167
+ | --- | ----------------------------------- | ------------- | ----------------- |
168
+ | 1 | `contact-form` (column · fields ×0) | `ContactForm` | |
171
169
 
172
170
  <!-- generated:end -->
173
171
 
172
+ <!-- generated:begin page=/unsubscribe -->
173
+
174
+ _Code route — no content, no sections._
175
+ <!-- generated:end -->
176
+
174
177
  <!-- generated:begin page=/meet -->
175
178
 
176
179
  | # | Section | Component | Copy (first line) |
@@ -182,12 +185,10 @@ _Detail route over `content/en/UseCase/` — 3 seed pages: `persona-1.mdx`, `per
182
185
 
183
186
  <!-- generated:begin page=/meet/[slug] -->
184
187
 
185
- | # | Section | Component | Copy (first line) |
186
- | --- | -------------------------------------- | -------------- | ------------------------------------------------ |
187
- | 1 | `hero` (eyebrow "Book a Call" · 1 CTA) | `Hero` | Book a Call |
188
- | 2 | `cta` (box · 1 CTA) | `CTA` | {What booking a call would do for your visitors} |
189
- | 3 | `items` (columns=3 · items ×3) | `Items` | What happens on the call? |
190
- | 4 | `content-block` (1 CTA) | `ContentBlock` | |
188
+ | # | Section | Component | Copy (first line) |
189
+ | --- | -------------------------------------- | -------------- | ----------------- |
190
+ | 1 | `hero` (eyebrow "Book a Call" · 1 CTA) | `Hero` | Book a Call |
191
+ | 2 | `content-block` (1 CTA) | `ContentBlock` | |
191
192
 
192
193
  <!-- generated:end -->
193
194
 
@@ -243,12 +244,11 @@ _Code route — no content, no sections._
243
244
 
244
245
  <!-- generated:begin page=/blog -->
245
246
 
246
- | # | Section | Component | Copy (first line) |
247
- | --- | ------------------------------------------------------------ | -------------- | ----------------------------------------------------------------- |
248
- | 1 | `hero` (centered · gapBelow=tight · eyebrow "Blog" · 2 CTAs) | `Hero` | Get free blog/docs from Fumadocs |
249
- | 2 | `blog-list` (grid) | `BlogList` | |
250
- | 3 | `logoCloud` (layout=inline · logos ×6) | `LogoCloud` | Don’t just take our word for it |
251
- | 4 | `testimonials` (quote · items ×1) | `Testimonials` | {A customer quote, in their own words, about the result they got} |
247
+ | # | Section | Component | Copy (first line) |
248
+ | --- | --------------------------------------------------- | -------------- | ----------------------------------------------------------------- |
249
+ | 1 | `hero` (centered · gapBelow=tight · eyebrow "Blog") | `Hero` | {Blog} |
250
+ | 2 | `logoCloud` (layout=inline · logos ×6) | `LogoCloud` | Don’t just take our word for it |
251
+ | 3 | `testimonials` (quote · items ×1) | `Testimonials` | {A customer quote, in their own words, about the result they got} |
252
252
 
253
253
  <!-- generated:end -->
254
254
 
@@ -344,6 +344,7 @@ local-business-service:
344
344
  - { route: "/faq", kind: page, content: ["content/en/FAQPage/faq.mdx"] }
345
345
  - { route: "/glossary", kind: page, content: ["content/en/GlossaryList/glossary.mdx"] }
346
346
  - { route: "/newsletter", kind: page, content: ["content/en/NewsletterSignup/newsletter.mdx"] }
347
+ - { route: "/unsubscribe", kind: route }
347
348
  - { route: "/sign-in", kind: route }
348
349
  - { route: "/sign-up", kind: route }
349
350
  - { route: "/purchase-policy", kind: page, content: ["content/en/PurchasePolicyPage/purchase-policy.mdx"] }
@@ -376,10 +377,10 @@ Every row is module-less: `requires` is `[marketing]` alone, so `mergeRoster` co
376
377
 
377
378
  <!-- generated:begin inventory -->
378
379
 
379
- | Tier | Used by this template |
380
- | -------- | ---------------------------------------------------------------------------------------------------------------------------------- |
381
- | Shell | `MarketingShell` |
382
- | Chrome | `Nav`, `Footer`, `Banner` (+ `BannerConsentIsland`, `BannerDismissIsland`) |
383
- | Sections | `BlogList`, `ContentBlock`, `CTA`, `DocumentChassis`, `FAQ`, `GlossaryIndex`, `Hero`, `Items`, `LogoCloud`, `Team`, `Testimonials` |
380
+ | Tier | Used by this template |
381
+ | -------- | ------------------------------------------------------------------------------------------------------------------------------------- |
382
+ | Shell | `MarketingShell` |
383
+ | Chrome | `Nav`, `Footer`, `Banner` (+ `BannerConsentIsland`, `BannerDismissIsland`) |
384
+ | Sections | `ContactForm`, `ContentBlock`, `CTA`, `DocumentChassis`, `FAQ`, `GlossaryIndex`, `Hero`, `Items`, `LogoCloud`, `Team`, `Testimonials` |
384
385
 
385
386
  <!-- generated:end -->
@@ -1,8 +1,8 @@
1
1
  ---
2
2
  type: "NewsletterSignup"
3
3
  slug: "newsletter"
4
- title: "{Start a free newsletter with Substack}"
5
- description: "{Or upgrade to Pro to capture every subscriber and build your own marketing database.}"
4
+ title: "Get the newsletter"
5
+ description: "{One sentence on what this newsletter covers and who it is for}"
6
6
  schema:
7
7
  mainEntity:
8
8
  "@type": "Offer"
@@ -12,48 +12,11 @@ schema:
12
12
  sections:
13
13
  [
14
14
  {
15
- "id": "hero",
16
- "type": "hero",
17
- "data":
18
- {
19
- "eyebrow": "Newsletter",
20
- "headline": "{Start a free newsletter with Substack}",
21
- "subheadline": "{Or upgrade to Pro to capture every subscriber and build your own marketing database.}",
22
- "primaryCta":
23
- { "label": "{Connect Substack}", "href": "https://substack.com" },
24
- "secondaryCta":
25
- {
26
- "label": "{Upgrade to Pro}",
27
- "href": "https://ailaunchkit.ai/pricing",
28
- "variant": "outline",
29
- },
30
- },
31
- },
32
- {
33
- "id": "faq",
34
- "type": "faq",
35
- "data":
36
- {
37
- "headline": "FAQs",
38
- "presentation": "expanded",
39
- "items":
40
- [
41
- {
42
- "question": "{How often will I hear from you?}",
43
- "answer": "{Answer in one or two plain sentences}",
44
- },
45
- {
46
- "question": "{What will I get?}",
47
- "answer": "{Answer in one or two plain sentences}",
48
- },
49
- {
50
- "question": "{Can I unsubscribe?}",
51
- "answer": "{Answer in one or two plain sentences}",
52
- },
53
- ],
54
- },
15
+ "id": "signup",
16
+ "type": "contact-form",
17
+ "data": { "variant": "column", "fields": [] },
55
18
  },
56
19
  ]
57
20
  ---
58
21
 
59
- {/* Rendered from frontmatter `sections[]` by the /newsletter route. The Free template has no signup form: the hero points the owner to Substack, or to Pro for subscriber capture. The `schema:` Offer is the page's JSON-LD main entity — a free subscription. Placeholder copy — replace every {brace} with your own words before you launch. */}
22
+ {/* Rendered from frontmatter `sections[]` by the /newsletter route. The page's one signup surface is the workspace's Newsletter magnet: its heading, sentence, field, consent, button and ending all come from the magnet, mounted by the route in this section's slot. To change the signup, change the magnet in Admin → Magnets. The `schema:` Offer is the page's JSON-LD main entity — a free subscription. Replace every {brace} with your own words before you launch. */}
@@ -4,7 +4,7 @@
4
4
  "categories": ["accounting", "legal", "real-estate"],
5
5
  "shape": "organization-service",
6
6
  "design": "standard",
7
- "generatedHash": "a6330a3da9b734cd384ee07ecb35c2e171d26effe3286caae36bf3b13f8955e4",
7
+ "generatedHash": "0da8ac867d5a28668e42f90a729af3e30522c0afa6d2629475a092679fffddf3",
8
8
  "layout": {
9
9
  "nav": "full",
10
10
  "footer": "columns",
@@ -189,15 +189,8 @@
189
189
  "chrome": "on",
190
190
  "sections": [
191
191
  {
192
- "type": "hero",
193
- "component": "Hero"
194
- },
195
- {
196
- "type": "items",
197
- "component": "Items",
198
- "options": {
199
- "columns": 2
200
- }
192
+ "type": "contact-form",
193
+ "component": "ContactForm"
201
194
  }
202
195
  ]
203
196
  },
@@ -253,15 +246,20 @@
253
246
  "chrome": "on",
254
247
  "sections": [
255
248
  {
256
- "type": "hero",
257
- "component": "Hero"
258
- },
259
- {
260
- "type": "faq",
261
- "component": "FAQ"
249
+ "type": "contact-form",
250
+ "component": "ContactForm"
262
251
  }
263
252
  ]
264
253
  },
254
+ {
255
+ "route": "/unsubscribe",
256
+ "kind": "route",
257
+ "pageType": null,
258
+ "schema": null,
259
+ "shell": "MarketingShell",
260
+ "chrome": "on",
261
+ "sections": []
262
+ },
265
263
  {
266
264
  "route": "/sign-in",
267
265
  "kind": "route",
@@ -363,10 +361,6 @@
363
361
  "gapBelow": "tight"
364
362
  }
365
363
  },
366
- {
367
- "type": "blog-list",
368
- "component": "BlogList"
369
- },
370
364
  {
371
365
  "type": "logoCloud",
372
366
  "component": "LogoCloud",
@@ -413,17 +407,6 @@
413
407
  "type": "hero",
414
408
  "component": "Hero"
415
409
  },
416
- {
417
- "type": "cta",
418
- "component": "CTA"
419
- },
420
- {
421
- "type": "items",
422
- "component": "Items",
423
- "options": {
424
- "columns": 3
425
- }
426
- },
427
410
  {
428
411
  "type": "content-block",
429
412
  "component": "ContentBlock"
@@ -131,10 +131,9 @@ _Detail route over `content/en/UseCase/` — 3 seed pages: `persona-1.mdx`, `per
131
131
 
132
132
  <!-- generated:begin page=/contact -->
133
133
 
134
- | # | Section | Component | Copy (first line) |
135
- | --- | --------------------------------------------------------- | --------- | ----------------------------------------- |
136
- | 1 | `hero` (split · eyebrow "Contact" · checklist ×3 · 1 CTA) | `Hero` | Get every message in your email, free |
137
- | 2 | `items` (tiles · columns=2 · items ×4) | `Items` | {Add appointment scheduling to your site} |
134
+ | # | Section | Component | Copy (first line) |
135
+ | --- | ----------------------------------- | ------------- | ----------------- |
136
+ | 1 | `contact-form` (column · fields ×0) | `ContactForm` | |
138
137
 
139
138
  <!-- generated:end -->
140
139
 
@@ -163,13 +162,17 @@ _Detail route over `content/en/UseCase/` — 3 seed pages: `persona-1.mdx`, `per
163
162
 
164
163
  <!-- generated:begin page=/newsletter -->
165
164
 
166
- | # | Section | Component | Copy (first line) |
167
- | --- | -------------------------------------- | --------- | --------------------------------------- |
168
- | 1 | `hero` (eyebrow "Newsletter" · 2 CTAs) | `Hero` | {Start a free newsletter with Substack} |
169
- | 2 | `faq` (expanded · items ×3) | `FAQ` | FAQs |
165
+ | # | Section | Component | Copy (first line) |
166
+ | --- | ----------------------------------- | ------------- | ----------------- |
167
+ | 1 | `contact-form` (column · fields ×0) | `ContactForm` | |
170
168
 
171
169
  <!-- generated:end -->
172
170
 
171
+ <!-- generated:begin page=/unsubscribe -->
172
+
173
+ _Code route — no content, no sections._
174
+ <!-- generated:end -->
175
+
173
176
  <!-- generated:begin page=/meet -->
174
177
 
175
178
  | # | Section | Component | Copy (first line) |
@@ -181,12 +184,10 @@ _Detail route over `content/en/UseCase/` — 3 seed pages: `persona-1.mdx`, `per
181
184
 
182
185
  <!-- generated:begin page=/meet/[slug] -->
183
186
 
184
- | # | Section | Component | Copy (first line) |
185
- | --- | -------------------------------------- | -------------- | ------------------------------------------------ |
186
- | 1 | `hero` (eyebrow "Book a Call" · 1 CTA) | `Hero` | Book a Call |
187
- | 2 | `cta` (box · 1 CTA) | `CTA` | {What booking a call would do for your visitors} |
188
- | 3 | `items` (columns=3 · items ×3) | `Items` | What happens on the call? |
189
- | 4 | `content-block` (1 CTA) | `ContentBlock` | |
187
+ | # | Section | Component | Copy (first line) |
188
+ | --- | -------------------------------------- | -------------- | ----------------- |
189
+ | 1 | `hero` (eyebrow "Book a Call" · 1 CTA) | `Hero` | Book a Call |
190
+ | 2 | `content-block` (1 CTA) | `ContentBlock` | |
190
191
 
191
192
  <!-- generated:end -->
192
193
 
@@ -242,12 +243,11 @@ _Code route — no content, no sections._
242
243
 
243
244
  <!-- generated:begin page=/blog -->
244
245
 
245
- | # | Section | Component | Copy (first line) |
246
- | --- | ------------------------------------------------------------ | -------------- | ----------------------------------------------------------------- |
247
- | 1 | `hero` (centered · gapBelow=tight · eyebrow "Blog" · 2 CTAs) | `Hero` | Get free blog/docs from Fumadocs |
248
- | 2 | `blog-list` (grid) | `BlogList` | |
249
- | 3 | `logoCloud` (layout=inline · logos ×6) | `LogoCloud` | Don’t just take our word for it |
250
- | 4 | `testimonials` (quote · items ×1) | `Testimonials` | {A customer quote, in their own words, about the result they got} |
246
+ | # | Section | Component | Copy (first line) |
247
+ | --- | --------------------------------------------------- | -------------- | ----------------------------------------------------------------- |
248
+ | 1 | `hero` (centered · gapBelow=tight · eyebrow "Blog") | `Hero` | {Blog} |
249
+ | 2 | `logoCloud` (layout=inline · logos ×6) | `LogoCloud` | Don’t just take our word for it |
250
+ | 3 | `testimonials` (quote · items ×1) | `Testimonials` | {A customer quote, in their own words, about the result they got} |
251
251
 
252
252
  <!-- generated:end -->
253
253
 
@@ -342,6 +342,7 @@ organization-service:
342
342
  - { route: "/faq", kind: page, content: ["content/en/FAQPage/faq.mdx"] }
343
343
  - { route: "/glossary", kind: page, content: ["content/en/GlossaryList/glossary.mdx"] }
344
344
  - { route: "/newsletter", kind: page, content: ["content/en/NewsletterSignup/newsletter.mdx"] }
345
+ - { route: "/unsubscribe", kind: route }
345
346
  - { route: "/sign-in", kind: route }
346
347
  - { route: "/sign-up", kind: route }
347
348
  - { route: "/privacy", kind: page, content: ["content/en/PrivacyPage/privacy.mdx"] }
@@ -374,10 +375,10 @@ Every row is module-less: `requires` is `[marketing]` alone, so `mergeRoster` co
374
375
 
375
376
  <!-- generated:begin inventory -->
376
377
 
377
- | Tier | Used by this template |
378
- | -------- | ---------------------------------------------------------------------------------------------------------------------------------- |
379
- | Shell | `MarketingShell` |
380
- | Chrome | `Nav`, `Footer`, `Banner` (+ `BannerConsentIsland`, `BannerDismissIsland`) |
381
- | Sections | `BlogList`, `ContentBlock`, `CTA`, `DocumentChassis`, `FAQ`, `GlossaryIndex`, `Hero`, `Items`, `LogoCloud`, `Team`, `Testimonials` |
378
+ | Tier | Used by this template |
379
+ | -------- | ------------------------------------------------------------------------------------------------------------------------------------- |
380
+ | Shell | `MarketingShell` |
381
+ | Chrome | `Nav`, `Footer`, `Banner` (+ `BannerConsentIsland`, `BannerDismissIsland`) |
382
+ | Sections | `ContactForm`, `ContentBlock`, `CTA`, `DocumentChassis`, `FAQ`, `GlossaryIndex`, `Hero`, `Items`, `LogoCloud`, `Team`, `Testimonials` |
382
383
 
383
384
  <!-- generated:end -->
@@ -1,8 +1,8 @@
1
1
  ---
2
2
  type: "NewsletterSignup"
3
3
  slug: "newsletter"
4
- title: "{Start a free newsletter with Substack}"
5
- description: "{Or upgrade to Pro to capture every subscriber and build your own marketing database.}"
4
+ title: "Get the newsletter"
5
+ description: "{One sentence on what this newsletter covers and who it is for}"
6
6
  schema:
7
7
  mainEntity:
8
8
  "@type": "Offer"
@@ -12,48 +12,11 @@ schema:
12
12
  sections:
13
13
  [
14
14
  {
15
- "id": "hero",
16
- "type": "hero",
17
- "data":
18
- {
19
- "eyebrow": "Newsletter",
20
- "headline": "{Start a free newsletter with Substack}",
21
- "subheadline": "{Or upgrade to Pro to capture every subscriber and build your own marketing database.}",
22
- "primaryCta":
23
- { "label": "{Connect Substack}", "href": "https://substack.com" },
24
- "secondaryCta":
25
- {
26
- "label": "{Upgrade to Pro}",
27
- "href": "https://ailaunchkit.ai/pricing",
28
- "variant": "outline",
29
- },
30
- },
31
- },
32
- {
33
- "id": "faq",
34
- "type": "faq",
35
- "data":
36
- {
37
- "headline": "FAQs",
38
- "presentation": "expanded",
39
- "items":
40
- [
41
- {
42
- "question": "{How often will I hear from you?}",
43
- "answer": "{Answer in one or two plain sentences}",
44
- },
45
- {
46
- "question": "{What will I get?}",
47
- "answer": "{Answer in one or two plain sentences}",
48
- },
49
- {
50
- "question": "{Can I unsubscribe?}",
51
- "answer": "{Answer in one or two plain sentences}",
52
- },
53
- ],
54
- },
15
+ "id": "signup",
16
+ "type": "contact-form",
17
+ "data": { "variant": "column", "fields": [] },
55
18
  },
56
19
  ]
57
20
  ---
58
21
 
59
- {/* Rendered from frontmatter `sections[]` by the /newsletter route. The Free template has no signup form: the hero points the owner to Substack, or to Pro for subscriber capture. The `schema:` Offer is the page's JSON-LD main entity — a free subscription. Placeholder copy — replace every {brace} with your own words before you launch. */}
22
+ {/* Rendered from frontmatter `sections[]` by the /newsletter route. The page's one signup surface is the workspace's Newsletter magnet: its heading, sentence, field, consent, button and ending all come from the magnet, mounted by the route in this section's slot. To change the signup, change the magnet in Admin → Magnets. The `schema:` Offer is the page's JSON-LD main entity — a free subscription. Replace every {brace} with your own words before you launch. */}
@@ -4,7 +4,7 @@
4
4
  "categories": ["consulting"],
5
5
  "shape": "person-service",
6
6
  "design": "standard",
7
- "generatedHash": "5017d55ac2de4c2cdb7a10fc2488c9ad675f30614f51a064b7e91ab983976e51",
7
+ "generatedHash": "a9b961f2271fdf4a0313426df1083bdf0cae7544e83f2ab50cdee580c69d8d48",
8
8
  "layout": {
9
9
  "nav": "full",
10
10
  "footer": "columns",
@@ -196,15 +196,8 @@
196
196
  "chrome": "on",
197
197
  "sections": [
198
198
  {
199
- "type": "hero",
200
- "component": "Hero"
201
- },
202
- {
203
- "type": "items",
204
- "component": "Items",
205
- "options": {
206
- "columns": 2
207
- }
199
+ "type": "contact-form",
200
+ "component": "ContactForm"
208
201
  }
209
202
  ]
210
203
  },
@@ -260,15 +253,20 @@
260
253
  "chrome": "on",
261
254
  "sections": [
262
255
  {
263
- "type": "hero",
264
- "component": "Hero"
265
- },
266
- {
267
- "type": "faq",
268
- "component": "FAQ"
256
+ "type": "contact-form",
257
+ "component": "ContactForm"
269
258
  }
270
259
  ]
271
260
  },
261
+ {
262
+ "route": "/unsubscribe",
263
+ "kind": "route",
264
+ "pageType": null,
265
+ "schema": null,
266
+ "shell": "MarketingShell",
267
+ "chrome": "on",
268
+ "sections": []
269
+ },
272
270
  {
273
271
  "route": "/sign-in",
274
272
  "kind": "route",
@@ -370,10 +368,6 @@
370
368
  "gapBelow": "tight"
371
369
  }
372
370
  },
373
- {
374
- "type": "blog-list",
375
- "component": "BlogList"
376
- },
377
371
  {
378
372
  "type": "logoCloud",
379
373
  "component": "LogoCloud",
@@ -420,17 +414,6 @@
420
414
  "type": "hero",
421
415
  "component": "Hero"
422
416
  },
423
- {
424
- "type": "cta",
425
- "component": "CTA"
426
- },
427
- {
428
- "type": "items",
429
- "component": "Items",
430
- "options": {
431
- "columns": 3
432
- }
433
- },
434
417
  {
435
418
  "type": "content-block",
436
419
  "component": "ContentBlock"