create-ailk 0.1.0 → 0.2.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 (620) hide show
  1. package/README.md +124 -3
  2. package/component-catalog.md +456 -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 +12 -5
  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 +78 -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 +241 -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 +558 -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 +869 -0
  115. package/templates/apps/api/src/routes/project-listings/__tests__/me-route-precedence.test.ts +221 -0
  116. package/templates/apps/api/src/routes/project-listings/__tests__/me.test.ts +468 -0
  117. package/templates/apps/api/src/routes/project-listings/__tests__/public.test.ts +424 -0
  118. package/templates/apps/api/src/routes/project-listings/__tests__/site-answers.test.ts +707 -0
  119. package/templates/apps/api/src/routes/project-listings/__tests__/site-key.test.ts +375 -0
  120. package/templates/apps/api/src/routes/project-listings/__tests__/structured-address.test.ts +467 -0
  121. package/templates/apps/api/src/routes/project-listings/__tests__/tenant-isolation.test.ts +566 -0
  122. package/templates/apps/api/src/routes/project-listings/get.ts +70 -0
  123. package/templates/apps/api/src/routes/project-listings/index.ts +120 -0
  124. package/templates/apps/api/src/routes/project-listings/list.ts +47 -0
  125. package/templates/apps/api/src/routes/project-listings/me.ts +76 -0
  126. package/templates/apps/api/src/routes/project-listings/patch-copy.ts +222 -0
  127. package/templates/apps/api/src/routes/project-listings/patch-draft.ts +97 -0
  128. package/templates/apps/api/src/routes/project-listings/patch.ts +136 -0
  129. package/templates/apps/api/src/routes/project-listings/public.ts +52 -0
  130. package/templates/apps/api/src/routes/project-listings/respond.ts +37 -0
  131. package/templates/apps/api/src/routes/project-listings/resume-token.ts +22 -0
  132. package/templates/apps/api/src/routes/project-listings/start.ts +106 -0
  133. package/templates/apps/api/src/routes/project-listings/submit.ts +122 -0
  134. package/templates/apps/api/src/routes/schedule/__tests__/index.test.ts +490 -0
  135. package/templates/apps/api/src/routes/schedule/index.ts +249 -0
  136. package/templates/apps/api/src/routes/slack/__tests__/actions.test.ts +385 -0
  137. package/templates/apps/api/src/routes/slack/actions.ts +177 -0
  138. package/templates/apps/api/src/routes/slack/index.ts +38 -0
  139. package/templates/apps/api/src/routes/test/auth/__tests__/session.test.ts +16 -6
  140. package/templates/apps/api/src/routes/test/auth/session.ts +8 -6
  141. package/templates/apps/api/src/routes/waitlist-experiments/__tests__/tenant-isolation.test.ts +577 -0
  142. package/templates/apps/api/src/routes/waitlist-experiments/comparison.ts +78 -0
  143. package/templates/apps/api/src/routes/waitlist-experiments/index.ts +41 -0
  144. package/templates/apps/api/src/routes/waitlist-experiments/list.ts +64 -0
  145. package/templates/apps/api/src/routes/waitlist-experiments/respond.ts +42 -0
  146. package/templates/apps/api/src/routes/waitlist-experiments/signup.ts +84 -0
  147. package/templates/apps/api/src/routes/waitlist-experiments/signups.ts +119 -0
  148. package/templates/apps/api/src/routes/waitlist-signups/__tests__/index.test.ts +238 -0
  149. package/templates/apps/api/src/routes/waitlist-signups/index.ts +101 -0
  150. package/templates/apps/api/src/routes/webhooks/README.md +35 -12
  151. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-flow-checkout.test.ts +315 -0
  152. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-org-billing.test.ts +270 -0
  153. package/templates/apps/api/src/routes/webhooks/stripe.ts +248 -20
  154. package/templates/apps/api/src/routes/workspaces/__tests__/config-tenant-isolation.test.ts +356 -0
  155. package/templates/apps/api/src/routes/workspaces/__tests__/tenant-isolation.test.ts +671 -0
  156. package/templates/apps/api/src/routes/workspaces/config.ts +125 -0
  157. package/templates/apps/api/src/routes/workspaces/index.ts +194 -0
  158. package/templates/apps/api/src/routes/workspaces/sessions.ts +218 -0
  159. package/templates/apps/api/src/server.ts +307 -7
  160. package/templates/apps/api/src/services/__tests__/abandon-email.test.ts +489 -0
  161. package/templates/apps/api/src/services/__tests__/aeo-score.test.ts +475 -0
  162. package/templates/apps/api/src/services/__tests__/answer-distributions.test.ts +132 -0
  163. package/templates/apps/api/src/services/__tests__/consent-migration.test.ts +65 -0
  164. package/templates/apps/api/src/services/__tests__/consent.test.ts +282 -0
  165. package/templates/apps/api/src/services/__tests__/deliverable-fulfillment.test.ts +523 -0
  166. package/templates/apps/api/src/services/__tests__/deliverable-resend.test.ts +359 -0
  167. package/templates/apps/api/src/services/__tests__/entitlements.test.ts +142 -0
  168. package/templates/apps/api/src/services/__tests__/flow-aggregate.test.ts +425 -0
  169. package/templates/apps/api/src/services/__tests__/flow-engine.test.ts +2840 -0
  170. package/templates/apps/api/src/services/__tests__/lead-promotion.test.ts +393 -0
  171. package/templates/apps/api/src/services/__tests__/lead-routing.test.ts +8 -8
  172. package/templates/apps/api/src/services/__tests__/listing-csv-sweep.test.ts +560 -0
  173. package/templates/apps/api/src/services/__tests__/listing-promotion.test.ts +684 -0
  174. package/templates/apps/api/src/services/__tests__/playbook-compile.test.ts +406 -0
  175. package/templates/apps/api/src/services/__tests__/playbook-render.test.ts +290 -0
  176. package/templates/apps/api/src/services/__tests__/project-listing-decision.test.ts +736 -0
  177. package/templates/apps/api/src/services/__tests__/project-listing-flow.test.ts +475 -0
  178. package/templates/apps/api/src/services/__tests__/project-listing-issue.test.ts +340 -0
  179. package/templates/apps/api/src/services/__tests__/recommender-capture.test.ts +983 -0
  180. package/templates/apps/api/src/services/__tests__/slack-notify.test.ts +278 -0
  181. package/templates/apps/api/src/services/__tests__/tenant-context-cascade.test.ts +71 -0
  182. package/templates/apps/api/src/services/__tests__/tenant-context.test.ts +379 -0
  183. package/templates/apps/api/src/services/__tests__/usage-aggregation.test.ts +941 -0
  184. package/templates/apps/api/src/services/__tests__/usage-credits.test.ts +588 -0
  185. package/templates/apps/api/src/services/__tests__/usage-metering.test.ts +768 -0
  186. package/templates/apps/api/src/services/__tests__/waitlist-dashboard.test.ts +1314 -0
  187. package/templates/apps/api/src/services/__tests__/waitlist-experiments.test.ts +341 -0
  188. package/templates/apps/api/src/services/__tests__/waitlist-followup.test.ts +567 -0
  189. package/templates/apps/api/src/services/__tests__/waitlist-scoring.test.ts +474 -0
  190. package/templates/apps/api/src/services/__tests__/waitlist-signups.test.ts +354 -0
  191. package/templates/apps/api/src/services/abandon-email.ts +307 -0
  192. package/templates/apps/api/src/services/aeo-score.ts +288 -0
  193. package/templates/apps/api/src/services/answer-distributions.ts +138 -0
  194. package/templates/apps/api/src/services/consent.ts +236 -0
  195. package/templates/apps/api/src/services/deliverable-fulfillment.ts +523 -0
  196. package/templates/apps/api/src/services/entitlements.ts +102 -0
  197. package/templates/apps/api/src/services/flow-aggregate.ts +232 -0
  198. package/templates/apps/api/src/services/flow-checkouts.ts +123 -0
  199. package/templates/apps/api/src/services/flow-engine.ts +1296 -0
  200. package/templates/apps/api/src/services/lead-promotion.ts +176 -0
  201. package/templates/apps/api/src/services/lead-routing.ts +3 -3
  202. package/templates/apps/api/src/services/listing-config.ts +102 -0
  203. package/templates/apps/api/src/services/listing-csv-sweep.ts +455 -0
  204. package/templates/apps/api/src/services/listing-promotion.ts +342 -0
  205. package/templates/apps/api/src/services/playbook-compile.ts +398 -0
  206. package/templates/apps/api/src/services/playbook-render.ts +263 -0
  207. package/templates/apps/api/src/services/project-listing-decision.ts +510 -0
  208. package/templates/apps/api/src/services/project-listing-flow.ts +426 -0
  209. package/templates/apps/api/src/services/project-listing-issue.ts +251 -0
  210. package/templates/apps/api/src/services/project-listings.ts +1472 -0
  211. package/templates/apps/api/src/services/recommender-capture.ts +835 -0
  212. package/templates/apps/api/src/services/scheduling/cal-provider.ts +392 -0
  213. package/templates/apps/api/src/services/scheduling/index.ts +63 -0
  214. package/templates/apps/api/src/services/scheduling/types.ts +88 -0
  215. package/templates/apps/api/src/services/slack-notify.ts +240 -0
  216. package/templates/apps/api/src/services/tenant-context.ts +451 -0
  217. package/templates/apps/api/src/services/usage-aggregation.ts +516 -0
  218. package/templates/apps/api/src/services/usage-credits.ts +340 -0
  219. package/templates/apps/api/src/services/usage-metering.ts +699 -0
  220. package/templates/apps/api/src/services/waitlist-dashboard.ts +947 -0
  221. package/templates/apps/api/src/services/waitlist-experiments.ts +213 -0
  222. package/templates/apps/api/src/services/waitlist-followup.ts +486 -0
  223. package/templates/apps/api/src/services/waitlist-scoring.ts +166 -0
  224. package/templates/apps/api/src/services/waitlist-signups.ts +165 -0
  225. package/templates/apps/api/src/vercel-handler.ts +165 -0
  226. package/templates/apps/api/tsconfig.json +0 -12
  227. package/templates/apps/mcp/CLAUDE.md +19 -9
  228. package/templates/apps/mcp/LICENSE +201 -0
  229. package/templates/apps/mcp/__tests__/create_page.test.ts +1 -0
  230. package/templates/apps/mcp/__tests__/delete_page.test.ts +1 -0
  231. package/templates/apps/mcp/__tests__/module-exclusion.test.ts +105 -0
  232. package/templates/apps/mcp/__tests__/parity.test.ts +70 -6
  233. package/templates/apps/mcp/__tests__/request_callback.test.ts +4 -4
  234. package/templates/apps/mcp/__tests__/schedule_tools.test.ts +242 -0
  235. package/templates/apps/mcp/__tests__/submit_lead.test.ts +4 -4
  236. package/templates/apps/mcp/__tests__/subscribe_newsletter.test.ts +4 -4
  237. package/templates/apps/mcp/__tests__/tools/purchase.test.ts +47 -0
  238. package/templates/apps/mcp/__tests__/update_page.test.ts +1 -0
  239. package/templates/apps/mcp/package.json +6 -4
  240. package/templates/apps/mcp/src/config/modules.ts +37 -0
  241. package/templates/apps/mcp/src/server.ts +109 -18
  242. package/templates/apps/mcp/src/tools/capture_lead.ts +1 -1
  243. package/templates/apps/mcp/src/tools/create_booking.ts +58 -0
  244. package/templates/apps/mcp/src/tools/create_page.ts +1 -0
  245. package/templates/apps/mcp/src/tools/delete_page.ts +1 -0
  246. package/templates/apps/mcp/src/tools/get_event_meta.ts +55 -0
  247. package/templates/apps/mcp/src/tools/get_flow.ts +61 -0
  248. package/templates/apps/mcp/src/tools/index.ts +25 -0
  249. package/templates/apps/mcp/src/tools/list_availability.ts +67 -0
  250. package/templates/apps/mcp/src/tools/purchase.ts +3 -0
  251. package/templates/apps/mcp/src/tools/submit_flow_step.ts +83 -0
  252. package/templates/apps/mcp/src/tools/update_page.ts +1 -0
  253. package/templates/apps/mcp/tsconfig.json +1 -9
  254. package/templates/apps/web/.env.example +44 -0
  255. package/templates/apps/web/CLAUDE.md +28 -0
  256. package/templates/apps/web/LICENSE +201 -0
  257. package/templates/apps/web/__tests__/__mocks__/code-highlight.jest-stub.ts +24 -0
  258. package/templates/apps/web/__tests__/__mocks__/next-intl-server.ts +33 -0
  259. package/templates/apps/web/__tests__/__mocks__/next-intl.ts +18 -0
  260. package/templates/apps/web/__tests__/__mocks__/server-only.ts +13 -0
  261. package/templates/apps/web/__tests__/__mocks__/style-mock.js +4 -0
  262. package/templates/apps/web/__tests__/__mocks__/vercel-analytics-server.ts +9 -0
  263. package/templates/apps/web/__tests__/jest-support/import-meta-transformer.cjs +90 -0
  264. package/templates/apps/web/__tests__/setup.ts +22 -32
  265. package/templates/apps/web/app/.well-known/ai-plugin.json/route.ts +6 -3
  266. package/templates/apps/web/app/.well-known/mcp.json/build-manifest.ts +8 -2
  267. package/templates/apps/web/app/[locale]/(authed)/account/__tests__/page.test.tsx +260 -0
  268. package/templates/apps/web/app/[locale]/(authed)/account/page.tsx +263 -0
  269. package/templates/apps/web/app/[locale]/(authed)/account/sign-out-button.tsx +39 -0
  270. package/templates/apps/web/app/[locale]/(authed)/layout.tsx +54 -0
  271. package/templates/apps/web/app/[locale]/(authed)/sign-in-gate.tsx +96 -0
  272. package/templates/apps/web/app/[locale]/(authed)/waitlist/[experimentId]/page.tsx +309 -0
  273. package/templates/apps/web/app/[locale]/(authed)/waitlist/[experimentId]/signups/[leadId]/page.tsx +149 -0
  274. package/templates/apps/web/app/[locale]/(authed)/waitlist/__tests__/comparison.test.tsx +273 -0
  275. package/templates/apps/web/app/[locale]/(authed)/waitlist/__tests__/gate.test.tsx +172 -0
  276. package/templates/apps/web/app/[locale]/(authed)/waitlist/__tests__/list.test.tsx +171 -0
  277. package/templates/apps/web/app/[locale]/(authed)/waitlist/__tests__/signup.test.tsx +179 -0
  278. package/templates/apps/web/app/[locale]/(authed)/waitlist/components/ExperimentsTable.tsx +116 -0
  279. package/templates/apps/web/app/[locale]/(authed)/waitlist/components/ForbiddenState.tsx +24 -0
  280. package/templates/apps/web/app/[locale]/(authed)/waitlist/components/OfferFunnelTable.tsx +66 -0
  281. package/templates/apps/web/app/[locale]/(authed)/waitlist/components/RollupTicker.tsx +61 -0
  282. package/templates/apps/web/app/[locale]/(authed)/waitlist/components/ScoreTrace.tsx +114 -0
  283. package/templates/apps/web/app/[locale]/(authed)/waitlist/components/SignupsTable.tsx +139 -0
  284. package/templates/apps/web/app/[locale]/(authed)/waitlist/components/WaitlistComparisonTabs.tsx +85 -0
  285. package/templates/apps/web/app/[locale]/(authed)/waitlist/components/status-badges.tsx +67 -0
  286. package/templates/apps/web/app/[locale]/(authed)/waitlist/format.ts +111 -0
  287. package/templates/apps/web/app/[locale]/(authed)/waitlist/page.tsx +179 -0
  288. package/templates/apps/web/app/[locale]/about/page.tsx +10 -1
  289. package/templates/apps/web/app/[locale]/blog/[[...slug]]/page.tsx +6 -1
  290. package/templates/apps/web/app/[locale]/careers/[slug]/page.tsx +9 -0
  291. package/templates/apps/web/app/[locale]/careers/__tests__/page-renderer-migration.test.tsx +3 -3
  292. package/templates/apps/web/app/[locale]/careers/page.tsx +9 -1
  293. package/templates/apps/web/app/[locale]/case-studies/[slug]/page.tsx +9 -0
  294. package/templates/apps/web/app/[locale]/case-studies/__tests__/page-renderer-migration.test.tsx +3 -3
  295. package/templates/apps/web/app/[locale]/case-studies/page.tsx +13 -1
  296. package/templates/apps/web/app/[locale]/clients/__tests__/page-renderer-migration.test.tsx +11 -1
  297. package/templates/apps/web/app/[locale]/clients/page.tsx +9 -1
  298. package/templates/apps/web/app/[locale]/contact/ContactForm.tsx +21 -1
  299. package/templates/apps/web/app/[locale]/contact/ConversationalIntakeWrapper.tsx +188 -0
  300. package/templates/apps/web/app/[locale]/contact/__tests__/ConversationalIntakeWrapper.test.tsx +242 -0
  301. package/templates/apps/web/app/[locale]/contact/__tests__/contact.actions.test.ts +29 -0
  302. package/templates/apps/web/app/[locale]/contact/__tests__/intake-analytics.test.ts +51 -0
  303. package/templates/apps/web/app/[locale]/contact/__tests__/page-renderer-migration.test.tsx +39 -15
  304. package/templates/apps/web/app/[locale]/contact/contact.actions.ts +21 -3
  305. package/templates/apps/web/app/[locale]/contact/intake-analytics.ts +49 -0
  306. package/templates/apps/web/app/[locale]/contact/intake-script.ts +66 -0
  307. package/templates/apps/web/app/[locale]/contact/page.tsx +14 -4
  308. package/templates/apps/web/app/[locale]/courses/[slug]/page.tsx +13 -1
  309. package/templates/apps/web/app/[locale]/courses/__tests__/page-renderer-migration.test.tsx +3 -3
  310. package/templates/apps/web/app/[locale]/courses/page.tsx +9 -1
  311. package/templates/apps/web/app/[locale]/docs/[[...slug]]/page.tsx +1 -0
  312. package/templates/apps/web/app/[locale]/downloads/__tests__/page-renderer-migration.test.tsx +11 -1
  313. package/templates/apps/web/app/[locale]/downloads/page.tsx +13 -1
  314. package/templates/apps/web/app/[locale]/events/[slug]/page.tsx +9 -0
  315. package/templates/apps/web/app/[locale]/events/__tests__/page-renderer-migration.test.tsx +12 -2
  316. package/templates/apps/web/app/[locale]/events/page.tsx +9 -1
  317. package/templates/apps/web/app/[locale]/faq/page.tsx +10 -1
  318. package/templates/apps/web/app/[locale]/flows/[slug]/FlowStepperClient.tsx +265 -0
  319. package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/FlowStepperClient.permalink.test.tsx +445 -0
  320. package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/FlowStepperClient.test.tsx +341 -0
  321. package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/checkout.actions.test.ts +287 -0
  322. package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/flow.actions.test.ts +302 -0
  323. package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/two-route-tool.test.tsx +128 -0
  324. package/templates/apps/web/app/[locale]/flows/[slug]/checkout.actions.ts +254 -0
  325. package/templates/apps/web/app/[locale]/flows/[slug]/flow.actions.ts +144 -0
  326. package/templates/apps/web/app/[locale]/flows/[slug]/page.tsx +108 -0
  327. package/templates/apps/web/app/[locale]/flows/[slug]/results/[payload]/ResultsClient.tsx +532 -0
  328. package/templates/apps/web/app/[locale]/flows/[slug]/results/[payload]/ResultsEmailStep.tsx +121 -0
  329. package/templates/apps/web/app/[locale]/flows/[slug]/results/[payload]/__tests__/ResultsClient.checkout.test.tsx +457 -0
  330. package/templates/apps/web/app/[locale]/flows/[slug]/results/[payload]/__tests__/page.test.tsx +396 -0
  331. package/templates/apps/web/app/[locale]/flows/[slug]/results/[payload]/page.tsx +114 -0
  332. package/templates/apps/web/app/[locale]/flows/[slug]/start/page.tsx +52 -0
  333. package/templates/apps/web/app/[locale]/how-to/[slug]/page.tsx +13 -1
  334. package/templates/apps/web/app/[locale]/how-to/__tests__/page-renderer-migration.test.tsx +1 -1
  335. package/templates/apps/web/app/[locale]/integrations/[slug]/page.tsx +9 -0
  336. package/templates/apps/web/app/[locale]/integrations/__tests__/page-renderer-migration.test.tsx +3 -3
  337. package/templates/apps/web/app/[locale]/integrations/page.tsx +13 -1
  338. package/templates/apps/web/app/[locale]/launch-service/page.tsx +14 -1
  339. package/templates/apps/web/app/[locale]/layout.tsx +127 -16
  340. package/templates/apps/web/app/[locale]/page.tsx +10 -1
  341. package/templates/apps/web/app/[locale]/partners/[slug]/page.tsx +9 -0
  342. package/templates/apps/web/app/[locale]/partners/__tests__/page-renderer-migration.test.tsx +3 -3
  343. package/templates/apps/web/app/[locale]/partners/page.tsx +9 -1
  344. package/templates/apps/web/app/[locale]/products/[slug]/page.tsx +9 -0
  345. package/templates/apps/web/app/[locale]/products/__tests__/page-renderer-migration.test.tsx +3 -3
  346. package/templates/apps/web/app/[locale]/products/page.tsx +9 -1
  347. package/templates/apps/web/app/[locale]/projects/[slug]/page.tsx +13 -1
  348. package/templates/apps/web/app/[locale]/projects/__tests__/page-renderer-migration.test.tsx +10 -0
  349. package/templates/apps/web/app/[locale]/projects/apply/ListingApplicationClient.tsx +110 -0
  350. package/templates/apps/web/app/[locale]/projects/apply/__tests__/ListingApplicationClient.test.tsx +96 -0
  351. package/templates/apps/web/app/[locale]/projects/page.tsx +13 -1
  352. package/templates/apps/web/app/[locale]/resources/[slug]/page.tsx +9 -0
  353. package/templates/apps/web/app/[locale]/resources/__tests__/page-renderer-migration.test.tsx +12 -2
  354. package/templates/apps/web/app/[locale]/resources/page.tsx +13 -1
  355. package/templates/apps/web/app/[locale]/schedule/__tests__/page.test.tsx +117 -0
  356. package/templates/apps/web/app/[locale]/schedule/confirmed/__tests__/page.test.tsx +96 -0
  357. package/templates/apps/web/app/[locale]/schedule/confirmed/page.tsx +92 -0
  358. package/templates/apps/web/app/[locale]/schedule/page.tsx +82 -0
  359. package/templates/apps/web/app/[locale]/services/[slug]/page.tsx +9 -0
  360. package/templates/apps/web/app/[locale]/services/__tests__/page-renderer-migration.test.tsx +3 -3
  361. package/templates/apps/web/app/[locale]/services/page.tsx +9 -1
  362. package/templates/apps/web/app/[locale]/sign-in/__tests__/next-path.test.ts +31 -0
  363. package/templates/apps/web/app/[locale]/sign-in/__tests__/page.test.tsx +152 -0
  364. package/templates/apps/web/app/[locale]/sign-in/next-path.ts +0 -0
  365. package/templates/apps/web/app/[locale]/sign-in/page.tsx +83 -0
  366. package/templates/apps/web/app/[locale]/sign-in/sign-in-card.tsx +123 -0
  367. package/templates/apps/web/app/[locale]/software/[slug]/page.tsx +13 -1
  368. package/templates/apps/web/app/[locale]/software/__tests__/page-renderer-migration.test.tsx +1 -1
  369. package/templates/apps/web/app/[locale]/tech-articles/[slug]/page.tsx +13 -1
  370. package/templates/apps/web/app/[locale]/tech-articles/__tests__/page-renderer-migration.test.tsx +1 -1
  371. package/templates/apps/web/app/[locale]/testimonials/__tests__/page-renderer-migration.test.tsx +11 -1
  372. package/templates/apps/web/app/[locale]/testimonials/page.tsx +13 -1
  373. package/templates/apps/web/app/[locale]/thanks/[slug]/__tests__/page.test.tsx +93 -0
  374. package/templates/apps/web/app/[locale]/thanks/[slug]/page.tsx +48 -0
  375. package/templates/apps/web/app/[locale]/use-cases/__tests__/page-renderer-migration.test.tsx +11 -1
  376. package/templates/apps/web/app/[locale]/use-cases/page.tsx +13 -1
  377. package/templates/apps/web/app/[locale]/whitepapers/[slug]/page.tsx +13 -1
  378. package/templates/apps/web/app/[locale]/whitepapers/__tests__/page-renderer-migration.test.tsx +1 -1
  379. package/templates/apps/web/app/globals.css +35 -0
  380. package/templates/apps/web/app/llms.txt/route.ts +2 -1
  381. package/templates/apps/web/app/og/route.tsx +10 -2
  382. package/templates/apps/web/auth.ts +8 -0
  383. package/templates/apps/web/components/sign-out-trigger.tsx +42 -0
  384. package/templates/apps/web/content/en/blog/README.txt +25 -0
  385. package/templates/apps/web/content/en/docs/index.mdx +28 -0
  386. package/templates/apps/web/jest.config.cjs +90 -27
  387. package/templates/apps/web/lib/__tests__/site-brand.test.ts +119 -0
  388. package/templates/apps/web/lib/__tests__/site-theme.test.ts +112 -0
  389. package/templates/apps/web/lib/__tests__/structured-data.test.tsx +499 -0
  390. package/templates/apps/web/lib/account-config.ts +13 -0
  391. package/templates/apps/web/lib/server-api.ts +85 -0
  392. package/templates/apps/web/lib/site-brand.tsx +121 -0
  393. package/templates/apps/web/lib/site-theme.ts +74 -0
  394. package/templates/apps/web/messages/en.json +275 -7
  395. package/templates/apps/web/middleware.ts +11 -3
  396. package/templates/apps/web/next.config.mjs +8 -2
  397. package/templates/apps/web/package.json +17 -7
  398. package/templates/apps/web/postcss.config.mjs +23 -0
  399. package/templates/apps/web/public/.well-known/security.txt +3 -3
  400. package/templates/apps/web/src/lib/routes.ts +15 -2
  401. package/templates/apps/web/tsconfig.json +1 -16
  402. package/templates/content/_site.mdx +36 -25
  403. package/templates/content/en/AboutPage/about.mdx +24 -14
  404. package/templates/content/en/ContactPage/contact.mdx +23 -14
  405. package/templates/content/en/FAQPage/faq.mdx +10 -392
  406. package/templates/content/en/HomePage/home.mdx +14 -285
  407. package/templates/database/CHANGELOG.md +443 -0
  408. package/templates/database/LICENSE +201 -0
  409. package/templates/database/README.md +3 -1
  410. package/templates/database/__tests__/flows-listing-diagnostic.test.ts +392 -0
  411. package/templates/database/__tests__/flows-presets.test.ts +173 -0
  412. package/templates/database/__tests__/prefixed-ids.db.test.ts +146 -0
  413. package/templates/database/__tests__/seed.test.ts +88 -0
  414. package/templates/database/__tests__/user-cascade.test.ts +19 -4
  415. package/templates/database/auth/schema.prisma +521 -0
  416. package/templates/database/config/schema.prisma +234 -0
  417. package/templates/database/content/schema.prisma +263 -0
  418. package/templates/database/flows/listing-diagnostic.ts +182 -0
  419. package/templates/database/flows/presets.ts +315 -0
  420. package/templates/database/inbox/__tests__/schema.test.ts +4 -0
  421. package/templates/database/inbox/schema.prisma +574 -3
  422. package/templates/database/jest.config.cjs +8 -0
  423. package/templates/database/migrations/20260712215647_add_multi_tenant_tenancy/migration.sql +201 -0
  424. package/templates/database/migrations/20260713143320_reanchor_site_config_to_workspace/migration.sql +67 -0
  425. package/templates/database/migrations/20260713174000_add_audit_logs/migration.sql +46 -0
  426. package/templates/database/migrations/20260713190000_drop_telemetry_records/migration.sql +25 -0
  427. package/templates/database/migrations/20260713192000_add_uuidv7_function/migration.sql +49 -0
  428. package/templates/database/migrations/20260713192429_prefixed_uuid_entity_ids/migration.sql +197 -0
  429. package/templates/database/migrations/20260713200000_add_org_billing/migration.sql +32 -0
  430. package/templates/database/migrations/20260714000000_add_lead_promotion_fields/migration.sql +22 -0
  431. package/templates/database/migrations/20260714010000_add_usage_billing_content_models/migration.sql +151 -0
  432. package/templates/database/migrations/20260714020000_add_usage_billing_auth_config_models/migration.sql +223 -0
  433. package/templates/database/migrations/20260714030000_credit_balance_non_negative/migration.sql +22 -0
  434. package/templates/database/migrations/20260714030000_widen_usage_billing_report_aggregates/migration.sql +32 -0
  435. package/templates/database/migrations/20260810233516_add_flow_engine_models/migration.sql +40 -0
  436. package/templates/database/migrations/20260811020000_add_flow_session_abandon_email_columns/migration.sql +4 -0
  437. package/templates/database/migrations/20260811030000_add_flow_session_abandon_email_index/migration.sql +2 -0
  438. package/templates/database/migrations/20260811040000_add_flow_session_segment/migration.sql +2 -0
  439. package/templates/database/migrations/20260811050000_add_deliverable_models/migration.sql +29 -0
  440. package/templates/database/migrations/20260812000000_add_deliverable_grant_send_columns/migration.sql +6 -0
  441. package/templates/database/migrations/20260902222948_add_waitlist_experiment_models/migration.sql +39 -0
  442. package/templates/database/migrations/20260902224500_add_waitlist_id_format_checks/migration.sql +24 -0
  443. package/templates/database/migrations/20260903004112_add_flow_session_flags_aeo_score/migration.sql +3 -0
  444. package/templates/database/migrations/20260903010000_add_playbook_instance/migration.sql +33 -0
  445. package/templates/database/migrations/20260904000000_add_waitlist_followup_send/migration.sql +30 -0
  446. package/templates/database/migrations/20260905230000_add_flow_checkout/migration.sql +47 -0
  447. package/templates/database/migrations/20260906000000_add_flow_checkout_idempotency/migration.sql +16 -0
  448. package/templates/database/migrations/20260907120000_add_project_listing/migration.sql +47 -0
  449. package/templates/database/migrations/20260907130000_add_project_listing_slack_columns/migration.sql +10 -0
  450. package/templates/database/migrations/20260907180000_add_listing_csv_send/migration.sql +26 -0
  451. package/templates/database/migrations/20260909120000_project_listings_platform/migration.sql +90 -0
  452. package/templates/database/migrations/20260909180000_listing_draft_and_fields/migration.sql +174 -0
  453. package/templates/database/migrations/20260910120000_listing_public_site_key/migration.sql +14 -0
  454. package/templates/database/migrations/20260911120000_listing_copy_edit_audit/migration.sql +25 -0
  455. package/templates/database/migrations/20260911140000_listing_structured_address/migration.sql +32 -0
  456. package/templates/database/migrations/20260911180000_consent_grants/migration.sql +71 -0
  457. package/templates/database/migrations/20260911200000_listing_site_answers/migration.sql +30 -0
  458. package/templates/database/migrations/20260912120000_listing_owner_link/migration.sql +49 -0
  459. package/templates/database/ops/schema.prisma +27 -0
  460. package/templates/database/package.json +42 -4
  461. package/templates/database/prisma.config.ts +1 -1
  462. package/templates/database/schema.prisma +19 -435
  463. package/templates/database/seed-test.ts +14 -4
  464. package/templates/database/seed.ts +148 -0
  465. package/templates/database/tenancy.ts +45 -0
  466. package/templates/database/tsconfig.flows.json +15 -0
  467. package/templates/database/tsconfig.json +7 -1
  468. package/templates/database/tsconfig.tenancy.json +14 -0
  469. package/templates/package.json +30 -55
  470. package/templates/pnpm-workspace.yaml +0 -3
  471. package/templates/project.yaml +1 -1
  472. package/templates/tsconfig.json +1 -37
  473. package/templates/apps/web/__tests__/auth/adversarial/cookie-attributes.test.ts +0 -94
  474. package/templates/apps/web/__tests__/auth/adversarial/oauth-state-parameter.test.ts +0 -75
  475. package/templates/apps/web/__tests__/auth/adversarial/redirect-uri-allowlist.test.ts +0 -82
  476. package/templates/apps/web/__tests__/auth/env-helpers.test.ts +0 -168
  477. package/templates/apps/web/__tests__/authority-list-routes.test.tsx +0 -208
  478. package/templates/apps/web/__tests__/better-stack.test.ts +0 -66
  479. package/templates/apps/web/__tests__/blog-dir-resolution.test.ts +0 -87
  480. package/templates/apps/web/__tests__/blog-source-populated.test.ts +0 -130
  481. package/templates/apps/web/__tests__/data-testid-coverage.test.tsx +0 -60
  482. package/templates/apps/web/__tests__/google-analytics.test.tsx +0 -104
  483. package/templates/apps/web/__tests__/i18n/middleware.test.ts +0 -119
  484. package/templates/apps/web/__tests__/i18n/routing.test.ts +0 -114
  485. package/templates/apps/web/__tests__/i18n/translations.test.ts +0 -191
  486. package/templates/apps/web/__tests__/json-ld.test.ts +0 -98
  487. package/templates/apps/web/__tests__/knowledge-events-routes.test.tsx +0 -580
  488. package/templates/apps/web/__tests__/layout-stealth.test.ts +0 -39
  489. package/templates/apps/web/__tests__/lighthouse-fixtures/improvement-image-shrink.tsx +0 -103
  490. package/templates/apps/web/__tests__/lighthouse-fixtures/override-fixture.md +0 -114
  491. package/templates/apps/web/__tests__/lighthouse-fixtures/regression-bloat.tsx +0 -94
  492. package/templates/apps/web/__tests__/page.test.tsx +0 -230
  493. package/templates/apps/web/__tests__/products-services-phase1.test.tsx +0 -321
  494. package/templates/apps/web/__tests__/projects-routes.test.tsx +0 -392
  495. package/templates/apps/web/__tests__/resources-downloads-integrations-phase2.test.tsx +0 -475
  496. package/templates/apps/web/__tests__/routes/ai-plugin-json.test.ts +0 -53
  497. package/templates/apps/web/__tests__/routes/blog-route.test.tsx +0 -191
  498. package/templates/apps/web/__tests__/routes/llms-txt.test.ts +0 -123
  499. package/templates/apps/web/__tests__/routes/robots-txt.test.ts +0 -52
  500. package/templates/apps/web/__tests__/routes/sitemap-xml.test.ts +0 -78
  501. package/templates/apps/web/__tests__/routes/well-known-mcp.test.ts +0 -203
  502. package/templates/apps/web/__tests__/section-routes.test.tsx +0 -693
  503. package/templates/apps/web/__tests__/security-headers.test.ts +0 -201
  504. package/templates/apps/web/__tests__/sentry-config.test.ts +0 -116
  505. package/templates/apps/web/__tests__/sitemap-locales.test.ts +0 -415
  506. package/templates/apps/web/__tests__/standalone-informational-routes.test.tsx +0 -844
  507. package/templates/apps/web/app/[locale]/__tests__/layout.test.tsx +0 -120
  508. package/templates/apps/web/app/[locale]/__tests__/page-renderer-migration.test.tsx +0 -202
  509. package/templates/apps/web/app/__tests__/error-boundaries.test.tsx +0 -152
  510. package/templates/apps/web/content/en/blog/index.mdx +0 -15
  511. package/templates/apps/web/content/en/blog/launching-ailk.mdx +0 -20
  512. package/templates/apps/web/content/en/docs/getting-started.mdx +0 -30
  513. package/templates/content/.gitkeep +0 -0
  514. package/templates/content/CLAUDE.md +0 -85
  515. package/templates/content/ar/HomePage/home.mdx +0 -123
  516. package/templates/content/ar/_site.mdx +0 -35
  517. package/templates/content/de/_site.mdx +0 -29
  518. package/templates/content/en/.gitkeep +0 -0
  519. package/templates/content/en/AboutPage/about.schema.json +0 -82
  520. package/templates/content/en/BookCall/book-call.mdx +0 -19
  521. package/templates/content/en/BookCall/book-call.schema.json +0 -121
  522. package/templates/content/en/BreadcrumbList/site-breadcrumbs.mdx +0 -20
  523. package/templates/content/en/CareersList/careers.mdx +0 -24
  524. package/templates/content/en/CaseStudiesList/case-studies.mdx +0 -22
  525. package/templates/content/en/CaseStudiesList/showcase.mdx +0 -8
  526. package/templates/content/en/CaseStudy/ailk-aeo-rollout.mdx +0 -32
  527. package/templates/content/en/CaseStudy/schema-builder-migration.mdx +0 -41
  528. package/templates/content/en/ClientsList/clients.mdx +0 -38
  529. package/templates/content/en/ContactPage/contact.schema.json +0 -100
  530. package/templates/content/en/ContactPoint/primary.mdx +0 -14
  531. package/templates/content/en/Course/aeo-fundamentals.mdx +0 -37
  532. package/templates/content/en/Course/schema-builder-workshop.mdx +0 -62
  533. package/templates/content/en/CoursesList/courses.mdx +0 -22
  534. package/templates/content/en/DownloadsList/downloads.mdx +0 -22
  535. package/templates/content/en/Event/aeo-office-hours-may-2026.mdx +0 -39
  536. package/templates/content/en/Event/ailk-launch-day-2026.mdx +0 -35
  537. package/templates/content/en/EventsList/events.mdx +0 -26
  538. package/templates/content/en/FAQPage/faq.schema.json +0 -231
  539. package/templates/content/en/GlossaryList/glossary.mdx +0 -19
  540. package/templates/content/en/GlossaryList/glossary.schema.json +0 -300
  541. package/templates/content/en/HomePage/home.schema.json +0 -88
  542. package/templates/content/en/HomePage/launch-service.mdx +0 -475
  543. package/templates/content/en/HomePage/launch-service.schema.json +0 -138
  544. package/templates/content/en/HowTo/add-mdx-content.mdx +0 -38
  545. package/templates/content/en/HowTo/configure-aeo-scoring.mdx +0 -35
  546. package/templates/content/en/HowTo/set-up-json-ld.mdx +0 -36
  547. package/templates/content/en/Integration/github-actions.mdx +0 -31
  548. package/templates/content/en/Integration/openai-api.mdx +0 -26
  549. package/templates/content/en/Integration/vercel.mdx +0 -32
  550. package/templates/content/en/IntegrationsList/integrations.mdx +0 -22
  551. package/templates/content/en/JobPosting/content-strategist.mdx +0 -46
  552. package/templates/content/en/JobPosting/developer-advocate.mdx +0 -47
  553. package/templates/content/en/JobPosting/senior-fullstack-engineer.mdx +0 -57
  554. package/templates/content/en/LandingPage/aeo-audit.mdx +0 -19
  555. package/templates/content/en/LandingPage/aeo-audit.schema.json +0 -92
  556. package/templates/content/en/LandingPage/agency-waitlist.mdx +0 -340
  557. package/templates/content/en/LandingPage/agency-waitlist.schema.json +0 -152
  558. package/templates/content/en/LandingPage/developers.mdx +0 -19
  559. package/templates/content/en/LandingPage/developers.schema.json +0 -109
  560. package/templates/content/en/LandingPage/for-agencies.mdx +0 -390
  561. package/templates/content/en/LandingPage/for-agencies.schema.json +0 -107
  562. package/templates/content/en/LandingPage/for-ai-search-agencies.mdx +0 -417
  563. package/templates/content/en/LandingPage/for-ai-search-agencies.schema.json +0 -105
  564. package/templates/content/en/LandingPage/for-businesses.mdx +0 -19
  565. package/templates/content/en/LandingPage/for-businesses.schema.json +0 -96
  566. package/templates/content/en/LandingPage/platform.mdx +0 -369
  567. package/templates/content/en/LandingPage/platform.schema.json +0 -166
  568. package/templates/content/en/LandingPage/vs-ai-website-builders.mdx +0 -19
  569. package/templates/content/en/LandingPage/vs-ai-website-builders.schema.json +0 -102
  570. package/templates/content/en/LandingPage/vs-wordpress.mdx +0 -19
  571. package/templates/content/en/LandingPage/vs-wordpress.schema.json +0 -53
  572. package/templates/content/en/NewsletterSignup/newsletter.mdx +0 -236
  573. package/templates/content/en/NewsletterSignup/newsletter.schema.json +0 -91
  574. package/templates/content/en/Organization/site-owner.mdx +0 -16
  575. package/templates/content/en/Partner/prisma.mdx +0 -31
  576. package/templates/content/en/Partner/supabase.mdx +0 -30
  577. package/templates/content/en/Partner/vercel.mdx +0 -28
  578. package/templates/content/en/PartnersList/partners.mdx +0 -22
  579. package/templates/content/en/Person/founder.mdx +0 -18
  580. package/templates/content/en/Pricing/pricing.mdx +0 -538
  581. package/templates/content/en/Pricing/pricing.schema.json +0 -209
  582. package/templates/content/en/PrivacyPage/privacy.mdx +0 -165
  583. package/templates/content/en/PrivacyPage/privacy.schema.json +0 -64
  584. package/templates/content/en/Product/ailk.mdx +0 -19
  585. package/templates/content/en/Product/ailk.schema.json +0 -94
  586. package/templates/content/en/Product/api-launch-kit.mdx +0 -26
  587. package/templates/content/en/Product/launch-kit.mdx +0 -28
  588. package/templates/content/en/ProductsList/products.mdx +0 -26
  589. package/templates/content/en/Project/ailk-phase-2.mdx +0 -54
  590. package/templates/content/en/ProjectsList/projects.mdx +0 -25
  591. package/templates/content/en/ResourceDetail/aeo-scoring-guide.mdx +0 -27
  592. package/templates/content/en/ResourceDetail/content-model-whitepaper.mdx +0 -28
  593. package/templates/content/en/ResourceDetail/schema-org-quick-reference.mdx +0 -39
  594. package/templates/content/en/ResourcesHub/resources.mdx +0 -22
  595. package/templates/content/en/Service/consulting.mdx +0 -22
  596. package/templates/content/en/Service/implementation.mdx +0 -30
  597. package/templates/content/en/Service/launch-service.mdx +0 -232
  598. package/templates/content/en/Service/launch.mdx +0 -228
  599. package/templates/content/en/ServicesList/services.mdx +0 -84
  600. package/templates/content/en/SoftwareProduct/ailk-aeo.mdx +0 -44
  601. package/templates/content/en/SoftwareProduct/ailk-content-adapters.mdx +0 -47
  602. package/templates/content/en/SoftwareProduct/ailk-schema.mdx +0 -49
  603. package/templates/content/en/TeamList/team.mdx +0 -63
  604. package/templates/content/en/TeamMember/founder.mdx +0 -72
  605. package/templates/content/en/TermsPage/terms.mdx +0 -19
  606. package/templates/content/en/TermsPage/terms.schema.json +0 -99
  607. package/templates/content/en/TestimonialsList/testimonials.mdx +0 -44
  608. package/templates/content/en/UseCasesList/use-cases.mdx +0 -30
  609. package/templates/content/en/Whitepaper/ax-first-product-development.mdx +0 -27
  610. package/templates/content/en/Whitepaper/open-core-commercial-strategy.mdx +0 -27
  611. package/templates/content/en/Whitepaper/structured-data-for-answer-engines.mdx +0 -31
  612. package/templates/content/en-XA/AboutPage/about.mdx +0 -8
  613. package/templates/content/en-XA/FAQPage/faq.mdx +0 -8
  614. package/templates/content/en-XA/HomePage/home.mdx +0 -8
  615. package/templates/content/es/_site.mdx +0 -30
  616. package/templates/content/fr/_site.mdx +0 -30
  617. package/templates/content/ja/_site.mdx +0 -30
  618. package/templates/content/pt-BR/AboutPage/about.mdx +0 -8
  619. package/templates/content/pt-BR/FAQPage/faq.mdx +0 -8
  620. package/templates/content/pt-BR/HomePage/home.mdx +0 -23
