Overview
Migrate Fish Cost Calculator from Vercel + Stack Auth to Cloudflare Pages/Workers + Better Auth, keeping Neon PostgreSQL as the database. This consolidates the current dual auth system (custom JWT + Stack Auth OAuth) into a single Better Auth implementation that runs natively in Cloudflare Workers.
Why
- Stack Auth is tied to the Vercel/Neon integration panel — not portable
- Neon Auth has moved to Better Auth under the hood — natural migration path
- Better Auth runs natively in CF Workers (no external API calls for auth verification)
- Consolidates dual auth (JWT + OAuth) into one system
- $0/month on Neon free tier (60K MAU) + Cloudflare free tier (100K req/day)
Current State
- Auth: Dual system — custom JWT (password) + Stack Auth (Google/GitHub OAuth)
- Database: Neon PostgreSQL via
@neondatabase/serverless
- Hosting: Vercel (serverless functions + static frontend)
- Integrations: 2x Neon + 1x Clerk (unused) on Vercel
Current Auth Files
| File |
Role |
api/_lib/auth.js |
requireAuth() middleware, JWT verify, Stack Auth fallback |
api/_lib/neon-auth.js |
Stack Auth session verification (calls api.stack-auth.com) |
api/login.js |
Password login → JWT token |
api/register.js |
Password registration → bcrypt hash |
app/src/context/AuthContext.jsx |
Frontend auth state, JWT + Stack Auth session checks |
app/src/config/neonAuth.js |
StackClientApp configuration |
app/src/App.jsx |
StackProvider wrapper, /handler/* OAuth callback route |
Protected Endpoints (8)
save-calc, saved-calcs, user-data/index, user-data/[id], contributor, export, upload-data
Database Tables
users — id, username, password (bcrypt), email, neon_auth_id, auth_provider, avatar_url, role
calculations — user_id FK
user_data — user_id FK
contributors — user_id FK
Target State
- Auth: Better Auth (self-hosted in CF Worker) — email/password + Google/GitHub OAuth
- Database: Neon PostgreSQL via Cloudflare Hyperdrive
- Hosting: Cloudflare Pages (frontend) + Workers (API)
- Auth data: Stored in Neon (
neon_auth schema or custom tables)
Phases
Phase 0: Cleanup (pre-migration)
Phase 1: Better Auth Setup
Phase 2: Backend Migration
Phase 3: Frontend Migration
Phase 4: Cloudflare Deployment
Phase 5: Cutover & Cleanup
User Data Migration
Existing users need to maintain access:
- Password users: Bcrypt hashes may need re-import into Better Auth's user table (or keep custom table with adapter)
- OAuth users:
neon_auth_id maps to Stack Auth IDs — Better Auth will assign new IDs on first OAuth login. Email-based linking preserves account continuity.
- Saved data:
calculations, user_data, contributors tables use user_id FK — must map old IDs to new Better Auth user IDs
Risk Mitigation
- Better Auth supports custom database adapters — can point at existing
users table structure
- Email-based identity linking means OAuth users reconnect automatically on first login
- Can run both auth systems in parallel during transition (current
requireAuth() already supports fallback pattern)
- Neon database is platform-agnostic — no data migration needed
References
Labels
epic, auth, cloudflare, migration
Overview
Migrate Fish Cost Calculator from Vercel + Stack Auth to Cloudflare Pages/Workers + Better Auth, keeping Neon PostgreSQL as the database. This consolidates the current dual auth system (custom JWT + Stack Auth OAuth) into a single Better Auth implementation that runs natively in Cloudflare Workers.
Why
Current State
@neondatabase/serverlessCurrent Auth Files
api/_lib/auth.jsrequireAuth()middleware, JWT verify, Stack Auth fallbackapi/_lib/neon-auth.jsapi.stack-auth.com)api/login.jsapi/register.jsapp/src/context/AuthContext.jsxapp/src/config/neonAuth.jsStackClientAppconfigurationapp/src/App.jsxStackProviderwrapper,/handler/*OAuth callback routeProtected Endpoints (8)
save-calc,saved-calcs,user-data/index,user-data/[id],contributor,export,upload-dataDatabase Tables
users— id, username, password (bcrypt), email, neon_auth_id, auth_provider, avatar_url, rolecalculations— user_id FKuser_data— user_id FKcontributors— user_id FKTarget State
neon_authschema or custom tables)Phases
Phase 0: Cleanup (pre-migration)
Phase 1: Better Auth Setup
better-authpackagePhase 2: Backend Migration
api/_lib/neon-auth.jswith Better Auth session verificationapi/_lib/auth.jsrequireAuth()to use Better Authapi/login.jswith Better Auth sign-inapi/register.jswith Better Auth sign-upPhase 3: Frontend Migration
StackProviderwith Better Auth React provider inApp.jsxapp/src/config/neonAuth.jswith Better Auth client configAuthContext.jsxto use Better Auth sessions/handler/*Stack Auth callback routePhase 4: Cloudflare Deployment
wrangler.tomlwithnodejs_compatflagPhase 5: Cutover & Cleanup
@stackframe/reactdependencyneon-auth.js,neonAuth.js)User Data Migration
Existing users need to maintain access:
neon_auth_idmaps to Stack Auth IDs — Better Auth will assign new IDs on first OAuth login. Email-based linking preserves account continuity.calculations,user_data,contributorstables useuser_idFK — must map old IDs to new Better Auth user IDsRisk Mitigation
userstable structurerequireAuth()already supports fallback pattern)References
Labels
epic, auth, cloudflare, migration