Documentation
Everything you need to ship
Getting started
Clone the repo, install dependencies, and copy the environment template:
pnpm install
cp .env.example apps/api/.dev.vars
cp .env.example apps/web/.env # keep only the VITE_* lines
Provision a Neon database, set DATABASE_URL, then push the schema and start everything:
pnpm db:generate && pnpm db:migrate
pnpm dev
The web app runs on localhost:3000, the API on localhost:8787.
Payments & subscriptions
RayStarter monetizes three ways, all through Stripe:
- Products — one-time purchases (courses, templates). Fulfilled by the webhook at
/api/webhooks/stripe. - Subscriptions — recurring plans you create and price in the admin dashboard; the matching Stripe products and prices are provisioned automatically. Renewals and credit grants are handled by the payments module via the Stripe webhook.
- Credit packs — prepaid AI credits that never expire.
For local testing: stripe listen --forward-to localhost:8787/api/webhooks/stripe
AI credits
Every AI generation is metered against per-model rates defined in packages/core/src/plans.ts. The system keeps an append-only ledger (credit_transaction) plus a cached balance on the user row — changed atomically in a single SQL statement, so the two can never drift.
Subscriptions grant monthly credits on every paid invoice, keyed by invoice ID so webhook retries can't double-grant.
Admin dashboard
Set a user's role to admin in the database (or via the Better Auth admin API) to unlock /admin:
UPDATE "user" SET role = 'admin' WHERE email = 'you@example.com';
From there you can manage products, write blog posts, cases and docs, review orders and AI usage, and ban or comp users.
Deploying
Both apps deploy to Cloudflare Workers:
pnpm --filter @raystarter/api deploy
pnpm --filter @raystarter/web deploy
Set production secrets with wrangler secret put in apps/api, create the R2 bucket (raystarter-media), and point Stripe's webhook endpoints at your deployed API.