@@ -0,0 +1,166 @@
1
+ /**
2
+ * @file waitlist-scoring.ts
3
+ * @description The Prisma-touching glue for the rules-layer scoring engine —
4
+ * A2 (#4662 D6).
5
+ *
6
+ * `scoreCompletedSignup` is the ONE `prisma.waitlistScore.upsert` write path
7
+ * in `apps/api` — one row per (lead, EXPERIMENT), re-scoring overwrites,
8
+ * never appends (A1 D3, scoped per experiment by #5036 D6d: a visitor who
9
+ * joins two founders' waitlists is one lead with two scores, and a
10
+ * lead-only key let the second silently erase the first). It loads the owning `WaitlistExperiment`, parses its config,
11
+ * evaluates via the pure `@working-theory/validation` evaluator, and
12
+ * persists the result. Every failure mode (no experiment row, an invalid
13
+ * config, an evaluator throw, a Prisma error) returns a typed outcome — it
14
+ * never throws to its caller (`flow-engine.ts`'s `completeSubmission`, which
15
+ * wraps the call in its own fail-soft try/catch as a residual net).
16
+ *
17
+ * PII boundary: logs carry only `{siteId, experimentKey, leadId, kind}` —
18
+ * never an answer value or the assembled payload (mirrors
19
+ * `waitlist-experiments.ts` / `flow-engine.ts`'s boundary).
20
+ */
21
+
22
+ import type { Prisma } from "@working-theory/database";
23
+ import { logger } from "@working-theory/observability";
24
+ import {
25
+ answersFromPayload,
26
+ evaluateWaitlistScoring,
27
+ waitlistExperimentConfigSchema,
28
+ type WaitlistFlags,
29
+ } from "@working-theory/validation";
30
+
31
+ import { prisma } from "../lib/prisma.js";
32
+
33
+ import { compileAndStorePlaybook, TARGETING_MATURITY_EXPERIMENT_KEY } from "./playbook-compile.js";
34
+
35
+ // ─── Types ────────────────────────────────────────────────────────────────────
36
+
37
+ export type ScoreCompletedSignupInput = {
38
+ siteId: string;
39
+ leadId: string;
40
+ experimentKey: string;
41
+ waitlistKey: string;
42
+ payload: Record<string, unknown>;
43
+ flags?: WaitlistFlags;
44
+ };
45
+
46
+ export type ScoreCompletedSignupSkipReason = "no_experiment" | "no_scoring";
47
+ export type ScoreCompletedSignupErrorKind =
48
+ | "invalid_config"
49
+ | "evaluation_failed"
50
+ | "persist_failed";
51
+
52
+ export type ScoreCompletedSignupResult =
53
+ | { ok: true; tier: string }
54
+ | { ok: true; skipped: ScoreCompletedSignupSkipReason }
55
+ | { ok: false; error: { kind: ScoreCompletedSignupErrorKind } };
56
+
57
+ function errKindOf(err: unknown): string {
58
+ return err instanceof Error ? err.constructor.name : typeof err;
59
+ }
60
+
61
+ // ─── scoreCompletedSignup — the ONE write path (D6) ─────────────────────────
62
+
63
+ /**
64
+ * Load the `[siteId, experimentKey]` `WaitlistExperiment`, evaluate the
65
+ * signup's answers against its `scoring` register (when declared), and
66
+ * upsert exactly one `WaitlistScore` row on `[leadId]`.
67
+ */
68
+ export async function scoreCompletedSignup(
69
+ input: ScoreCompletedSignupInput,
70
+ ): Promise<ScoreCompletedSignupResult> {
71
+ const { siteId, leadId, experimentKey, waitlistKey, payload, flags } = input;
72
+
73
+ const row = await prisma.waitlistExperiment.findUnique({
74
+ where: { siteId_key: { siteId, key: experimentKey } },
75
+ });
76
+ if (!row) {
77
+ return { ok: true, skipped: "no_experiment" };
78
+ }
79
+
80
+ const parsed = waitlistExperimentConfigSchema.safeParse(row.config);
81
+ if (!parsed.success) {
82
+ logger.error(
83
+ { siteId, experimentKey, leadId, kind: "invalid_config" },
84
+ "[waitlist-scoring] experiment config failed validation (defensive — the row was validated on write)",
85
+ );
86
+ return { ok: false, error: { kind: "invalid_config" } };
87
+ }
88
+ const config = parsed.data;
89
+ if (!config.scoring) {
90
+ return { ok: true, skipped: "no_scoring" };
91
+ }
92
+
93
+ const answers = answersFromPayload(config.questionSet, payload);
94
+ let evaluation;
95
+ try {
96
+ evaluation = evaluateWaitlistScoring(config.scoring, answers, flags ?? {});
97
+ } catch (err) {
98
+ logger.error(
99
+ { siteId, experimentKey, leadId, kind: "evaluation_failed", errKind: errKindOf(err) },
100
+ "[waitlist-scoring] evaluation failed",
101
+ );
102
+ return { ok: false, error: { kind: "evaluation_failed" } };
103
+ }
104
+
105
+ let scoreRow;
106
+ try {
107
+ scoreRow = await prisma.waitlistScore.upsert({
108
+ where: { leadId_experimentKey: { leadId, experimentKey } },
109
+ create: {
110
+ siteId,
111
+ leadId,
112
+ experimentKey,
113
+ waitlistKey,
114
+ tier: evaluation.tier,
115
+ score: evaluation.score,
116
+ categoryScores: evaluation.categoryScores as unknown as Prisma.InputJsonValue,
117
+ ruleTrace: evaluation.ruleTrace as unknown as Prisma.InputJsonValue,
118
+ },
119
+ update: {
120
+ tier: evaluation.tier,
121
+ score: evaluation.score,
122
+ categoryScores: evaluation.categoryScores as unknown as Prisma.InputJsonValue,
123
+ ruleTrace: evaluation.ruleTrace as unknown as Prisma.InputJsonValue,
124
+ },
125
+ });
126
+ } catch (err) {
127
+ logger.error(
128
+ { siteId, experimentKey, leadId, kind: "persist_failed", errKind: errKindOf(err) },
129
+ "[waitlist-scoring] persist failed",
130
+ );
131
+ return { ok: false, error: { kind: "persist_failed" } };
132
+ }
133
+
134
+ // FEAT-074 U4a (#4715): the compile is the next link in this ONE write
135
+ // path (D4) — gated on experimentKey, fail-soft internally
136
+ // (compileAndStorePlaybook never throws by contract). The try/catch here
137
+ // is the residual safety net (mirrors flow-engine.ts's own "swallowed by
138
+ // design" fulfillment guard) — the score row above is ALREADY persisted,
139
+ // so a genuine escape here must never turn this already-successful score
140
+ // into a thrown failure this function's own header promises it never does.
141
+ if (experimentKey === TARGETING_MATURITY_EXPERIMENT_KEY) {
142
+ try {
143
+ await compileAndStorePlaybook({
144
+ siteId,
145
+ leadId,
146
+ experimentKey,
147
+ scoreId: scoreRow.id,
148
+ tier: evaluation.tier,
149
+ ruleTrace: evaluation.ruleTrace,
150
+ });
151
+ } catch (err) {
152
+ logger.error(
153
+ {
154
+ siteId,
155
+ experimentKey,
156
+ leadId,
157
+ kind: "playbook_compile_escaped",
158
+ errKind: errKindOf(err),
159
+ },
160
+ "[waitlist-scoring] compileAndStorePlaybook escaped its own fail-soft catch — the score is unaffected",
161
+ );
162
+ }
163
+ }
164
+
165
+ return { ok: true, tier: evaluation.tier };
166
+ }
@@ -0,0 +1,165 @@
1
+ /**
2
+ * @file waitlist-signups.ts
3
+ * @description The respondent read (#4731 D2/D3/D4) — `readMySignup`, the
4
+ * ONLY read path behind `GET /v1/waitlist-signups/me`: a signed-in,
5
+ * email-verified user reads their OWN newest waitlist signup for one
6
+ * experiment. Nothing here enumerates, nothing accepts an email, nothing
7
+ * reads across sites.
8
+ *
9
+ * Mirrors `lead-promotion.ts` (ADR 0009 D3 service-layer pattern): the same
10
+ * `User {id, email, emailVerified}` read, the same verified-email refusal
11
+ * (D2 there — the consent basis for linking anonymous-lead PII to a user;
12
+ * here a hard 403, evaluated BEFORE any Lead read), and a scalar-only join
13
+ * to the inbox namespace by email — `Lead` carries no `@relation` (ADR 0009
14
+ * invariant #1), so the read is four narrow queries, each scoped to
15
+ * `currentSiteId()` (#4665 D3: the scope is a parameter of every query,
16
+ * never a post-filter).
17
+ *
18
+ * Email normalization (#4731 D3, the contract's open question): the
19
+ * respondent email is persisted AS TYPED — `flow-engine.ts`'s
20
+ * `extractMappedEmail` and `lead-routing.ts`'s `persistToDb` neither trim
21
+ * nor lower-case it (the boundary validator `z.string().email()` already
22
+ * rejects surrounding whitespace). So the match is `lower(trim())` on both
23
+ * sides: `equals` on the trimmed, lower-cased user email with
24
+ * `mode: "insensitive"` for the stored value.
25
+ *
26
+ * PII boundary: logs carry only `{ siteId, experimentKey, leadId, kind }` —
27
+ * never email, payload, or an answer value.
28
+ */
29
+
30
+ import { logger } from "@working-theory/observability";
31
+ import {
32
+ aeoScoreResultSchema,
33
+ type WaitlistSignupMeResponse,
34
+ } from "@working-theory/validation";
35
+
36
+ import { prisma } from "../lib/prisma.js";
37
+ import { currentSiteId } from "../lib/site.js";
38
+
39
+ // ─── Types ────────────────────────────────────────────────────────────────────
40
+
41
+ export type ReadMySignupResult =
42
+ | { ok: true; value: WaitlistSignupMeResponse }
43
+ | {
44
+ ok: false;
45
+ error: {
46
+ kind: "not_found_user" | "email_unverified" | "signup_not_found";
47
+ message: string;
48
+ };
49
+ };
50
+
51
+ // ─── Helpers ──────────────────────────────────────────────────────────────────
52
+
53
+ /** A string-valued payload key, or undefined when absent / not a string. */
54
+ function readPayloadString(payload: unknown, key: string): string | undefined {
55
+ if (payload === null || typeof payload !== "object" || Array.isArray(payload)) return undefined;
56
+ const value = (payload as Record<string, unknown>)[key];
57
+ return typeof value === "string" ? value : undefined;
58
+ }
59
+
60
+ /** A schema-defensive read of the stored `FlowSession.aeoScore` JSON value (mirrors flow-engine.ts). */
61
+ function readAeoScore(value: unknown): WaitlistSignupMeResponse["aeoScore"] {
62
+ if (value === null || value === undefined) return null;
63
+ const parsed = aeoScoreResultSchema.safeParse(value);
64
+ return parsed.success ? parsed.data : null;
65
+ }
66
+
67
+ const SIGNUP_NOT_FOUND: ReadMySignupResult = {
68
+ ok: false,
69
+ error: { kind: "signup_not_found", message: "Signup not found" },
70
+ };
71
+
72
+ // ─── Main export ──────────────────────────────────────────────────────────────
73
+
74
+ /**
75
+ * Read the calling user's newest signup for `experimentKey` at the current
76
+ * site. `userId` is the auth preHandler's `request.userId` — the ONLY
77
+ * identity input; `experimentKey` is boundary-validated by the route.
78
+ *
79
+ * Result kinds (the route maps them to HTTP):
80
+ * - `not_found_user` — no `User` row for `userId` (404 on the wire).
81
+ * - `email_unverified` — `User.emailVerified !== true`; refused BEFORE any
82
+ * Lead read (403).
83
+ * - `signup_not_found` — no `Lead` at this site with this user's email and
84
+ * this `experimentKey` (or a corrupt row missing
85
+ * `waitlistKey`) (404).
86
+ */
87
+ export async function readMySignup(
88
+ userId: string,
89
+ experimentKey: string,
90
+ ): Promise<ReadMySignupResult> {
91
+ const siteId = currentSiteId();
92
+
93
+ // D2 — the exact read lead-promotion.ts performs, mirrored not forked.
94
+ const user = await prisma.user.findUnique({
95
+ where: { id: userId },
96
+ select: { id: true, email: true, emailVerified: true },
97
+ });
98
+ if (!user) {
99
+ return { ok: false, error: { kind: "not_found_user", message: "User not found" } };
100
+ }
101
+
102
+ // D2 — the verified-email gate is a service-level invariant: an unverified
103
+ // address never reaches a Lead read, whatever the call site.
104
+ if (user.emailVerified !== true) {
105
+ return {
106
+ ok: false,
107
+ error: { kind: "email_unverified", message: "Verify your email to view your signup" },
108
+ };
109
+ }
110
+
111
+ // D3 — lower(trim()) on both sides; D4 — scoped, newest wins.
112
+ const lead = await prisma.lead.findFirst({
113
+ where: {
114
+ siteId,
115
+ email: { equals: user.email.trim().toLowerCase(), mode: "insensitive" },
116
+ payload: { path: ["experimentKey"], equals: experimentKey },
117
+ },
118
+ orderBy: { createdAt: "desc" },
119
+ select: { id: true, payload: true, createdAt: true },
120
+ });
121
+ if (!lead) return SIGNUP_NOT_FOUND;
122
+
123
+ // `waitlistKey` is server-written LAST beside `experimentKey` (flow-engine
124
+ // D4) — a lead carrying one without the other is corrupt data, treated as
125
+ // not-found rather than emitting an out-of-contract value (the
126
+ // waitlist-dashboard.ts `getSignup` posture, PR #4687).
127
+ const waitlistKey = readPayloadString(lead.payload, "waitlistKey");
128
+ if (!waitlistKey) {
129
+ logger.warn(
130
+ { siteId, experimentKey, leadId: lead.id, kind: "missing_waitlist_key" },
131
+ "[waitlist-signups] signup missing waitlistKey — treating as not_found",
132
+ );
133
+ return SIGNUP_NOT_FOUND;
134
+ }
135
+
136
+ // D4 — `@@unique([leadId, experimentKey])` (#5036 D6d); the scope ANDed in,
137
+ // never a post-filter.
138
+ const scoreRow = await prisma.waitlistScore.findFirst({
139
+ where: { leadId: lead.id, siteId, experimentKey },
140
+ select: { tier: true, score: true },
141
+ });
142
+
143
+ // D4 — the completing session (leadId is stamped in the same completion
144
+ // call that created the lead). Fallback to Lead.createdAt if absent (D5).
145
+ const session = await prisma.flowSession.findFirst({
146
+ where: { leadId: lead.id, siteId, completedAt: { not: null } },
147
+ orderBy: { completedAt: "desc" },
148
+ select: { aeoScore: true, completedAt: true },
149
+ });
150
+
151
+ // D5 — seven fields, nothing more. `waitlistKey` and `q3` are the ONLY
152
+ // payload keys that leave the row.
153
+ return {
154
+ ok: true,
155
+ value: {
156
+ experimentKey,
157
+ waitlistKey,
158
+ completedAt: (session?.completedAt ?? lead.createdAt).toISOString(),
159
+ tier: scoreRow?.tier ?? null,
160
+ score: scoreRow?.score ?? null,
161
+ aeoScore: readAeoScore(session?.aeoScore),
162
+ answers: { q3: readPayloadString(lead.payload, "q3") ?? null },
163
+ },
164
+ };
165
+ }
@@ -0,0 +1,165 @@
1
+ /**
2
+ * Vercel Serverless Function Handler for Customer Template Backend
3
+ * This file wraps the Fastify server for Vercel's serverless functions
4
+ */
5
+
6
+ import type { VercelRequest, VercelResponse } from '@vercel/node';
7
+ import { logger } from '@working-theory/observability';
8
+ import type { InjectOptions } from 'fastify';
9
+
10
+ import type { build as buildServer } from './server.js';
11
+
12
+ type FastifyServer = Awaited<ReturnType<typeof buildServer>>;
13
+
14
+ // Import the build function from server
15
+ async function getBuildFunction(): Promise<typeof buildServer> {
16
+ try {
17
+ const srcModule = await import('./server.js');
18
+ logger.info('[Vercel Handler] Using server from src/server.js');
19
+ return srcModule.build;
20
+ } catch (srcError) {
21
+ logger.error(
22
+ {
23
+ err: srcError instanceof Error ? srcError.message : String(srcError),
24
+ stack: srcError instanceof Error ? srcError.stack : undefined,
25
+ },
26
+ '[Vercel Handler] Failed to import server',
27
+ );
28
+ throw new Error(`Cannot find server module: ${srcError instanceof Error ? srcError.message : String(srcError)}`, { cause: srcError });
29
+ }
30
+ }
31
+
32
+ // Initialize build function
33
+ const buildPromise = getBuildFunction();
34
+ let serverInstance: FastifyServer | null = null;
35
+
36
+ /**
37
+ * Get or create the Fastify server instance
38
+ */
39
+ async function getServer() {
40
+ if (!serverInstance) {
41
+ logger.info('[Vercel Handler] Building server instance...');
42
+ const startTime = Date.now();
43
+
44
+ try {
45
+ const buildTimeout = new Promise<never>((_, reject) => {
46
+ setTimeout(() => reject(new Error('Server build timeout after 10s')), 10000);
47
+ });
48
+
49
+ const build = await Promise.race([buildPromise, buildTimeout]);
50
+ logger.info('[Vercel Handler] Build function obtained, creating server...');
51
+
52
+ const initTimeout = new Promise<never>((_, reject) => {
53
+ setTimeout(() => reject(new Error('Server initialization timeout after 10s')), 10000);
54
+ });
55
+
56
+ serverInstance = await Promise.race([build(), initTimeout]);
57
+
58
+ const buildTime = Date.now() - startTime;
59
+ logger.info({ buildTime }, '[Vercel Handler] Server built successfully');
60
+ } catch (error) {
61
+ const buildTime = Date.now() - startTime;
62
+ logger.error({ err: error, buildTime }, '[Vercel Handler] Failed to build server');
63
+ throw new Error(`Server build failed: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
64
+ }
65
+ }
66
+ return serverInstance;
67
+ }
68
+
69
+ /**
70
+ * Vercel serverless function handler
71
+ */
72
+ export default async function handler(
73
+ req: VercelRequest,
74
+ res: VercelResponse
75
+ ): Promise<void> {
76
+ const timeout = setTimeout(() => {
77
+ if (!res.headersSent) {
78
+ logger.error('[Vercel Handler] Request timeout');
79
+ res.status(504).json({
80
+ error: 'Gateway Timeout',
81
+ message: 'Request took too long to process',
82
+ });
83
+ }
84
+ }, 25000);
85
+
86
+ try {
87
+ logger.info({ method: req.method, url: req.url }, '[Vercel Handler] Starting request');
88
+
89
+ const server = await getServer();
90
+
91
+ const url = new URL(req.url || '/', 'http://localhost');
92
+ const pathname = url.pathname;
93
+
94
+ logger.info({ method: req.method, pathname }, '[Vercel Handler] Processing request');
95
+
96
+ // Strip content-length/content-encoding before forwarding. Both
97
+ // describe the ORIGINAL byte stream the client sent; req.body here is
98
+ // already the PARSED object, and light-my-request re-serializes it
99
+ // itself. It only computes a fresh content-length when the header is
100
+ // absent (`req.headers['content-length'] = req.headers['content-length']
101
+ // || ...`), so a stale header survives and Fastify's own content-length
102
+ // check rejects any body whose re-serialized length differs from the
103
+ // original — e.g. pretty-printed JSON or a trailing newline
104
+ // (FST_ERR_CTP_INVALID_CONTENT_LENGTH, #5168). Matched case-insensitively
105
+ // since header casing isn't guaranteed, even though Node lower-cases
106
+ // incoming header names in practice.
107
+ const forwardedHeaders = { ...req.headers } as Record<string, string>;
108
+ for (const key of Object.keys(forwardedHeaders)) {
109
+ if (key.toLowerCase() === 'content-length' || key.toLowerCase() === 'content-encoding') {
110
+ delete forwardedHeaders[key];
111
+ }
112
+ }
113
+
114
+ const fastifyRequest = {
115
+ method: req.method || 'GET',
116
+ url: pathname,
117
+ headers: forwardedHeaders,
118
+ body: req.body,
119
+ query: req.query as Record<string, string>,
120
+ };
121
+
122
+ const response = await server.inject(fastifyRequest as InjectOptions);
123
+
124
+ logger.info({ status: response.statusCode }, '[Vercel Handler] Response status');
125
+
126
+ clearTimeout(timeout);
127
+
128
+ res.status(response.statusCode);
129
+
130
+ Object.entries(response.headers).forEach(([key, value]) => {
131
+ if (value !== undefined && !res.headersSent) {
132
+ const headerValue = Array.isArray(value)
133
+ ? value.map((v) => String(v)).join(', ')
134
+ : String(value);
135
+ res.setHeader(key, headerValue);
136
+ }
137
+ });
138
+
139
+ if (!res.getHeader('Content-Type') && !res.headersSent) {
140
+ res.setHeader('Content-Type', 'application/json');
141
+ }
142
+
143
+ if (!res.headersSent) {
144
+ // Forward the raw bytes light-my-request kept alongside `.body` — the
145
+ // decoded-as-UTF-8-string form corrupts any non-UTF-8 response (a
146
+ // generated PDF, any binary payload) by replacing every invalid byte
147
+ // with U+FFFD before it reaches the wire (salessmyth/samhenry#199).
148
+ // `rawPayload` is byte-identical to what Fastify sent regardless of
149
+ // content type, so this also covers the JSON case unchanged.
150
+ res.send(response.rawPayload);
151
+ logger.info('[Vercel Handler] Response sent successfully');
152
+ }
153
+ } catch (error) {
154
+ clearTimeout(timeout);
155
+
156
+ logger.error({ err: error }, '[Vercel Handler] Error handling request');
157
+
158
+ if (!res.headersSent) {
159
+ res.status(500).json({
160
+ error: 'Internal Server Error',
161
+ message: error instanceof Error ? error.message : String(error),
162
+ });
163
+ }
164
+ }
165
+ }
@@ -18,17 +18,5 @@
18
18
  "**/__tests__/**",
19
19
  "**/*.test.ts",
20
20
  "**/*.spec.ts"
21
- ],
22
- "references": [
23
- { "path": "../../packages/analytics" },
24
- { "path": "../../packages/common" },
25
- { "path": "../../packages/content-adapters" },
26
- { "path": "../../packages/content-projection" },
27
- { "path": "../../packages/email" },
28
- { "path": "../../packages/license" },
29
- { "path": "../../packages/observability" },
30
- { "path": "../../packages/schema" },
31
- { "path": "../../packages/stripe-client" },
32
- { "path": "../../packages/validation" }
33
21
  ]
34
22
  }
