Local Development

First run

  1. npm install
  2. Populate .env.local — see environment.md.
  3. npm run db:push — creates tables in your Neon branch.
  4. npm run dev — starts Next.js on port 3000.
  5. Visit /register to create user + org, then /overview.

Minimum env to boot without errors

To run the dev server and hit the dashboard:

  • DATABASE_URL
  • NEXTAUTH_SECRET (any random string)
  • NEXTAUTH_URL=http://localhost:3000

Stripe/AWS/Upstash envs only matter when you hit code paths that use them (send email, upgrade billing, rate limit).

Testing the API without AWS

Create a test API key from /overview/api-keys. Test keys (sok_test_*) skip AWS provider calls and usage limit checks — they only write to the messages table.

curl -X POST http://localhost:3000/api/v1/emails \
  -H "Authorization: Bearer sok_test_..." \
  -H "Content-Type: application/json" \
  -d '{"from":"a@example.com","to":["b@example.com"],"subject":"Hi","text":"Hi"}'

Drizzle Studio

npm run db:studio

Opens a browser-based DB inspector.

Dashboard auth

  • /register — creates user + organization + org_member rows.
  • /login — NextAuth credentials provider, bcrypt compare.
  • Proxy (src/proxy.ts) redirects unauthenticated traffic on /overview/* to /login, and is also where 2FA confinement and /api/v1 CORS live.

Next 16 renamed middleware.ts to proxy.ts, and the exported function must be named proxy, not middleware. Two things about the location are worth knowing before you move it:

  • It must sit at src/proxy.ts, beside app/ — not beside package.json. Next resolves it relative to the app root, so a root-level copy type-checks, lints, and never runs. It sat there once and the org 2FA mandate, whose only enforcement point is this file, was unenforced in production the whole time.
  • next build prints ƒ Proxy (Middleware) in the route table when it is wired up. If that line is absent, the file is not being loaded. src/proxy.location.test.ts asserts the placement so the mistake fails a test run rather than a deploy.