create-ailk 0.1.0 → 0.1.1

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 (605) hide show
  1. package/README.md +124 -3
  2. package/component-catalog.md +295 -0
  3. package/dist/cli.js +92 -16
  4. package/dist/component-catalog.d.ts +11 -0
  5. package/dist/component-catalog.js +39 -0
  6. package/dist/copy.d.ts +7 -0
  7. package/dist/copy.js +24 -0
  8. package/dist/derive-architecture.d.ts +13 -0
  9. package/dist/derive-architecture.js +238 -0
  10. package/dist/index.d.ts +7 -2
  11. package/dist/index.js +19 -2
  12. package/dist/lib/extract-module-bundle.d.ts +16 -0
  13. package/dist/lib/extract-module-bundle.js +184 -0
  14. package/dist/lib/fetch-module.d.ts +55 -0
  15. package/dist/lib/fetch-module.js +125 -0
  16. package/dist/lib/module-license-gate.d.ts +48 -0
  17. package/dist/lib/module-license-gate.js +67 -0
  18. package/dist/lib/module-tier.d.ts +35 -0
  19. package/dist/lib/module-tier.js +37 -0
  20. package/dist/module-architecture.d.ts +175 -0
  21. package/dist/module-architecture.js +663 -0
  22. package/dist/parse-args.d.ts +47 -1
  23. package/dist/parse-args.js +143 -2
  24. package/dist/programmatic.d.ts +160 -3
  25. package/dist/programmatic.js +196 -7
  26. package/dist/surfaces.d.ts +211 -0
  27. package/dist/surfaces.js +532 -0
  28. package/dist/sync-routes.d.ts +92 -0
  29. package/dist/sync-routes.js +350 -0
  30. package/package.json +22 -14
  31. package/templates/.claude/rules/architecture.md +6 -2
  32. package/templates/.claude/skills/README.md +9 -9
  33. package/templates/.claude/skills/add-schema/SKILL.md +14 -7
  34. package/templates/.claude/skills/add-schema/references/schema-types.md +109 -6
  35. package/templates/.claude/skills/provision-config/SKILL.md +1 -1
  36. package/templates/.claude/skills/scaffold-commerce/SKILL.md +498 -1
  37. package/templates/.claude/skills/scaffold-commerce/templates/checkout-route.template.ts +370 -0
  38. package/templates/.claude/skills/scaffold-commerce/templates/invoice-route.template.ts +376 -0
  39. package/templates/.claude/skills/scaffold-commerce/templates/payment-link-route.template.ts +471 -0
  40. package/templates/.claude/skills/scaffold-commerce/templates/portal-route.template.ts +365 -0
  41. package/templates/.claude/skills/scaffold-commerce/templates/stripe-config.template.ts +60 -0
  42. package/templates/.claude/skills/scaffold-commerce/templates/subscription-route.template.ts +446 -0
  43. package/templates/.claude/skills/suggest-site-pages/references/categories.md +4 -4
  44. package/templates/.env.example +126 -2
  45. package/templates/CLAUDE.md +11 -5
  46. package/templates/README.md +1 -1
  47. package/templates/apps/api/.env.example +38 -0
  48. package/templates/apps/api/CLAUDE.md +75 -1
  49. package/templates/apps/api/LICENSE +201 -0
  50. package/templates/apps/api/api/index.ts +6 -141
  51. package/templates/apps/api/jest.config.cjs +16 -0
  52. package/templates/apps/api/package.json +22 -6
  53. package/templates/apps/api/src/__tests__/module-exclusion.test.ts +141 -0
  54. package/templates/apps/api/src/__tests__/server.test.ts +46 -0
  55. package/templates/apps/api/src/__tests__/vercel-handler.test.ts +211 -0
  56. package/templates/apps/api/src/bin/abandon-sweep.ts +42 -0
  57. package/templates/apps/api/src/bin/deliverable-resend.ts +144 -0
  58. package/templates/apps/api/src/bin/deliverable-upload.ts +114 -0
  59. package/templates/apps/api/src/bin/followup-sweep.ts +44 -0
  60. package/templates/apps/api/src/bin/listing-csv-sweep.ts +46 -0
  61. package/templates/apps/api/src/bin/seed-presets.ts +58 -0
  62. package/templates/apps/api/src/bin/seed-waitlist-experiments.ts +104 -0
  63. package/templates/apps/api/src/bin/session-retention-sweep.ts +46 -0
  64. package/templates/apps/api/src/cli.ts +5 -11
  65. package/templates/apps/api/src/config/index.ts +35 -0
  66. package/templates/apps/api/src/config/modules.ts +43 -0
  67. package/templates/apps/api/src/lib/__mocks__/prisma-client.js +11 -0
  68. package/templates/apps/api/src/lib/__mocks__/prisma.ts +231 -0
  69. package/templates/apps/api/src/lib/__tests__/lead-capture-store.test.ts +2 -2
  70. package/templates/apps/api/src/lib/site.ts +16 -0
  71. package/templates/apps/api/src/lib/stripe.ts +22 -0
  72. package/templates/apps/api/src/lib/tenant-db.ts +225 -0
  73. package/templates/apps/api/src/lib/ws-token.ts +91 -0
  74. package/templates/apps/api/src/middleware/__tests__/adversarial/session-fixation.test.ts +7 -1
  75. package/templates/apps/api/src/middleware/__tests__/auth.cookie-path.test.ts +7 -1
  76. package/templates/apps/api/src/middleware/__tests__/rate-limit.test.ts +91 -4
  77. package/templates/apps/api/src/middleware/auth.ts +43 -8
  78. package/templates/apps/api/src/middleware/rate-limit.ts +78 -3
  79. package/templates/apps/api/src/middleware/tenant.ts +99 -0
  80. package/templates/apps/api/src/openapi/__tests__/openapi.test.ts +92 -0
  81. package/templates/apps/api/src/openapi/spec.ts +312 -3
  82. package/templates/apps/api/src/routes/aeo/__tests__/index.test.ts +175 -0
  83. package/templates/apps/api/src/routes/aeo/index.ts +107 -0
  84. package/templates/apps/api/src/routes/auth/__tests__/auth-tokens.functional.test.ts +5 -2
  85. package/templates/apps/api/src/routes/auth/__tests__/tokens.test.ts +22 -3
  86. package/templates/apps/api/src/routes/auth/tokens.ts +13 -1
  87. package/templates/apps/api/src/routes/billing/__tests__/portal.test.ts +450 -0
  88. package/templates/apps/api/src/routes/billing/__tests__/read.test.ts +262 -0
  89. package/templates/apps/api/src/routes/billing/__tests__/usage.test.ts +436 -0
  90. package/templates/apps/api/src/routes/billing/index.ts +36 -0
  91. package/templates/apps/api/src/routes/billing/portal.ts +182 -0
  92. package/templates/apps/api/src/routes/billing/read.ts +75 -0
  93. package/templates/apps/api/src/routes/billing/usage.ts +153 -0
  94. package/templates/apps/api/src/routes/checkout/__tests__/sessions.test.ts +99 -0
  95. package/templates/apps/api/src/routes/checkout/sessions.ts +20 -8
  96. package/templates/apps/api/src/routes/content/create.ts +1 -0
  97. package/templates/apps/api/src/routes/content/delete.ts +1 -0
  98. package/templates/apps/api/src/routes/content/index.ts +42 -6
  99. package/templates/apps/api/src/routes/content/update.ts +1 -0
  100. package/templates/apps/api/src/routes/deliverables/__tests__/index.test.ts +393 -0
  101. package/templates/apps/api/src/routes/deliverables/index.ts +200 -0
  102. package/templates/apps/api/src/routes/flow-checkouts/__tests__/index.test.ts +443 -0
  103. package/templates/apps/api/src/routes/flow-checkouts/index.ts +82 -0
  104. package/templates/apps/api/src/routes/flows/README.md +147 -0
  105. package/templates/apps/api/src/routes/flows/__tests__/index.test.ts +752 -0
  106. package/templates/apps/api/src/routes/flows/__tests__/recommender.test.ts +671 -0
  107. package/templates/apps/api/src/routes/flows/index.ts +202 -0
  108. package/templates/apps/api/src/routes/flows/recommender.ts +443 -0
  109. package/templates/apps/api/src/routes/leads/__tests__/index.test.ts +438 -31
  110. package/templates/apps/api/src/routes/leads/__tests__/track.test.ts +10 -10
  111. package/templates/apps/api/src/routes/leads/index.ts +43 -9
  112. package/templates/apps/api/src/routes/project-listings/__tests__/configured-application.test.ts +547 -0
  113. package/templates/apps/api/src/routes/project-listings/__tests__/copy-edit.test.ts +815 -0
  114. package/templates/apps/api/src/routes/project-listings/__tests__/drafts.test.ts +742 -0
  115. package/templates/apps/api/src/routes/project-listings/__tests__/public.test.ts +424 -0
  116. package/templates/apps/api/src/routes/project-listings/__tests__/site-key.test.ts +364 -0
  117. package/templates/apps/api/src/routes/project-listings/__tests__/tenant-isolation.test.ts +566 -0
  118. package/templates/apps/api/src/routes/project-listings/get.ts +70 -0
  119. package/templates/apps/api/src/routes/project-listings/index.ts +105 -0
  120. package/templates/apps/api/src/routes/project-listings/list.ts +47 -0
  121. package/templates/apps/api/src/routes/project-listings/patch-copy.ts +222 -0
  122. package/templates/apps/api/src/routes/project-listings/patch-draft.ts +97 -0
  123. package/templates/apps/api/src/routes/project-listings/patch.ts +136 -0
  124. package/templates/apps/api/src/routes/project-listings/public.ts +52 -0
  125. package/templates/apps/api/src/routes/project-listings/respond.ts +37 -0
  126. package/templates/apps/api/src/routes/project-listings/resume-token.ts +22 -0
  127. package/templates/apps/api/src/routes/project-listings/start.ts +98 -0
  128. package/templates/apps/api/src/routes/project-listings/submit.ts +122 -0
  129. package/templates/apps/api/src/routes/schedule/__tests__/index.test.ts +490 -0
  130. package/templates/apps/api/src/routes/schedule/index.ts +249 -0
  131. package/templates/apps/api/src/routes/slack/__tests__/actions.test.ts +385 -0
  132. package/templates/apps/api/src/routes/slack/actions.ts +177 -0
  133. package/templates/apps/api/src/routes/slack/index.ts +38 -0
  134. package/templates/apps/api/src/routes/test/auth/__tests__/session.test.ts +16 -6
  135. package/templates/apps/api/src/routes/test/auth/session.ts +8 -6
  136. package/templates/apps/api/src/routes/waitlist-experiments/__tests__/tenant-isolation.test.ts +577 -0
  137. package/templates/apps/api/src/routes/waitlist-experiments/comparison.ts +78 -0
  138. package/templates/apps/api/src/routes/waitlist-experiments/index.ts +41 -0
  139. package/templates/apps/api/src/routes/waitlist-experiments/list.ts +64 -0
  140. package/templates/apps/api/src/routes/waitlist-experiments/respond.ts +42 -0
  141. package/templates/apps/api/src/routes/waitlist-experiments/signup.ts +84 -0
  142. package/templates/apps/api/src/routes/waitlist-experiments/signups.ts +119 -0
  143. package/templates/apps/api/src/routes/waitlist-signups/__tests__/index.test.ts +238 -0
  144. package/templates/apps/api/src/routes/waitlist-signups/index.ts +101 -0
  145. package/templates/apps/api/src/routes/webhooks/README.md +35 -12
  146. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-flow-checkout.test.ts +315 -0
  147. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-org-billing.test.ts +270 -0
  148. package/templates/apps/api/src/routes/webhooks/stripe.ts +248 -20
  149. package/templates/apps/api/src/routes/workspaces/__tests__/config-tenant-isolation.test.ts +356 -0
  150. package/templates/apps/api/src/routes/workspaces/__tests__/tenant-isolation.test.ts +671 -0
  151. package/templates/apps/api/src/routes/workspaces/config.ts +125 -0
  152. package/templates/apps/api/src/routes/workspaces/index.ts +194 -0
  153. package/templates/apps/api/src/routes/workspaces/sessions.ts +218 -0
  154. package/templates/apps/api/src/server.ts +293 -7
  155. package/templates/apps/api/src/services/__tests__/abandon-email.test.ts +489 -0
  156. package/templates/apps/api/src/services/__tests__/aeo-score.test.ts +475 -0
  157. package/templates/apps/api/src/services/__tests__/answer-distributions.test.ts +132 -0
  158. package/templates/apps/api/src/services/__tests__/deliverable-fulfillment.test.ts +523 -0
  159. package/templates/apps/api/src/services/__tests__/deliverable-resend.test.ts +359 -0
  160. package/templates/apps/api/src/services/__tests__/entitlements.test.ts +142 -0
  161. package/templates/apps/api/src/services/__tests__/flow-aggregate.test.ts +425 -0
  162. package/templates/apps/api/src/services/__tests__/flow-engine.test.ts +2840 -0
  163. package/templates/apps/api/src/services/__tests__/lead-promotion.test.ts +393 -0
  164. package/templates/apps/api/src/services/__tests__/lead-routing.test.ts +8 -8
  165. package/templates/apps/api/src/services/__tests__/listing-csv-sweep.test.ts +560 -0
  166. package/templates/apps/api/src/services/__tests__/playbook-compile.test.ts +406 -0
  167. package/templates/apps/api/src/services/__tests__/playbook-render.test.ts +290 -0
  168. package/templates/apps/api/src/services/__tests__/project-listing-decision.test.ts +736 -0
  169. package/templates/apps/api/src/services/__tests__/project-listing-flow.test.ts +475 -0
  170. package/templates/apps/api/src/services/__tests__/project-listing-issue.test.ts +340 -0
  171. package/templates/apps/api/src/services/__tests__/recommender-capture.test.ts +983 -0
  172. package/templates/apps/api/src/services/__tests__/slack-notify.test.ts +278 -0
  173. package/templates/apps/api/src/services/__tests__/tenant-context-cascade.test.ts +71 -0
  174. package/templates/apps/api/src/services/__tests__/tenant-context.test.ts +379 -0
  175. package/templates/apps/api/src/services/__tests__/usage-aggregation.test.ts +941 -0
  176. package/templates/apps/api/src/services/__tests__/usage-credits.test.ts +588 -0
  177. package/templates/apps/api/src/services/__tests__/usage-metering.test.ts +768 -0
  178. package/templates/apps/api/src/services/__tests__/waitlist-dashboard.test.ts +1314 -0
  179. package/templates/apps/api/src/services/__tests__/waitlist-experiments.test.ts +341 -0
  180. package/templates/apps/api/src/services/__tests__/waitlist-followup.test.ts +567 -0
  181. package/templates/apps/api/src/services/__tests__/waitlist-scoring.test.ts +474 -0
  182. package/templates/apps/api/src/services/__tests__/waitlist-signups.test.ts +354 -0
  183. package/templates/apps/api/src/services/abandon-email.ts +307 -0
  184. package/templates/apps/api/src/services/aeo-score.ts +288 -0
  185. package/templates/apps/api/src/services/answer-distributions.ts +138 -0
  186. package/templates/apps/api/src/services/deliverable-fulfillment.ts +523 -0
  187. package/templates/apps/api/src/services/entitlements.ts +102 -0
  188. package/templates/apps/api/src/services/flow-aggregate.ts +232 -0
  189. package/templates/apps/api/src/services/flow-checkouts.ts +123 -0
  190. package/templates/apps/api/src/services/flow-engine.ts +1278 -0
  191. package/templates/apps/api/src/services/lead-promotion.ts +176 -0
  192. package/templates/apps/api/src/services/lead-routing.ts +3 -3
  193. package/templates/apps/api/src/services/listing-config.ts +102 -0
  194. package/templates/apps/api/src/services/listing-csv-sweep.ts +455 -0
  195. package/templates/apps/api/src/services/playbook-compile.ts +398 -0
  196. package/templates/apps/api/src/services/playbook-render.ts +263 -0
  197. package/templates/apps/api/src/services/project-listing-decision.ts +490 -0
  198. package/templates/apps/api/src/services/project-listing-flow.ts +426 -0
  199. package/templates/apps/api/src/services/project-listing-issue.ts +251 -0
  200. package/templates/apps/api/src/services/project-listings.ts +1124 -0
  201. package/templates/apps/api/src/services/recommender-capture.ts +835 -0
  202. package/templates/apps/api/src/services/scheduling/cal-provider.ts +392 -0
  203. package/templates/apps/api/src/services/scheduling/index.ts +63 -0
  204. package/templates/apps/api/src/services/scheduling/types.ts +88 -0
  205. package/templates/apps/api/src/services/slack-notify.ts +240 -0
  206. package/templates/apps/api/src/services/tenant-context.ts +451 -0
  207. package/templates/apps/api/src/services/usage-aggregation.ts +516 -0
  208. package/templates/apps/api/src/services/usage-credits.ts +340 -0
  209. package/templates/apps/api/src/services/usage-metering.ts +699 -0
  210. package/templates/apps/api/src/services/waitlist-dashboard.ts +947 -0
  211. package/templates/apps/api/src/services/waitlist-experiments.ts +213 -0
  212. package/templates/apps/api/src/services/waitlist-followup.ts +486 -0
  213. package/templates/apps/api/src/services/waitlist-scoring.ts +166 -0
  214. package/templates/apps/api/src/services/waitlist-signups.ts +165 -0
  215. package/templates/apps/api/src/vercel-handler.ts +165 -0
  216. package/templates/apps/api/tsconfig.json +0 -12
  217. package/templates/apps/mcp/CLAUDE.md +19 -9
  218. package/templates/apps/mcp/LICENSE +201 -0
  219. package/templates/apps/mcp/__tests__/create_page.test.ts +1 -0
  220. package/templates/apps/mcp/__tests__/delete_page.test.ts +1 -0
  221. package/templates/apps/mcp/__tests__/module-exclusion.test.ts +105 -0
  222. package/templates/apps/mcp/__tests__/parity.test.ts +70 -6
  223. package/templates/apps/mcp/__tests__/request_callback.test.ts +4 -4
  224. package/templates/apps/mcp/__tests__/schedule_tools.test.ts +242 -0
  225. package/templates/apps/mcp/__tests__/submit_lead.test.ts +4 -4
  226. package/templates/apps/mcp/__tests__/subscribe_newsletter.test.ts +4 -4
  227. package/templates/apps/mcp/__tests__/tools/purchase.test.ts +47 -0
  228. package/templates/apps/mcp/__tests__/update_page.test.ts +1 -0
  229. package/templates/apps/mcp/package.json +6 -4
  230. package/templates/apps/mcp/src/config/modules.ts +37 -0
  231. package/templates/apps/mcp/src/server.ts +109 -18
  232. package/templates/apps/mcp/src/tools/capture_lead.ts +1 -1
  233. package/templates/apps/mcp/src/tools/create_booking.ts +58 -0
  234. package/templates/apps/mcp/src/tools/create_page.ts +1 -0
  235. package/templates/apps/mcp/src/tools/delete_page.ts +1 -0
  236. package/templates/apps/mcp/src/tools/get_event_meta.ts +55 -0
  237. package/templates/apps/mcp/src/tools/get_flow.ts +61 -0
  238. package/templates/apps/mcp/src/tools/index.ts +25 -0
  239. package/templates/apps/mcp/src/tools/list_availability.ts +67 -0
  240. package/templates/apps/mcp/src/tools/purchase.ts +3 -0
  241. package/templates/apps/mcp/src/tools/submit_flow_step.ts +83 -0
  242. package/templates/apps/mcp/src/tools/update_page.ts +1 -0
  243. package/templates/apps/mcp/tsconfig.json +1 -9
  244. package/templates/apps/web/.env.example +44 -0
  245. package/templates/apps/web/CLAUDE.md +28 -0
  246. package/templates/apps/web/LICENSE +201 -0
  247. package/templates/apps/web/__tests__/__mocks__/code-highlight.jest-stub.ts +24 -0
  248. package/templates/apps/web/__tests__/__mocks__/next-intl-server.ts +33 -0
  249. package/templates/apps/web/__tests__/__mocks__/next-intl.ts +18 -0
  250. package/templates/apps/web/__tests__/__mocks__/server-only.ts +13 -0
  251. package/templates/apps/web/__tests__/__mocks__/style-mock.js +4 -0
  252. package/templates/apps/web/__tests__/__mocks__/vercel-analytics-server.ts +9 -0
  253. package/templates/apps/web/__tests__/jest-support/import-meta-transformer.cjs +90 -0
  254. package/templates/apps/web/__tests__/setup.ts +22 -32
  255. package/templates/apps/web/app/.well-known/ai-plugin.json/route.ts +6 -3
  256. package/templates/apps/web/app/.well-known/mcp.json/build-manifest.ts +8 -2
  257. package/templates/apps/web/app/[locale]/(authed)/account/__tests__/page.test.tsx +260 -0
  258. package/templates/apps/web/app/[locale]/(authed)/account/page.tsx +263 -0
  259. package/templates/apps/web/app/[locale]/(authed)/account/sign-out-button.tsx +39 -0
  260. package/templates/apps/web/app/[locale]/(authed)/layout.tsx +54 -0
  261. package/templates/apps/web/app/[locale]/(authed)/sign-in-gate.tsx +96 -0
  262. package/templates/apps/web/app/[locale]/(authed)/waitlist/[experimentId]/page.tsx +309 -0
  263. package/templates/apps/web/app/[locale]/(authed)/waitlist/[experimentId]/signups/[leadId]/page.tsx +149 -0
  264. package/templates/apps/web/app/[locale]/(authed)/waitlist/__tests__/comparison.test.tsx +273 -0
  265. package/templates/apps/web/app/[locale]/(authed)/waitlist/__tests__/gate.test.tsx +172 -0
  266. package/templates/apps/web/app/[locale]/(authed)/waitlist/__tests__/list.test.tsx +171 -0
  267. package/templates/apps/web/app/[locale]/(authed)/waitlist/__tests__/signup.test.tsx +179 -0
  268. package/templates/apps/web/app/[locale]/(authed)/waitlist/components/ExperimentsTable.tsx +116 -0
  269. package/templates/apps/web/app/[locale]/(authed)/waitlist/components/ForbiddenState.tsx +24 -0
  270. package/templates/apps/web/app/[locale]/(authed)/waitlist/components/OfferFunnelTable.tsx +66 -0
  271. package/templates/apps/web/app/[locale]/(authed)/waitlist/components/RollupTicker.tsx +61 -0
  272. package/templates/apps/web/app/[locale]/(authed)/waitlist/components/ScoreTrace.tsx +114 -0
  273. package/templates/apps/web/app/[locale]/(authed)/waitlist/components/SignupsTable.tsx +139 -0
  274. package/templates/apps/web/app/[locale]/(authed)/waitlist/components/WaitlistComparisonTabs.tsx +85 -0
  275. package/templates/apps/web/app/[locale]/(authed)/waitlist/components/status-badges.tsx +67 -0
  276. package/templates/apps/web/app/[locale]/(authed)/waitlist/format.ts +111 -0
  277. package/templates/apps/web/app/[locale]/(authed)/waitlist/page.tsx +179 -0
  278. package/templates/apps/web/app/[locale]/about/page.tsx +10 -1
  279. package/templates/apps/web/app/[locale]/blog/[[...slug]]/page.tsx +6 -1
  280. package/templates/apps/web/app/[locale]/careers/[slug]/page.tsx +9 -0
  281. package/templates/apps/web/app/[locale]/careers/__tests__/page-renderer-migration.test.tsx +3 -3
  282. package/templates/apps/web/app/[locale]/careers/page.tsx +9 -1
  283. package/templates/apps/web/app/[locale]/case-studies/[slug]/page.tsx +9 -0
  284. package/templates/apps/web/app/[locale]/case-studies/__tests__/page-renderer-migration.test.tsx +3 -3
  285. package/templates/apps/web/app/[locale]/case-studies/page.tsx +13 -1
  286. package/templates/apps/web/app/[locale]/clients/__tests__/page-renderer-migration.test.tsx +11 -1
  287. package/templates/apps/web/app/[locale]/clients/page.tsx +9 -1
  288. package/templates/apps/web/app/[locale]/contact/ContactForm.tsx +21 -1
  289. package/templates/apps/web/app/[locale]/contact/ConversationalIntakeWrapper.tsx +188 -0
  290. package/templates/apps/web/app/[locale]/contact/__tests__/ConversationalIntakeWrapper.test.tsx +242 -0
  291. package/templates/apps/web/app/[locale]/contact/__tests__/contact.actions.test.ts +29 -0
  292. package/templates/apps/web/app/[locale]/contact/__tests__/intake-analytics.test.ts +51 -0
  293. package/templates/apps/web/app/[locale]/contact/__tests__/page-renderer-migration.test.tsx +39 -15
  294. package/templates/apps/web/app/[locale]/contact/contact.actions.ts +21 -3
  295. package/templates/apps/web/app/[locale]/contact/intake-analytics.ts +49 -0
  296. package/templates/apps/web/app/[locale]/contact/intake-script.ts +66 -0
  297. package/templates/apps/web/app/[locale]/contact/page.tsx +14 -4
  298. package/templates/apps/web/app/[locale]/courses/[slug]/page.tsx +13 -1
  299. package/templates/apps/web/app/[locale]/courses/__tests__/page-renderer-migration.test.tsx +3 -3
  300. package/templates/apps/web/app/[locale]/courses/page.tsx +9 -1
  301. package/templates/apps/web/app/[locale]/docs/[[...slug]]/page.tsx +1 -0
  302. package/templates/apps/web/app/[locale]/downloads/__tests__/page-renderer-migration.test.tsx +11 -1
  303. package/templates/apps/web/app/[locale]/downloads/page.tsx +13 -1
  304. package/templates/apps/web/app/[locale]/events/[slug]/page.tsx +9 -0
  305. package/templates/apps/web/app/[locale]/events/__tests__/page-renderer-migration.test.tsx +12 -2
  306. package/templates/apps/web/app/[locale]/events/page.tsx +9 -1
  307. package/templates/apps/web/app/[locale]/faq/page.tsx +10 -1
  308. package/templates/apps/web/app/[locale]/flows/[slug]/FlowStepperClient.tsx +265 -0
  309. package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/FlowStepperClient.permalink.test.tsx +445 -0
  310. package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/FlowStepperClient.test.tsx +341 -0
  311. package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/checkout.actions.test.ts +287 -0
  312. package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/flow.actions.test.ts +302 -0
  313. package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/two-route-tool.test.tsx +128 -0
  314. package/templates/apps/web/app/[locale]/flows/[slug]/checkout.actions.ts +254 -0
  315. package/templates/apps/web/app/[locale]/flows/[slug]/flow.actions.ts +144 -0
  316. package/templates/apps/web/app/[locale]/flows/[slug]/page.tsx +108 -0
  317. package/templates/apps/web/app/[locale]/flows/[slug]/results/[payload]/ResultsClient.tsx +532 -0
  318. package/templates/apps/web/app/[locale]/flows/[slug]/results/[payload]/ResultsEmailStep.tsx +121 -0
  319. package/templates/apps/web/app/[locale]/flows/[slug]/results/[payload]/__tests__/ResultsClient.checkout.test.tsx +457 -0
  320. package/templates/apps/web/app/[locale]/flows/[slug]/results/[payload]/__tests__/page.test.tsx +396 -0
  321. package/templates/apps/web/app/[locale]/flows/[slug]/results/[payload]/page.tsx +114 -0
  322. package/templates/apps/web/app/[locale]/flows/[slug]/start/page.tsx +52 -0
  323. package/templates/apps/web/app/[locale]/how-to/[slug]/page.tsx +13 -1
  324. package/templates/apps/web/app/[locale]/how-to/__tests__/page-renderer-migration.test.tsx +1 -1
  325. package/templates/apps/web/app/[locale]/integrations/[slug]/page.tsx +9 -0
  326. package/templates/apps/web/app/[locale]/integrations/__tests__/page-renderer-migration.test.tsx +3 -3
  327. package/templates/apps/web/app/[locale]/integrations/page.tsx +13 -1
  328. package/templates/apps/web/app/[locale]/launch-service/page.tsx +14 -1
  329. package/templates/apps/web/app/[locale]/layout.tsx +115 -16
  330. package/templates/apps/web/app/[locale]/page.tsx +10 -1
  331. package/templates/apps/web/app/[locale]/partners/[slug]/page.tsx +9 -0
  332. package/templates/apps/web/app/[locale]/partners/__tests__/page-renderer-migration.test.tsx +3 -3
  333. package/templates/apps/web/app/[locale]/partners/page.tsx +9 -1
  334. package/templates/apps/web/app/[locale]/products/[slug]/page.tsx +9 -0
  335. package/templates/apps/web/app/[locale]/products/__tests__/page-renderer-migration.test.tsx +3 -3
  336. package/templates/apps/web/app/[locale]/products/page.tsx +9 -1
  337. package/templates/apps/web/app/[locale]/projects/[slug]/page.tsx +13 -1
  338. package/templates/apps/web/app/[locale]/projects/__tests__/page-renderer-migration.test.tsx +10 -0
  339. package/templates/apps/web/app/[locale]/projects/apply/ListingApplicationClient.tsx +110 -0
  340. package/templates/apps/web/app/[locale]/projects/apply/__tests__/ListingApplicationClient.test.tsx +96 -0
  341. package/templates/apps/web/app/[locale]/projects/page.tsx +13 -1
  342. package/templates/apps/web/app/[locale]/resources/[slug]/page.tsx +9 -0
  343. package/templates/apps/web/app/[locale]/resources/__tests__/page-renderer-migration.test.tsx +12 -2
  344. package/templates/apps/web/app/[locale]/resources/page.tsx +13 -1
  345. package/templates/apps/web/app/[locale]/schedule/__tests__/page.test.tsx +117 -0
  346. package/templates/apps/web/app/[locale]/schedule/confirmed/__tests__/page.test.tsx +96 -0
  347. package/templates/apps/web/app/[locale]/schedule/confirmed/page.tsx +92 -0
  348. package/templates/apps/web/app/[locale]/schedule/page.tsx +82 -0
  349. package/templates/apps/web/app/[locale]/services/[slug]/page.tsx +9 -0
  350. package/templates/apps/web/app/[locale]/services/__tests__/page-renderer-migration.test.tsx +3 -3
  351. package/templates/apps/web/app/[locale]/services/page.tsx +9 -1
  352. package/templates/apps/web/app/[locale]/sign-in/__tests__/next-path.test.ts +31 -0
  353. package/templates/apps/web/app/[locale]/sign-in/__tests__/page.test.tsx +152 -0
  354. package/templates/apps/web/app/[locale]/sign-in/next-path.ts +0 -0
  355. package/templates/apps/web/app/[locale]/sign-in/page.tsx +83 -0
  356. package/templates/apps/web/app/[locale]/sign-in/sign-in-card.tsx +123 -0
  357. package/templates/apps/web/app/[locale]/software/[slug]/page.tsx +13 -1
  358. package/templates/apps/web/app/[locale]/software/__tests__/page-renderer-migration.test.tsx +1 -1
  359. package/templates/apps/web/app/[locale]/tech-articles/[slug]/page.tsx +13 -1
  360. package/templates/apps/web/app/[locale]/tech-articles/__tests__/page-renderer-migration.test.tsx +1 -1
  361. package/templates/apps/web/app/[locale]/testimonials/__tests__/page-renderer-migration.test.tsx +11 -1
  362. package/templates/apps/web/app/[locale]/testimonials/page.tsx +13 -1
  363. package/templates/apps/web/app/[locale]/thanks/[slug]/__tests__/page.test.tsx +93 -0
  364. package/templates/apps/web/app/[locale]/thanks/[slug]/page.tsx +48 -0
  365. package/templates/apps/web/app/[locale]/use-cases/__tests__/page-renderer-migration.test.tsx +11 -1
  366. package/templates/apps/web/app/[locale]/use-cases/page.tsx +13 -1
  367. package/templates/apps/web/app/[locale]/whitepapers/[slug]/page.tsx +13 -1
  368. package/templates/apps/web/app/[locale]/whitepapers/__tests__/page-renderer-migration.test.tsx +1 -1
  369. package/templates/apps/web/app/globals.css +35 -0
  370. package/templates/apps/web/app/llms.txt/route.ts +2 -1
  371. package/templates/apps/web/app/og/route.tsx +10 -2
  372. package/templates/apps/web/auth.ts +8 -0
  373. package/templates/apps/web/components/sign-out-trigger.tsx +42 -0
  374. package/templates/apps/web/content/en/blog/README.txt +25 -0
  375. package/templates/apps/web/content/en/docs/index.mdx +28 -0
  376. package/templates/apps/web/jest.config.cjs +84 -27
  377. package/templates/apps/web/lib/__tests__/site-brand.test.ts +119 -0
  378. package/templates/apps/web/lib/__tests__/structured-data.test.tsx +499 -0
  379. package/templates/apps/web/lib/account-config.ts +13 -0
  380. package/templates/apps/web/lib/server-api.ts +85 -0
  381. package/templates/apps/web/lib/site-brand.tsx +118 -0
  382. package/templates/apps/web/messages/en.json +275 -7
  383. package/templates/apps/web/middleware.ts +11 -3
  384. package/templates/apps/web/next.config.mjs +8 -2
  385. package/templates/apps/web/package.json +16 -7
  386. package/templates/apps/web/postcss.config.mjs +23 -0
  387. package/templates/apps/web/public/.well-known/security.txt +3 -3
  388. package/templates/apps/web/src/lib/routes.ts +15 -2
  389. package/templates/apps/web/tsconfig.json +1 -16
  390. package/templates/content/_site.mdx +24 -25
  391. package/templates/content/en/AboutPage/about.mdx +24 -14
  392. package/templates/content/en/ContactPage/contact.mdx +23 -14
  393. package/templates/content/en/FAQPage/faq.mdx +10 -392
  394. package/templates/content/en/HomePage/home.mdx +14 -285
  395. package/templates/database/CHANGELOG.md +382 -0
  396. package/templates/database/LICENSE +201 -0
  397. package/templates/database/README.md +3 -1
  398. package/templates/database/__tests__/flows-listing-diagnostic.test.ts +392 -0
  399. package/templates/database/__tests__/flows-presets.test.ts +173 -0
  400. package/templates/database/__tests__/prefixed-ids.db.test.ts +146 -0
  401. package/templates/database/__tests__/seed.test.ts +88 -0
  402. package/templates/database/__tests__/user-cascade.test.ts +19 -4
  403. package/templates/database/auth/schema.prisma +521 -0
  404. package/templates/database/config/schema.prisma +234 -0
  405. package/templates/database/content/schema.prisma +263 -0
  406. package/templates/database/flows/listing-diagnostic.ts +182 -0
  407. package/templates/database/flows/presets.ts +315 -0
  408. package/templates/database/inbox/__tests__/schema.test.ts +4 -0
  409. package/templates/database/inbox/schema.prisma +476 -3
  410. package/templates/database/jest.config.cjs +8 -0
  411. package/templates/database/migrations/20260712215647_add_multi_tenant_tenancy/migration.sql +201 -0
  412. package/templates/database/migrations/20260713143320_reanchor_site_config_to_workspace/migration.sql +67 -0
  413. package/templates/database/migrations/20260713174000_add_audit_logs/migration.sql +46 -0
  414. package/templates/database/migrations/20260713190000_drop_telemetry_records/migration.sql +25 -0
  415. package/templates/database/migrations/20260713192000_add_uuidv7_function/migration.sql +49 -0
  416. package/templates/database/migrations/20260713192429_prefixed_uuid_entity_ids/migration.sql +197 -0
  417. package/templates/database/migrations/20260713200000_add_org_billing/migration.sql +32 -0
  418. package/templates/database/migrations/20260714000000_add_lead_promotion_fields/migration.sql +22 -0
  419. package/templates/database/migrations/20260714010000_add_usage_billing_content_models/migration.sql +151 -0
  420. package/templates/database/migrations/20260714020000_add_usage_billing_auth_config_models/migration.sql +223 -0
  421. package/templates/database/migrations/20260714030000_credit_balance_non_negative/migration.sql +22 -0
  422. package/templates/database/migrations/20260714030000_widen_usage_billing_report_aggregates/migration.sql +32 -0
  423. package/templates/database/migrations/20260810233516_add_flow_engine_models/migration.sql +40 -0
  424. package/templates/database/migrations/20260811020000_add_flow_session_abandon_email_columns/migration.sql +4 -0
  425. package/templates/database/migrations/20260811030000_add_flow_session_abandon_email_index/migration.sql +2 -0
  426. package/templates/database/migrations/20260811040000_add_flow_session_segment/migration.sql +2 -0
  427. package/templates/database/migrations/20260811050000_add_deliverable_models/migration.sql +29 -0
  428. package/templates/database/migrations/20260812000000_add_deliverable_grant_send_columns/migration.sql +6 -0
  429. package/templates/database/migrations/20260902222948_add_waitlist_experiment_models/migration.sql +39 -0
  430. package/templates/database/migrations/20260902224500_add_waitlist_id_format_checks/migration.sql +24 -0
  431. package/templates/database/migrations/20260903004112_add_flow_session_flags_aeo_score/migration.sql +3 -0
  432. package/templates/database/migrations/20260903010000_add_playbook_instance/migration.sql +33 -0
  433. package/templates/database/migrations/20260904000000_add_waitlist_followup_send/migration.sql +30 -0
  434. package/templates/database/migrations/20260905230000_add_flow_checkout/migration.sql +47 -0
  435. package/templates/database/migrations/20260906000000_add_flow_checkout_idempotency/migration.sql +16 -0
  436. package/templates/database/migrations/20260907120000_add_project_listing/migration.sql +47 -0
  437. package/templates/database/migrations/20260907130000_add_project_listing_slack_columns/migration.sql +10 -0
  438. package/templates/database/migrations/20260907180000_add_listing_csv_send/migration.sql +26 -0
  439. package/templates/database/migrations/20260909120000_project_listings_platform/migration.sql +90 -0
  440. package/templates/database/migrations/20260909180000_listing_draft_and_fields/migration.sql +174 -0
  441. package/templates/database/migrations/20260910120000_listing_public_site_key/migration.sql +14 -0
  442. package/templates/database/migrations/20260911120000_listing_copy_edit_audit/migration.sql +25 -0
  443. package/templates/database/ops/schema.prisma +27 -0
  444. package/templates/database/package.json +42 -4
  445. package/templates/database/prisma.config.ts +1 -1
  446. package/templates/database/schema.prisma +19 -435
  447. package/templates/database/scripts/db-generate-locked.sh +0 -0
  448. package/templates/database/seed-test.ts +14 -4
  449. package/templates/database/seed.ts +148 -0
  450. package/templates/database/tenancy.ts +45 -0
  451. package/templates/database/tsconfig.flows.json +15 -0
  452. package/templates/database/tsconfig.json +7 -1
  453. package/templates/database/tsconfig.tenancy.json +14 -0
  454. package/templates/package.json +30 -55
  455. package/templates/pnpm-workspace.yaml +0 -3
  456. package/templates/project.yaml +1 -1
  457. package/templates/tsconfig.json +1 -37
  458. package/templates/apps/web/__tests__/auth/adversarial/cookie-attributes.test.ts +0 -94
  459. package/templates/apps/web/__tests__/auth/adversarial/oauth-state-parameter.test.ts +0 -75
  460. package/templates/apps/web/__tests__/auth/adversarial/redirect-uri-allowlist.test.ts +0 -82
  461. package/templates/apps/web/__tests__/auth/env-helpers.test.ts +0 -168
  462. package/templates/apps/web/__tests__/authority-list-routes.test.tsx +0 -208
  463. package/templates/apps/web/__tests__/better-stack.test.ts +0 -66
  464. package/templates/apps/web/__tests__/blog-dir-resolution.test.ts +0 -87
  465. package/templates/apps/web/__tests__/blog-source-populated.test.ts +0 -130
  466. package/templates/apps/web/__tests__/data-testid-coverage.test.tsx +0 -60
  467. package/templates/apps/web/__tests__/google-analytics.test.tsx +0 -104
  468. package/templates/apps/web/__tests__/i18n/middleware.test.ts +0 -119
  469. package/templates/apps/web/__tests__/i18n/routing.test.ts +0 -114
  470. package/templates/apps/web/__tests__/i18n/translations.test.ts +0 -191
  471. package/templates/apps/web/__tests__/json-ld.test.ts +0 -98
  472. package/templates/apps/web/__tests__/knowledge-events-routes.test.tsx +0 -580
  473. package/templates/apps/web/__tests__/layout-stealth.test.ts +0 -39
  474. package/templates/apps/web/__tests__/lighthouse-fixtures/improvement-image-shrink.tsx +0 -103
  475. package/templates/apps/web/__tests__/lighthouse-fixtures/override-fixture.md +0 -114
  476. package/templates/apps/web/__tests__/lighthouse-fixtures/regression-bloat.tsx +0 -94
  477. package/templates/apps/web/__tests__/page.test.tsx +0 -230
  478. package/templates/apps/web/__tests__/products-services-phase1.test.tsx +0 -321
  479. package/templates/apps/web/__tests__/projects-routes.test.tsx +0 -392
  480. package/templates/apps/web/__tests__/resources-downloads-integrations-phase2.test.tsx +0 -475
  481. package/templates/apps/web/__tests__/routes/ai-plugin-json.test.ts +0 -53
  482. package/templates/apps/web/__tests__/routes/blog-route.test.tsx +0 -191
  483. package/templates/apps/web/__tests__/routes/llms-txt.test.ts +0 -123
  484. package/templates/apps/web/__tests__/routes/robots-txt.test.ts +0 -52
  485. package/templates/apps/web/__tests__/routes/sitemap-xml.test.ts +0 -78
  486. package/templates/apps/web/__tests__/routes/well-known-mcp.test.ts +0 -203
  487. package/templates/apps/web/__tests__/section-routes.test.tsx +0 -693
  488. package/templates/apps/web/__tests__/security-headers.test.ts +0 -201
  489. package/templates/apps/web/__tests__/sentry-config.test.ts +0 -116
  490. package/templates/apps/web/__tests__/sitemap-locales.test.ts +0 -415
  491. package/templates/apps/web/__tests__/standalone-informational-routes.test.tsx +0 -844
  492. package/templates/apps/web/app/[locale]/__tests__/layout.test.tsx +0 -120
  493. package/templates/apps/web/app/[locale]/__tests__/page-renderer-migration.test.tsx +0 -202
  494. package/templates/apps/web/app/__tests__/error-boundaries.test.tsx +0 -152
  495. package/templates/apps/web/content/en/blog/index.mdx +0 -15
  496. package/templates/apps/web/content/en/blog/launching-ailk.mdx +0 -20
  497. package/templates/apps/web/content/en/docs/getting-started.mdx +0 -30
  498. package/templates/content/.gitkeep +0 -0
  499. package/templates/content/CLAUDE.md +0 -85
  500. package/templates/content/ar/HomePage/home.mdx +0 -123
  501. package/templates/content/ar/_site.mdx +0 -35
  502. package/templates/content/de/_site.mdx +0 -29
  503. package/templates/content/en/.gitkeep +0 -0
  504. package/templates/content/en/AboutPage/about.schema.json +0 -82
  505. package/templates/content/en/BookCall/book-call.mdx +0 -19
  506. package/templates/content/en/BookCall/book-call.schema.json +0 -121
  507. package/templates/content/en/BreadcrumbList/site-breadcrumbs.mdx +0 -20
  508. package/templates/content/en/CareersList/careers.mdx +0 -24
  509. package/templates/content/en/CaseStudiesList/case-studies.mdx +0 -22
  510. package/templates/content/en/CaseStudiesList/showcase.mdx +0 -8
  511. package/templates/content/en/CaseStudy/ailk-aeo-rollout.mdx +0 -32
  512. package/templates/content/en/CaseStudy/schema-builder-migration.mdx +0 -41
  513. package/templates/content/en/ClientsList/clients.mdx +0 -38
  514. package/templates/content/en/ContactPage/contact.schema.json +0 -100
  515. package/templates/content/en/ContactPoint/primary.mdx +0 -14
  516. package/templates/content/en/Course/aeo-fundamentals.mdx +0 -37
  517. package/templates/content/en/Course/schema-builder-workshop.mdx +0 -62
  518. package/templates/content/en/CoursesList/courses.mdx +0 -22
  519. package/templates/content/en/DownloadsList/downloads.mdx +0 -22
  520. package/templates/content/en/Event/aeo-office-hours-may-2026.mdx +0 -39
  521. package/templates/content/en/Event/ailk-launch-day-2026.mdx +0 -35
  522. package/templates/content/en/EventsList/events.mdx +0 -26
  523. package/templates/content/en/FAQPage/faq.schema.json +0 -231
  524. package/templates/content/en/GlossaryList/glossary.mdx +0 -19
  525. package/templates/content/en/GlossaryList/glossary.schema.json +0 -300
  526. package/templates/content/en/HomePage/home.schema.json +0 -88
  527. package/templates/content/en/HomePage/launch-service.mdx +0 -475
  528. package/templates/content/en/HomePage/launch-service.schema.json +0 -138
  529. package/templates/content/en/HowTo/add-mdx-content.mdx +0 -38
  530. package/templates/content/en/HowTo/configure-aeo-scoring.mdx +0 -35
  531. package/templates/content/en/HowTo/set-up-json-ld.mdx +0 -36
  532. package/templates/content/en/Integration/github-actions.mdx +0 -31
  533. package/templates/content/en/Integration/openai-api.mdx +0 -26
  534. package/templates/content/en/Integration/vercel.mdx +0 -32
  535. package/templates/content/en/IntegrationsList/integrations.mdx +0 -22
  536. package/templates/content/en/JobPosting/content-strategist.mdx +0 -46
  537. package/templates/content/en/JobPosting/developer-advocate.mdx +0 -47
  538. package/templates/content/en/JobPosting/senior-fullstack-engineer.mdx +0 -57
  539. package/templates/content/en/LandingPage/aeo-audit.mdx +0 -19
  540. package/templates/content/en/LandingPage/aeo-audit.schema.json +0 -92
  541. package/templates/content/en/LandingPage/agency-waitlist.mdx +0 -340
  542. package/templates/content/en/LandingPage/agency-waitlist.schema.json +0 -152
  543. package/templates/content/en/LandingPage/developers.mdx +0 -19
  544. package/templates/content/en/LandingPage/developers.schema.json +0 -109
  545. package/templates/content/en/LandingPage/for-agencies.mdx +0 -390
  546. package/templates/content/en/LandingPage/for-agencies.schema.json +0 -107
  547. package/templates/content/en/LandingPage/for-ai-search-agencies.mdx +0 -417
  548. package/templates/content/en/LandingPage/for-ai-search-agencies.schema.json +0 -105
  549. package/templates/content/en/LandingPage/for-businesses.mdx +0 -19
  550. package/templates/content/en/LandingPage/for-businesses.schema.json +0 -96
  551. package/templates/content/en/LandingPage/platform.mdx +0 -369
  552. package/templates/content/en/LandingPage/platform.schema.json +0 -166
  553. package/templates/content/en/LandingPage/vs-ai-website-builders.mdx +0 -19
  554. package/templates/content/en/LandingPage/vs-ai-website-builders.schema.json +0 -102
  555. package/templates/content/en/LandingPage/vs-wordpress.mdx +0 -19
  556. package/templates/content/en/LandingPage/vs-wordpress.schema.json +0 -53
  557. package/templates/content/en/NewsletterSignup/newsletter.mdx +0 -236
  558. package/templates/content/en/NewsletterSignup/newsletter.schema.json +0 -91
  559. package/templates/content/en/Organization/site-owner.mdx +0 -16
  560. package/templates/content/en/Partner/prisma.mdx +0 -31
  561. package/templates/content/en/Partner/supabase.mdx +0 -30
  562. package/templates/content/en/Partner/vercel.mdx +0 -28
  563. package/templates/content/en/PartnersList/partners.mdx +0 -22
  564. package/templates/content/en/Person/founder.mdx +0 -18
  565. package/templates/content/en/Pricing/pricing.mdx +0 -538
  566. package/templates/content/en/Pricing/pricing.schema.json +0 -209
  567. package/templates/content/en/PrivacyPage/privacy.mdx +0 -165
  568. package/templates/content/en/PrivacyPage/privacy.schema.json +0 -64
  569. package/templates/content/en/Product/ailk.mdx +0 -19
  570. package/templates/content/en/Product/ailk.schema.json +0 -94
  571. package/templates/content/en/Product/api-launch-kit.mdx +0 -26
  572. package/templates/content/en/Product/launch-kit.mdx +0 -28
  573. package/templates/content/en/ProductsList/products.mdx +0 -26
  574. package/templates/content/en/Project/ailk-phase-2.mdx +0 -54
  575. package/templates/content/en/ProjectsList/projects.mdx +0 -25
  576. package/templates/content/en/ResourceDetail/aeo-scoring-guide.mdx +0 -27
  577. package/templates/content/en/ResourceDetail/content-model-whitepaper.mdx +0 -28
  578. package/templates/content/en/ResourceDetail/schema-org-quick-reference.mdx +0 -39
  579. package/templates/content/en/ResourcesHub/resources.mdx +0 -22
  580. package/templates/content/en/Service/consulting.mdx +0 -22
  581. package/templates/content/en/Service/implementation.mdx +0 -30
  582. package/templates/content/en/Service/launch-service.mdx +0 -232
  583. package/templates/content/en/Service/launch.mdx +0 -228
  584. package/templates/content/en/ServicesList/services.mdx +0 -84
  585. package/templates/content/en/SoftwareProduct/ailk-aeo.mdx +0 -44
  586. package/templates/content/en/SoftwareProduct/ailk-content-adapters.mdx +0 -47
  587. package/templates/content/en/SoftwareProduct/ailk-schema.mdx +0 -49
  588. package/templates/content/en/TeamList/team.mdx +0 -63
  589. package/templates/content/en/TeamMember/founder.mdx +0 -72
  590. package/templates/content/en/TermsPage/terms.mdx +0 -19
  591. package/templates/content/en/TermsPage/terms.schema.json +0 -99
  592. package/templates/content/en/TestimonialsList/testimonials.mdx +0 -44
  593. package/templates/content/en/UseCasesList/use-cases.mdx +0 -30
  594. package/templates/content/en/Whitepaper/ax-first-product-development.mdx +0 -27
  595. package/templates/content/en/Whitepaper/open-core-commercial-strategy.mdx +0 -27
  596. package/templates/content/en/Whitepaper/structured-data-for-answer-engines.mdx +0 -31
  597. package/templates/content/en-XA/AboutPage/about.mdx +0 -8
  598. package/templates/content/en-XA/FAQPage/faq.mdx +0 -8
  599. package/templates/content/en-XA/HomePage/home.mdx +0 -8
  600. package/templates/content/es/_site.mdx +0 -30
  601. package/templates/content/fr/_site.mdx +0 -30
  602. package/templates/content/ja/_site.mdx +0 -30
  603. package/templates/content/pt-BR/AboutPage/about.mdx +0 -8
  604. package/templates/content/pt-BR/FAQPage/faq.mdx +0 -8
  605. package/templates/content/pt-BR/HomePage/home.mdx +0 -23
