mono/packages/ui/docs/deploy/ditch-supabase-server.md
2026-04-08 23:39:46 +02:00

99 lines
6.2 KiB
Markdown

# Server Infrastructure Migration: Ditching Supabase (Execution Status)
> **Status**: Active Migration / Implementation
> **Target Architecture**: Self-hosted Postgres, Prisma ORM, Zitadel (Auth/Tenancy), S3-compatible Storage (MinIO or VFS)
> **Prior Reference**: `ditch-supabase.md` (initial research)
This document tracks concrete migration status and remaining work to remove Supabase dependencies from server infrastructure.
---
## 1) Database & ORM: Prisma
While Drizzle was initially highly considered, the current CLI implementation (`pm-cli-cms`) successfully validated **Prisma** (with `@prisma/adapter-pg` and `pg.Pool`) as our query layer of choice.
**Why Prisma?**
- Type safety and schema synchronization is best-in-class.
- The `schema.prisma` file serves as the definitive source of truth for the database layout.
- The CLI testbed proved we can dynamically spin up connections to different tenant databases.
### Status / Next steps:
1. **Schema Centralization**: Establish a core `schema.prisma` representing the standard tenant database.
2. **Server-Side Integration**: Replace the ~27 server files currently making PostgREST `supabase.from()` calls with Prisma queries (`prisma.posts.findMany()`, etc.).
3. **Connection Pooling**: Implement a caching/pooling mechanism in the server backend to hold active Prisma clients for each tenant (since Zitadel manages tenancy per-database).
---
## 2) Authentication & Tenancy: Zitadel
The architecture has evolved beyond simple email/password auth. We are utilizing **Zitadel** as our central Identity Provider (IdP). Zitadel is explicitly designed to handle B2B tenancy.
**Auth chapter (flows, payloads, host setup, references):** `docs/supabase/auth-zitadel.md`
**The Multi-Tenant Database Model**:
Instead of relying on Supabase Row-Level Security (RLS) to isolate tenant data inside a massive single database, we are opting for **database-per-tenant** (or schema-per-tenant) isolation mapped by Zitadel.
### Status / Next steps:
1. **API Middleware**: Replace the Supabase JWT verifiers in Hono with Zitadel token verification.
2. **Instance Provisioning**: When Zitadel registers a new application/tenant, our backend needs a Webhook/Event trigger to dynamically fire the `pm-cli-cms site-init` or equivalent workflow to provision an isolated Postgres database.
3. **Database Routing**: The server backend must extract the Tenant ID from the Zitadel JWT on incoming requests and fetch/instantiate the Prisma client bound to that specific tenant's `DATABASE_URL`.
---
## 3) Storage Migration Strategy (VFS & Mounts)
We are fully moving away from Supabase Storage (Buckets). The replacement strategy relies heavily on our mature, battle-tested **Virtual File System (VFS)** located at `server/src/products/storage/api/vfs.ts`.
**Why the VFS replaces Supabase Buckets:**
- **Native File Abstraction**: The VFS supports flexible storage mounts. We can seamlessly swap out the underlying physical backend to an S3-compatible generic provider (like MinIO) or local disk without rewriting any of our API handlers.
- **Built-in ACL Integration**: The VFS natively integrates with `@polymech/acl` for granular permission checks (Read/Write/Delete) against file paths, meaning we no longer need Supabase bucket policies.
### Current implemented tooling:
1. **`pm-cli-cms backup-store`**
- can export Supabase bucket files directly into local VFS images root:
- `pm-cli-cms backup-store --source ./server --target ./server/storage/images`
- preserves `cache/...` paths and emits picture UUID aliases under `storage/<user_id>/<picture_id>.<ext>`.
2. **`pm-cli-cms migrate-images-vfs`**
- rewrites `pictures.image_url` to VFS URLs:
- `<IMAGE_VFS_URL>/api/vfs/get/<IMAGE_VFS_STORE>/<user_id>/<picture_id>[.<ext>]`
- supports direct Supabase URLs and nested `/api/images/render?url=...` wrappers.
- resolves missing local files via hash matching and optional hydration from old URL content.
3. **Server-side image compatibility**
- `server/src/products/images/index.ts` contains compatibility handlers for legacy thumbnail/render URL patterns during migration.
---
## 4) Authorization & Security (ACL Strategy)
**The major milestone: RLS is deprecated.**
We no longer rely on Supabase Row-Level Security (`auth.uid()`) at the database level.
**Application-Layer Enforcement via `@polymech/acl`:**
- Our own ACL engine correctly evaluates paths, nested inheritance, and group-based hierarchies via `acl_groups` and `resource_acl`.
- Because Zitadel gives us Tenant IDs and specific roles up-front in the JWT middleware, the application layer resolves exactly what the connection session is permitted to access.
- **Done**: The core logic required to isolate access is fully complete inside the ACL module. It's strictly a matter of stripping the old RLS policies from the Postgres schemas entirely (treating the database as fully trusted by the API backend).
---
## 5) Execution Pipeline
### Milestone 1: Data Migration Engine (Completed)
- ✅ Validated raw self-hosted Postgres (`polymech.info:5432`)
-`pg_dump` and `psql` wrapping via our CLI (`pm-cli-cms backup-site` / `db-import`).
- ✅ Stripping out Supabase-specific system schemas (`auth`, `realtime`, `storage`) from exported backups to ensure hygienic vanilla Postgres DBs.
### Milestone 2: Server ORM Cut-Over (In Progress)
- 🚧 Bootstrap `prisma/schema.prisma` matching the clean vanilla Postgres schema.
- 🚧 Systematically replace `supabase.from()` with ORM query paths in server modules.
- ✅ Added Drizzle query CLI baseline: `pm-cli-cms db-query-drizzle` with query/transaction timing metrics and report output.
### Milestone 3: Zitadel & Routing
- 🚧 Replace `@polymech/acl`'s dependency on `auth.uid()` or Supabase cookies with Zitadel JWT payload assertions.
- 🚧 Implement the dynamic database connection router to select the right Prisma instance based on the Zitadel Tenant ID.
### Milestone 4: Storage Migration Cut-Over (In Progress)
- ✅ VFS-backed image upload path implemented (`/api/images?forward=vfs`).
- ✅ CLI workflows added for file backup + URL rewrite (`backup-store`, `migrate-images-vfs`).
- 🚧 Complete migration runbooks + verification reports in production.
- 🚧 Remove temporary legacy URL compatibility code after migration is complete.