Skip to content

About

No description, website, or topics provided.

Resources

Code of conduct

Contributing

Stars

5 stars

Watchers

0 watching

Forks

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Astro SaaS Template (Cloudflare Worker) — Astro + React + Hono

English · 中文

A starter kit for building a real SaaS on Cloudflare: marketing pages, a dashboard, an API, teams, and Stripe credits — with sensible defaults and CI out of the box.

A SaaS starter that ships as one Cloudflare Worker:

  • Marketing + SEO pages: Astro
  • Dashboard app: React SPA (mounted under /dashboard/*)
  • API: Hono (/api/*)
  • Optional chat: Durable Objects + WebSocket

License: MIT (see LICENSE).

Who is this for?

  • You want a Cloudflare-first SaaS template (Worker + D1 + KV + R2).
  • You prefer Astro for marketing/SEO, but still want a React dashboard.
  • You want a “works end-to-end” baseline: auth, teams, billing, admin, CI.

What’s included (in plain terms)

  • A public website (SEO pages + blog)
  • A logged-in dashboard (React app)
  • A backend API (/api/*)
  • A database schema + migrations (D1)
  • Stripe payments (credits) with webhook-based crediting
  • Admin screens (blog/SEO/users/billing helpers)

Features

  • Auth: email/password, email verification, sessions (optional Google OAuth)
  • Teams: workspace + membership + basic roles/permissions
  • Billing (credits): Stripe PaymentIntent + webhook is the source of truth (idempotent)
  • Admin: manage blog posts, basic user/billing ops, SEO config, email templates
  • i18n: en (default, no prefix) + zh + ja (prefixed on marketing routes)
  • CI: lint + typecheck + build + Playwright E2E

Demo

  • Local: pnpm dev then open http://localhost:4321
  • Dashboard entry: /dashboard
  • Admin entry: /admin

Tech stack

  • Runtime: Cloudflare Workers
  • Web: Astro (SSR) + React (SPA for dashboard)
  • API: Hono
  • DB: Cloudflare D1 + Drizzle
  • Storage: R2 (blog + uploads), KV (sessions + tokens)
  • Payments: Stripe
  • Email: Resend

Quick start

Requirements:

  • Node.js 20+
  • pnpm (repo pins pnpm@10.0.0 in package.json)
pnpm install
cp .dev.vars.example .dev.vars
pnpm dev

Open http://localhost:4321.

If you don’t need chat/WebSocket, use pnpm dev:web (faster).

Project structure (high level)

  • src/pages/*: Astro routes (marketing + auth pages)
  • src/pages/dashboard/*: React dashboard shell routes
  • src/pages/settings/*: legacy convenience routes (redirect to /dashboard/settings/*)
  • src/components/dashboard/*: dashboard React components/pages
  • src/api/*: Hono API routes + helpers
  • packages/db/*: Drizzle schema + D1 migrations
  • wrangler*.jsonc: Cloudflare config examples

Cloudflare bindings

Expected bindings (names matter):

  • DB (D1): users, teams, billing, email templates, etc.
  • KV: sessions + one-time tokens
  • BLOG_STORAGE (R2): blog content + uploads (/media/uploads/*)
  • Durable Objects: chat (only if you enable/run it)

Configured via:

  • Local: wrangler.dev.jsonc + .dev.vars
  • Production: wrangler.jsonc + Cloudflare secrets/vars

Environment variables

Common Worker vars/secrets:

  • Stripe:
    • STRIPE_SECRET_KEY (server)
    • STRIPE_PUBLISHABLE_KEY (browser)
    • STRIPE_WEBHOOK_SECRET (webhook signature)
  • Email:
    • RESEND_API_KEY
  • Google OAuth (optional):
    • GOOGLE_CLIENT_ID
    • GOOGLE_CLIENT_SECRET
  • Site URL (recommended in production):
    • SITE_URL
  • Turnstile (captcha; enforced in production):
    • TURNSTILE_SITE_KEY
    • TURNSTILE_SECRET_KEY

Database migrations (D1)

Migrations are in packages/db/src/db/migrations/.

  • Local: pnpm db:migrate:local
  • Remote: pnpm db:migrate:remote

“Remote migration” is not merging databases — it just upgrades the tables/columns/indexes on your Cloudflare D1 to match the code.

Stripe billing notes

  • Webhook: POST /api/stripe/webhook
  • Admin reconcile (when a webhook was missed): POST /api/admin/stripe/reconcile

This template is intentionally “webhook-first”: credits are granted by the webhook, not by the browser redirect page.

Account deletion

Dashboard includes “Delete account” (requires password).

  • Data is hard-deleted.
  • If a user is the only owner of a team, the team is deleted too.

Deployment (GitHub Actions)

Workflow: .github/workflows/deploy.yml.

Required GitHub Secrets:

  • CLOUDFLARE_API_TOKEN
  • CLOUDFLARE_ACCOUNT_ID

Deploy triggers:

  • Push a version tag (e.g. v1.2.3)
  • Or run it manually via workflow_dispatch
git tag v0.1.0
git push origin v0.1.0

Tip: creating a GitHub Release usually creates the tag too.

Deploy does:

  1. apply remote D1 migrations
  2. deploy the Worker

Troubleshooting

  • /settings is a redirect stub (it sends you to /dashboard/settings/*).
  • StripeAuthenticationError: Invalid API Key usually means your .dev.vars has a placeholder/typo for STRIPE_SECRET_KEY.
  • If CI says “set CLOUDFLARE_API_TOKEN”, that’s expected for remote D1 migrations in non-interactive runners.

Contributing

See CONTRIBUTING.md.

Security

We use GitHub’s built-in security reporting (Security Advisories / “Report a vulnerability”).

About

No description, website, or topics provided.

Resources

Code of conduct

Contributing

Stars

5 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages