This document tracks the concrete implementation phases for migrating Impactify from Supabase Auth + Supabase Postgres/Storage to Better Auth, generic Postgres (local via Docker), Cloudflare R2, and Prisma as the schema brain.
- Goals
- Freeze current architecture in docs (
ARCHITECTURE.md,PROJECT_OVERVIEW.md,current-db-schema.md). - Decide target stack: Better Auth + generic Postgres (local via Docker, managed later), Cloudflare R2, Prisma as schema brain.
- Freeze current architecture in docs (
- Exit criteria
- Written plan (
migrate-to-better-auth-and-local-postgres). - Clear decision that Supabase Auth is being replaced and Supabase DB/Storage are legacy.
- Written plan (
- Goals
- Run the existing app against local Postgres in Docker for development.
- Key tasks
- Use
docker-compose.postgres.ymlto run a local Postgres (impactifyDB/user/password, port5432). - Point
impactis-server/.env.localDATABASE_URLat the Docker Postgres. - Add a script (e.g.
npm run db:migrate:local) to apply allsupabase/migrations/*.sqlto local Postgres. - Smoke test: run
impactis-server+impactis-clienton local Postgres; workspace, billing, and data room work end-to-end.
- Use
- Exit criteria
- One command to bring up DB and another to apply migrations.
- Local dev no longer depends on Supabase Postgres.
- Goals
- Switch authentication from Supabase Auth to Better Auth for all workspace flows.
- Key tasks
- Client (
impactis-client)- Better Auth is configured and used for
/auth/*pages and session management. /api/auth/*routes are handled by Better Auth.- Workspace/server actions call NestJS using the Better Auth token (via
getBetterAuthTokenandAuthorization: Bearerheader). - Security → Active Sessions page lists Better Auth sessions and can revoke specific sessions or all other sessions using
authClient.listSessions,revokeSession, andrevokeOtherSessions.
- Better Auth is configured and used for
- Server (
impactis-server)- Auth integration validates Better Auth JWTs using JWKS (
BETTER_AUTH_JWKS_URL) and issuer (BETTER_AUTH_ISSUER). - All workspace/billing/startups/organizations/profile controllers use the Better Auth–backed guard; there is no
SupabaseJwtGuard. - Legacy Supabase-based
auth.sessionsquerying inSessionsServicehas been disabled; NestJS no longer depends on Supabase Auth tables.
- Auth integration validates Better Auth JWTs using JWKS (
- Env cleanup
- Supabase auth envs are no longer required by the NestJS codebase.
- Better Auth envs (
BETTER_AUTH_JWKS_URL,BETTER_AUTH_ISSUER) are documented and used.
- Client (
- Exit criteria
- Users sign up / sign in via Better Auth and use workspace, billing, and data room in dev.
- Supabase Auth is not needed to run the stack locally.
- Goals
- Use Prisma as the structured representation of the schema while keeping SQL migrations as the DDL source of truth.
- Key tasks
- Add
schema.prismaunderimpactis-serverand pull the schema from local Postgres as a starting point. - Hand-align
schema.prismawithdocs/current-db-schema.md(tables, relations, enums). - Generate Prisma Client and integrate it with
PrismaService:- Start using Prisma Client for straightforward queries (e.g. profiles, organizations).
- Keep raw SQL for complex views and reporting.
- Update
docs/current-db-schema.mdto mentionschema.prismaas the code-side mirror of the DB schema.
- Add
- Exit criteria
schema.prismaandcurrent-db-schema.mddescribe the same schema.- Prisma Client is used in at least one module without regressions.
- Goals
- Move uploads (avatars, logos, data room docs) from legacy Supabase-style URLs to Cloudflare R2, preserving existing data where needed.
- Key tasks
- Backend
FilesModuleR2 integration is active with signed upload URL endpoints for:- Startup data room documents.
- Organization logos.
- Profile avatars.
- Ensure DB continues to use
storage_bucketandstorage_object_pathconsistently, with new R2 bucket names (e.g.startup-data-room-assets).
- Frontend
- Upload actions:
- Request signed URL from NestJS.
- PUT file bytes directly to R2.
- Persist file metadata via existing APIs (
startup_data_room_documents,profiles,organizations).
- Existing legacy URLs already stored in
file_urlcan still be rendered; new uploads use the R2 URL shape end-to-end.
- Upload actions:
- Docs
ARCHITECTURE.md“File flows” shows R2 as the primary storage backend.PROJECT_OVERVIEW.mddocuments that avatars, logos, and data-room docs now use R2 via signed URLs.
- Backend
- Exit criteria
- New uploads use R2 in dev.
- Data room, logos, and avatars work end-to-end with R2.
- Goals
- Remove remaining Supabase-specific coupling and lock in the new stack (Better Auth + NestJS + generic Postgres + R2).
- Key tasks
- Confirm there is no Supabase SDK or Supabase auth usage in client or server code.
- Keep only legacy URL parsing where needed to read old Supabase-style
file_urlvalues; new uploads must not depend on Supabase. - Maintain a concise “Local Dev & Deployment” section in
ARCHITECTURE.mdthat explains:- How to run DB, migrations, server, and client.
- How Better Auth, Postgres, Prisma, and R2 fit together.
- Document and enforce capability-based feature gates, especially:
dataroom.uploadanddataroom.managefor startup data-room docs.data_room_documents_limitplan feature for per-org document limits.
- Exit criteria
- No code paths require Supabase Auth or Supabase-specific env vars to run the app.
- New contributors can follow the docs to spin up the full stack locally using Docker Postgres, Better Auth, Prisma, and R2.