create-nextdevtpl 2.6.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 (425) hide show
  1. package/README.md +29 -0
  2. package/catalog.json +385 -0
  3. package/dist/catalog.d.ts +3 -0
  4. package/dist/catalog.js +112 -0
  5. package/dist/catalog.js.map +1 -0
  6. package/dist/cli.d.ts +3 -0
  7. package/dist/cli.js +115 -0
  8. package/dist/cli.js.map +1 -0
  9. package/dist/filesystem.d.ts +10 -0
  10. package/dist/filesystem.js +86 -0
  11. package/dist/filesystem.js.map +1 -0
  12. package/dist/generate.d.ts +5 -0
  13. package/dist/generate.js +758 -0
  14. package/dist/generate.js.map +1 -0
  15. package/dist/index.d.ts +4 -0
  16. package/dist/index.js +4 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/selection.d.ts +2 -0
  19. package/dist/selection.js +111 -0
  20. package/dist/selection.js.map +1 -0
  21. package/dist/service-templates.d.ts +4 -0
  22. package/dist/service-templates.js +180 -0
  23. package/dist/service-templates.js.map +1 -0
  24. package/dist/types.d.ts +65 -0
  25. package/dist/types.js +2 -0
  26. package/dist/types.js.map +1 -0
  27. package/package.json +54 -0
  28. package/template/.dockerignore +14 -0
  29. package/template/.env.example +282 -0
  30. package/template/.gitattributes +17 -0
  31. package/template/.node-version +1 -0
  32. package/template/Dockerfile +45 -0
  33. package/template/LICENSE +21 -0
  34. package/template/README.md +267 -0
  35. package/template/biome.json +68 -0
  36. package/template/cloudflare/templates/logger.ts +162 -0
  37. package/template/cloudflare/templates/mail/server.ts +6 -0
  38. package/template/cloudflare/templates/mail/templates.ts +87 -0
  39. package/template/cloudflare/templates/mail/utils.ts +69 -0
  40. package/template/cloudflare/worker.mjs +25 -0
  41. package/template/components.json +22 -0
  42. package/template/compose.yaml +74 -0
  43. package/template/deploy/check-health.mjs +25 -0
  44. package/template/deploy/docker/README.md +14 -0
  45. package/template/deploy/server/README.md +24 -0
  46. package/template/deploy/server/build.sh +24 -0
  47. package/template/deploy/server/nextdevtpl.service +19 -0
  48. package/template/deploy/server/start.sh +19 -0
  49. package/template/deploy/vercel/README.md +16 -0
  50. package/template/deploy/verify-production-health.mjs +86 -0
  51. package/template/drizzle.config.ts +47 -0
  52. package/template/gitignore +62 -0
  53. package/template/manifest.json +35 -0
  54. package/template/messages/en.json +766 -0
  55. package/template/messages/zh.json +762 -0
  56. package/template/next.config.mjs +28 -0
  57. package/template/open-next.config.ts +3 -0
  58. package/template/package.json +125 -0
  59. package/template/pnpm-lock.yaml +15901 -0
  60. package/template/postcss.config.mjs +7 -0
  61. package/template/public/file.svg +1 -0
  62. package/template/public/globe.svg +1 -0
  63. package/template/public/logo.svg +6 -0
  64. package/template/public/next.svg +1 -0
  65. package/template/public/vercel.svg +1 -0
  66. package/template/public/window.svg +1 -0
  67. package/template/sentry.client.config.ts +10 -0
  68. package/template/sentry.edge.config.ts +10 -0
  69. package/template/sentry.server.config.ts +10 -0
  70. package/template/source.config.ts +59 -0
  71. package/template/src/adapters/ai/anthropic.ts +113 -0
  72. package/template/src/adapters/ai/index.ts +6 -0
  73. package/template/src/adapters/ai/openai-compatible.ts +88 -0
  74. package/template/src/adapters/ai/workers-ai.ts +63 -0
  75. package/template/src/adapters/index.ts +10 -0
  76. package/template/src/adapters/jobs/cloudflare-workflows.ts +46 -0
  77. package/template/src/adapters/jobs/index.ts +5 -0
  78. package/template/src/adapters/jobs/inngest/adapter.ts +29 -0
  79. package/template/src/adapters/jobs/inngest/client.ts +8 -0
  80. package/template/src/adapters/jobs/inngest/functions.ts +17 -0
  81. package/template/src/adapters/jobs/inngest/handler.ts +6 -0
  82. package/template/src/adapters/jobs/inngest/index.ts +4 -0
  83. package/template/src/adapters/mail/cloudflare-email.ts +50 -0
  84. package/template/src/adapters/mail/disabled.ts +17 -0
  85. package/template/src/adapters/mail/index.ts +7 -0
  86. package/template/src/adapters/mail/resend.ts +76 -0
  87. package/template/src/adapters/mail/smtp.ts +82 -0
  88. package/template/src/adapters/payment/creem.ts +269 -0
  89. package/template/src/adapters/payment/index.ts +2 -0
  90. package/template/src/adapters/payment/stripe.ts +302 -0
  91. package/template/src/adapters/rate-limit/cloudflare.ts +42 -0
  92. package/template/src/adapters/rate-limit/index.ts +6 -0
  93. package/template/src/adapters/rate-limit/noop.ts +27 -0
  94. package/template/src/adapters/rate-limit/upstash.ts +113 -0
  95. package/template/src/adapters/registry.ts +228 -0
  96. package/template/src/adapters/storage/index.ts +3 -0
  97. package/template/src/adapters/storage/r2-binding.ts +105 -0
  98. package/template/src/adapters/storage/s3-compatible.ts +149 -0
  99. package/template/src/app/[locale]/(admin)/admin/layout.tsx +36 -0
  100. package/template/src/app/[locale]/(admin)/admin/page.tsx +345 -0
  101. package/template/src/app/[locale]/(admin)/admin/tickets/[id]/page.tsx +261 -0
  102. package/template/src/app/[locale]/(admin)/admin/tickets/page.tsx +236 -0
  103. package/template/src/app/[locale]/(admin)/admin/users/page.tsx +557 -0
  104. package/template/src/app/[locale]/(auth)/forgot-password/page.tsx +9 -0
  105. package/template/src/app/[locale]/(auth)/layout.tsx +28 -0
  106. package/template/src/app/[locale]/(auth)/sign-in/page.tsx +9 -0
  107. package/template/src/app/[locale]/(auth)/sign-up/page.tsx +9 -0
  108. package/template/src/app/[locale]/(dashboard)/dashboard/credits/buy/buy-credits-view.tsx +170 -0
  109. package/template/src/app/[locale]/(dashboard)/dashboard/credits/buy/page.tsx +12 -0
  110. package/template/src/app/[locale]/(dashboard)/dashboard/credits/page.tsx +5 -0
  111. package/template/src/app/[locale]/(dashboard)/dashboard/loading.tsx +41 -0
  112. package/template/src/app/[locale]/(dashboard)/dashboard/page.tsx +299 -0
  113. package/template/src/app/[locale]/(dashboard)/dashboard/settings/page.tsx +38 -0
  114. package/template/src/app/[locale]/(dashboard)/dashboard/support/[id]/page.tsx +220 -0
  115. package/template/src/app/[locale]/(dashboard)/dashboard/support/new/page.tsx +183 -0
  116. package/template/src/app/[locale]/(dashboard)/dashboard/support/page.tsx +145 -0
  117. package/template/src/app/[locale]/(dashboard)/layout.tsx +35 -0
  118. package/template/src/app/[locale]/(marketing)/blog/[slug]/page.tsx +178 -0
  119. package/template/src/app/[locale]/(marketing)/blog/blog-post-card.tsx +95 -0
  120. package/template/src/app/[locale]/(marketing)/blog/page.tsx +127 -0
  121. package/template/src/app/[locale]/(marketing)/demo/plan-badges/page.tsx +36 -0
  122. package/template/src/app/[locale]/(marketing)/layout.tsx +15 -0
  123. package/template/src/app/[locale]/(marketing)/legal/[slug]/page.tsx +130 -0
  124. package/template/src/app/[locale]/(marketing)/page.tsx +94 -0
  125. package/template/src/app/[locale]/(marketing)/pseo/[slug]/page.tsx +68 -0
  126. package/template/src/app/[locale]/(marketing)/pseo/page.tsx +137 -0
  127. package/template/src/app/[locale]/docs/[[...slug]]/page.tsx +63 -0
  128. package/template/src/app/[locale]/docs/layout.tsx +39 -0
  129. package/template/src/app/[locale]/layout.tsx +80 -0
  130. package/template/src/app/[locale]/opengraph-image.tsx +20 -0
  131. package/template/src/app/[locale]/twitter-image.tsx +20 -0
  132. package/template/src/app/api/auth/[...all]/route.ts +20 -0
  133. package/template/src/app/api/health/route.ts +45 -0
  134. package/template/src/app/api/inngest/route.ts +12 -0
  135. package/template/src/app/api/jobs/credits/expire/route.ts +102 -0
  136. package/template/src/app/api/search/route.ts +17 -0
  137. package/template/src/app/api/upload/presigned/route.ts +98 -0
  138. package/template/src/app/api/webhooks/payment/route.ts +363 -0
  139. package/template/src/app/globals.css +406 -0
  140. package/template/src/app/icon.svg +6 -0
  141. package/template/src/app/image-proxy/[...path]/route.ts +137 -0
  142. package/template/src/app/layout.tsx +73 -0
  143. package/template/src/app/robots.ts +29 -0
  144. package/template/src/app/sitemap.ts +68 -0
  145. package/template/src/components/motion/reveal.tsx +49 -0
  146. package/template/src/components/seo/json-ld.tsx +87 -0
  147. package/template/src/components/seo/og-image-template.tsx +118 -0
  148. package/template/src/components/ui/accordion.tsx +66 -0
  149. package/template/src/components/ui/alert-dialog.tsx +195 -0
  150. package/template/src/components/ui/avatar.tsx +53 -0
  151. package/template/src/components/ui/badge.tsx +46 -0
  152. package/template/src/components/ui/button.tsx +65 -0
  153. package/template/src/components/ui/card.tsx +92 -0
  154. package/template/src/components/ui/checkbox.tsx +32 -0
  155. package/template/src/components/ui/collapsible.tsx +33 -0
  156. package/template/src/components/ui/dialog.tsx +124 -0
  157. package/template/src/components/ui/dropdown-menu.tsx +257 -0
  158. package/template/src/components/ui/form.tsx +233 -0
  159. package/template/src/components/ui/index.ts +2 -0
  160. package/template/src/components/ui/input.tsx +21 -0
  161. package/template/src/components/ui/label.tsx +24 -0
  162. package/template/src/components/ui/navigation-menu.tsx +167 -0
  163. package/template/src/components/ui/pagination.tsx +125 -0
  164. package/template/src/components/ui/popover.tsx +48 -0
  165. package/template/src/components/ui/progress.tsx +27 -0
  166. package/template/src/components/ui/radio-group.tsx +45 -0
  167. package/template/src/components/ui/select.tsx +190 -0
  168. package/template/src/components/ui/separator.tsx +28 -0
  169. package/template/src/components/ui/sheet.tsx +140 -0
  170. package/template/src/components/ui/switch.tsx +31 -0
  171. package/template/src/components/ui/tabs.tsx +75 -0
  172. package/template/src/components/ui/textarea.tsx +18 -0
  173. package/template/src/config/index.ts +31 -0
  174. package/template/src/config/nav.ts +238 -0
  175. package/template/src/config/payment.ts +282 -0
  176. package/template/src/config/site.ts +53 -0
  177. package/template/src/config/subscription-plan.ts +164 -0
  178. package/template/src/content/blog/en/hello-world.mdx +48 -0
  179. package/template/src/content/blog/zh/hello-world.mdx +48 -0
  180. package/template/src/content/blog/zh/nextdevtpl-linuxdo-intro.mdx +98 -0
  181. package/template/src/content/docs/en/admin-and-support.mdx +65 -0
  182. package/template/src/content/docs/en/authentication.mdx +71 -0
  183. package/template/src/content/docs/en/background-jobs.mdx +53 -0
  184. package/template/src/content/docs/en/configuration.mdx +71 -0
  185. package/template/src/content/docs/en/credits.mdx +69 -0
  186. package/template/src/content/docs/en/customization.mdx +95 -0
  187. package/template/src/content/docs/en/database.mdx +66 -0
  188. package/template/src/content/docs/en/deployment.mdx +62 -0
  189. package/template/src/content/docs/en/email.mdx +48 -0
  190. package/template/src/content/docs/en/index.mdx +48 -0
  191. package/template/src/content/docs/en/internationalization.mdx +78 -0
  192. package/template/src/content/docs/en/meta.json +22 -0
  193. package/template/src/content/docs/en/observability.mdx +69 -0
  194. package/template/src/content/docs/en/payments.mdx +64 -0
  195. package/template/src/content/docs/en/project-structure.mdx +82 -0
  196. package/template/src/content/docs/en/quick-start.mdx +113 -0
  197. package/template/src/content/docs/en/storage.mdx +51 -0
  198. package/template/src/content/docs/zh/admin-and-support.mdx +65 -0
  199. package/template/src/content/docs/zh/authentication.mdx +71 -0
  200. package/template/src/content/docs/zh/background-jobs.mdx +53 -0
  201. package/template/src/content/docs/zh/configuration.mdx +70 -0
  202. package/template/src/content/docs/zh/credits.mdx +69 -0
  203. package/template/src/content/docs/zh/customization.mdx +95 -0
  204. package/template/src/content/docs/zh/database.mdx +66 -0
  205. package/template/src/content/docs/zh/deployment.mdx +61 -0
  206. package/template/src/content/docs/zh/email.mdx +47 -0
  207. package/template/src/content/docs/zh/index.mdx +48 -0
  208. package/template/src/content/docs/zh/internationalization.mdx +78 -0
  209. package/template/src/content/docs/zh/meta.json +22 -0
  210. package/template/src/content/docs/zh/observability.mdx +68 -0
  211. package/template/src/content/docs/zh/payments.mdx +64 -0
  212. package/template/src/content/docs/zh/project-structure.mdx +82 -0
  213. package/template/src/content/docs/zh/quick-start.mdx +110 -0
  214. package/template/src/content/docs/zh/storage.mdx +51 -0
  215. package/template/src/content/legal/en/cookie-policy.mdx +78 -0
  216. package/template/src/content/legal/en/privacy.mdx +131 -0
  217. package/template/src/content/legal/en/terms.mdx +93 -0
  218. package/template/src/content/legal/zh/cookie-policy.mdx +78 -0
  219. package/template/src/content/legal/zh/privacy.mdx +131 -0
  220. package/template/src/content/legal/zh/terms.mdx +92 -0
  221. package/template/src/core/modules/contract.ts +225 -0
  222. package/template/src/core/modules/index.ts +1 -0
  223. package/template/src/core/services/ai.ts +31 -0
  224. package/template/src/core/services/common.ts +112 -0
  225. package/template/src/core/services/index.ts +8 -0
  226. package/template/src/core/services/jobs.ts +24 -0
  227. package/template/src/core/services/mail.ts +35 -0
  228. package/template/src/core/services/manifest.ts +51 -0
  229. package/template/src/core/services/payment.ts +92 -0
  230. package/template/src/core/services/rate-limit.ts +47 -0
  231. package/template/src/core/services/storage.ts +42 -0
  232. package/template/src/db/index.ts +71 -0
  233. package/template/src/db/schema/auth.ts +67 -0
  234. package/template/src/db/schema/credits.ts +94 -0
  235. package/template/src/db/schema/index.ts +5 -0
  236. package/template/src/db/schema/mail.ts +14 -0
  237. package/template/src/db/schema/subscription.ts +21 -0
  238. package/template/src/db/schema/support.ts +56 -0
  239. package/template/src/db/schema.ts +2 -0
  240. package/template/src/features/admin/components/admin-sidebar.tsx +213 -0
  241. package/template/src/features/admin/components/index.ts +2 -0
  242. package/template/src/features/admin/index.ts +3 -0
  243. package/template/src/features/admin/manifest.ts +41 -0
  244. package/template/src/features/analytics/components/analytics.tsx +62 -0
  245. package/template/src/features/analytics/components/index.ts +2 -0
  246. package/template/src/features/analytics/index.ts +3 -0
  247. package/template/src/features/analytics/manifest.ts +13 -0
  248. package/template/src/features/auth/components/auth-brand-panel.tsx +82 -0
  249. package/template/src/features/auth/components/auth-error-alert.tsx +28 -0
  250. package/template/src/features/auth/components/auth-footer.tsx +52 -0
  251. package/template/src/features/auth/components/auth-logo.tsx +30 -0
  252. package/template/src/features/auth/components/forgot-password-form.tsx +146 -0
  253. package/template/src/features/auth/components/index.ts +9 -0
  254. package/template/src/features/auth/components/sign-in-form.tsx +241 -0
  255. package/template/src/features/auth/components/sign-up-form.tsx +307 -0
  256. package/template/src/features/auth/index.ts +3 -0
  257. package/template/src/features/auth/manifest.ts +30 -0
  258. package/template/src/features/blog/components/blog-post-item.tsx +72 -0
  259. package/template/src/features/blog/components/index.ts +1 -0
  260. package/template/src/features/blog/data/mock-posts.ts +62 -0
  261. package/template/src/features/blog/index.ts +3 -0
  262. package/template/src/features/blog/manifest.ts +22 -0
  263. package/template/src/features/credits/account.ts +76 -0
  264. package/template/src/features/credits/actions.ts +427 -0
  265. package/template/src/features/credits/components/credit-balance-badge.tsx +54 -0
  266. package/template/src/features/credits/components/credit-usage-section.tsx +160 -0
  267. package/template/src/features/credits/components/index.ts +7 -0
  268. package/template/src/features/credits/components/transaction-history.tsx +346 -0
  269. package/template/src/features/credits/config.ts +70 -0
  270. package/template/src/features/credits/consume.ts +140 -0
  271. package/template/src/features/credits/core.ts +23 -0
  272. package/template/src/features/credits/errors.ts +26 -0
  273. package/template/src/features/credits/expire.ts +112 -0
  274. package/template/src/features/credits/grant.ts +168 -0
  275. package/template/src/features/credits/index.ts +6 -0
  276. package/template/src/features/credits/manifest.ts +36 -0
  277. package/template/src/features/credits/query.ts +65 -0
  278. package/template/src/features/credits/types.ts +48 -0
  279. package/template/src/features/dashboard/components/index.ts +3 -0
  280. package/template/src/features/dashboard/components/main-wrapper.tsx +100 -0
  281. package/template/src/features/dashboard/components/sidebar.tsx +341 -0
  282. package/template/src/features/dashboard/context/index.ts +2 -0
  283. package/template/src/features/dashboard/context/sidebar-context.tsx +72 -0
  284. package/template/src/features/dashboard/index.ts +4 -0
  285. package/template/src/features/dashboard/manifest.ts +28 -0
  286. package/template/src/features/mail/actions.ts +175 -0
  287. package/template/src/features/mail/index.ts +5 -0
  288. package/template/src/features/mail/manifest.ts +13 -0
  289. package/template/src/features/mail/server.ts +8 -0
  290. package/template/src/features/mail/templates/index.ts +11 -0
  291. package/template/src/features/mail/templates/primary-action-email.tsx +224 -0
  292. package/template/src/features/mail/templates/welcome-email.tsx +121 -0
  293. package/template/src/features/mail/utils.ts +190 -0
  294. package/template/src/features/marketing/components/animated-price.tsx +51 -0
  295. package/template/src/features/marketing/components/cookie-consent.tsx +255 -0
  296. package/template/src/features/marketing/components/cta-section.tsx +50 -0
  297. package/template/src/features/marketing/components/faq-section.tsx +59 -0
  298. package/template/src/features/marketing/components/feature-grid.tsx +80 -0
  299. package/template/src/features/marketing/components/footer.tsx +128 -0
  300. package/template/src/features/marketing/components/header.tsx +255 -0
  301. package/template/src/features/marketing/components/hero-section.tsx +323 -0
  302. package/template/src/features/marketing/components/how-it-works.tsx +115 -0
  303. package/template/src/features/marketing/components/index.ts +14 -0
  304. package/template/src/features/marketing/components/nav-menu.tsx +236 -0
  305. package/template/src/features/marketing/components/pricing-section.tsx +446 -0
  306. package/template/src/features/marketing/components/testimonials.tsx +59 -0
  307. package/template/src/features/marketing/components/use-cases-section.tsx +78 -0
  308. package/template/src/features/marketing/index.ts +3 -0
  309. package/template/src/features/marketing/manifest.ts +35 -0
  310. package/template/src/features/payment/actions.ts +182 -0
  311. package/template/src/features/payment/index.ts +4 -0
  312. package/template/src/features/payment/manifest.ts +18 -0
  313. package/template/src/features/payment/server.ts +7 -0
  314. package/template/src/features/payment/types.ts +202 -0
  315. package/template/src/features/pseo/components/index.ts +6 -0
  316. package/template/src/features/pseo/components/pseo-cta.tsx +51 -0
  317. package/template/src/features/pseo/components/pseo-faq.tsx +40 -0
  318. package/template/src/features/pseo/components/pseo-feature-grid.tsx +74 -0
  319. package/template/src/features/pseo/components/pseo-hero.tsx +106 -0
  320. package/template/src/features/pseo/components/pseo-related.tsx +62 -0
  321. package/template/src/features/pseo/components/pseo-use-cases.tsx +50 -0
  322. package/template/src/features/pseo/data/pseo-pages.json +534 -0
  323. package/template/src/features/pseo/index.ts +4 -0
  324. package/template/src/features/pseo/lib/pseo-data.ts +140 -0
  325. package/template/src/features/pseo/manifest.ts +22 -0
  326. package/template/src/features/settings/actions/delete-account.ts +50 -0
  327. package/template/src/features/settings/actions/index.ts +3 -0
  328. package/template/src/features/settings/actions/update-profile.ts +49 -0
  329. package/template/src/features/settings/components/billing-section.tsx +283 -0
  330. package/template/src/features/settings/components/index.ts +3 -0
  331. package/template/src/features/settings/components/profile-form.tsx +154 -0
  332. package/template/src/features/settings/components/security-section.tsx +158 -0
  333. package/template/src/features/settings/components/settings-profile-view.tsx +506 -0
  334. package/template/src/features/settings/index.ts +5 -0
  335. package/template/src/features/settings/manifest.ts +28 -0
  336. package/template/src/features/settings/schemas/index.ts +2 -0
  337. package/template/src/features/settings/schemas/update-profile.ts +21 -0
  338. package/template/src/features/shared/components/cookie-settings-dialog.tsx +282 -0
  339. package/template/src/features/shared/components/index.ts +5 -0
  340. package/template/src/features/shared/components/language-switcher.tsx +82 -0
  341. package/template/src/features/shared/components/max-width-wrapper.tsx +49 -0
  342. package/template/src/features/shared/components/mode-toggle.tsx +119 -0
  343. package/template/src/features/shared/icons/google-icon.tsx +39 -0
  344. package/template/src/features/shared/icons/index.ts +7 -0
  345. package/template/src/features/shared/index.ts +5 -0
  346. package/template/src/features/shared/manifest.ts +13 -0
  347. package/template/src/features/shared/providers.tsx +59 -0
  348. package/template/src/features/storage/actions.ts +107 -0
  349. package/template/src/features/storage/index.ts +6 -0
  350. package/template/src/features/storage/manifest.ts +22 -0
  351. package/template/src/features/storage/types.ts +143 -0
  352. package/template/src/features/storage/utils.ts +85 -0
  353. package/template/src/features/storage/validation.ts +151 -0
  354. package/template/src/features/subscription/actions/get-user-plan.ts +26 -0
  355. package/template/src/features/subscription/actions/index.ts +5 -0
  356. package/template/src/features/subscription/components/current-plan-badge.tsx +18 -0
  357. package/template/src/features/subscription/components/index.ts +6 -0
  358. package/template/src/features/subscription/components/plan-badge.tsx +98 -0
  359. package/template/src/features/subscription/index.ts +25 -0
  360. package/template/src/features/subscription/manifest.ts +13 -0
  361. package/template/src/features/subscription/services/user-plan.ts +181 -0
  362. package/template/src/features/support/actions/admin-ticket.ts +172 -0
  363. package/template/src/features/support/actions/admin-users.ts +295 -0
  364. package/template/src/features/support/actions/index.ts +22 -0
  365. package/template/src/features/support/actions/ticket.ts +12 -0
  366. package/template/src/features/support/actions/user-ticket.ts +153 -0
  367. package/template/src/features/support/components/admin-ticket-reply-form.tsx +109 -0
  368. package/template/src/features/support/components/admin-ticket-status-select.tsx +119 -0
  369. package/template/src/features/support/components/index.ts +6 -0
  370. package/template/src/features/support/components/ticket-message-form.tsx +99 -0
  371. package/template/src/features/support/components/user-role-select.tsx +107 -0
  372. package/template/src/features/support/index.ts +5 -0
  373. package/template/src/features/support/manifest.ts +53 -0
  374. package/template/src/features/support/schemas/index.ts +15 -0
  375. package/template/src/features/support/schemas/ticket.ts +81 -0
  376. package/template/src/hooks/index.ts +2 -0
  377. package/template/src/i18n/index.ts +12 -0
  378. package/template/src/i18n/request.ts +24 -0
  379. package/template/src/i18n/routing.ts +23 -0
  380. package/template/src/instrumentation.ts +19 -0
  381. package/template/src/lib/ai/index.ts +16 -0
  382. package/template/src/lib/api-logger.ts +24 -0
  383. package/template/src/lib/auth/admin.ts +54 -0
  384. package/template/src/lib/auth/api.ts +17 -0
  385. package/template/src/lib/auth/client.ts +227 -0
  386. package/template/src/lib/auth/edge.ts +84 -0
  387. package/template/src/lib/auth/errors.ts +99 -0
  388. package/template/src/lib/auth/index.ts +159 -0
  389. package/template/src/lib/auth/server.ts +46 -0
  390. package/template/src/lib/auth/session-context.tsx +96 -0
  391. package/template/src/lib/cloudflare/bindings.ts +31 -0
  392. package/template/src/lib/cookie-consent.ts +33 -0
  393. package/template/src/lib/file-utils.ts +45 -0
  394. package/template/src/lib/fingerprint/index.ts +73 -0
  395. package/template/src/lib/health/checks.ts +6 -0
  396. package/template/src/lib/health/core.ts +86 -0
  397. package/template/src/lib/health/index.ts +11 -0
  398. package/template/src/lib/health/types.ts +13 -0
  399. package/template/src/lib/index.ts +2 -0
  400. package/template/src/lib/logger/index.ts +258 -0
  401. package/template/src/lib/monitoring/index.ts +384 -0
  402. package/template/src/lib/rate-limit/anonymous.ts +85 -0
  403. package/template/src/lib/rate-limit/index.ts +111 -0
  404. package/template/src/lib/safe-action.ts +127 -0
  405. package/template/src/lib/seo/json-ld.ts +188 -0
  406. package/template/src/lib/source.ts +122 -0
  407. package/template/src/lib/utils.ts +6 -0
  408. package/template/src/middleware.ts +162 -0
  409. package/template/src/modules/index.ts +10 -0
  410. package/template/src/modules/presets.ts +8 -0
  411. package/template/src/modules/registry.ts +34 -0
  412. package/template/src/modules/selection.ts +45 -0
  413. package/template/src/services/ai.ts +49 -0
  414. package/template/src/services/index.ts +6 -0
  415. package/template/src/services/jobs.ts +3 -0
  416. package/template/src/services/mail.ts +7 -0
  417. package/template/src/services/payment.ts +3 -0
  418. package/template/src/services/rate-limit.ts +12 -0
  419. package/template/src/services/storage.ts +3 -0
  420. package/template/src/types/fumadocs-source.d.ts +14 -0
  421. package/template/src/types/index.ts +2 -0
  422. package/template/tsconfig.json +53 -0
  423. package/template/vercel.json +11 -0
  424. package/template/vitest.config.ts +51 -0
  425. package/template/wrangler.jsonc +30 -0
