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.
- package/README.md +29 -0
- package/catalog.json +385 -0
- package/dist/catalog.d.ts +3 -0
- package/dist/catalog.js +112 -0
- package/dist/catalog.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +115 -0
- package/dist/cli.js.map +1 -0
- package/dist/filesystem.d.ts +10 -0
- package/dist/filesystem.js +86 -0
- package/dist/filesystem.js.map +1 -0
- package/dist/generate.d.ts +5 -0
- package/dist/generate.js +758 -0
- package/dist/generate.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/selection.d.ts +2 -0
- package/dist/selection.js +111 -0
- package/dist/selection.js.map +1 -0
- package/dist/service-templates.d.ts +4 -0
- package/dist/service-templates.js +180 -0
- package/dist/service-templates.js.map +1 -0
- package/dist/types.d.ts +65 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +54 -0
- package/template/.dockerignore +14 -0
- package/template/.env.example +282 -0
- package/template/.gitattributes +17 -0
- package/template/.node-version +1 -0
- package/template/Dockerfile +45 -0
- package/template/LICENSE +21 -0
- package/template/README.md +267 -0
- package/template/biome.json +68 -0
- package/template/cloudflare/templates/logger.ts +162 -0
- package/template/cloudflare/templates/mail/server.ts +6 -0
- package/template/cloudflare/templates/mail/templates.ts +87 -0
- package/template/cloudflare/templates/mail/utils.ts +69 -0
- package/template/cloudflare/worker.mjs +25 -0
- package/template/components.json +22 -0
- package/template/compose.yaml +74 -0
- package/template/deploy/check-health.mjs +25 -0
- package/template/deploy/docker/README.md +14 -0
- package/template/deploy/server/README.md +24 -0
- package/template/deploy/server/build.sh +24 -0
- package/template/deploy/server/nextdevtpl.service +19 -0
- package/template/deploy/server/start.sh +19 -0
- package/template/deploy/vercel/README.md +16 -0
- package/template/deploy/verify-production-health.mjs +86 -0
- package/template/drizzle.config.ts +47 -0
- package/template/gitignore +62 -0
- package/template/manifest.json +35 -0
- package/template/messages/en.json +766 -0
- package/template/messages/zh.json +762 -0
- package/template/next.config.mjs +28 -0
- package/template/open-next.config.ts +3 -0
- package/template/package.json +125 -0
- package/template/pnpm-lock.yaml +15901 -0
- package/template/postcss.config.mjs +7 -0
- package/template/public/file.svg +1 -0
- package/template/public/globe.svg +1 -0
- package/template/public/logo.svg +6 -0
- package/template/public/next.svg +1 -0
- package/template/public/vercel.svg +1 -0
- package/template/public/window.svg +1 -0
- package/template/sentry.client.config.ts +10 -0
- package/template/sentry.edge.config.ts +10 -0
- package/template/sentry.server.config.ts +10 -0
- package/template/source.config.ts +59 -0
- package/template/src/adapters/ai/anthropic.ts +113 -0
- package/template/src/adapters/ai/index.ts +6 -0
- package/template/src/adapters/ai/openai-compatible.ts +88 -0
- package/template/src/adapters/ai/workers-ai.ts +63 -0
- package/template/src/adapters/index.ts +10 -0
- package/template/src/adapters/jobs/cloudflare-workflows.ts +46 -0
- package/template/src/adapters/jobs/index.ts +5 -0
- package/template/src/adapters/jobs/inngest/adapter.ts +29 -0
- package/template/src/adapters/jobs/inngest/client.ts +8 -0
- package/template/src/adapters/jobs/inngest/functions.ts +17 -0
- package/template/src/adapters/jobs/inngest/handler.ts +6 -0
- package/template/src/adapters/jobs/inngest/index.ts +4 -0
- package/template/src/adapters/mail/cloudflare-email.ts +50 -0
- package/template/src/adapters/mail/disabled.ts +17 -0
- package/template/src/adapters/mail/index.ts +7 -0
- package/template/src/adapters/mail/resend.ts +76 -0
- package/template/src/adapters/mail/smtp.ts +82 -0
- package/template/src/adapters/payment/creem.ts +269 -0
- package/template/src/adapters/payment/index.ts +2 -0
- package/template/src/adapters/payment/stripe.ts +302 -0
- package/template/src/adapters/rate-limit/cloudflare.ts +42 -0
- package/template/src/adapters/rate-limit/index.ts +6 -0
- package/template/src/adapters/rate-limit/noop.ts +27 -0
- package/template/src/adapters/rate-limit/upstash.ts +113 -0
- package/template/src/adapters/registry.ts +228 -0
- package/template/src/adapters/storage/index.ts +3 -0
- package/template/src/adapters/storage/r2-binding.ts +105 -0
- package/template/src/adapters/storage/s3-compatible.ts +149 -0
- package/template/src/app/[locale]/(admin)/admin/layout.tsx +36 -0
- package/template/src/app/[locale]/(admin)/admin/page.tsx +345 -0
- package/template/src/app/[locale]/(admin)/admin/tickets/[id]/page.tsx +261 -0
- package/template/src/app/[locale]/(admin)/admin/tickets/page.tsx +236 -0
- package/template/src/app/[locale]/(admin)/admin/users/page.tsx +557 -0
- package/template/src/app/[locale]/(auth)/forgot-password/page.tsx +9 -0
- package/template/src/app/[locale]/(auth)/layout.tsx +28 -0
- package/template/src/app/[locale]/(auth)/sign-in/page.tsx +9 -0
- package/template/src/app/[locale]/(auth)/sign-up/page.tsx +9 -0
- package/template/src/app/[locale]/(dashboard)/dashboard/credits/buy/buy-credits-view.tsx +170 -0
- package/template/src/app/[locale]/(dashboard)/dashboard/credits/buy/page.tsx +12 -0
- package/template/src/app/[locale]/(dashboard)/dashboard/credits/page.tsx +5 -0
- package/template/src/app/[locale]/(dashboard)/dashboard/loading.tsx +41 -0
- package/template/src/app/[locale]/(dashboard)/dashboard/page.tsx +299 -0
- package/template/src/app/[locale]/(dashboard)/dashboard/settings/page.tsx +38 -0
- package/template/src/app/[locale]/(dashboard)/dashboard/support/[id]/page.tsx +220 -0
- package/template/src/app/[locale]/(dashboard)/dashboard/support/new/page.tsx +183 -0
- package/template/src/app/[locale]/(dashboard)/dashboard/support/page.tsx +145 -0
- package/template/src/app/[locale]/(dashboard)/layout.tsx +35 -0
- package/template/src/app/[locale]/(marketing)/blog/[slug]/page.tsx +178 -0
- package/template/src/app/[locale]/(marketing)/blog/blog-post-card.tsx +95 -0
- package/template/src/app/[locale]/(marketing)/blog/page.tsx +127 -0
- package/template/src/app/[locale]/(marketing)/demo/plan-badges/page.tsx +36 -0
- package/template/src/app/[locale]/(marketing)/layout.tsx +15 -0
- package/template/src/app/[locale]/(marketing)/legal/[slug]/page.tsx +130 -0
- package/template/src/app/[locale]/(marketing)/page.tsx +94 -0
- package/template/src/app/[locale]/(marketing)/pseo/[slug]/page.tsx +68 -0
- package/template/src/app/[locale]/(marketing)/pseo/page.tsx +137 -0
- package/template/src/app/[locale]/docs/[[...slug]]/page.tsx +63 -0
- package/template/src/app/[locale]/docs/layout.tsx +39 -0
- package/template/src/app/[locale]/layout.tsx +80 -0
- package/template/src/app/[locale]/opengraph-image.tsx +20 -0
- package/template/src/app/[locale]/twitter-image.tsx +20 -0
- package/template/src/app/api/auth/[...all]/route.ts +20 -0
- package/template/src/app/api/health/route.ts +45 -0
- package/template/src/app/api/inngest/route.ts +12 -0
- package/template/src/app/api/jobs/credits/expire/route.ts +102 -0
- package/template/src/app/api/search/route.ts +17 -0
- package/template/src/app/api/upload/presigned/route.ts +98 -0
- package/template/src/app/api/webhooks/payment/route.ts +363 -0
- package/template/src/app/globals.css +406 -0
- package/template/src/app/icon.svg +6 -0
- package/template/src/app/image-proxy/[...path]/route.ts +137 -0
- package/template/src/app/layout.tsx +73 -0
- package/template/src/app/robots.ts +29 -0
- package/template/src/app/sitemap.ts +68 -0
- package/template/src/components/motion/reveal.tsx +49 -0
- package/template/src/components/seo/json-ld.tsx +87 -0
- package/template/src/components/seo/og-image-template.tsx +118 -0
- package/template/src/components/ui/accordion.tsx +66 -0
- package/template/src/components/ui/alert-dialog.tsx +195 -0
- package/template/src/components/ui/avatar.tsx +53 -0
- package/template/src/components/ui/badge.tsx +46 -0
- package/template/src/components/ui/button.tsx +65 -0
- package/template/src/components/ui/card.tsx +92 -0
- package/template/src/components/ui/checkbox.tsx +32 -0
- package/template/src/components/ui/collapsible.tsx +33 -0
- package/template/src/components/ui/dialog.tsx +124 -0
- package/template/src/components/ui/dropdown-menu.tsx +257 -0
- package/template/src/components/ui/form.tsx +233 -0
- package/template/src/components/ui/index.ts +2 -0
- package/template/src/components/ui/input.tsx +21 -0
- package/template/src/components/ui/label.tsx +24 -0
- package/template/src/components/ui/navigation-menu.tsx +167 -0
- package/template/src/components/ui/pagination.tsx +125 -0
- package/template/src/components/ui/popover.tsx +48 -0
- package/template/src/components/ui/progress.tsx +27 -0
- package/template/src/components/ui/radio-group.tsx +45 -0
- package/template/src/components/ui/select.tsx +190 -0
- package/template/src/components/ui/separator.tsx +28 -0
- package/template/src/components/ui/sheet.tsx +140 -0
- package/template/src/components/ui/switch.tsx +31 -0
- package/template/src/components/ui/tabs.tsx +75 -0
- package/template/src/components/ui/textarea.tsx +18 -0
- package/template/src/config/index.ts +31 -0
- package/template/src/config/nav.ts +238 -0
- package/template/src/config/payment.ts +282 -0
- package/template/src/config/site.ts +53 -0
- package/template/src/config/subscription-plan.ts +164 -0
- package/template/src/content/blog/en/hello-world.mdx +48 -0
- package/template/src/content/blog/zh/hello-world.mdx +48 -0
- package/template/src/content/blog/zh/nextdevtpl-linuxdo-intro.mdx +98 -0
- package/template/src/content/docs/en/admin-and-support.mdx +65 -0
- package/template/src/content/docs/en/authentication.mdx +71 -0
- package/template/src/content/docs/en/background-jobs.mdx +53 -0
- package/template/src/content/docs/en/configuration.mdx +71 -0
- package/template/src/content/docs/en/credits.mdx +69 -0
- package/template/src/content/docs/en/customization.mdx +95 -0
- package/template/src/content/docs/en/database.mdx +66 -0
- package/template/src/content/docs/en/deployment.mdx +62 -0
- package/template/src/content/docs/en/email.mdx +48 -0
- package/template/src/content/docs/en/index.mdx +48 -0
- package/template/src/content/docs/en/internationalization.mdx +78 -0
- package/template/src/content/docs/en/meta.json +22 -0
- package/template/src/content/docs/en/observability.mdx +69 -0
- package/template/src/content/docs/en/payments.mdx +64 -0
- package/template/src/content/docs/en/project-structure.mdx +82 -0
- package/template/src/content/docs/en/quick-start.mdx +113 -0
- package/template/src/content/docs/en/storage.mdx +51 -0
- package/template/src/content/docs/zh/admin-and-support.mdx +65 -0
- package/template/src/content/docs/zh/authentication.mdx +71 -0
- package/template/src/content/docs/zh/background-jobs.mdx +53 -0
- package/template/src/content/docs/zh/configuration.mdx +70 -0
- package/template/src/content/docs/zh/credits.mdx +69 -0
- package/template/src/content/docs/zh/customization.mdx +95 -0
- package/template/src/content/docs/zh/database.mdx +66 -0
- package/template/src/content/docs/zh/deployment.mdx +61 -0
- package/template/src/content/docs/zh/email.mdx +47 -0
- package/template/src/content/docs/zh/index.mdx +48 -0
- package/template/src/content/docs/zh/internationalization.mdx +78 -0
- package/template/src/content/docs/zh/meta.json +22 -0
- package/template/src/content/docs/zh/observability.mdx +68 -0
- package/template/src/content/docs/zh/payments.mdx +64 -0
- package/template/src/content/docs/zh/project-structure.mdx +82 -0
- package/template/src/content/docs/zh/quick-start.mdx +110 -0
- package/template/src/content/docs/zh/storage.mdx +51 -0
- package/template/src/content/legal/en/cookie-policy.mdx +78 -0
- package/template/src/content/legal/en/privacy.mdx +131 -0
- package/template/src/content/legal/en/terms.mdx +93 -0
- package/template/src/content/legal/zh/cookie-policy.mdx +78 -0
- package/template/src/content/legal/zh/privacy.mdx +131 -0
- package/template/src/content/legal/zh/terms.mdx +92 -0
- package/template/src/core/modules/contract.ts +225 -0
- package/template/src/core/modules/index.ts +1 -0
- package/template/src/core/services/ai.ts +31 -0
- package/template/src/core/services/common.ts +112 -0
- package/template/src/core/services/index.ts +8 -0
- package/template/src/core/services/jobs.ts +24 -0
- package/template/src/core/services/mail.ts +35 -0
- package/template/src/core/services/manifest.ts +51 -0
- package/template/src/core/services/payment.ts +92 -0
- package/template/src/core/services/rate-limit.ts +47 -0
- package/template/src/core/services/storage.ts +42 -0
- package/template/src/db/index.ts +71 -0
- package/template/src/db/schema/auth.ts +67 -0
- package/template/src/db/schema/credits.ts +94 -0
- package/template/src/db/schema/index.ts +5 -0
- package/template/src/db/schema/mail.ts +14 -0
- package/template/src/db/schema/subscription.ts +21 -0
- package/template/src/db/schema/support.ts +56 -0
- package/template/src/db/schema.ts +2 -0
- package/template/src/features/admin/components/admin-sidebar.tsx +213 -0
- package/template/src/features/admin/components/index.ts +2 -0
- package/template/src/features/admin/index.ts +3 -0
- package/template/src/features/admin/manifest.ts +41 -0
- package/template/src/features/analytics/components/analytics.tsx +62 -0
- package/template/src/features/analytics/components/index.ts +2 -0
- package/template/src/features/analytics/index.ts +3 -0
- package/template/src/features/analytics/manifest.ts +13 -0
- package/template/src/features/auth/components/auth-brand-panel.tsx +82 -0
- package/template/src/features/auth/components/auth-error-alert.tsx +28 -0
- package/template/src/features/auth/components/auth-footer.tsx +52 -0
- package/template/src/features/auth/components/auth-logo.tsx +30 -0
- package/template/src/features/auth/components/forgot-password-form.tsx +146 -0
- package/template/src/features/auth/components/index.ts +9 -0
- package/template/src/features/auth/components/sign-in-form.tsx +241 -0
- package/template/src/features/auth/components/sign-up-form.tsx +307 -0
- package/template/src/features/auth/index.ts +3 -0
- package/template/src/features/auth/manifest.ts +30 -0
- package/template/src/features/blog/components/blog-post-item.tsx +72 -0
- package/template/src/features/blog/components/index.ts +1 -0
- package/template/src/features/blog/data/mock-posts.ts +62 -0
- package/template/src/features/blog/index.ts +3 -0
- package/template/src/features/blog/manifest.ts +22 -0
- package/template/src/features/credits/account.ts +76 -0
- package/template/src/features/credits/actions.ts +427 -0
- package/template/src/features/credits/components/credit-balance-badge.tsx +54 -0
- package/template/src/features/credits/components/credit-usage-section.tsx +160 -0
- package/template/src/features/credits/components/index.ts +7 -0
- package/template/src/features/credits/components/transaction-history.tsx +346 -0
- package/template/src/features/credits/config.ts +70 -0
- package/template/src/features/credits/consume.ts +140 -0
- package/template/src/features/credits/core.ts +23 -0
- package/template/src/features/credits/errors.ts +26 -0
- package/template/src/features/credits/expire.ts +112 -0
- package/template/src/features/credits/grant.ts +168 -0
- package/template/src/features/credits/index.ts +6 -0
- package/template/src/features/credits/manifest.ts +36 -0
- package/template/src/features/credits/query.ts +65 -0
- package/template/src/features/credits/types.ts +48 -0
- package/template/src/features/dashboard/components/index.ts +3 -0
- package/template/src/features/dashboard/components/main-wrapper.tsx +100 -0
- package/template/src/features/dashboard/components/sidebar.tsx +341 -0
- package/template/src/features/dashboard/context/index.ts +2 -0
- package/template/src/features/dashboard/context/sidebar-context.tsx +72 -0
- package/template/src/features/dashboard/index.ts +4 -0
- package/template/src/features/dashboard/manifest.ts +28 -0
- package/template/src/features/mail/actions.ts +175 -0
- package/template/src/features/mail/index.ts +5 -0
- package/template/src/features/mail/manifest.ts +13 -0
- package/template/src/features/mail/server.ts +8 -0
- package/template/src/features/mail/templates/index.ts +11 -0
- package/template/src/features/mail/templates/primary-action-email.tsx +224 -0
- package/template/src/features/mail/templates/welcome-email.tsx +121 -0
- package/template/src/features/mail/utils.ts +190 -0
- package/template/src/features/marketing/components/animated-price.tsx +51 -0
- package/template/src/features/marketing/components/cookie-consent.tsx +255 -0
- package/template/src/features/marketing/components/cta-section.tsx +50 -0
- package/template/src/features/marketing/components/faq-section.tsx +59 -0
- package/template/src/features/marketing/components/feature-grid.tsx +80 -0
- package/template/src/features/marketing/components/footer.tsx +128 -0
- package/template/src/features/marketing/components/header.tsx +255 -0
- package/template/src/features/marketing/components/hero-section.tsx +323 -0
- package/template/src/features/marketing/components/how-it-works.tsx +115 -0
- package/template/src/features/marketing/components/index.ts +14 -0
- package/template/src/features/marketing/components/nav-menu.tsx +236 -0
- package/template/src/features/marketing/components/pricing-section.tsx +446 -0
- package/template/src/features/marketing/components/testimonials.tsx +59 -0
- package/template/src/features/marketing/components/use-cases-section.tsx +78 -0
- package/template/src/features/marketing/index.ts +3 -0
- package/template/src/features/marketing/manifest.ts +35 -0
- package/template/src/features/payment/actions.ts +182 -0
- package/template/src/features/payment/index.ts +4 -0
- package/template/src/features/payment/manifest.ts +18 -0
- package/template/src/features/payment/server.ts +7 -0
- package/template/src/features/payment/types.ts +202 -0
- package/template/src/features/pseo/components/index.ts +6 -0
- package/template/src/features/pseo/components/pseo-cta.tsx +51 -0
- package/template/src/features/pseo/components/pseo-faq.tsx +40 -0
- package/template/src/features/pseo/components/pseo-feature-grid.tsx +74 -0
- package/template/src/features/pseo/components/pseo-hero.tsx +106 -0
- package/template/src/features/pseo/components/pseo-related.tsx +62 -0
- package/template/src/features/pseo/components/pseo-use-cases.tsx +50 -0
- package/template/src/features/pseo/data/pseo-pages.json +534 -0
- package/template/src/features/pseo/index.ts +4 -0
- package/template/src/features/pseo/lib/pseo-data.ts +140 -0
- package/template/src/features/pseo/manifest.ts +22 -0
- package/template/src/features/settings/actions/delete-account.ts +50 -0
- package/template/src/features/settings/actions/index.ts +3 -0
- package/template/src/features/settings/actions/update-profile.ts +49 -0
- package/template/src/features/settings/components/billing-section.tsx +283 -0
- package/template/src/features/settings/components/index.ts +3 -0
- package/template/src/features/settings/components/profile-form.tsx +154 -0
- package/template/src/features/settings/components/security-section.tsx +158 -0
- package/template/src/features/settings/components/settings-profile-view.tsx +506 -0
- package/template/src/features/settings/index.ts +5 -0
- package/template/src/features/settings/manifest.ts +28 -0
- package/template/src/features/settings/schemas/index.ts +2 -0
- package/template/src/features/settings/schemas/update-profile.ts +21 -0
- package/template/src/features/shared/components/cookie-settings-dialog.tsx +282 -0
- package/template/src/features/shared/components/index.ts +5 -0
- package/template/src/features/shared/components/language-switcher.tsx +82 -0
- package/template/src/features/shared/components/max-width-wrapper.tsx +49 -0
- package/template/src/features/shared/components/mode-toggle.tsx +119 -0
- package/template/src/features/shared/icons/google-icon.tsx +39 -0
- package/template/src/features/shared/icons/index.ts +7 -0
- package/template/src/features/shared/index.ts +5 -0
- package/template/src/features/shared/manifest.ts +13 -0
- package/template/src/features/shared/providers.tsx +59 -0
- package/template/src/features/storage/actions.ts +107 -0
- package/template/src/features/storage/index.ts +6 -0
- package/template/src/features/storage/manifest.ts +22 -0
- package/template/src/features/storage/types.ts +143 -0
- package/template/src/features/storage/utils.ts +85 -0
- package/template/src/features/storage/validation.ts +151 -0
- package/template/src/features/subscription/actions/get-user-plan.ts +26 -0
- package/template/src/features/subscription/actions/index.ts +5 -0
- package/template/src/features/subscription/components/current-plan-badge.tsx +18 -0
- package/template/src/features/subscription/components/index.ts +6 -0
- package/template/src/features/subscription/components/plan-badge.tsx +98 -0
- package/template/src/features/subscription/index.ts +25 -0
- package/template/src/features/subscription/manifest.ts +13 -0
- package/template/src/features/subscription/services/user-plan.ts +181 -0
- package/template/src/features/support/actions/admin-ticket.ts +172 -0
- package/template/src/features/support/actions/admin-users.ts +295 -0
- package/template/src/features/support/actions/index.ts +22 -0
- package/template/src/features/support/actions/ticket.ts +12 -0
- package/template/src/features/support/actions/user-ticket.ts +153 -0
- package/template/src/features/support/components/admin-ticket-reply-form.tsx +109 -0
- package/template/src/features/support/components/admin-ticket-status-select.tsx +119 -0
- package/template/src/features/support/components/index.ts +6 -0
- package/template/src/features/support/components/ticket-message-form.tsx +99 -0
- package/template/src/features/support/components/user-role-select.tsx +107 -0
- package/template/src/features/support/index.ts +5 -0
- package/template/src/features/support/manifest.ts +53 -0
- package/template/src/features/support/schemas/index.ts +15 -0
- package/template/src/features/support/schemas/ticket.ts +81 -0
- package/template/src/hooks/index.ts +2 -0
- package/template/src/i18n/index.ts +12 -0
- package/template/src/i18n/request.ts +24 -0
- package/template/src/i18n/routing.ts +23 -0
- package/template/src/instrumentation.ts +19 -0
- package/template/src/lib/ai/index.ts +16 -0
- package/template/src/lib/api-logger.ts +24 -0
- package/template/src/lib/auth/admin.ts +54 -0
- package/template/src/lib/auth/api.ts +17 -0
- package/template/src/lib/auth/client.ts +227 -0
- package/template/src/lib/auth/edge.ts +84 -0
- package/template/src/lib/auth/errors.ts +99 -0
- package/template/src/lib/auth/index.ts +159 -0
- package/template/src/lib/auth/server.ts +46 -0
- package/template/src/lib/auth/session-context.tsx +96 -0
- package/template/src/lib/cloudflare/bindings.ts +31 -0
- package/template/src/lib/cookie-consent.ts +33 -0
- package/template/src/lib/file-utils.ts +45 -0
- package/template/src/lib/fingerprint/index.ts +73 -0
- package/template/src/lib/health/checks.ts +6 -0
- package/template/src/lib/health/core.ts +86 -0
- package/template/src/lib/health/index.ts +11 -0
- package/template/src/lib/health/types.ts +13 -0
- package/template/src/lib/index.ts +2 -0
- package/template/src/lib/logger/index.ts +258 -0
- package/template/src/lib/monitoring/index.ts +384 -0
- package/template/src/lib/rate-limit/anonymous.ts +85 -0
- package/template/src/lib/rate-limit/index.ts +111 -0
- package/template/src/lib/safe-action.ts +127 -0
- package/template/src/lib/seo/json-ld.ts +188 -0
- package/template/src/lib/source.ts +122 -0
- package/template/src/lib/utils.ts +6 -0
- package/template/src/middleware.ts +162 -0
- package/template/src/modules/index.ts +10 -0
- package/template/src/modules/presets.ts +8 -0
- package/template/src/modules/registry.ts +34 -0
- package/template/src/modules/selection.ts +45 -0
- package/template/src/services/ai.ts +49 -0
- package/template/src/services/index.ts +6 -0
- package/template/src/services/jobs.ts +3 -0
- package/template/src/services/mail.ts +7 -0
- package/template/src/services/payment.ts +3 -0
- package/template/src/services/rate-limit.ts +12 -0
- package/template/src/services/storage.ts +3 -0
- package/template/src/types/fumadocs-source.d.ts +14 -0
- package/template/src/types/index.ts +2 -0
- package/template/tsconfig.json +53 -0
- package/template/vercel.json +11 -0
- package/template/vitest.config.ts +51 -0
- package/template/wrangler.jsonc +30 -0
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 订阅计划权限配置
|
|
3
|
+
*
|
|
4
|
+
* 定义各计划的特权限制和功能访问权限
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { PRICE_IDS } from "./payment";
|
|
8
|
+
|
|
9
|
+
// ============================================
|
|
10
|
+
// 计划类型定义
|
|
11
|
+
// ============================================
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* 订阅计划类型
|
|
15
|
+
*/
|
|
16
|
+
export type SubscriptionPlan = "free" | "starter" | "pro" | "ultra";
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* 队列优先级
|
|
20
|
+
*/
|
|
21
|
+
export type QueuePriority = "normal" | "priority" | "highest";
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* 计划特权配置
|
|
25
|
+
*/
|
|
26
|
+
export interface PlanPrivileges {
|
|
27
|
+
/** 计划名称 */
|
|
28
|
+
name: string;
|
|
29
|
+
/** 单文件大小上限 (bytes) */
|
|
30
|
+
maxFileSizeBytes: number;
|
|
31
|
+
/** 队列优先级 */
|
|
32
|
+
queuePriority: QueuePriority;
|
|
33
|
+
/** 月度积分配额 (免费版为一次性) */
|
|
34
|
+
monthlyCredits: number;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// ============================================
|
|
38
|
+
// 计划特权配置
|
|
39
|
+
// ============================================
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* 各计划的特权配置
|
|
43
|
+
*/
|
|
44
|
+
export const PLAN_PRIVILEGES: Record<SubscriptionPlan, PlanPrivileges> = {
|
|
45
|
+
free: {
|
|
46
|
+
name: "Free",
|
|
47
|
+
maxFileSizeBytes: 5 * 1024 * 1024, // 5MB
|
|
48
|
+
queuePriority: "normal",
|
|
49
|
+
monthlyCredits: 200, // 一次性
|
|
50
|
+
},
|
|
51
|
+
starter: {
|
|
52
|
+
name: "Starter",
|
|
53
|
+
maxFileSizeBytes: 20 * 1024 * 1024, // 20MB
|
|
54
|
+
queuePriority: "normal",
|
|
55
|
+
monthlyCredits: 3_000,
|
|
56
|
+
},
|
|
57
|
+
pro: {
|
|
58
|
+
name: "Pro",
|
|
59
|
+
maxFileSizeBytes: 50 * 1024 * 1024, // 50MB
|
|
60
|
+
queuePriority: "priority",
|
|
61
|
+
monthlyCredits: 8_000,
|
|
62
|
+
},
|
|
63
|
+
ultra: {
|
|
64
|
+
name: "Ultra",
|
|
65
|
+
maxFileSizeBytes: 100 * 1024 * 1024, // 100MB
|
|
66
|
+
queuePriority: "highest",
|
|
67
|
+
monthlyCredits: 16_000,
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
// ============================================
|
|
72
|
+
// Price ID 到计划的映射
|
|
73
|
+
// ============================================
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* 根据 Price ID 获取计划类型
|
|
77
|
+
*
|
|
78
|
+
* @param priceId - 价格/产品 ID
|
|
79
|
+
* @returns 计划类型,如果未找到则返回 null
|
|
80
|
+
*/
|
|
81
|
+
export function getPlanFromPriceId(priceId: string): SubscriptionPlan | null {
|
|
82
|
+
// Starter
|
|
83
|
+
if (
|
|
84
|
+
priceId === PRICE_IDS.STARTER_MONTHLY ||
|
|
85
|
+
priceId === PRICE_IDS.STARTER_YEARLY
|
|
86
|
+
) {
|
|
87
|
+
return "starter";
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Pro
|
|
91
|
+
if (priceId === PRICE_IDS.PRO_MONTHLY || priceId === PRICE_IDS.PRO_YEARLY) {
|
|
92
|
+
return "pro";
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Ultra
|
|
96
|
+
if (
|
|
97
|
+
priceId === PRICE_IDS.ULTRA_MONTHLY ||
|
|
98
|
+
priceId === PRICE_IDS.ULTRA_YEARLY
|
|
99
|
+
) {
|
|
100
|
+
return "ultra";
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// ============================================
|
|
107
|
+
// 特权检查工具函数
|
|
108
|
+
// ============================================
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* 获取计划的特权配置
|
|
112
|
+
*
|
|
113
|
+
* @param plan - 订阅计划
|
|
114
|
+
* @returns 计划特权配置
|
|
115
|
+
*/
|
|
116
|
+
export function getPlanPrivileges(plan: SubscriptionPlan): PlanPrivileges {
|
|
117
|
+
return PLAN_PRIVILEGES[plan];
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* 检查文件大小是否在限制内
|
|
122
|
+
*
|
|
123
|
+
* @param plan - 订阅计划
|
|
124
|
+
* @param fileSizeBytes - 文件大小(字节)
|
|
125
|
+
* @returns 是否在限制内
|
|
126
|
+
*/
|
|
127
|
+
export function isWithinFileSizeLimit(
|
|
128
|
+
plan: SubscriptionPlan,
|
|
129
|
+
fileSizeBytes: number
|
|
130
|
+
): boolean {
|
|
131
|
+
return fileSizeBytes <= PLAN_PRIVILEGES[plan].maxFileSizeBytes;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* 格式化文件大小限制(用于错误消息)
|
|
136
|
+
*
|
|
137
|
+
* @param plan - 订阅计划
|
|
138
|
+
* @returns 格式化的文件大小字符串(如 "5MB")
|
|
139
|
+
*/
|
|
140
|
+
export function formatFileSizeLimit(plan: SubscriptionPlan): string {
|
|
141
|
+
const bytes = PLAN_PRIVILEGES[plan].maxFileSizeBytes;
|
|
142
|
+
return `${bytes / (1024 * 1024)}MB`;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* 获取升级建议(当特权不足时)
|
|
147
|
+
*
|
|
148
|
+
* @param currentPlan - 当前计划
|
|
149
|
+
* @param requiredFeature - 需要的功能描述
|
|
150
|
+
* @returns 升级建议消息
|
|
151
|
+
*/
|
|
152
|
+
export function getUpgradeMessage(
|
|
153
|
+
currentPlan: SubscriptionPlan,
|
|
154
|
+
requiredFeature: string
|
|
155
|
+
): string {
|
|
156
|
+
const upgradeTo =
|
|
157
|
+
currentPlan === "free"
|
|
158
|
+
? "Starter"
|
|
159
|
+
: currentPlan === "starter"
|
|
160
|
+
? "Pro"
|
|
161
|
+
: "Ultra";
|
|
162
|
+
|
|
163
|
+
return `${requiredFeature} requires ${upgradeTo} plan or higher. Please upgrade to continue.`;
|
|
164
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Hello World
|
|
3
|
+
description: Welcome to our blog! This is our first post introducing NextDevTpl.
|
|
4
|
+
date: 2024-01-15
|
|
5
|
+
author: NextDevTpl Team
|
|
6
|
+
tags:
|
|
7
|
+
- announcement
|
|
8
|
+
- getting-started
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Hello World
|
|
12
|
+
|
|
13
|
+
Welcome to the NextDevTpl blog! We're excited to share our journey of building the ultimate Next.js starter kit.
|
|
14
|
+
|
|
15
|
+
## What is NextDevTpl?
|
|
16
|
+
|
|
17
|
+
NextDevTpl is a modern, production-ready SaaS boilerplate built with:
|
|
18
|
+
|
|
19
|
+
- **Next.js 16** - The React framework for production
|
|
20
|
+
- **TypeScript** - Type-safe development
|
|
21
|
+
- **Tailwind CSS** - Utility-first styling
|
|
22
|
+
- **Better Auth** - Modern authentication
|
|
23
|
+
- **Drizzle ORM** - Type-safe database access
|
|
24
|
+
|
|
25
|
+
## Why We Built This
|
|
26
|
+
|
|
27
|
+
Building a SaaS application from scratch is time-consuming. You need to set up authentication, database connections, styling, and countless other features before you can even start working on your actual product.
|
|
28
|
+
|
|
29
|
+
NextDevTpl solves this by providing a solid foundation that includes:
|
|
30
|
+
|
|
31
|
+
1. **Authentication** - Email/password, OAuth providers
|
|
32
|
+
2. **Database** - PostgreSQL with Drizzle ORM
|
|
33
|
+
3. **UI Components** - Beautiful, accessible components
|
|
34
|
+
4. **Internationalization** - Multi-language support
|
|
35
|
+
5. **SEO** - Optimized for search engines
|
|
36
|
+
|
|
37
|
+
## Getting Started
|
|
38
|
+
|
|
39
|
+
To get started with NextDevTpl, simply clone the repository and follow the setup instructions in our documentation.
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
git clone https://github.com/nextdevtpl/nextdevtpl.git
|
|
43
|
+
cd nextdevtpl
|
|
44
|
+
pnpm install
|
|
45
|
+
pnpm dev
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Stay tuned for more updates and tutorials!
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: 你好世界
|
|
3
|
+
description: 欢迎来到我们的博客!这是我们介绍 NextDevTpl 的第一篇文章。
|
|
4
|
+
date: 2024-01-15
|
|
5
|
+
author: NextDevTpl 团队
|
|
6
|
+
tags:
|
|
7
|
+
- 公告
|
|
8
|
+
- 入门指南
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# 你好世界
|
|
12
|
+
|
|
13
|
+
欢迎来到 NextDevTpl 博客!我们很高兴与您分享构建终极 Next.js 启动模板的旅程。
|
|
14
|
+
|
|
15
|
+
## 什么是 NextDevTpl?
|
|
16
|
+
|
|
17
|
+
NextDevTpl 是一个现代化、生产就绪的 SaaS 模板,采用以下技术构建:
|
|
18
|
+
|
|
19
|
+
- **Next.js 16** - 用于生产环境的 React 框架
|
|
20
|
+
- **TypeScript** - 类型安全的开发体验
|
|
21
|
+
- **Tailwind CSS** - 实用优先的样式方案
|
|
22
|
+
- **Better Auth** - 现代化认证方案
|
|
23
|
+
- **Drizzle ORM** - 类型安全的数据库访问
|
|
24
|
+
|
|
25
|
+
## 为什么我们要构建它
|
|
26
|
+
|
|
27
|
+
从零开始构建 SaaS 应用程序非常耗时。在开始开发实际产品之前,您需要设置身份验证、数据库连接、样式和无数其他功能。
|
|
28
|
+
|
|
29
|
+
NextDevTpl 通过提供坚实的基础来解决这个问题,包括:
|
|
30
|
+
|
|
31
|
+
1. **身份验证** - 邮箱/密码、OAuth 提供商
|
|
32
|
+
2. **数据库** - PostgreSQL 配合 Drizzle ORM
|
|
33
|
+
3. **UI 组件** - 美观、无障碍的组件
|
|
34
|
+
4. **国际化** - 多语言支持
|
|
35
|
+
5. **SEO** - 搜索引擎优化
|
|
36
|
+
|
|
37
|
+
## 开始使用
|
|
38
|
+
|
|
39
|
+
要开始使用 NextDevTpl,只需克隆仓库并按照文档中的设置说明操作。
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
git clone https://github.com/nextdevtpl/nextdevtpl.git
|
|
43
|
+
cd nextdevtpl
|
|
44
|
+
pnpm install
|
|
45
|
+
pnpm dev
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
敬请期待更多更新和教程!
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "[开源] NextDevTpl:一个面向独立开发者的 Next.js 全栈 SaaS 模板"
|
|
3
|
+
description: "不是能跑 Demo 的脚手架,而是可直接落地业务的全栈模板。内置认证、支付、积分、邮件、存储、工单与后台管理。"
|
|
4
|
+
date: 2026-02-16
|
|
5
|
+
author: NextDevTpl 团队
|
|
6
|
+
tags:
|
|
7
|
+
- 开源
|
|
8
|
+
- SaaS
|
|
9
|
+
- Next.js
|
|
10
|
+
- 独立开发
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# [开源] NextDevTpl:一个面向独立开发者的 Next.js 全栈 SaaS 模板
|
|
14
|
+
|
|
15
|
+
大家好,最近我把自己在多个项目里反复打磨的一套模板整理成了开源项目:`NextDevTpl`。
|
|
16
|
+
目标很明确:它不是“能跑起来的 Demo”,而是“可以直接承接真实业务”的全栈模板。
|
|
17
|
+
|
|
18
|
+
## 为什么做这个模板?
|
|
19
|
+
|
|
20
|
+
做过几次从 0 到 1 的朋友应该都懂:最耗时间的往往不是业务本身,而是重复基建。
|
|
21
|
+
|
|
22
|
+
- 登录注册、权限和会话管理
|
|
23
|
+
- 支付订阅、Webhook、账单状态同步
|
|
24
|
+
- 积分扣减、发放、过期与流水
|
|
25
|
+
- 邮件通知、文件上传、用户工单
|
|
26
|
+
- 管理后台、日志监控、错误告警
|
|
27
|
+
|
|
28
|
+
这些内容每次都要重做,不仅耗时,也容易在上线后暴露隐患。
|
|
29
|
+
所以我把这些高频模块统一抽成一套可复用模板,尽量做到开箱即用、可持续扩展。
|
|
30
|
+
|
|
31
|
+
## 技术栈(当前版本)
|
|
32
|
+
|
|
33
|
+
- **Next.js 16 + React 19 + TypeScript**
|
|
34
|
+
- **Tailwind CSS 4 + Shadcn/UI**
|
|
35
|
+
- **Drizzle ORM + PostgreSQL**
|
|
36
|
+
- **Better Auth(账号体系)**
|
|
37
|
+
- **next-intl(国际化)**
|
|
38
|
+
- **S3/R2 兼容对象存储**
|
|
39
|
+
- **Vitest + Biome 工程化支持**
|
|
40
|
+
|
|
41
|
+
## 已内置能力(不是空壳)
|
|
42
|
+
|
|
43
|
+
### 1) 用户与权限
|
|
44
|
+
|
|
45
|
+
- 邮箱注册/登录与 OAuth
|
|
46
|
+
- 会话管理与角色隔离(user/admin)
|
|
47
|
+
|
|
48
|
+
### 2) 商业化能力
|
|
49
|
+
|
|
50
|
+
- 订阅支付流程
|
|
51
|
+
- Webhook 处理
|
|
52
|
+
- 积分账本与扣费逻辑
|
|
53
|
+
|
|
54
|
+
### 3) 运营支持能力
|
|
55
|
+
|
|
56
|
+
- 邮件模板与发送
|
|
57
|
+
- 文件上传与管理
|
|
58
|
+
- 工单系统(用户侧 + 管理侧)
|
|
59
|
+
- 管理后台(用户管理、数据面板)
|
|
60
|
+
|
|
61
|
+
### 4) 工程保障能力
|
|
62
|
+
|
|
63
|
+
- API 限流(可选)
|
|
64
|
+
- 结构化日志(可选)
|
|
65
|
+
- 错误监控(可选)
|
|
66
|
+
- 外部服务未配置时可自动降级,便于本地开发与调试
|
|
67
|
+
|
|
68
|
+
## 适合谁使用?
|
|
69
|
+
|
|
70
|
+
- 想快速上线 MVP 的独立开发者
|
|
71
|
+
- 想统一技术底座的小团队
|
|
72
|
+
- 不想每次项目都从认证、支付、后台重复造轮子的开发者
|
|
73
|
+
|
|
74
|
+
## 快速启动
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
git clone git@github.com:evepupil/NextDevTpl.git
|
|
78
|
+
cd NextDevTpl
|
|
79
|
+
pnpm install
|
|
80
|
+
cp .env.example .env.local
|
|
81
|
+
pnpm db:push
|
|
82
|
+
pnpm dev
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## 我希望它解决的问题
|
|
86
|
+
|
|
87
|
+
我做这个项目的核心目标并不是“堆技术名词”,而是帮你把时间真正花在更重要的事情上:
|
|
88
|
+
|
|
89
|
+
1. 业务闭环和核心价值
|
|
90
|
+
2. 用户反馈与迭代效率
|
|
91
|
+
3. 商业化验证与增长
|
|
92
|
+
|
|
93
|
+
## 欢迎交流与共建
|
|
94
|
+
|
|
95
|
+
如果你愿意试用,欢迎直接反馈真实问题:
|
|
96
|
+
你最在意哪些模块?哪些地方还不够生产可用?你希望优先补齐什么能力?
|
|
97
|
+
|
|
98
|
+
也欢迎提交 Issue / PR,一起把它打磨成真正可落地的生产级模板。欢迎在 linux.do 交流想法,我会持续迭代。
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Admin and Support
|
|
3
|
+
description: Manage users, roles, tickets, and customer support workflows.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Admin and Support
|
|
7
|
+
|
|
8
|
+
The template includes a simple but practical admin area and support ticket system.
|
|
9
|
+
|
|
10
|
+
## Admin area
|
|
11
|
+
|
|
12
|
+
Admin routes live under:
|
|
13
|
+
|
|
14
|
+
```txt
|
|
15
|
+
src/app/[locale]/(admin)/admin
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Main components:
|
|
19
|
+
|
|
20
|
+
| Path | Purpose |
|
|
21
|
+
| --- | --- |
|
|
22
|
+
| `src/features/admin/components/admin-sidebar.tsx` | Admin navigation |
|
|
23
|
+
| `src/app/[locale]/(admin)/admin/page.tsx` | Admin overview |
|
|
24
|
+
| `src/app/[locale]/(admin)/admin/users/page.tsx` | User management |
|
|
25
|
+
| `src/app/[locale]/(admin)/admin/tickets/page.tsx` | Ticket queue |
|
|
26
|
+
| `src/app/[locale]/(admin)/admin/tickets/[id]/page.tsx` | Ticket detail |
|
|
27
|
+
|
|
28
|
+
## Support tickets
|
|
29
|
+
|
|
30
|
+
User ticket routes live under:
|
|
31
|
+
|
|
32
|
+
```txt
|
|
33
|
+
src/app/[locale]/(dashboard)/dashboard/support
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Feature files:
|
|
37
|
+
|
|
38
|
+
| Path | Purpose |
|
|
39
|
+
| --- | --- |
|
|
40
|
+
| `src/features/support/actions/ticket.ts` | Ticket actions |
|
|
41
|
+
| `src/features/support/actions/admin-users.ts` | Admin user helpers |
|
|
42
|
+
| `src/features/support/components` | Ticket forms, replies, status controls |
|
|
43
|
+
| `src/features/support/schemas` | Validation schemas |
|
|
44
|
+
| `src/test/support` | Ticket and admin user tests |
|
|
45
|
+
|
|
46
|
+
## Ticket lifecycle
|
|
47
|
+
|
|
48
|
+
Recommended status flow:
|
|
49
|
+
|
|
50
|
+
```txt
|
|
51
|
+
open -> in_progress -> resolved
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Keep user-facing replies clear and avoid exposing internal logs or secrets.
|
|
55
|
+
|
|
56
|
+
## Admin access
|
|
57
|
+
|
|
58
|
+
Admin access depends on the authenticated user's role. For local testing, create a user and set `role = 'admin'` in the database.
|
|
59
|
+
|
|
60
|
+
## Tests
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
pnpm test:run src/test/support
|
|
64
|
+
```
|
|
65
|
+
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Authentication
|
|
3
|
+
description: Understand Better Auth integration, auth routes, roles, and protected pages.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Authentication
|
|
7
|
+
|
|
8
|
+
Authentication is built with Better Auth and integrated into the App Router, middleware, dashboard, and admin area.
|
|
9
|
+
|
|
10
|
+
## Main files
|
|
11
|
+
|
|
12
|
+
| Path | Purpose |
|
|
13
|
+
| --- | --- |
|
|
14
|
+
| `src/lib/auth/api.ts` | Better Auth API configuration |
|
|
15
|
+
| `src/lib/auth/client.ts` | Client-side auth helpers |
|
|
16
|
+
| `src/lib/auth/server.ts` | Server-side session helpers |
|
|
17
|
+
| `src/lib/auth/edge.ts` | Middleware-safe auth checks and public route config |
|
|
18
|
+
| `src/lib/auth/admin.ts` | Admin-specific helpers |
|
|
19
|
+
| `src/app/api/auth/[...all]/route.ts` | Better Auth route handler |
|
|
20
|
+
| `src/features/auth/components` | Sign-in, sign-up, forgot-password UI |
|
|
21
|
+
|
|
22
|
+
## Supported flows
|
|
23
|
+
|
|
24
|
+
| Flow | Notes |
|
|
25
|
+
| --- | --- |
|
|
26
|
+
| Email/password | Baseline local auth flow |
|
|
27
|
+
| GitHub OAuth | Requires GitHub OAuth app credentials |
|
|
28
|
+
| Google OAuth | Requires Google Cloud OAuth credentials |
|
|
29
|
+
| Password reset | Requires email delivery to send reset messages |
|
|
30
|
+
| Role-based access | `user` and `admin` roles are used by dashboard/admin protection |
|
|
31
|
+
|
|
32
|
+
## Public and protected routes
|
|
33
|
+
|
|
34
|
+
The middleware/auth edge helpers decide which routes are public and which need a session. Public routes include marketing pages, auth pages, blog, legal pages, docs, and selected API endpoints.
|
|
35
|
+
|
|
36
|
+
Authenticated pages live under:
|
|
37
|
+
|
|
38
|
+
```txt
|
|
39
|
+
src/app/[locale]/(dashboard)/dashboard
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Admin pages live under:
|
|
43
|
+
|
|
44
|
+
```txt
|
|
45
|
+
src/app/[locale]/(admin)/admin
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Make yourself an admin
|
|
49
|
+
|
|
50
|
+
After creating a local user, update the user's role in the database:
|
|
51
|
+
|
|
52
|
+
```sql
|
|
53
|
+
update "user"
|
|
54
|
+
set role = 'admin'
|
|
55
|
+
where email = 'you@example.com';
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Then visit:
|
|
59
|
+
|
|
60
|
+
```txt
|
|
61
|
+
/en/admin
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Adding an OAuth provider
|
|
65
|
+
|
|
66
|
+
1. Create credentials in the provider console.
|
|
67
|
+
2. Add the provider credentials to `.env.local`.
|
|
68
|
+
3. Register callback URLs that match `BETTER_AUTH_URL`.
|
|
69
|
+
4. Update the auth UI if you want to expose a new provider button.
|
|
70
|
+
5. Test sign-in locally before enabling it in production.
|
|
71
|
+
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Background Jobs
|
|
3
|
+
description: Run async product workflows with Inngest.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Background Jobs
|
|
7
|
+
|
|
8
|
+
Background jobs are powered by Inngest. Use jobs for workflows that should not block a request, such as credit expiration, delivery retries, email batching, or async product processing.
|
|
9
|
+
|
|
10
|
+
## Main files
|
|
11
|
+
|
|
12
|
+
| Path | Purpose |
|
|
13
|
+
| --- | --- |
|
|
14
|
+
| `src/inngest/client.ts` | Inngest client |
|
|
15
|
+
| `src/inngest/functions.ts` | Function definitions |
|
|
16
|
+
| `src/inngest/index.ts` | Exports |
|
|
17
|
+
| `src/app/api/inngest/route.ts` | Inngest route handler |
|
|
18
|
+
| `src/app/api/jobs/credits/expire/route.ts` | Credit expiration job endpoint |
|
|
19
|
+
| `src/test/jobs/cron-expire.test.ts` | Job test coverage |
|
|
20
|
+
|
|
21
|
+
## Local development
|
|
22
|
+
|
|
23
|
+
Start the app:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
pnpm dev
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Then use the Inngest dev server if you need to inspect or trigger functions locally.
|
|
30
|
+
|
|
31
|
+
## Production variables
|
|
32
|
+
|
|
33
|
+
| Variable | Purpose |
|
|
34
|
+
| --- | --- |
|
|
35
|
+
| `INNGEST_EVENT_KEY` | Sends events to Inngest |
|
|
36
|
+
| `INNGEST_SIGNING_KEY` | Verifies requests from Inngest |
|
|
37
|
+
|
|
38
|
+
## Job design rules
|
|
39
|
+
|
|
40
|
+
- Keep jobs idempotent.
|
|
41
|
+
- Store enough state to recover from retries.
|
|
42
|
+
- Do not grant credits or change subscription state twice for the same external event.
|
|
43
|
+
- Prefer small composable functions over one large workflow.
|
|
44
|
+
- Log job identifiers and external event IDs.
|
|
45
|
+
|
|
46
|
+
## Testing
|
|
47
|
+
|
|
48
|
+
Run job tests after touching expiration logic:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
pnpm test:run src/test/jobs
|
|
52
|
+
```
|
|
53
|
+
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Configuration
|
|
3
|
+
description: Configure the required and optional services used by NextDevTpl.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Configuration
|
|
7
|
+
|
|
8
|
+
Configuration is environment-variable driven. Start with the required variables, then enable optional services as needed.
|
|
9
|
+
|
|
10
|
+
## Required for local boot
|
|
11
|
+
|
|
12
|
+
| Variable | Purpose |
|
|
13
|
+
| --- | --- |
|
|
14
|
+
| `DATABASE_URL` | PostgreSQL connection string used by Drizzle and Better Auth |
|
|
15
|
+
| `BETTER_AUTH_SECRET` | Secret used to sign auth/session data |
|
|
16
|
+
| `BETTER_AUTH_URL` | Base URL for Better Auth callbacks and cookies |
|
|
17
|
+
|
|
18
|
+
Example:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
DATABASE_URL="postgresql://postgres:password@localhost:5432/nextdevtpl"
|
|
22
|
+
BETTER_AUTH_SECRET="replace-with-a-random-secret"
|
|
23
|
+
BETTER_AUTH_URL="http://localhost:3000"
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Recommended during development
|
|
27
|
+
|
|
28
|
+
| Service | Variables | Notes |
|
|
29
|
+
| --- | --- | --- |
|
|
30
|
+
| GitHub OAuth | `GITHUB_CLIENT_ID`, `GITHUB_CLIENT_SECRET` | Callback: `/api/auth/callback/github` |
|
|
31
|
+
| Google OAuth | `GOOGLE_CLIENT_ID`, `GOOGLE_CLIENT_SECRET` | Callback: `/api/auth/callback/google` |
|
|
32
|
+
| Resend | `RESEND_API_KEY`, `EMAIL_FROM` | Enables real email verification and reset emails |
|
|
33
|
+
|
|
34
|
+
If email is not configured, test authentication flows that do not require delivery first.
|
|
35
|
+
|
|
36
|
+
## Optional product services
|
|
37
|
+
|
|
38
|
+
| Service | Variables | Used by |
|
|
39
|
+
| --- | --- | --- |
|
|
40
|
+
| Creem | `CREEM_API_KEY`, `CREEM_WEBHOOK_SECRET` | Subscription checkout, credit purchases, webhooks |
|
|
41
|
+
| S3/R2 | `STORAGE_ENDPOINT`, `STORAGE_REGION`, `STORAGE_BUCKET`, `STORAGE_ACCESS_KEY_ID`, `STORAGE_SECRET_ACCESS_KEY` | File uploads and proxy routes |
|
|
42
|
+
| Upstash Redis | `UPSTASH_REDIS_REST_URL`, `UPSTASH_REDIS_REST_TOKEN` | API and anonymous rate limiting |
|
|
43
|
+
| Axiom | `AXIOM_TOKEN`, `AXIOM_DATASET` | Structured cloud logs |
|
|
44
|
+
| Sentry | `NEXT_PUBLIC_SENTRY_DSN`, `SENTRY_AUTH_TOKEN` | Error capture and release uploads |
|
|
45
|
+
| OpenAI-compatible AI | `OPENAI_API_KEY`, provider-specific base URL/model vars if configured | AI abstraction in `src/lib/ai` |
|
|
46
|
+
| Inngest | `INNGEST_EVENT_KEY`, `INNGEST_SIGNING_KEY` | Background jobs in production |
|
|
47
|
+
|
|
48
|
+
## Degradation model
|
|
49
|
+
|
|
50
|
+
Optional services should not block a basic local boot. The intended behavior is:
|
|
51
|
+
|
|
52
|
+
| Missing service | Expected behavior |
|
|
53
|
+
| --- | --- |
|
|
54
|
+
| Redis | Rate limiter falls back instead of crashing |
|
|
55
|
+
| Axiom | Logger writes locally |
|
|
56
|
+
| Sentry | Monitoring hooks become no-op or console-only |
|
|
57
|
+
| Storage | Upload flows are unavailable, app shell still runs |
|
|
58
|
+
| Creem | Payment flows are unavailable, non-payment pages still run |
|
|
59
|
+
| Inngest keys | Local development can run without production signing keys |
|
|
60
|
+
|
|
61
|
+
## Where configuration lives
|
|
62
|
+
|
|
63
|
+
| Path | What to edit |
|
|
64
|
+
| --- | --- |
|
|
65
|
+
| `src/config/site.ts` | Site name, URL, metadata, social links |
|
|
66
|
+
| `src/config/nav.ts` | Header, footer, dashboard, and admin navigation |
|
|
67
|
+
| `src/config/payment.ts` | Payment product and checkout configuration |
|
|
68
|
+
| `src/config/subscription-plan.ts` | Plan limits and pricing display |
|
|
69
|
+
| `messages/*.json` | UI copy |
|
|
70
|
+
| `.env.local` | Local secrets and service credentials |
|
|
71
|
+
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Credits
|
|
3
|
+
description: Understand the built-in credit system, ledger entries, and expiration model.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Credits
|
|
7
|
+
|
|
8
|
+
The credits module is one of the main product primitives in NextDevTpl. It is designed for AI tools, usage-based SaaS products, paid exports, and other metered features.
|
|
9
|
+
|
|
10
|
+
## Main files
|
|
11
|
+
|
|
12
|
+
| Path | Purpose |
|
|
13
|
+
| --- | --- |
|
|
14
|
+
| `src/features/credits/core.ts` | Core balance and transaction logic |
|
|
15
|
+
| `src/features/credits/actions.ts` | Server Actions for credit operations |
|
|
16
|
+
| `src/features/credits/config.ts` | Credit packages and display config |
|
|
17
|
+
| `src/features/credits/components` | Balance, usage, purchase, and history UI |
|
|
18
|
+
| `src/app/[locale]/(dashboard)/dashboard/credits/buy` | Credit purchase page |
|
|
19
|
+
| `src/test/credits` | Credit integrity and purchase tests |
|
|
20
|
+
|
|
21
|
+
## Concepts
|
|
22
|
+
|
|
23
|
+
| Concept | Meaning |
|
|
24
|
+
| --- | --- |
|
|
25
|
+
| Balance | Current spendable credits for a user |
|
|
26
|
+
| Transaction | A recorded credit movement |
|
|
27
|
+
| Batch | Credits granted together with shared expiration metadata |
|
|
28
|
+
| FIFO expiration | Older credits are consumed before newer credits |
|
|
29
|
+
| Purchase package | A configured one-time purchase amount |
|
|
30
|
+
|
|
31
|
+
## Typical flows
|
|
32
|
+
|
|
33
|
+
### Purchase credits
|
|
34
|
+
|
|
35
|
+
1. User opens `/dashboard/credits/buy`.
|
|
36
|
+
2. User selects a package.
|
|
37
|
+
3. The app creates a checkout through the payment layer.
|
|
38
|
+
4. The webhook confirms payment.
|
|
39
|
+
5. Credits are granted to the user.
|
|
40
|
+
6. Transaction history reflects the purchase.
|
|
41
|
+
|
|
42
|
+
### Spend credits
|
|
43
|
+
|
|
44
|
+
Feature code should use the credits core instead of manually decrementing a number. This keeps transactions auditable and preserves expiration rules.
|
|
45
|
+
|
|
46
|
+
### Expire credits
|
|
47
|
+
|
|
48
|
+
Expiration is handled by batch metadata and background jobs. See [Background Jobs](/en/docs/background-jobs) for the job route and Inngest integration.
|
|
49
|
+
|
|
50
|
+
## Customizing packages
|
|
51
|
+
|
|
52
|
+
Edit:
|
|
53
|
+
|
|
54
|
+
```txt
|
|
55
|
+
src/features/credits/config.ts
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Keep package IDs stable once they are used in payment or audit records.
|
|
59
|
+
|
|
60
|
+
## Testing
|
|
61
|
+
|
|
62
|
+
Run focused tests when touching credits:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
pnpm test:run src/test/credits
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Always preserve transaction integrity. Bugs in credits are financial/accounting bugs, not only UI bugs.
|
|
69
|
+
|