@@ -20,23 +20,25 @@ Every tool maps 1:1 to an `apps/api` endpoint. When you change a tool, change th
20
20
 
21
21
  <!-- SOFT_LOCK_OK: doc clarification for issue #2238 — explaining 14 vs 15 vs 18 tool counts in CLAUDE.md (no code or signature changes) -->
22
22
 
23
- ## The 14 OSS tools (enabled at launch)
23
+ ## The free anonymous tools (enabled at launch)
24
24
 
25
25
  **Read (9):** `list_pages`, `read_content`, `search_content`, `get_site_info`, `get_business_hours`, `get_locations`, `get_offerings`, `get_pricing`, `get_faq`
26
26
  **Conversion-write (3):** `capture_lead`, `subscribe_newsletter`, `request_callback`
27
27
  **Maintenance (2):** `audit`, `scaffold`
28
+ **Flow (2):** `get_flow`, `submit_flow_step`
29
+ **Booking (3):** `list_availability`, `get_event_meta`, `create_booking`
28
30
 
29
- ### Why the catalog reports 18 and the server registers 17
31
+ ### Why the catalog reports 23 and the server registers 22
30
32
 
31
- - **18 in the catalog / parity test**: the `TOOLS` array in
32
- `packages/metadata/src/mcp-tool-catalog.ts` defines 18 tools; the parity
33
- test's `tools.size === 18` assertion counts that full catalog.
34
- - **17 registered at runtime**: `createMcpServer` (`apps/mcp/src/server.ts`)
33
+ - **23 in the catalog / parity test**: the `TOOLS` array in
34
+ `packages/metadata/src/mcp-tool-catalog.ts` defines 23 tools; the parity
35
+ test counts that full catalog.
36
+ - **22 registered at runtime**: `createMcpServer` (`apps/mcp/src/server.ts`)
35
37
  registers `getMcpToolRegistrations()` minus `OSS_DISABLED_TOOLS`, whose only