@@ -0,0 +1,534 @@
1
+ [
2
+ {
3
+ "slug": "ai-meeting-notes",
4
+ "category": "Product Ops",
5
+ "locales": {
6
+ "en": {
7
+ "seo": {
8
+ "title": "AI Meeting Notes for Product Teams | NextDevTpl",
9
+ "description": "Turn messy transcripts into clear decisions, action items, and follow-ups with automated meeting notes."
10
+ },
11
+ "hero": {
12
+ "badge": "PSEO Template",
13
+ "title": "AI Meeting Notes for",
14
+ "highlight": "Product Teams",
15
+ "subtitle": "Transform raw call transcripts into structured decisions, action items, and follow-ups in minutes.",
16
+ "primaryCta": {
17
+ "label": "Start free",
18
+ "href": "/sign-up"
19
+ },
20
+ "secondaryCta": {
21
+ "label": "See pricing",
22
+ "href": "/#pricing"
23
+ },
24
+ "summaryTitle": "Workflow snapshot",
25
+ "summaryItems": [
26
+ "Auto-generated recap and decisions",
27
+ "Action items mapped to owners",
28
+ "Stakeholder-ready highlights"
29
+ ]
30
+ },
31
+ "stats": [
32
+ {
33
+ "label": "Time saved",
34
+ "value": "6.5 hrs/week",
35
+ "detail": "Average across PM syncs"
36
+ },
37
+ {
38
+ "label": "Follow-up speed",
39
+ "value": "2x faster",
40
+ "detail": "From meeting to action"
41
+ },
42
+ {
43
+ "label": "Adoption",
44
+ "value": "94%",
45
+ "detail": "Teams stay active after month 1"
46
+ }
47
+ ],
48
+ "sections": {
49
+ "features": {
50
+ "title": "Features built for high-velocity product teams",
51
+ "subtitle": "Everything you need to capture decisions and keep roadmaps moving."
52
+ },
53
+ "useCases": {
54
+ "title": "Where teams use this template",
55
+ "subtitle": "From customer discovery to sprint reviews, keep every meeting accountable."
56
+ },
57
+ "faq": {
58
+ "title": "FAQ",
59
+ "subtitle": "Quick answers about this PSEO workflow."
60
+ },
61
+ "related": {
62
+ "title": "More PSEO templates",
63
+ "subtitle": "Explore other JSON-driven landing pages in the demo."
64
+ }
65
+ },
66
+ "features": [
67
+ {
68
+ "title": "Agenda-aware summaries",
69
+ "description": "Detect agenda sections and group decisions automatically.",
70
+ "icon": "sparkles"
71
+ },
72
+ {
73
+ "title": "Action item routing",
74
+ "description": "Assign owners, due dates, and sync tasks to Jira or Linear.",
75
+ "icon": "target"
76
+ },
77
+ {
78
+ "title": "Speaker insights",
79
+ "description": "Track talk time, sentiment, and open questions by stakeholder.",
80
+ "icon": "lineChart"
81
+ },
82
+ {
83
+ "title": "Stakeholder sharing",
84
+ "description": "Publish recap links in branded templates within seconds.",
85
+ "icon": "share"
86
+ }
87
+ ],
88
+ "useCases": [
89
+ {
90
+ "title": "Customer discovery calls",
91
+ "description": "Capture pain points and keep roadmaps aligned after every interview.",
92
+ "metric": "32%",
93
+ "metricLabel": "faster follow-ups"
94
+ },
95
+ {
96
+ "title": "Weekly product syncs",
97
+ "description": "Record decisions, owners, and dependencies without extra notes.",
98
+ "metric": "48h",
99
+ "metricLabel": "decision turnaround"
100
+ },
101
+ {
102
+ "title": "Sprint reviews",
103
+ "description": "Summaries ready for execs and customers within hours.",
104
+ "metric": "3x",
105
+ "metricLabel": "faster summaries"
106
+ }
107
+ ],
108
+ "faq": [
109
+ {
110
+ "question": "Can I connect this with my task tracker?",
111
+ "answer": "Yes. The workflow exports action items to Jira, Linear, and Notion, plus custom webhooks."
112
+ },
113
+ {
114
+ "question": "Does it support multiple meeting formats?",
115
+ "answer": "The template ships with presets for 1:1s, sprint reviews, and discovery calls."
116
+ },
117
+ {
118
+ "question": "How are summaries generated?",
119
+ "answer": "You can use AI models or manually curated rules. Both are configured in the JSON dataset."
120
+ }
121
+ ],
122
+ "cta": {
123
+ "title": "Launch your meeting hub",
124
+ "description": "Start with the AI Meeting Notes template and generate hundreds of pages for every team or industry.",
125
+ "primaryCta": {
126
+ "label": "Start free",
127
+ "href": "/sign-up"
128
+ },
129
+ "secondaryCta": {
130
+ "label": "See pricing",
131
+ "href": "/#pricing"
132
+ },
133
+ "note": "No credit card required."
134
+ }
135
+ },
136
+ "zh": {
137
+ "seo": {
138
+ "title": "产品团队的 AI 会议纪要 | NextDevTpl",
139
+ "description": "把杂乱会议记录自动整理为决策、行动项和跟进计划。"
140
+ },
141
+ "hero": {
142
+ "badge": "PSEO 模板",
143
+ "title": "为产品团队打造的",
144
+ "highlight": "AI 会议纪要",
145
+ "subtitle": "将会议录音与转录快速整理为结构化结论、行动项与复盘摘要。",
146
+ "primaryCta": {
147
+ "label": "免费开始",
148
+ "href": "/sign-up"
149
+ },
150
+ "secondaryCta": {
151
+ "label": "查看定价",
152
+ "href": "/#pricing"
153
+ },
154
+ "summaryTitle": "模板速览",
155
+ "summaryItems": [
156
+ "自动生成会议总结与结论",
157
+ "行动项自动分配责任人",
158
+ "一键分享给关键干系人"
159
+ ]
160
+ },
161
+ "stats": [
162
+ {
163
+ "label": "节省时间",
164
+ "value": "6.5 小时/周",
165
+ "detail": "来自产品同步会议"
166
+ },
167
+ {
168
+ "label": "跟进效率",
169
+ "value": "提升 2 倍",
170
+ "detail": "从会议到执行"
171
+ },
172
+ {
173
+ "label": "持续使用",
174
+ "value": "94%",
175
+ "detail": "第 1 个月后仍活跃"
176
+ }
177
+ ],
178
+ "sections": {
179
+ "features": {
180
+ "title": "专为高节奏产品团队设计的能力",
181
+ "subtitle": "帮助你快速捕捉决策、推动 roadmap。"
182
+ },
183
+ "useCases": {
184
+ "title": "适用场景",
185
+ "subtitle": "从用户访谈到迭代复盘,让每场会议都有产出。"
186
+ },
187
+ "faq": {
188
+ "title": "常见问题",
189
+ "subtitle": "关于该 PSEO 模板的常见解答。"
190
+ },
191
+ "related": {
192
+ "title": "更多 PSEO 模板",
193
+ "subtitle": "继续探索更多 JSON 驱动的落地页。"
194
+ }
195
+ },
196
+ "features": [
197
+ {
198
+ "title": "议程识别总结",
199
+ "description": "自动识别议程并聚合关键决策。",
200
+ "icon": "sparkles"
201
+ },
202
+ {
203
+ "title": "行动项流转",
204
+ "description": "分配负责人、截止时间并同步到 Jira/Linear。",
205
+ "icon": "target"
206
+ },
207
+ {
208
+ "title": "发言洞察",
209
+ "description": "追踪讨论热度、情绪与未解决问题。",
210
+ "icon": "lineChart"
211
+ },
212
+ {
213
+ "title": "干系人分享",
214
+ "description": "秒级生成可分享的品牌化纪要。",
215
+ "icon": "share"
216
+ }
217
+ ],
218
+ "useCases": [
219
+ {
220
+ "title": "用户访谈",
221
+ "description": "记录痛点与需求,推动产品方向一致。",
222
+ "metric": "32%",
223
+ "metricLabel": "更快跟进"
224
+ },
225
+ {
226
+ "title": "周会同步",
227
+ "description": "决策、负责人、依赖关系清晰可追踪。",
228
+ "metric": "48 小时",
229
+ "metricLabel": "决策周期"
230
+ },
231
+ {
232
+ "title": "迭代复盘",
233
+ "description": "快速生成给管理层的复盘摘要。",
234
+ "metric": "3 倍",
235
+ "metricLabel": "更快总结"
236
+ }
237
+ ],
238
+ "faq": [
239
+ {
240
+ "question": "可以对接任务管理工具吗?",
241
+ "answer": "可以。支持 Jira、Linear、Notion 的行动项同步,并可配置 webhook。"
242
+ },
243
+ {
244
+ "question": "支持不同会议模板吗?",
245
+ "answer": "内置 1:1、迭代复盘、用户访谈等预设场景。"
246
+ },
247
+ {
248
+ "question": "总结是如何生成的?",
249
+ "answer": "可选择 AI 模型或自定义规则,全部在 JSON 数据中配置。"
250
+ }
251
+ ],
252
+ "cta": {
253
+ "title": "开启你的会议中心",
254
+ "description": "使用 AI 会议纪要模板,快速扩展到更多团队与行业。",
255
+ "primaryCta": {
256
+ "label": "免费开始",
257
+ "href": "/sign-up"
258
+ },
259
+ "secondaryCta": {
260
+ "label": "查看定价",
261
+ "href": "/#pricing"
262
+ },
263
+ "note": "无需信用卡。"
264
+ }
265
+ }
266
+ }
267
+ },
268
+ {
269
+ "slug": "sales-playbook",
270
+ "category": "Revenue",
271
+ "locales": {
272
+ "en": {
273
+ "seo": {
274
+ "title": "Sales Playbook Generator for Growth Teams | NextDevTpl",
275
+ "description": "Generate tailored sales playbooks for every segment using structured JSON data."
276
+ },
277
+ "hero": {
278
+ "badge": "PSEO Template",
279
+ "title": "Sales Playbook Generator for",
280
+ "highlight": "Growth Teams",
281
+ "subtitle": "Create segment-specific messaging, objections, and next steps with repeatable workflows.",
282
+ "primaryCta": {
283
+ "label": "Start free",
284
+ "href": "/sign-up"
285
+ },
286
+ "secondaryCta": {
287
+ "label": "View demo",
288
+ "href": "/#pricing"
289
+ },
290
+ "summaryTitle": "Playbook snapshot",
291
+ "summaryItems": [
292
+ "Persona-specific messaging",
293
+ "Deal stage checklists",
294
+ "Competitive battlecards"
295
+ ]
296
+ },
297
+ "stats": [
298
+ {
299
+ "label": "Win rate lift",
300
+ "value": "18%",
301
+ "detail": "Average after 60 days"
302
+ },
303
+ {
304
+ "label": "Rep ramp time",
305
+ "value": "14 days",
306
+ "detail": "From hire to quota"
307
+ },
308
+ {
309
+ "label": "Templates",
310
+ "value": "120+",
311
+ "detail": "Ready for new segments"
312
+ }
313
+ ],
314
+ "sections": {
315
+ "features": {
316
+ "title": "Features that scale revenue enablement",
317
+ "subtitle": "Generate messaging that stays consistent across every segment."
318
+ },
319
+ "useCases": {
320
+ "title": "Use cases by growth stage",
321
+ "subtitle": "Adapt playbooks for outbound, expansion, and renewals."
322
+ },
323
+ "faq": {
324
+ "title": "FAQ",
325
+ "subtitle": "Everything you need to run this playbook at scale."
326
+ },
327
+ "related": {
328
+ "title": "More PSEO templates",
329
+ "subtitle": "Explore other JSON-driven landing pages in the demo."
330
+ }
331
+ },
332
+ "features": [
333
+ {
334
+ "title": "Segment logic",
335
+ "description": "Drive custom messaging by industry, ARR, or intent score.",
336
+ "icon": "layers"
337
+ },
338
+ {
339
+ "title": "Objection handling",
340
+ "description": "Generate rebuttals and proof points based on deal stage.",
341
+ "icon": "shield"
342
+ },
343
+ {
344
+ "title": "Deal acceleration",
345
+ "description": "Surface next-best actions to move opportunities forward.",
346
+ "icon": "zap"
347
+ },
348
+ {
349
+ "title": "Rep coaching",
350
+ "description": "Personalized tips and talk tracks for new hires.",
351
+ "icon": "users"
352
+ }
353
+ ],
354
+ "useCases": [
355
+ {
356
+ "title": "Mid-market outbound",
357
+ "description": "Auto-generate personalized messaging by vertical.",
358
+ "metric": "22%",
359
+ "metricLabel": "reply rate"
360
+ },
361
+ {
362
+ "title": "Enterprise expansion",
363
+ "description": "Align playbooks with multi-threaded account plans.",
364
+ "metric": "1.6x",
365
+ "metricLabel": "pipeline lift"
366
+ },
367
+ {
368
+ "title": "Renewal operations",
369
+ "description": "Standardize health check scripts and success metrics.",
370
+ "metric": "30%",
371
+ "metricLabel": "churn reduction"
372
+ }
373
+ ],
374
+ "faq": [
375
+ {
376
+ "question": "Can this pull data from our CRM?",
377
+ "answer": "Yes. Connect Salesforce or HubSpot to hydrate playbooks with live account data."
378
+ },
379
+ {
380
+ "question": "How do we update templates?",
381
+ "answer": "Edit the JSON dataset or import changes from a spreadsheet. Updates go live instantly."
382
+ },
383
+ {
384
+ "question": "Is there support for multiple brands?",
385
+ "answer": "Multi-brand setups are supported with theme tokens and per-brand content blocks."
386
+ }
387
+ ],
388
+ "cta": {
389
+ "title": "Scale your sales enablement",
390
+ "description": "Launch the Sales Playbook template and generate targeted pages for every segment.",
391
+ "primaryCta": {
392
+ "label": "Start free",
393
+ "href": "/sign-up"
394
+ },
395
+ "secondaryCta": {
396
+ "label": "See pricing",
397
+ "href": "/#pricing"
398
+ },
399
+ "note": "No implementation services required."
400
+ }
401
+ },
402
+ "zh": {
403
+ "seo": {
404
+ "title": "增长团队的销售作战手册 | NextDevTpl",
405
+ "description": "用结构化 JSON 数据为每个细分市场生成专属销售手册。"
406
+ },
407
+ "hero": {
408
+ "badge": "PSEO 模板",
409
+ "title": "增长团队的",
410
+ "highlight": "销售作战手册",
411
+ "subtitle": "为不同客群生成话术、异议处理与下一步行动建议。",
412
+ "primaryCta": {
413
+ "label": "免费开始",
414
+ "href": "/sign-up"
415
+ },
416
+ "secondaryCta": {
417
+ "label": "查看演示",
418
+ "href": "/#pricing"
419
+ },
420
+ "summaryTitle": "手册速览",
421
+ "summaryItems": [
422
+ "按画像生成的沟通策略",
423
+ "标准化的阶段清单",
424
+ "竞品对比与战术卡片"
425
+ ]
426
+ },
427
+ "stats": [
428
+ {
429
+ "label": "赢单提升",
430
+ "value": "18%",
431
+ "detail": "60 天内平均表现"
432
+ },
433
+ {
434
+ "label": "新人上手",
435
+ "value": "14 天",
436
+ "detail": "从入职到达标"
437
+ },
438
+ {
439
+ "label": "模板数量",
440
+ "value": "120+",
441
+ "detail": "覆盖更多细分"
442
+ }
443
+ ],
444
+ "sections": {
445
+ "features": {
446
+ "title": "驱动收入增长的关键能力",
447
+ "subtitle": "让每个细分市场都能输出一致话术。"
448
+ },
449
+ "useCases": {
450
+ "title": "增长阶段典型场景",
451
+ "subtitle": "外呼、续费、扩张策略一网打尽。"
452
+ },
453
+ "faq": {
454
+ "title": "常见问题",
455
+ "subtitle": "关于销售作战手册的常见解答。"
456
+ },
457
+ "related": {
458
+ "title": "更多 PSEO 模板",
459
+ "subtitle": "查看其他 JSON 驱动的落地页示例。"
460
+ }
461
+ },
462
+ "features": [
463
+ {
464
+ "title": "细分逻辑",
465
+ "description": "按照行业、ARR、意向评分生成定制话术。",
466
+ "icon": "layers"
467
+ },
468
+ {
469
+ "title": "异议处理",
470
+ "description": "按阶段生成证据与反驳要点。",
471
+ "icon": "shield"
472
+ },
473
+ {
474
+ "title": "推进节奏",
475
+ "description": "提示下一步行动并加速成交。",
476
+ "icon": "zap"
477
+ },
478
+ {
479
+ "title": "新人辅导",
480
+ "description": "提供角色化建议与话术提示。",
481
+ "icon": "users"
482
+ }
483
+ ],
484
+ "useCases": [
485
+ {
486
+ "title": "中端市场外呼",
487
+ "description": "按行业快速生成个性化脚本。",
488
+ "metric": "22%",
489
+ "metricLabel": "回复率"
490
+ },
491
+ {
492
+ "title": "大客户扩张",
493
+ "description": "多线程计划与账户协同。",
494
+ "metric": "1.6 倍",
495
+ "metricLabel": "pipeline 提升"
496
+ },
497
+ {
498
+ "title": "续费运营",
499
+ "description": "标准化健康度检查与成功指标。",
500
+ "metric": "30%",
501
+ "metricLabel": "流失下降"
502
+ }
503
+ ],
504
+ "faq": [
505
+ {
506
+ "question": "可以同步 CRM 数据吗?",
507
+ "answer": "可以对接 Salesforce 或 HubSpot,为手册注入实时客户数据。"
508
+ },
509
+ {
510
+ "question": "如何更新模板内容?",
511
+ "answer": "直接修改 JSON 或从表格导入,更新立即生效。"
512
+ },
513
+ {
514
+ "question": "支持多品牌版本吗?",
515
+ "answer": "支持。可基于主题令牌与内容块区分品牌。"
516
+ }
517
+ ],
518
+ "cta": {
519
+ "title": "规模化你的销售赋能",
520
+ "description": "用销售作战手册模板为每个细分市场生成专属页面。",
521
+ "primaryCta": {
522
+ "label": "免费开始",
523
+ "href": "/sign-up"
524
+ },
525
+ "secondaryCta": {
526
+ "label": "查看定价",
527
+ "href": "/#pricing"
528
+ },
529
+ "note": "无需额外实施服务。"
530
+ }
531
+ }
532
+ }
533
+ }
534
+ ]
@@ -0,0 +1,4 @@
1
+ // PSEO Feature
2
+ export * from "./components";
3
+ export * from "./lib/pseo-data";
4
+ export { pseoModule } from "./manifest";
@@ -0,0 +1,140 @@
1
+ import pseoPages from "../data/pseo-pages.json";
2
+
3
+ export interface PseoCtaLink {
4
+ label: string;
5
+ href: string;
6
+ }
7
+
8
+ export interface PseoHeroData {
9
+ badge: string;
10
+ title: string;
11
+ highlight: string;
12
+ subtitle: string;
13
+ primaryCta: PseoCtaLink;
14
+ secondaryCta: PseoCtaLink;
15
+ summaryTitle: string;
16
+ summaryItems: string[];
17
+ }
18
+
19
+ export interface PseoStat {
20
+ label: string;
21
+ value: string;
22
+ detail: string;
23
+ }
24
+
25
+ export interface PseoSectionCopy {
26
+ title: string;
27
+ subtitle: string;
28
+ }
29
+
30
+ export interface PseoFeature {
31
+ title: string;
32
+ description: string;
33
+ icon: string;
34
+ }
35
+
36
+ export interface PseoUseCase {
37
+ title: string;
38
+ description: string;
39
+ metric: string;
40
+ metricLabel: string;
41
+ }
42
+
43
+ export interface PseoFaqItem {
44
+ question: string;
45
+ answer: string;
46
+ }
47
+
48
+ export interface PseoCtaData {
49
+ title: string;
50
+ description: string;
51
+ primaryCta: PseoCtaLink;
52
+ secondaryCta: PseoCtaLink;
53
+ note: string;
54
+ }
55
+
56
+ export interface PseoLocaleData {
57
+ seo: {
58
+ title: string;
59
+ description: string;
60
+ };
61
+ hero: PseoHeroData;
62
+ stats: PseoStat[];
63
+ sections: {
64
+ features: PseoSectionCopy;
65
+ useCases: PseoSectionCopy;
66
+ faq: PseoSectionCopy;
67
+ related: PseoSectionCopy;
68
+ };
69
+ features: PseoFeature[];
70
+ useCases: PseoUseCase[];
71
+ faq: PseoFaqItem[];
72
+ cta: PseoCtaData;
73
+ }
74
+
75
+ export interface PseoPageRecord {
76
+ slug: string;
77
+ category: string;
78
+ locales: Record<string, PseoLocaleData>;
79
+ }
80
+
81
+ export interface PseoPage {
82
+ slug: string;
83
+ category: string;
84
+ locale: string;
85
+ data: PseoLocaleData;
86
+ }
87
+
88
+ const pages = pseoPages as PseoPageRecord[];
89
+ const fallbackLocale = "en";
90
+
91
+ export function getPseoPages(locale: string) {
92
+ return pages
93
+ .map((page) => {
94
+ const data = page.locales[locale] ?? page.locales[fallbackLocale];
95
+ if (!data) {
96
+ return null;
97
+ }
98
+ const resolvedLocale = page.locales[locale] ? locale : fallbackLocale;
99
+ return {
100
+ slug: page.slug,
101
+ category: page.category,
102
+ locale: resolvedLocale,
103
+ data,
104
+ } satisfies PseoPage;
105
+ })
106
+ .filter((page): page is PseoPage => page !== null);
107
+ }
108
+
109
+ export function getPseoPage(locale: string, slug: string) {
110
+ const page = pages.find((entry) => entry.slug === slug);
111
+ if (!page) {
112
+ return null;
113
+ }
114
+ const data = page.locales[locale] ?? page.locales[fallbackLocale];
115
+ if (!data) {
116
+ return null;
117
+ }
118
+ const resolvedLocale = page.locales[locale] ? locale : fallbackLocale;
119
+ return {
120
+ slug: page.slug,
121
+ category: page.category,
122
+ locale: resolvedLocale,
123
+ data,
124
+ } satisfies PseoPage;
125
+ }
126
+
127
+ export function getRelatedPseoPages(locale: string, slug: string, limit = 3) {
128
+ return getPseoPages(locale)
129
+ .filter((page) => page.slug !== slug)
130
+ .slice(0, limit);
131
+ }
132
+
133
+ export function getAllPseoParams() {
134
+ return pages.flatMap((page) =>
135
+ Object.keys(page.locales).map((locale) => ({
136
+ locale,
137
+ slug: page.slug,
138
+ }))
139
+ );
140
+ }
@@ -0,0 +1,22 @@
1
+ import { defineModule } from "@/core/modules";
2
+
3
+ export const pseoModule = defineModule({
4
+ id: "pseo",
5
+ name: "Programmatic SEO",
6
+ description: "结构化 SEO 落地页和静态参数",
7
+ kind: "optional",
8
+ dependencies: ["marketing"],
9
+ routes: [
10
+ {
11
+ path: "/pseo",
12
+ source: "src/app/[locale]/(marketing)/pseo/page.tsx",
13
+ },
14
+ {
15
+ path: "/pseo/[slug]",
16
+ source: "src/app/[locale]/(marketing)/pseo/[slug]/page.tsx",
17
+ },
18
+ ],
19
+ navigation: [],
20
+ translations: [],
21
+ schema: [],
22
+ });