@@ -12,30 +12,139 @@
12
12
  import cors from '@fastify/cors';
13
13
  import rateLimit from '@fastify/rate-limit';
14
14
  import Fastify from 'fastify';
15
+ import type { FastifyPluginAsync, FastifyPluginCallback } from 'fastify';
15
16
 
16
17
  import { config } from './config/index.js';
18
+ import { isModuleEnabled } from './config/modules.js';
17
19
  import { registerErrorSerializer } from './lib/error-serializer.js';
18
20
  import { validateLeadCaptureDir } from './lib/lead-capture-store.js';
19
21
  import { assertSandboxKey } from './lib/stripe.js';
20
22
  import { authPreHandlerPlugin } from './middleware/auth.js';
21
- import { rateLimitMiddleware } from './middleware/rate-limit.js';
23
+ import {
24
+ rateLimitMiddleware,
25
+ DEFAULT_PER_IP_PER_MINUTE_STRICT,
26
+ } from './middleware/rate-limit.js';
22
27
  import { openapiRoutes } from './openapi/index.js';
28
+ import { exampleAeoRoute, scoreAeoRoute } from './routes/aeo/index.js';
23
29
  import { tokenRoutes } from './routes/auth/tokens.js';
24
30
  import { userRoutes } from './routes/auth/user.js';
