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,61 @@
1
+ ---
2
+ title: 部署
3
+ description: 使用现有脚本或托管 Next.js 平台部署 NextDevTpl。
4
+ ---
5
+
6
+ # 部署
7
+
8
+ 仓库内置了自托管部署流程,也可以部署到托管 Next.js 平台。
9
+
10
+ ## 自托管流程
11
+
12
+ 现有脚本:
13
+
14
+ | 文件 | 运行位置 | 作用 |
15
+ | --- | --- | --- |
16
+ | `deploy-build.bat` | Windows 本地机器 | 构建、打包、上传产物 |
17
+ | `start-prod.sh` | Linux 服务器 | 安装生产依赖并启动/重启应用 |
18
+
19
+ 典型流程:
20
+
21
+ 1. 在 `deploy-build.bat` 顶部配置 SSH host、部署目录和 key path。
22
+ 2. 确认服务器上已经有生产 `.env`。
23
+ 3. 本地运行:
24
+
25
+ ```bat
26
+ deploy-build.bat
27
+ ```
28
+
29
+ 4. 脚本会本地构建、打包、上传,然后在服务器启动应用。
30
+
31
+ ## 生产环境变量
32
+
33
+ 最少需要:
34
+
35
+ ```bash
36
+ DATABASE_URL="postgresql://..."
37
+ BETTER_AUTH_SECRET="strong-production-secret"
38
+ BETTER_AUTH_URL="https://your-domain.com"
39
+ ```
40
+
41
+ 再按实际启用的功能补 Creem、Resend、Storage、Redis、Sentry、Axiom、Inngest 和 AI provider 凭证。
42
+
43
+ ## Vercel
44
+
45
+ 部署到 Vercel:
46
+
47
+ 1. 导入 GitHub 仓库。
48
+ 2. 设置生产环境变量。
49
+ 3. 确认数据库能从 Vercel 访问。
50
+ 4. 使用 Vercel 生产域名配置 webhook URL。
51
+ 5. 发布前或发布时执行数据库迁移。
52
+
53
+ ## 发布 checklist
54
+
55
+ - `pnpm typecheck` 通过。
56
+ - `pnpm build` 通过。
57
+ - 数据库迁移已准备。
58
+ - `BETTER_AUTH_URL` 使用生产域名。
59
+ - OAuth callback URL 使用生产域名。
60
+ - Creem webhook 指向 `/api/webhooks/creem`。
61
+ - Sentry/Axiom 不接收原始密钥。
@@ -0,0 +1,47 @@
1
+ ---
2
+ title: 邮件
3
+ description: 使用 Resend 和 React Email 模板发送产品邮件。
4
+ ---
5
+
6
+ # 邮件
7
+
8
+ 邮件发送使用 Resend,模板使用 React Email 组件。
9
+
10
+ ## 主要文件
11
+
12
+ | 路径 | 作用 |
13
+ | --- | --- |
14
+ | `src/features/mail/client.ts` | Resend client 配置 |
15
+ | `src/features/mail/actions.ts` | 发信 actions |
16
+ | `src/features/mail/utils.ts` | 邮件工具函数 |
17
+ | `src/features/mail/templates` | React Email 模板 |
18
+ | `src/test/mail/newsletter.test.ts` | 邮件相关测试 |
19
+
20
+ ## 环境变量
21
+
22
+ | 变量 | 作用 |
23
+ | --- | --- |
24
+ | `RESEND_API_KEY` | Resend API 凭证 |
25
+ | `EMAIL_FROM` | 用户看到的发件人 |
26
+
27
+ 示例:
28
+
29
+ ```bash
30
+ RESEND_API_KEY="re_xxxxxxxxx"
31
+ EMAIL_FROM="NextDevTpl <noreply@example.com>"
32
+ ```
33
+
34
+ ## 模板
35
+
36
+ 邮件模板是 React 组件:
37
+
38
+ | 模板 | 作用 |
39
+ | --- | --- |
40
+ | `welcome-email.tsx` | 欢迎/引导邮件 |
41
+ | `primary-action-email.tsx` | 带按钮的通用操作邮件 |
42
+
43
+ 改邮件模板时,文案尽量短,不要依赖复杂 CSS。邮件客户端的 CSS 支持很有限。
44
+
45
+ ## 本地行为
46
+
47
+ 没有配置 Resend 时,依赖邮件投递的功能应该视为不可用。先测试基础邮箱密码流程,再启用 Resend 测试验证邮件和重置密码。
@@ -0,0 +1,48 @@
1
+ ---
2
+ title: 介绍
3
+ description: 了解 NextDevTpl 内置能力,以及如何把它作为生产级 SaaS 起点。
4
+ ---
5
+
6
+ # NextDevTpl 文档
7
+
8
+ NextDevTpl 是一个偏生产落地的 SaaS 启动模板,基于 Next.js、React、TypeScript、PostgreSQL、Drizzle ORM、Better Auth、next-intl、Creem 支付、积分系统、管理后台、工单、邮件、对象存储、可观测性和后台任务构建。
9
+
10
+ 它不是只展示一个首页的 UI 模板,而是提供一套可以继续二开的产品骨架。
11
+
12
+ ## 内置能力
13
+
14
+ | 模块 | 说明 |
15
+ | --- | --- |
16
+ | 应用骨架 | 多语言营销页、博客、文档、Dashboard、Admin、法律页面 |
17
+ | 认证 | Better Auth 邮箱密码、OAuth、session、角色权限 |
18
+ | 数据库 | PostgreSQL schema、Drizzle ORM、迁移和集成测试 |
19
+ | 支付 | Creem checkout、订阅、webhook、一次性积分购买 |
20
+ | 积分 | 账本式积分记录、FIFO 批次过期、余额读取 |
21
+ | 运营 | 用户管理、工单、日志、监控、限流、后台任务 |
22
+ | 内容 | Fumadocs 文档、MDX 博客、next-intl UI 翻译 |
23
+
24
+ ## 推荐阅读顺序
25
+
26
+ 如果你想先跑起来,建议看:
27
+
28
+ - [快速开始](/zh/docs/quick-start)
29
+ - [项目结构](/zh/docs/project-structure)
30
+ - [配置说明](/zh/docs/configuration)
31
+
32
+ 如果你要接入业务功能,建议看:
33
+
34
+ - [认证](/zh/docs/authentication)
35
+ - [支付](/zh/docs/payments)
36
+ - [积分系统](/zh/docs/credits)
37
+ - [国际化](/zh/docs/internationalization)
38
+
39
+ 如果你准备上线,建议看:
40
+
41
+ - [部署](/zh/docs/deployment)
42
+ - [可观测性](/zh/docs/observability)
43
+ - [后台任务](/zh/docs/background-jobs)
44
+
45
+ ## 核心原则
46
+
47
+ 本地开发时,大多数外部服务都应该是可选的。项目先用数据库和基础认证跑起来,再按产品需要逐步启用 OAuth、邮件、支付、对象存储、Redis、Sentry、Axiom 和 Inngest。
48
+
@@ -0,0 +1,78 @@
1
+ ---
2
+ title: 国际化
3
+ description: 使用 next-intl 路由、UI 文案和多语言文档。
4
+ ---
5
+
6
+ # 国际化
7
+
8
+ NextDevTpl 使用 `next-intl` 处理 UI 翻译和带语言前缀的路由。文档内容通过 Fumadocs 的语言目录管理。
9
+
10
+ ## 当前语言
11
+
12
+ 语言配置在:
13
+
14
+ ```txt
15
+ src/i18n/routing.ts
16
+ ```
17
+
18
+ 当前值:
19
+
20
+ ```ts
21
+ locales: ["en", "zh"]
22
+ defaultLocale: "en"
23
+ ```
24
+
25
+ ## UI 文案
26
+
27
+ | 文件 | 作用 |
28
+ | --- | --- |
29
+ | `messages/en.json` | 英文 UI 文案 |
30
+ | `messages/zh.json` | 中文 UI 文案 |
31
+ | `src/i18n/request.ts` | 加载当前语言 messages |
32
+ | `src/features/shared/components/language-switcher.tsx` | Header 语言切换器 |
33
+
34
+ Client Component 使用 `useTranslations()`。Server Component 使用 next-intl 的服务端 helpers。
35
+
36
+ ## 路由结构
37
+
38
+ 大多数页面都在:
39
+
40
+ ```txt
41
+ src/app/[locale]
42
+ ```
43
+
44
+ 示例:
45
+
46
+ ```txt
47
+ /en
48
+ /zh
49
+ /en/dashboard
50
+ /zh/dashboard
51
+ /en/docs
52
+ /zh/docs
53
+ ```
54
+
55
+ ## 文档国际化
56
+
57
+ 文档按语言存放:
58
+
59
+ ```txt
60
+ src/content/docs/en
61
+ src/content/docs/zh
62
+ ```
63
+
64
+ `src/lib/source.ts` 中的 loader 使用 Fumadocs i18n,并采用 `dir` parser。docs route 会根据 `params.locale` 取页面,所以 `/en/docs` 和 `/zh/docs` 是两棵独立文档树。
65
+
66
+ ## 新增语言
67
+
68
+ 1. 在 `src/i18n/routing.ts` 添加 locale。
69
+ 2. 新增 `messages/<locale>.json`。
70
+ 3. 新增 `src/content/docs/<locale>`。
71
+ 4. 如果博客和法律页面也支持该语言,也要补对应内容。
72
+ 5. 必要时更新 sitemap metadata。
73
+ 6. 测试导航和语言切换。
74
+
75
+ ## 翻译原则
76
+
77
+ 不要机械翻译技术名词。Next.js、Drizzle、Better Auth、Creem、Inngest、Sentry、Axiom、Fumadocs、next-intl 这些框架或服务名保持英文。
78
+
@@ -0,0 +1,22 @@
1
+ {
2
+ "title": "NextDevTpl",
3
+ "root": true,
4
+ "pages": [
5
+ "index",
6
+ "quick-start",
7
+ "project-structure",
8
+ "configuration",
9
+ "authentication",
10
+ "database",
11
+ "credits",
12
+ "payments",
13
+ "email",
14
+ "storage",
15
+ "internationalization",
16
+ "background-jobs",
17
+ "admin-and-support",
18
+ "observability",
19
+ "deployment",
20
+ "customization"
21
+ ]
22
+ }
@@ -0,0 +1,68 @@
1
+ ---
2
+ title: 可观测性
3
+ description: 配置日志、监控、限流和请求诊断。
4
+ ---
5
+
6
+ # 可观测性
7
+
8
+ NextDevTpl 包含结构化日志、可选云端日志、Sentry 监控、限流和 API 请求日志工具。
9
+
10
+ ## 日志
11
+
12
+ | 路径 | 作用 |
13
+ | --- | --- |
14
+ | `src/lib/logger/index.ts` | Pino logger wrapper |
15
+ | `src/lib/api-logger.ts` | API logging helpers |
16
+
17
+ 配置 Axiom 后,日志可以发送到 Axiom。未配置时,日志应仍然能在本地看到。
18
+
19
+ 常见变量:
20
+
21
+ ```bash
22
+ AXIOM_TOKEN="xaat-..."
23
+ AXIOM_DATASET="nextdevtpl"
24
+ ```
25
+
26
+ ## 错误监控
27
+
28
+ Sentry 配置文件:
29
+
30
+ | 路径 | 作用 |
31
+ | --- | --- |
32
+ | `sentry.client.config.ts` | 浏览器 Sentry 配置 |
33
+ | `sentry.server.config.ts` | 服务端 Sentry 配置 |
34
+ | `sentry.edge.config.ts` | Edge Sentry 配置 |
35
+ | `src/instrumentation.ts` | Next.js instrumentation hook |
36
+ | `src/lib/monitoring/index.ts` | Monitoring helpers |
37
+
38
+ 常见变量:
39
+
40
+ ```bash
41
+ NEXT_PUBLIC_SENTRY_DSN="https://..."
42
+ SENTRY_AUTH_TOKEN="sntrys_..."
43
+ ```
44
+
45
+ ## 限流
46
+
47
+ 限流代码在:
48
+
49
+ ```txt
50
+ src/lib/rate-limit
51
+ ```
52
+
53
+ Upstash 变量:
54
+
55
+ ```bash
56
+ UPSTASH_REDIS_REST_URL="https://..."
57
+ UPSTASH_REDIS_REST_TOKEN="..."
58
+ ```
59
+
60
+ 没有 Redis 时,开发环境不应该因为限流配置缺失而启动失败。
61
+
62
+ ## 生产 checklist
63
+
64
+ - 用户可见错误接入 Sentry。
65
+ - webhook 和支付流程开启结构化日志。
66
+ - 支付和 job retry 日志记录外部事件 id。
67
+ - 不记录原始密钥、token、authorization headers。
68
+ - 检查公开 mutation endpoint 的限流。
@@ -0,0 +1,64 @@
1
+ ---
2
+ title: 支付
3
+ description: 配置 Creem 支付、订阅、一次性购买和 webhooks。
4
+ ---
5
+
6
+ # 支付
7
+
8
+ 支付层基于 Creem。模板包含订阅、一次性积分购买、webhook 处理和用户套餐查询。
9
+
10
+ ## 主要文件
11
+
12
+ | 路径 | 作用 |
13
+ | --- | --- |
14
+ | `src/features/payment/creem.ts` | Creem client 和 API 集成 |
15
+ | `src/features/payment/actions.ts` | Checkout 和支付 Server Actions |
16
+ | `src/features/payment/types.ts` | 支付相关类型 |
17
+ | `src/config/payment.ts` | 产品和支付配置 |
18
+ | `src/config/subscription-plan.ts` | 套餐定义 |
19
+ | `src/app/api/webhooks/creem/route.ts` | Creem webhook endpoint |
20
+ | `src/features/subscription` | 用户套餐查询和订阅 UI |
21
+ | `src/test/payment` | 支付和订阅测试 |
22
+
23
+ ## 必要环境变量
24
+
25
+ | 变量 | 作用 |
26
+ | --- | --- |
27
+ | `CREEM_API_KEY` | 调用 Creem API |
28
+ | `CREEM_WEBHOOK_SECRET` | 校验 webhook 签名 |
29
+
30
+ 生产环境的 callback 和 webhook URL 应该使用正式域名。
31
+
32
+ ## 订阅流程
33
+
34
+ 1. 套餐定义在 `src/config/subscription-plan.ts`。
35
+ 2. 定价 UI 展示套餐。
36
+ 3. checkout action 创建 Creem checkout session。
37
+ 4. Creem 发送 webhook 事件。
38
+ 5. webhook 更新订阅状态。
39
+ 6. Dashboard 读取当前用户套餐。
40
+
41
+ ## 积分购买流程
42
+
43
+ 一次性积分购买复用支付层,在付款成功后发放积分套餐。账本行为见 [积分系统](/zh/docs/credits)。
44
+
45
+ ## Webhook 上线 checklist
46
+
47
+ 上线前确认:
48
+
49
+ 1. 配置 Creem webhook URL:
50
+
51
+ ```txt
52
+ https://your-domain.com/api/webhooks/creem
53
+ ```
54
+
55
+ 2. 设置 `CREEM_WEBHOOK_SECRET`。
56
+ 3. 如果 Creem 支持 sandbox,先跑 sandbox checkout。
57
+ 4. 确认订阅状态会更新。
58
+ 5. 确认重复 webhook 不会重复发积分。
59
+ 6. 跑支付测试。
60
+
61
+ ```bash
62
+ pnpm test:run src/test/payment
63
+ ```
64
+
@@ -0,0 +1,82 @@
1
+ ---
2
+ title: 项目结构
3
+ description: 了解应用目录、功能模块和基础设施代码如何组织。
4
+ ---
5
+
6
+ # 项目结构
7
+
8
+ NextDevTpl 使用按功能组织的结构。路由放在 `src/app`,可复用产品模块放在 `src/features`,底层工具和基础设施放在 `src/lib`。
9
+
10
+ ## 顶层文件
11
+
12
+ | 路径 | 作用 |
13
+ | --- | --- |
14
+ | `package.json` | 脚本和依赖版本 |
15
+ | `next.config.mjs` | Next.js、MDX、构建配置 |
16
+ | `source.config.ts` | Fumadocs 内容集合配置 |
17
+ | `drizzle.config.ts` | Drizzle 迁移配置 |
18
+ | `.env.example` | 环境变量参考 |
19
+ | `deploy-build.bat` | Windows 本地构建和上传脚本 |
20
+ | `start-prod.sh` | Linux 服务器生产启动脚本 |
21
+
22
+ ## 应用路由
23
+
24
+ ```txt
25
+ src/app/
26
+ ├── [locale]/
27
+ │ ├── (marketing)/ # 首页、博客、法律页面、PSEO 等公开页面
28
+ │ ├── (auth)/ # 登录、注册、找回密码
29
+ │ ├── (dashboard)/ # 登录后的用户工作台
30
+ │ ├── (admin)/ # 管理员后台
31
+ │ └── docs/ # Fumadocs 文档
32
+ └── api/ # Route handlers 和 webhooks
33
+ ```
34
+
35
+ `[locale]` 由 `next-intl` 处理。当前语言配置在 `src/i18n/routing.ts`。
36
+
37
+ ## 功能模块
38
+
39
+ | 模块 | 作用 |
40
+ | --- | --- |
41
+ | `src/features/auth` | 登录、注册等认证 UI 和 hooks |
42
+ | `src/features/credits` | 积分账本、购买、余额工具 |
43
+ | `src/features/payment` | Creem checkout 和支付 actions |
44
+ | `src/features/subscription` | 用户套餐查询和订阅 UI |
45
+ | `src/features/settings` | 资料、安全、账单、账户设置 |
46
+ | `src/features/support` | 用户工单和管理员回复 |
47
+ | `src/features/admin` | 管理后台 UI 组件 |
48
+ | `src/features/marketing` | Header、Footer、Hero、Pricing、FAQ 等首页模块 |
49
+ | `src/features/storage` | S3/R2 上传和存储 provider |
50
+ | `src/features/mail` | React Email 模板和发信逻辑 |
51
+ | `src/features/shared` | Providers、主题切换、语言切换、共享图标 |
52
+
53
+ ## 基础设施模块
54
+
55
+ | 路径 | 职责 |
56
+ | --- | --- |
57
+ | `src/db/schema.ts` | 数据库表定义 |
58
+ | `src/lib/auth` | Better Auth server/client/edge/admin helpers |
59
+ | `src/lib/rate-limit` | 基于 Upstash 的限流和降级逻辑 |
60
+ | `src/lib/logger` | Pino logger 和 Axiom 集成 |
61
+ | `src/lib/monitoring` | Sentry 监控 helpers |
62
+ | `src/lib/source.ts` | Docs、Blog、Legal 内容加载器 |
63
+ | `src/lib/safe-action.ts` | Server Action client 配置 |
64
+ | `src/inngest` | Inngest client 和后台函数 |
65
+
66
+ ## 内容目录
67
+
68
+ | 路径 | 内容 |
69
+ | --- | --- |
70
+ | `src/content/docs/en` | 英文文档 |
71
+ | `src/content/docs/zh` | 中文文档 |
72
+ | `src/content/blog/en` | 英文博客 |
73
+ | `src/content/blog/zh` | 中文博客 |
74
+ | `src/content/legal/en` | 英文法律页面 |
75
+ | `src/content/legal/zh` | 中文法律页面 |
76
+ | `messages/en.json` | 英文 UI 文案 |
77
+ | `messages/zh.json` | 中文 UI 文案 |
78
+
79
+ ## 测试
80
+
81
+ 集成测试在 `src/test`。目前覆盖支付、积分、工单、存储安全、设置、后台任务和邮件等流程。
82
+
@@ -0,0 +1,110 @@
1
+ ---
2
+ title: 快速开始
3
+ description: 使用最小配置在本地启动 NextDevTpl。
4
+ ---
5
+
6
+ # 快速开始
7
+
8
+ 这篇文档用于用最小配置启动本地开发环境。
9
+
10
+ ## 前置要求
11
+
12
+ | 工具 | 版本 | 说明 |
13
+ | --- | --- | --- |
14
+ | Node.js | 20+ | 当前依赖要求 Node 20 以上 |
15
+ | pnpm | 推荐 10+ | lockfile 使用 pnpm 维护 |
16
+ | PostgreSQL | 推荐 14+ | 可以用本地 PostgreSQL、Neon、Supabase 等兼容服务 |
17
+
18
+ ## 安装依赖
19
+
20
+ ```bash
21
+ git clone git@github.com:evepupil/NextDevTpl.git
22
+ cd NextDevTpl
23
+ pnpm install
24
+ ```
25
+
26
+ ## 创建环境变量文件
27
+
28
+ ```bash
29
+ cp .env.example .env.local
30
+ ```
31
+
32
+ Windows PowerShell:
33
+
34
+ ```powershell
35
+ Copy-Item .env.example .env.local
36
+ ```
37
+
38
+ ## 最小启动配置
39
+
40
+ 只要下面 3 个变量存在,项目就应该能完成基础启动:
41
+
42
+ ```bash
43
+ DATABASE_URL="postgresql://postgres:password@localhost:5432/nextdevtpl"
44
+ BETTER_AUTH_SECRET="replace-with-a-random-secret"
45
+ BETTER_AUTH_URL="http://localhost:3000"
46
+ ```
47
+
48
+ 可以用下面命令生成随机密钥:
49
+
50
+ ```bash
51
+ openssl rand -base64 32
52
+ ```
53
+
54
+ OAuth、邮件、支付、对象存储、Redis、日志、监控、AI、后台任务都可以后续再接。
55
+
56
+ ## 初始化数据库
57
+
58
+ 新本地库建议直接推送当前 Drizzle schema:
59
+
60
+ ```bash
61
+ pnpm db:push
62
+ ```
63
+
64
+ 共享环境或生产环境建议走迁移:
65
+
66
+ ```bash
67
+ pnpm db:generate
68
+ pnpm db:migrate
69
+ ```
70
+
71
+ ## 启动开发服务
72
+
73
+ ```bash
74
+ pnpm dev
75
+ ```
76
+
77
+ 打开:
78
+
79
+ ```txt
80
+ http://localhost:3000
81
+ ```
82
+
83
+ 中间件会根据语言配置进入对应路径,例如 `/en` 或 `/zh`。
84
+
85
+ ## 启动后检查
86
+
87
+ | 检查项 | 预期结果 |
88
+ | --- | --- |
89
+ | 首页 | 营销页正常渲染,没有缺失翻译报错 |
90
+ | 注册 | 可以创建邮箱密码账号 |
91
+ | 登录 | 登录后进入 `/dashboard` |
92
+ | Dashboard | 侧边栏、设置、积分、工单入口正常 |
93
+ | Admin | `role = "admin"` 的用户可以访问 `/admin` |
94
+ | Docs | `/en/docs` 和 `/zh/docs` 显示各自语言的内容 |
95
+
96
+ ## 常用命令
97
+
98
+ ```bash
99
+ pnpm dev # 启动 Next.js 开发服务
100
+ pnpm build # 生产构建
101
+ pnpm start # 启动生产服务
102
+ pnpm typecheck # TypeScript 类型检查
103
+ pnpm lint # Biome lint
104
+ pnpm check # Biome check 并自动修复
105
+ pnpm db:push # 开发环境推送 Drizzle schema
106
+ pnpm db:generate # 生成迁移文件
107
+ pnpm db:migrate # 执行迁移
108
+ pnpm db:studio # 打开 Drizzle Studio
109
+ pnpm test:run # 单次运行测试
110
+ ```
@@ -0,0 +1,51 @@
1
+ ---
2
+ title: 对象存储
3
+ description: 配置 S3 或 Cloudflare R2 兼容存储和 presigned upload。
4
+ ---
5
+
6
+ # 对象存储
7
+
8
+ 存储层兼容 S3 风格服务,例如 AWS S3、Cloudflare R2 和 MinIO。
9
+
10
+ ## 主要文件
11
+
12
+ | 路径 | 作用 |
13
+ | --- | --- |
14
+ | `src/features/storage/providers/s3.ts` | S3-compatible provider |
15
+ | `src/features/storage/actions.ts` | 存储 Server Actions |
16
+ | `src/features/storage/utils.ts` | 工具函数 |
17
+ | `src/features/storage/types.ts` | 存储类型 |
18
+ | `src/app/api/upload/presigned/route.ts` | Presigned upload endpoint |
19
+ | `src/app/image-proxy/[...path]/route.ts` | 图片代理路由 |
20
+ | `src/test/storage/security.test.ts` | 存储安全测试 |
21
+
22
+ ## 环境变量
23
+
24
+ | 变量 | 作用 |
25
+ | --- | --- |
26
+ | `STORAGE_ENDPOINT` | Provider endpoint,例如 R2 endpoint |
27
+ | `STORAGE_REGION` | S3 region 或兼容值 |
28
+ | `STORAGE_BUCKET` | Bucket 名称 |
29
+ | `STORAGE_ACCESS_KEY_ID` | Access key |
30
+ | `STORAGE_SECRET_ACCESS_KEY` | Secret key |
31
+
32
+ ## 上传模型
33
+
34
+ 1. 客户端请求 presigned upload URL。
35
+ 2. 服务端校验请求并返回上传 metadata。
36
+ 3. 客户端直传到对象存储。
37
+ 4. 应用保存或使用 object key。
38
+ 5. 公开展示时可以走 image proxy。
39
+
40
+ ## 安全 checklist
41
+
42
+ - 创建 presigned URL 前校验文件类型和大小。
43
+ - object key 要有作用域,不要可预测。
44
+ - 不要把 secret key 暴露给浏览器。
45
+ - 优先使用私有 bucket,配合 signed read 或 proxy route。
46
+ - 修改上传规则后运行存储安全测试。
47
+
48
+ ```bash
49
+ pnpm test:run src/test/storage
50
+ ```
51
+