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
@@ -1,120 +0,0 @@
1
- /**
2
- * Tests for LocaleLayout — verifies the <html dir> attribute is set
3
- * correctly based on the active locale.
4
- *
5
- * The layout is an async server component; jest renders it by awaiting
6
- * the returned ReactElement promise. Heavy Next.js/next-intl deps are
7
- * mocked so the test focuses on the dir attribute wiring only.
8
- */
9
- import React from "react";
10
- import { render } from "@testing-library/react";
11
-
12
- // ── Mock heavy/Next.js-specific dependencies ──────────────────────────
13
- jest.mock("next/navigation", () => ({
14
- usePathname: jest.fn().mockReturnValue("/en/"),
15
- }));
16
-
17
- jest.mock("next/headers", () => ({
18
- headers: jest.fn().mockResolvedValue({
19
- get: jest.fn().mockReturnValue("/"),
20
- }),
21
- }));
22
-
23
- jest.mock("next-intl/server", () => ({
24
- getMessages: jest.fn().mockResolvedValue({}),
25
- getTranslations: jest.fn().mockImplementation(({ namespace }: { namespace: string }) => {
26
- if (namespace === "nav") {
27
- const t = (key: string) => key;
28
- return Promise.resolve(t);
29
- }
30
- const t = (key: string) => key;
31
- return Promise.resolve(t);
32
- }),
33
- }));
34
-
35
- jest.mock("next-intl", () => ({
36
- NextIntlClientProvider: ({ children }: { children: React.ReactNode }) => (
37
- <>{children}</>
38
- ),
39
- }));
40
-
41
- jest.mock("@working-theory/web-i18n", () => ({
42
- readLocales: jest.fn().mockReturnValue(["en"]),
43
- buildHreflangAlternates: jest.fn().mockReturnValue({}),
44
- getStealthRobots: jest.fn().mockReturnValue({}),
45
- }));
46
-
47
- jest.mock("@working-theory/analytics", () => ({
48
- Telemetry: () => null,
49
- VerificationMeta: () => null,
50
- }));
51
-
52
- // ── Import subject under test ──────────────────────────────────────────
53
- import LocaleLayout, { generateMetadata } from "../layout";
54
-
55
- async function renderLayout(locale: string): Promise<void> {
56
- const element = LocaleLayout({
57
- children: <span data-testid="child">content</span>,
58
- params: Promise.resolve({ locale }),
59
- });
60
- const resolved = await element;
61
- render(resolved);
62
- }
63
-
64
- describe("generateMetadata()", () => {
65
- it("returns a title and description", async () => {
66
- const metadata = await generateMetadata();
67
- expect(metadata.title).toBe("AI Launch Kit");
68
- expect(metadata.description).toMatch(/OSS/);
69
- });
70
-
71
- it("includes alternates.languages from buildHreflangAlternates", async () => {
72
- const metadata = await generateMetadata();
73
- expect(metadata.alternates).toBeDefined();
74
- expect(metadata.alternates?.languages).toBeDefined();
75
- });
76
- });
77
-
78
- describe("LocaleLayout — chrome smoke (#1451)", () => {
79
- it("renders Nav with aria-label=Primary", async () => {
80
- await renderLayout("en");
81
- expect(document.querySelector("nav[aria-label='Primary']")).toBeInTheDocument();
82
- });
83
-
84
- it("renders Footer element", async () => {
85
- await renderLayout("en");
86
- expect(document.querySelector("footer")).toBeInTheDocument();
87
- });
88
-
89
- it("renders nav logo link pointing to locale home", async () => {
90
- await renderLayout("en");
91
- const logoLink = document.querySelector("[data-testid='brand-logo-link']");
92
- expect(logoLink).toBeInTheDocument();
93
- // as-needed dialect (#3450): bare for the default locale.
94
- expect(logoLink?.getAttribute("href")).toBe("/");
95
- });
96
- });
97
-
98
- describe("LocaleLayout — <html dir> attribute", () => {
99
- // React 19 + jsdom: <html> is a singleton (document.documentElement);
100
- // RTL merges the rendered <html> attributes onto the live document root.
101
- it('renders dir="ltr" for locale "en"', async () => {
102
- await renderLayout("en");
103
- expect(document.documentElement.getAttribute("dir")).toBe("ltr");
104
- });
105
-
106
- it('renders dir="rtl" for locale "ar"', async () => {
107
- await renderLayout("ar");
108
- expect(document.documentElement.getAttribute("dir")).toBe("rtl");
109
- });
110
-
111
- it('preserves lang attribute for locale "en"', async () => {
112
- await renderLayout("en");
113
- expect(document.documentElement.getAttribute("lang")).toBe("en");
114
- });
115
-
116
- it('preserves lang attribute for locale "ar"', async () => {
117
- await renderLayout("ar");
118
- expect(document.documentElement.getAttribute("lang")).toBe("ar");
119
- });
120
- });
@@ -1,202 +0,0 @@
1
- /**
2
- * HTML snapshot regression tests for the apps/web → @working-theory/page-renderer migration.
3
- *
4
- * Node version: captured against Node 22.x (same as CI).
5
- * MDX seed content: DI-injected stub — no fs reads, deterministic across environments.
6
- *
7
- * Two-commit strategy (per spec §8 Open Questions):
8
- * Commit 1: this file added; snapshots captured against pre-migration routes (RED-passing).
9
- * Commit 2: routes migrated; same snapshots verify diff=0 (GREEN).
10
- *
11
- * Each of the four routes is tested in two states:
12
- * - empty: getMdxSource returns null → empty-state branch
13
- * - populated: getMdxSource returns a minimal MdxPageSource → full render
14
- *
15
- * Failure = snapshot diff > 0 bytes. DO NOT regenerate snapshots to pass.
16
- * A non-zero diff indicates a behavior regression in the migration. Escalate.
17
- */
18
- import React from "react";
19
- import { render } from "@testing-library/react";
20
- import { stripJsonLd } from "@working-theory/page-renderer/testing";
21
-
22
- // ── @working-theory/ui mock ─────────────────────────────────────────────────────────────
23
- // SectionRenderer renders a predictable deterministic div so the snapshot is
24
- // stable across section-component implementations.
25
- jest.mock("@working-theory/ui", () => ({
26
- SectionRenderer: ({ sections }: { sections: unknown[] }) =>
27
- React.createElement("div", {
28
- "data-testid": "section-renderer",
29
- "data-section-count": String(sections.length),
30
- }),
31
- }));
32
-
33
- // ── Import page components ─────────────────────────────────────────────────────
34
- import HomePage from "../page";
35
- import AboutPage from "../about/page";
36
- import FAQPage from "../faq/page";
37
- import LaunchServicePage from "../launch-service/page";
38
-
39
- // ── Shared stubs ───────────────────────────────────────────────────────────────
40
-
41
- function makeSource(
42
- type: string,
43
- slug: string,
44
- title: string,
45
- description: string,
46
- ) {
47
- return {
48
- frontmatter: {
49
- type: type as "HomePage",
50
- slug,
51
- title,
52
- description,
53
- },
54
- body: "",
55
- };
56
- }
57
-
58
- const getMdxSourceEmpty = jest.fn().mockResolvedValue(null);
59
- const getPageSectionsEmpty = jest.fn().mockResolvedValue([]);
60
-
61
- // ── HomePage ───────────────────────────────────────────────────────────────────
62
-
63
- describe("HomePage — snapshot regression", () => {
64
- it("empty state renders deterministic HTML", async () => {
65
- const element = await HomePage({
66
- params: Promise.resolve({ locale: "en" }),
67
- getMdxSource: getMdxSourceEmpty,
68
- getPageSections: getPageSectionsEmpty,
69
- });
70
- const { container } = render(element);
71
- expect(stripJsonLd(container.innerHTML)).toMatchInlineSnapshot(
72
- `"<main><h1>AI Launch Kit</h1><p data-testid="home-description">AX-first OSS template for shipping software with API + MCP as canonical surfaces.</p></main>"`,
73
- );
74
- });
75
-
76
- it("populated state renders deterministic HTML", async () => {
77
- const source = makeSource(
78
- "HomePage",
79
- "home",
80
- "AI Launch Kit",
81
- "AX-first OSS template for shipping software with API + MCP as canonical surfaces.",
82
- );
83
- const getMdxSourcePopulated = jest.fn().mockResolvedValue(source);
84
- const getPageSectionsPopulated = jest.fn().mockResolvedValue([]);
85
-
86
- const element = await HomePage({
87
- params: Promise.resolve({ locale: "en" }),
88
- getMdxSource: getMdxSourcePopulated,
89
- getPageSections: getPageSectionsPopulated,
90
- });
91
- const { container } = render(element);
92
- expect(stripJsonLd(container.innerHTML)).toMatchInlineSnapshot(
93
- `"<main><h1>AI Launch Kit</h1><p data-testid="home-description">AX-first OSS template for shipping software with API + MCP as canonical surfaces.</p><div data-testid="section-renderer" data-section-count="0"></div></main>"`,
94
- );
95
- });
96
- });
97
-
98
- // ── AboutPage ──────────────────────────────────────────────────────────────────
99
-
100
- describe("AboutPage — snapshot regression", () => {
101
- it("empty state renders deterministic HTML", async () => {
102
- const element = await AboutPage({
103
- params: Promise.resolve({ locale: "en" }),
104
- getMdxSource: getMdxSourceEmpty,
105
- getPageSections: getPageSectionsEmpty,
106
- });
107
- const { container } = render(element);
108
- expect(stripJsonLd(container.innerHTML)).toMatchInlineSnapshot(
109
- `"<main><h1>About</h1><p data-testid="section-empty-state">About page content coming soon.</p></main>"`,
110
- );
111
- });
112
-
113
- it("populated state renders deterministic HTML", async () => {
114
- const source = makeSource("AboutPage", "about", "About Us", "Who we are.");
115
- const getMdxSourcePopulated = jest.fn().mockResolvedValue(source);
116
- const getPageSectionsPopulated = jest.fn().mockResolvedValue([]);
117
-
118
- const element = await AboutPage({
119
- params: Promise.resolve({ locale: "en" }),
120
- getMdxSource: getMdxSourcePopulated,
121
- getPageSections: getPageSectionsPopulated,
122
- });
123
- const { container } = render(element);
124
- expect(stripJsonLd(container.innerHTML)).toMatchInlineSnapshot(
125
- `"<main><h1>About Us</h1><p data-testid="about-description">Who we are.</p><div data-testid="section-renderer" data-section-count="0"></div></main>"`,
126
- );
127
- });
128
- });
129
-
130
- // ── FAQPage ────────────────────────────────────────────────────────────────────
131
-
132
- describe("FAQPage — snapshot regression", () => {
133
- it("empty state renders deterministic HTML (with scaffold JSON-LD)", async () => {
134
- const element = await FAQPage({
135
- params: Promise.resolve({ locale: "en" }),
136
- getMdxSource: getMdxSourceEmpty,
137
- getPageSections: getPageSectionsEmpty,
138
- });
139
- const { container } = render(element);
140
- expect(stripJsonLd(container.innerHTML)).toMatchInlineSnapshot(
141
- `"<main><h1>FAQ</h1><p data-testid="section-empty-state">Frequently asked questions content coming soon.</p></main>"`,
142
- );
143
- });
144
-
145
- it("populated state renders deterministic HTML", async () => {
146
- const source = makeSource(
147
- "FAQPage",
148
- "faq",
149
- "FAQ",
150
- "Frequently asked questions.",
151
- );
152
- const getMdxSourcePopulated = jest.fn().mockResolvedValue(source);
153
- const getPageSectionsPopulated = jest.fn().mockResolvedValue([]);
154
-
155
- const element = await FAQPage({
156
- params: Promise.resolve({ locale: "en" }),
157
- getMdxSource: getMdxSourcePopulated,
158
- getPageSections: getPageSectionsPopulated,
159
- });
160
- const { container } = render(element);
161
- expect(stripJsonLd(container.innerHTML)).toMatchInlineSnapshot(
162
- `"<main><h1>FAQ</h1><p data-testid="faq-description">Frequently asked questions.</p><div data-testid="section-renderer" data-section-count="0"></div></main>"`,
163
- );
164
- });
165
- });
166
-
167
- // ── LaunchServicePage ──────────────────────────────────────────────────────────
168
-
169
- describe("LaunchServicePage — snapshot regression", () => {
170
- it("empty state renders deterministic HTML", async () => {
171
- const element = await LaunchServicePage({
172
- params: Promise.resolve({ locale: "en" }),
173
- getMdxSource: getMdxSourceEmpty,
174
- getPageSections: getPageSectionsEmpty,
175
- });
176
- const { container } = render(element);
177
- expect(stripJsonLd(container.innerHTML)).toMatchInlineSnapshot(
178
- `"<main><h1>Launch Service</h1><p data-testid="section-empty-state">Launch Service page content coming soon.</p></main>"`,
179
- );
180
- });
181
-
182
- it("populated state renders deterministic HTML", async () => {
183
- const source = makeSource(
184
- "Service",
185
- "launch-service",
186
- "Launch Service",
187
- "Our launch service offering.",
188
- );
189
- const getMdxSourcePopulated = jest.fn().mockResolvedValue(source);
190
- const getPageSectionsPopulated = jest.fn().mockResolvedValue([]);
191
-
192
- const element = await LaunchServicePage({
193
- params: Promise.resolve({ locale: "en" }),
194
- getMdxSource: getMdxSourcePopulated,
195
- getPageSections: getPageSectionsPopulated,
196
- });
197
- const { container } = render(element);
198
- expect(stripJsonLd(container.innerHTML)).toMatchInlineSnapshot(
199
- `"<main><h1>Launch Service</h1><p data-testid="launch-service-description">Our launch service offering.</p><div data-testid="section-renderer" data-section-count="0"></div></main>"`,
200
- );
201
- });
202
- });
@@ -1,152 +0,0 @@
1
- import React from "react";
2
- import { render, screen, fireEvent } from "@testing-library/react";
3
- import "@testing-library/jest-dom";
4
-
5
- import RootError from "../error";
6
- import NotFound from "../not-found";
7
- import ContactError from "../[locale]/contact/error";
8
- import PurchaseError from "../[locale]/dev/purchase/error";
9
-
10
- function buildError(message = "Test error"): Error & { digest?: string } {
11
- const err = new Error(message) as Error & { digest?: string };
12
- err.digest = "test-digest-1";
13
- return err;
14
- }
15
-
16
- describe("RootError", () => {
17
- beforeEach(() => {
18
- jest.spyOn(console, "error").mockImplementation(() => {});
19
- });
20
-
21
- afterEach(() => {
22
- (console.error as jest.Mock).mockRestore();
23
- });
24
-
25
- it("renders a fallback heading when an error is provided", () => {
26
- const err = buildError("Something bad");
27
- const reset = jest.fn();
28
- render(<RootError error={err} reset={reset} />);
29
- expect(screen.getByRole("heading", { level: 1 })).toBeInTheDocument();
30
- });
31
-
32
- it("renders a Try again button", () => {
33
- const err = buildError();
34
- const reset = jest.fn();
35
- render(<RootError error={err} reset={reset} />);
36
- expect(
37
- screen.getByRole("button", { name: /try again/i }),
38
- ).toBeInTheDocument();
39
- });
40
-
41
- it("calls reset when Try again is clicked", () => {
42
- const err = buildError();
43
- const reset = jest.fn();
44
- render(<RootError error={err} reset={reset} />);
45
- fireEvent.click(screen.getByRole("button", { name: /try again/i }));
46
- expect(reset).toHaveBeenCalledTimes(1);
47
- });
48
-
49
- it("calls console.error with the error on mount", () => {
50
- const err = buildError("logged error");
51
- const reset = jest.fn();
52
- render(<RootError error={err} reset={reset} />);
53
- expect(console.error).toHaveBeenCalledWith(err);
54
- });
55
- });
56
-
57
- describe("NotFound", () => {
58
- it("renders a 404 heading", () => {
59
- render(<NotFound />);
60
- expect(screen.getByRole("heading", { level: 1 })).toBeInTheDocument();
61
- });
62
-
63
- it("renders a link back to the home page", () => {
64
- render(<NotFound />);
65
- const link = screen.getByRole("link");
66
- expect(link).toHaveAttribute("href", "/");
67
- });
68
- });
69
-
70
- describe("ContactError", () => {
71
- beforeEach(() => {
72
- jest.spyOn(console, "error").mockImplementation(() => {});
73
- });
74
-
75
- afterEach(() => {
76
- (console.error as jest.Mock).mockRestore();
77
- });
78
-
79
- it("renders a heading specific to the lead-capture flow (message/contact)", () => {
80
- const err = buildError("Contact error");
81
- const reset = jest.fn();
82
- render(<ContactError error={err} reset={reset} />);
83
- const heading = screen.getByRole("heading", { level: 1 });
84
- expect(heading.textContent?.toLowerCase()).toMatch(/message|contact/);
85
- });
86
-
87
- it("does NOT render generic 'something went wrong' as the heading", () => {
88
- const err = buildError();
89
- const reset = jest.fn();
90
- render(<ContactError error={err} reset={reset} />);
91
- const heading = screen.getByRole("heading", { level: 1 });
92
- expect(heading.textContent?.toLowerCase()).not.toBe("something went wrong");
93
- });
94
-
95
- it("renders a Try again button that calls reset", () => {
96
- const err = buildError();
97
- const reset = jest.fn();
98
- render(<ContactError error={err} reset={reset} />);
99
- fireEvent.click(screen.getByRole("button", { name: /try again/i }));
100
- expect(reset).toHaveBeenCalledTimes(1);
101
- });
102
-
103
- it("calls console.error with the error on mount", () => {
104
- const err = buildError("contact logged");
105
- const reset = jest.fn();
106
- render(<ContactError error={err} reset={reset} />);
107
- expect(console.error).toHaveBeenCalledWith(err);
108
- });
109
- });
110
-
111
- describe("PurchaseError", () => {
112
- beforeEach(() => {
113
- jest.spyOn(console, "error").mockImplementation(() => {});
114
- });
115
-
116
- afterEach(() => {
117
- (console.error as jest.Mock).mockRestore();
118
- });
119
-
120
- it("renders a heading specific to the checkout flow (checkout/purchase)", () => {
121
- const err = buildError("Purchase error");
122
- const reset = jest.fn();
123
- render(<PurchaseError error={err} reset={reset} />);
124
- const heading = screen.getByRole("heading", { level: 1 });
125
- expect(heading.textContent?.toLowerCase()).toMatch(/checkout|purchase/);
126
- });
127
-
128
- it("does NOT claim payment was or was not processed in the heading", () => {
129
- const err = buildError();
130
- const reset = jest.fn();
131
- render(<PurchaseError error={err} reset={reset} />);
132
- const heading = screen.getByRole("heading", { level: 1 });
133
- expect(heading.textContent?.toLowerCase()).not.toMatch(
134
- /payment (was|not|failed|charged)/,
135
- );
136
- });
137
-
138
- it("renders a Try again button that calls reset", () => {
139
- const err = buildError();
140
- const reset = jest.fn();
141
- render(<PurchaseError error={err} reset={reset} />);
142
- fireEvent.click(screen.getByRole("button", { name: /try again/i }));
143
- expect(reset).toHaveBeenCalledTimes(1);
144
- });
145
-
146
- it("calls console.error with the error on mount", () => {
147
- const err = buildError("purchase logged");
148
- const reset = jest.fn();
149
- render(<PurchaseError error={err} reset={reset} />);
150
- expect(console.error).toHaveBeenCalledWith(err);
151
- });
152
- });
@@ -1,15 +0,0 @@
1
- ---
2
- title: Blog
3
- description: Writing on AEO, answer-engine citation readiness, and what it means to ship software with three peers — UX, API, and MCP.
4
- author:
5
- name: The AI Launch Kit Team
6
- tags:
7
- - AEO
8
- - AX
9
- ---
10
-
11
- # Blog
12
-
13
- This is where we think out loud. The topics stay close to the work: schema.org implementation details, how LLMs decide what to cite, and what AX-first looks like in practice.
14
-
15
- The posts are opinionated because vague advice isn't useful. If something here turns out to be wrong, we'll update it and say so.
@@ -1,20 +0,0 @@
1
- ---
2
- title: Launching AI Launch Kit
3
- description: A short note on why we built an AX-first OSS template and what ships in v1.
4
- date: "2026-05-06"
5
- author:
6
- name: The AI Launch Kit Team
7
- tags:
8
- - Announcements
9
- - AX
10
- ---
11
-
12
- # Launching AI Launch Kit
13
-
14
- We're shipping the first public version today. The template gives you three
15
- peer apps (web, api, mcp), a content-adapter contract with MDX as the default
16
- backend, and a JSON-LD pipeline for SEO that doesn't require manual schema.org
17
- authoring.
18
-
19
- The goal is clone-to-shipping in under an hour. If you hit friction, the
20
- README's standalone test should catch it before you do.
@@ -1,30 +0,0 @@
1
- ---
2
- title: Getting Started
3
- description: Everything you need to know to get your AI Launch Kit project running.
4
- ---
5
-
6
- # Getting Started
7
-
8
- Welcome to AI Launch Kit. This guide walks you through the first steps after cloning the template.
9
-
10
- ## Prerequisites
11
-
12
- - Node.js 20+
13
- - pnpm 9+
14
-
15
- ## Quick start
16
-
17
- ```bash
18
- pnpm install
19
- pnpm dev
20
- ```
21
-
22
- The dev server starts three apps in parallel:
23
-
24
- - **web** (`localhost:3000`) — the Next.js UX surface
25
- - **api** (`localhost:3001`) — the Fastify REST API
26
- - **mcp** — the MCP server (stdio transport)
27
-
28
- ## Next steps
29
-
30
- Replace the seed content in `apps/web/content/en/` with your own pages, blog posts, and docs. Each MDX file maps to a route automatically via Fumadocs.
File without changes
@@ -1,85 +0,0 @@
1
- # content/ — MDX Content Authoring
2
-
3
- Inherits root `CLAUDE.md`. This file owns content-authoring rules.
4
-
5
- ## What lives here
6
-
7
- File-based MDX content, one file per page, organized by page type:
8
-
9
- content/
10
- ├── HomePage/home.mdx
11
- ├── ServicesList/services.mdx
12
- ├── Service/<slug>.mdx
13
- ├── BlogList/blog.mdx
14
- ├── BlogPosting/<slug>.mdx
15
- └── ...
16
-
17
- For the full list of supported page types and what each emits, see `packages/schema/README.md`. It's the source of truth. For per-page-type component guidance (which `@working-theory/ui` components are idiomatic for each family), see `packages/schema/CLAUDE.md` § `@working-theory/ui` component map.
18
-
19
- ## Frontmatter contract (hard rule)
20
-
21
- Every MDX file has frontmatter validated at build time against `@working-theory/schema`. Required:
22
-
23
- - `type` — must match a `SchemaOrgType` key from the schema README
24
- - `slug` — URL slug, no leading slash
25
- - `title` — visible page title
26
- - `description` — meta description and JSON-LD `description`
27
-
28
- Optional:
29
-
30
- - `locale` — defaults to `'en'`. Emitted as `inLanguage`.
31
- - `publishedAt`, `updatedAt`, `image`
32
- - `schema` — escape hatch (see below)
33
-
34
- Build fails on missing/invalid frontmatter. Fix the frontmatter, not the validator.
35
-
36
- ## The `schema` field (escape hatch)
37
-
38
- `schema` is a shallow-merged record. Frontmatter wins on conflicts with the builder. Use it to:
39
-
40
- - Add structured sub-entities (`author`, `mainEntity`, `step`)
41
- - Enrich page types whose schema.org default is generic (e.g. Integration → `mainEntity: SoftwareApplication`)
42
- - Override a derived field (rare)
43
-
44
- Some types (JobPosting in particular) REQUIRE programmatic overrides for full coverage — frontmatter alone can't express `baseSalary`, `employmentType`. See `packages/schema/README.md` for which types need code-level overrides.
45
-
46
- After using `schema`, run `ailk audit` — a malformed override produces invalid JSON-LD and tanks AEO scoring.
47
-
48
- ## Component vocabulary (universal — page type doesn't change this)
49
-
50
- These components are available on any page. Choice depends on content, not page type. An FAQ block belongs in `<FAQ>` whether it's on a HomePage, ServicePage, or FAQPage.
51
-
52
- - `<Hero>` — top-of-page hero. One per page max.
53
- - `<FAQ>` — FAQ entry. **One question per block** (see AEO rules below).
54
- - `<CTA>` — call-to-action card. Use sparingly.
55
- - `<Testimonial>` — single testimonial. Multiple = multiple blocks.
56
- - `<PriceTable>` — pricing display.
57
- - `<FeatureGrid>` — feature/benefit grid.
58
- - `<Locations>` — physical locations.
59
- - `<BusinessHours>` — hours of operation.
60
-
61
- For the per-page-type editorial map (which family of pages typically uses which components), see `packages/schema/CLAUDE.md` § `@working-theory/ui` component map.
62
-
63
- Don't use raw HTML where a component exists. Components carry schema and styling guarantees; `<div>` soup throws both away.
64
-
65
- ## AEO editorial craft (universal — this is the wedge)
66
-
67
- **Lead with the answer.** First 60 words of body content state the answer to the page's implicit question. LLM citation extractors read top-down and bail early. Backstory comes after.
68
-
69
- **One question per `<FAQ>` block.** Don't cram multiple Q&As into one block. Each block becomes one `Question` entity in JSON-LD — separation drives citability.
70
-
71
- **Entity clarity in the first paragraph.** Name the company, product, location, or person explicitly. "We" and "our service" are entity-opaque. AEO rewards unambiguous attribution.
72
-
73
- **Concrete claims over adjectives.** "Ships in 48 hours" beats "fast turnaround." Specifics get cited; vagueness gets skipped.
74
-
75
- **Headings as questions when natural.** H2/H3 phrased as questions (when the content actually answers one) align with passage extraction.
76
-
77
- **Don't pad for length.** A 400-word page that answers cleanly outperforms a 1,500-word page that buries the answer.
78
-
79
- ## What NOT to do
80
-
81
- - Don't hand-roll JSON-LD in MDX body. Ever.
82
- - Don't use `<script type="application/ld+json">` inside content.
83
- - Don't bypass the frontmatter validator.
84
- - Don't write `type: WebPage` to silence a validator error — pick the right type.
85
- - Don't use raw `<h1>` in body. The page template emits the H1 from `title`.