25
31
  import { checkoutRoutes } from './routes/checkout/index.js';
26
- import { contentRoutes } from './routes/content/index.js';
32
+ import { getPageRoute } from './routes/content/get-page.js';
33
+ import { listPagesRoute } from './routes/content/list-pages.js';
34
+ import { listTypesRoute } from './routes/content/list-types.js';
27
35
  import {
28
36
  CONTENT_RATE_LIMIT_UNAUTH,
29
37
  CONTENT_RATE_LIMIT_WINDOW,
30
38
  } from './routes/content/rate-limit.js';
39
+ import { deliverableDownloadRoute } from './routes/deliverables/index.js';
40
+ import { flowCheckoutRoutes } from './routes/flow-checkouts/index.js';
41
+ import { getFlowAggregateRoute, getFlowRoute, submitFlowStepRoute } from './routes/flows/index.js';
42
+ import { checkoutRecommendationRoute, saveRecommendationRoute } from './routes/flows/recommender.js';
31
43
  import {
32
44
  leadCallbackRoute,
33
45
  leadSubmitRoute,
34
46
  leadSubscribeRoute,
35
47
  } from './routes/leads/index.js';
48
+ import {
49
+ projectListingDraftPatchRoute,
50
+ projectListingPublicRoute,
51
+ projectListingStartRoute,
52
+ projectListingSubmitRoute,
53
+ } from './routes/project-listings/index.js';
54
+ import { slackActionsRoute } from './routes/slack/index.js';
36
55
  import { registerTestAuthRoute, shouldMountTestAuth } from './routes/test/auth/session.js';