36
- entry is `start_purchase` — so 17 tools are registered on the server.
37
- - **14 free anonymous tools**: of the 17 registered, three are Pro tools
38
+ entry is `start_purchase` — so 22 tools are registered on the server.
39
+ - **19 free anonymous tools**: of the 22 registered, three are Pro tools
38
40
  (`create_page`, `update_page`, `delete_page`) gated at call time by
39
- `requirePaidTier()`, leaving the 14 free anonymous tools above.
41
+ `requirePaidTier()`, leaving the 19 free anonymous tools above.
40
42
  `index.ts` is the transport entry point and exports no tools — registration
41
43
  is entirely via `createMcpServer`.
42
44
 
@@ -52,6 +54,10 @@ Every tool maps 1:1 to an `apps/api` endpoint. When you change a tool, change th
52
54
  server entirely. Re-enable criteria live at
53
55
  `docs/internal/roadmaps/phase-3-readiness.md`.
54
56
 
57
+ **Re-derive these counts rather than trusting them here** — the catalog in
58
+ `packages/metadata/src/mcp-tool-catalog.ts` is the source; free anonymous =
59
+ catalog − `OSS_DISABLED_TOOLS` − `tier: "pro"`.
60
+
55
61
  Don't add identity logic to any tool signature. Don't remove `start_purchase`
