Full Prisma migration: Supabase SDK data access removed from 13 files
Dshamir replaces every `supabase.from()` call in the backend with Prisma client queries against Postgres, decoupling persistence from the Supabase SDK. This is the fork's largest single change - 13 files rewritten, roughly 2100 lines net removed.
The thread runs across six commits. Prisma is initialized, a 408-line schema is added with 17 models, 7 enums, a deletedAt soft-delete column on six tables, and an AuditLog model. A custom Prisma client wraps the base client with a $extends hook: for findMany, findFirst, and count on soft-delete models it injects where: { ...args.where, deletedAt: null } automatically; for delete and deleteMany it converts the call to an updateMany that sets deletedAt: new Date(). This means callers write ordinary Prisma queries and get soft-delete behavior for free.
The capstone commit touches 8 routes (chat, projectChat, projects, documents, tabular, workflows, user, downloads) and 5 libraries (access, chatTools, documentVersions, userApiKeys, userSettings). The mechanical change is replacing supabase.from("table").select(...).eq(...).single() patterns with prisma.model.findUnique(...) equivalents. The schema uses camelCase field names (userId, sharedWith, deletedAt) so all the access checks that previously used snake_case fields required corresponding updates.
One nuance: the self-hosted stack still runs gotrue and postgrest containers. This migration is specifically about DB access - Prisma holds the service-role Postgres connection and bypasses RLS, while the PostgREST anon role remains in place for whatever it was doing. That separation becomes load-bearing in the later RLS hardening work, where a deny-all policy is applied specifically to block the PostgREST anon role while leaving Prisma's service-role unaffected.
The soft-delete extension has a type cast: (basePrisma as any)[model[0].toLowerCase() + model.slice(1)].update(...). It works, but the as any indicates Prisma's type system doesn't know about the custom behavior at compile time. The schema also has several as any casts on JSON fields - acknowledged in the fork's own roadmap as technical debt.
Spotted something wrong? Or know the PR text has fresher detail than the writeup above?