56
+ import { waitlistSignupRoutes } from './routes/waitlist-signups/index.js';
37
57
  import { webhooksRoutes } from './routes/webhooks/index.js';
38
58
 
59
+ /**
60
+ * Paid-module SLICE entry points, keyed by the export each branch needs
61
+ * (#5182).
62
+ *
63
+ * Every value here names a file the OSS strip removes. A shipping file may not
64
+ * name a stripped file in ANY import form (spec D1): `import()` defers
65
+ * EVALUATION, not RESOLUTION, so `tsc` resolves a string-literal specifier
66
+ * whether or not the `isModuleEnabled()` branch containing it can ever run. The
67
+ * ten literal `await import()` calls that used to sit at these call sites were
68
+ * therefore ten TS2307 errors on the public tree, and the static
69
+ * `./middleware/tenant.js` import was an eleventh — measured on a stripped
70
+ * tree, not argued.
71
+ *
72
+ * Reading the specifier from this table is what makes it non-literal at the
73
+ * call site, and that INDIRECTION — not the type of the value — is what defeats
74
+ * resolution. S1's `isModuleEnabled()` gate is unchanged and still decides
75
+ * whether the branch runs; `AILK_ENABLED_MODULES` unset still means every
76
+ * module on, so a default build registers exactly what it registered before.
77
+ *
78
+ * This mechanism is sound here because `apps/api` is a `tsc`-only surface with
79
+ * no bundler. It is NOT sound in `packages/ui`: webpack cannot statically
80
+ * analyse a non-literal `import()` either, and compiles it to an async context
81
+ * with no members, so the module silently fails to load on the tree that HAS
82
+ * it. See the note above the imports in `packages/ui/src/sections/SectionRenderer.tsx`.
83
+ *
84
+ * `./routes/project-listings/index.js` is deliberately absent: that barrel is a
85
+ * MIXED directory that ships (the free anonymous listing routes are registered
86
+ * from it statically at the top of this file), so its dynamic import at the
87
+ * tenant scope is a literal on purpose and resolves fine on both trees.
88
+ */
89
+ const SLICE_PLUGIN_SPECIFIERS = {
90
+ workspaceContextRoutes: './routes/workspaces/index.js',
91
+ workspaceSessionRoutes: './routes/workspaces/index.js',
92
+ sessionRoutes: './routes/workspaces/sessions.js',
93
+ workspaceConfigRoutes: './routes/workspaces/config.js',
94
+ billingRoutes: './routes/billing/index.js',
95
+ waitlistExperimentRoutes: './routes/waitlist-experiments/index.js',
96
+ createPageRoute: './routes/content/create.js',
97
+ updatePageRoute: './routes/content/update.js',
98
+ deletePageRoute: './routes/content/delete.js',
99
+ listAvailabilityRoute: './routes/schedule/index.js',
100
+ getEventMetaRoute: './routes/schedule/index.js',
101
+ createBookingRoute: './routes/schedule/index.js',
102
+ } satisfies Record<string, string>;
103
+
104
+ type SlicePluginName = keyof typeof SLICE_PLUGIN_SPECIFIERS;
105
+
106
+ /**
107
+ * Load one slice route plugin. Every entry above is a `FastifyPluginAsync`
108
+ * export, which is the cast's whole content — `import(nonLiteral)` yields
109
+ * `any`, so this boundary is the load-bearing line and names the exact shape
110
+ * rather than spreading `any` into `register()`.
111
+ *
112
+ * Throws rather than skipping if the export is missing: the branch only runs
113
+ * when the module is declared enabled, so an absent export is a build/packaging
114
+ * fault to surface at boot, not a condition to degrade through.
115
+ */
116
+ async function sliceRoutePlugin(
117
+ name: SlicePluginName,
118
+ ): Promise<FastifyPluginAsync> {
119
+ const specifier: string = SLICE_PLUGIN_SPECIFIERS[name];
120
+ const mod = (await import(specifier)) as Record<
121
+ string,
122
+ FastifyPluginAsync | undefined
123
+ >;
124
+ const plugin = mod[name];
125
+ if (!plugin) {
126
+ throw new Error(`slice export ${name} missing from ${specifier}`);
127
+ }
128
+ return plugin;
129
+ }
130
+
131
+ /**
132
+ * The multi-tenant preHandler plugin — the one slice entry that is not a
133
+ * route plugin. `FastifyPluginCallback`, registered with no options
134
+ * (apps/api/src/middleware/tenant.ts:83).
135
+ */
136
+ async function tenantPreHandlerSlicePlugin(): Promise<FastifyPluginCallback> {
137
+ const specifier: string = './middleware/tenant.js';
138
+ const mod = (await import(specifier)) as {
139
+ tenantPreHandlerPlugin?: FastifyPluginCallback;
140
+ };
141
+ const plugin = mod.tenantPreHandlerPlugin;
142
+ if (!plugin) {
143
+ throw new Error('slice export tenantPreHandlerPlugin missing from ' + specifier);
144
+ }
145
+ return plugin;
146
+ }
147
+
39
148
  /**
40
149
  * Build Fastify server instance (for serverless or standalone)
41
150
  * @returns Configured Fastify instance ready for requests
@@ -51,8 +160,31 @@ export async function build() {
51
160
  assertSandboxKey(config.STRIPE_SECRET_KEY);
52
161
  }
53
162
 
163
+ // trustProxy: true (#4730) — the Vercel serverless handler
164
+ // (apps/api/api/index.ts) bridges every request through Fastify's
165
+ // `.inject()` rather than a real socket, so `req.socket.remoteAddress`
166
+ // (the trustProxy:false default) is a meaningless simulated value, not
167
+ // the caller's address. With trustProxy enabled, req.ip instead resolves
168
+ // from `X-Forwarded-For` (the header Vercel's own edge sets on every
169
+ // inbound request) via Fastify's built-in proxy-addr parsing — reading
170
+ // the LEFTMOST address in a multi-hop chain, i.e. the address farthest
171
+ // from this process. This is what lets the per-scope rate limiter
172
+ // (middleware/rate-limit.ts) key on a real visitor's IP instead of a
173
+ // constant fallback or a shared intermediary's egress IP (see the flows/
174
+ // leads/aeo/schedule scopes below).
175
+ //
176
+ // Trade-off: X-Forwarded-For is caller-suppliable to anyone hitting this
177
+ // API directly (there is no fixed, allowlistable upstream proxy — this
178
+ // API's actual "proxies" are arbitrary consumer web functions), so a
179
+ // direct caller can still spoof a fresh identity per request. Per-IP
180
+ // rate limiting on these anonymous surfaces is a best-effort abuse
181
+ // deterrent, not a hard security boundary; this trades a small amount of
182
+ // spoof-resistance for correctness on the overwhelmingly common path
183
+ // (server-action-forwarded traffic), which was previously broken for
184
+ // every caller.
54
185
  const server = Fastify({
55
186
  logger: true,
187
+ trustProxy: true,
56
188
  });
57
189
 
58
190
  // Register error serializer — maps internal exceptions to generic strings
@@ -60,9 +192,14 @@ export async function build() {
60
192
  // never reach the client. Full detail still goes to pino at error level.
61
193
  registerErrorSerializer(server);
62
194
 
63
- // Register CORS — public read API + same-origin auth callers
195
+ // Register CORS — public read API + same-origin auth callers.
196
+ // With FRONTEND_URL unset: reflect any origin in dev/test (zero-config
197
+ // boot) but fail CLOSED in production — `origin: true` combined with
198
+ // `credentials: true` would let any website read credentialed responses
199
+ // (security review M1). `false` disables cross-origin access entirely;
200
+ // same-origin and non-browser callers are unaffected.
64
201
  await server.register(cors, {
65
- origin: config.FRONTEND_URL || true,
202
+ origin: config.FRONTEND_URL || config.NODE_ENV !== 'production',
66
203
  credentials: true,
67
204
  });
68
205
 
@@ -99,6 +236,8 @@ export async function build() {
99
236
  contentList: 'GET /v1/content/:type',
100
237
  contentPage: 'GET /v1/content/:type/:slug',
101
238
  checkoutSessions: 'POST /v1/checkout/sessions',
239
+ billing: 'GET /v1/billing',
240
+ billingPortalSession: 'POST /v1/billing/portal-session',
102
241
  },
103
242
  };
104
243
  });
@@ -112,11 +251,75 @@ export async function build() {
112
251
  });
113
252
  await authScope.register(tokenRoutes);
114
253
  await authScope.register(userRoutes);
254
+
255
+ // Tenant-context routes (multi-tenant module) — auth only. They
256
+ // establish/inspect the active workspace, so the tenant guard does not
257
+ // apply to them; each enforces membership in the service layer.
258
+ // Module-conditional (S1, #5088): without the multi-tenant module there
259
+ // is no workspace concept to switch or inspect.
260
+ if (isModuleEnabled('multi-tenant')) {
261
+ await authScope.register(await sliceRoutePlugin('workspaceContextRoutes'));
262
+ }
263
+
264
+ // Respondent signup read (#4731) — auth only, NOT tenant-guarded: a
265
+ // respondent has no workspace membership and the tenant guard is
266
+ // default-deny. Identity is request.userId; the service re-checks
267
+ // User.emailVerified before any Lead read.
268
+ await authScope.register(waitlistSignupRoutes);
269
+
270
+ // Respondent checkouts read (#4984) — the same posture as the signup
271
+ // read above: auth only, NOT tenant-guarded. Identity is request.userId;
272
+ // the only join is the lead-promotion link (never an email match).
273
+ await authScope.register(flowCheckoutRoutes);
274
+
275
+ // Tenant-guarded domain routes (multi-tenant module) — the tenant
276
+ // preHandler (default-deny guard, see middleware/tenant.ts) runs after
277
+ // auth for every route in this inner scope. No domain handler executes
278
+ // without request.tenant, and without the multi-tenant module there is
279
+ // no tenant concept at all — the whole scope is module-conditional
280
+ // (S1, #5088), so an OSS build that excludes multi-tenant registers
281
+ // none of it.
282
+ if (isModuleEnabled('multi-tenant')) {
283
+ await authScope.register(async (tenantScope) => {
284
+ await tenantScope.register(await tenantPreHandlerSlicePlugin());
285
+ await tenantScope.register(await sliceRoutePlugin('workspaceSessionRoutes'));
286
+ await tenantScope.register(await sliceRoutePlugin('sessionRoutes'));
287
+ await tenantScope.register(await sliceRoutePlugin('workspaceConfigRoutes'));
288
+ // Org-billing routes (#3701) — org-scoped read + Stripe customer-portal.
289
+ await tenantScope.register(await sliceRoutePlugin('billingRoutes'));
290
+ // Waitlist operator-dashboard read API (#4665 D7, B0) — tenant-scoped
291
+ // list/comparison/signups reads over A1's waitlist-experiment rows.
292
+ await tenantScope.register(
293
+ await sliceRoutePlugin('waitlistExperimentRoutes'),
294
+ );
295
+ // Project-listings dashboard (#4998) — tenant-scoped list/get/patch
296
+ // over the founder's-application-row lifecycle.
297
+ const { projectListingTenantRoutes } = await import(
298
+ './routes/project-listings/index.js'
299
+ );
300
+ await tenantScope.register(projectListingTenantRoutes);
301
+ });
302
+ }
115
303
  });
116
304
 
117
305
  // Public routes — no auth required.
118
- await server.register(contentRoutes);
306
+ await server.register(listTypesRoute);
307
+ await server.register(listPagesRoute);
308
+ await server.register(getPageRoute);
309
+ // Content-write routes (create/update/delete) — already Pro-tier gated at
310
+ // CALL time via requirePaidTier (apps/api/src/lib/require-paid-tier.ts);
311
+ // module-conditional at REGISTRATION too (S1, #5088) so an OSS build that
312
+ // excludes the content-write slice never wires the handler in at all. Not
313
+ // a MODULE_SLICES entry — see config/modules.ts.
314
+ if (isModuleEnabled('content-write')) {
315
+ await server.register(await sliceRoutePlugin('createPageRoute'));
316
+ await server.register(await sliceRoutePlugin('updatePageRoute'));
317
+ await server.register(await sliceRoutePlugin('deletePageRoute'));
318
+ }
119
319
  await server.register(checkoutRoutes);
320
+ // Deliverable download — a capability-token URL (#3961 D5); the token
321
+ // itself is the sole gate, so no auth preHandler applies.
322
+ await server.register(deliverableDownloadRoute);
120
323
 
121
324
  // Webhooks routes — raw-body parser scoped to this sub-router only so the
122
325
  // global JSON parser on all other routes is unaffected.
@@ -128,17 +331,100 @@ export async function build() {
128
331
  done(null, body);
129
332
  },
130
333
  );
334
+ // Slack's block_actions payload arrives as a urlencoded `payload` form
335
+ // field (#4999) — raw buffer here too, so the signature is verified over
336
+ // the EXACT bytes Slack signed, never a re-serialized parse.
337
+ webhooksScope.addContentTypeParser(
338
+ 'application/x-www-form-urlencoded',
339
+ { parseAs: 'buffer' },
340
+ (_req, body, done) => {
341
+ done(null, body);
342
+ },
343
+ );
131
344
  await webhooksScope.register(webhooksRoutes);
345
+ await webhooksScope.register(slackActionsRoute);
132
346
  });
133
347
 
134
- // Leads routes — rate-limit middleware scoped to this sub-router
348
+ // Leads routes — rate-limit middleware scoped to this sub-router. Own
349
+ // default (10/min, pre-#4730) rather than inheriting the wider
350
+ // flows-sized default (#5111, DEF-004 — #4730's shared-default bump was
351
+ // never meant to loosen abuse protection here).
135
352
  await server.register(async (leadsScope) => {
136
- leadsScope.register(rateLimitMiddleware);
353
+ leadsScope.register(rateLimitMiddleware, {
354
+ perIpPerMinute: DEFAULT_PER_IP_PER_MINUTE_STRICT,
355
+ });
137
356
  await leadsScope.register(leadSubmitRoute);
138
357
  await leadsScope.register(leadSubscribeRoute);
139
358
  await leadsScope.register(leadCallbackRoute);
359
+ // Project-listings anonymous surface (#4998, reshaped by #5036) — the
360
+ // three-operation draft lifecycle plus the public page-render read, all
361
+ // on the same rate-limited, identity-blind posture as the leads routes
362
+ // above.
363
+ //
364
+ // Do NOT read that rate limit as a bound on anonymous draft creation. It
365
+ // keys on `req.ip`, and `trustProxy` is on (see the note at the top of this
366
+ // file), so a caller reaching the API directly can vary
367
+ // `X-Forwarded-For` and get a fresh budget per request. That is a
368
+ // pre-existing property of the limiter, not of these routes; what these
369
+ // routes do is keep the cost of an unbounded call small — `start` writes
370
+ // one row and sends nothing, and the Lead write with its operator
371
+ // notification waits for `submit` (PR #5042 security review, finding 4).
372
+ await leadsScope.register(projectListingStartRoute);
373
+ await leadsScope.register(projectListingDraftPatchRoute);
374
+ await leadsScope.register(projectListingSubmitRoute);
375
+ await leadsScope.register(projectListingPublicRoute);
376
+ });
377
+
378
+ // Flows routes — anonymous surface; rate-limit middleware scoped to this
379
+ // sub-router, matching the leads scope above (#3956 D4 Clarifications:
380
+ // "follows whatever the existing anonymous /v1/leads/* routes do today").
381
+ // Keeps the wider, env-var-driven default (#4730 — see
382
+ // apps/api/src/routes/flows/README.md § Rate limit) — this is the ONE
383
+ // scope #4730's bump was actually sized for; unchanged by #5111.
384
+ await server.register(async (flowsScope) => {
385
+ flowsScope.register(rateLimitMiddleware);
386
+ await flowsScope.register(getFlowRoute);
387
+ await flowsScope.register(submitFlowStepRoute);
388
+ await flowsScope.register(getFlowAggregateRoute);
389
+ // The recommender's email-moment routes (#4841) — same anonymous,
390
+ // rate-limited posture as the three above.
391
+ await flowsScope.register(saveRecommendationRoute);
392
+ await flowsScope.register(checkoutRecommendationRoute);
393
+ });
394
+
395
+ // AEO score routes (#4666) — anonymous surface, same posture as the flows
396
+ // scope above: a waitlist respondent has no account. Rate-limited because
397
+ // each call fans out to the respondent's own site (an external fetch), the
398
+ // same reason the schedule scope below is rate-limited for a third party.
399
+ // Own default (10/min, pre-#4730) — see the leads scope's comment above
400
+ // (#5111, DEF-004).
401
+ await server.register(async (aeoScope) => {
402
+ aeoScope.register(rateLimitMiddleware, {
403
+ perIpPerMinute: DEFAULT_PER_IP_PER_MINUTE_STRICT,
404
+ });
405
+ await aeoScope.register(scoreAeoRoute);
406
+ await aeoScope.register(exampleAeoRoute);
140
407
  });
141
408
 
409
+ // Schedule routes (#4416) — anonymous surface, same posture as the flows
410
+ // and leads scopes above: a prospect booking a call has no account, and the
411
+ // calLink in the request names the event, so there is no tenant scope to
412
+ // bind. Rate-limited because each call fans out to a third-party provider.
413
+ // Own default (10/min, pre-#4730) — see the leads scope's comment above
414
+ // (#5111, DEF-004). Module-conditional (S1, #5088): the scheduling module
415
+ // owns this whole route set, so an OSS build that excludes it registers
416
+ // neither the routes nor their imports.
417
+ if (isModuleEnabled('scheduling')) {
418
+ await server.register(async (scheduleScope) => {
419
+ scheduleScope.register(rateLimitMiddleware, {
420
+ perIpPerMinute: DEFAULT_PER_IP_PER_MINUTE_STRICT,
421
+ });
422
+ await scheduleScope.register(await sliceRoutePlugin('listAvailabilityRoute'));
423
+ await scheduleScope.register(await sliceRoutePlugin('getEventMetaRoute'));
424
+ await scheduleScope.register(await sliceRoutePlugin('createBookingRoute'));
425
+ });
426
+ }
427
+
142
428
  // Test-auth route — triple-gated (NODE_ENV !== production AND
143
429
  // AILK_TEST_AUTH_ENABLED === 'true' AND AILK_TEST_AUTH_USER_ALLOWLIST
144
430
  // non-empty). When any gate fails, the route is never registered and