56
62
  from `OSS_DISABLED_TOOLS` without satisfying the Phase 3 re-enable criteria.
57
63
 
@@ -82,3 +88,7 @@ Example (lead routing):
82
88
  - Don't put business logic in tool handlers — they're adapters.
83
89
 
84
90
  Last updated: 2026-07-09 — corrected the tool-count explanation (18 catalog → 17 registered → 14 free anonymous) and the Pro-tool gating (registered + `requirePaidTier()`-gated, not `OSS_DISABLED_TOOLS`-disabled).
91
+
92
+ Last updated: 2026-08-26 — doc-sync: tool-count explanation "18 catalog → 17 registered → 14 free anonymous" → "22 catalog → 21 registered → 18 free anonymous" (derived from `packages/metadata/src/mcp-tool-catalog.ts`: `get_flow`/`submit_flow_step` landed via PR #3973, `list_availability`/`create_booking` landed via PR #4421). Added the Booking category to the free-tool enumeration above. `CLAUDE.md` and `docs/ARCHITECTURE.md` re-verified as non-drift (already correct); `packages/create-ailk/templates/apps/mcp/CLAUDE.md` no longer exists in the scaffolder template tree (structure changed since the count was scoped there).
93
+
94
+ Last updated: 2026-08-31 — doc-sync: tool counts 22/21/18 → 23/22/19 and Booking (2) → Booking (3): `get_event_meta` added (#4633), the meta-only scheduling read twinning `GET /v1/schedule/event-meta` — derived from `packages/metadata/src/mcp-tool-catalog.ts`.