{"slug":"operations/DE_SUPABASE_MIGRATION","title":"De-Supabase Migration — Cloudflare-Only Product Plane","section":"operations","sectionLabel":"Operations","status":"unclassified","type":"document","path":"operations/DE_SUPABASE_MIGRATION.md","bytes":6650,"description":null,"updated":null,"source":"integratewise/Integratewise-docs-wiki","content":"\n> **Status: SUPERSEDED MIGRATION SNAPSHOT.** The no-new-Supabase direction\n> remains valid, but the Cloudflare-only/D1 destination does not. Current target:\n> Neon for canonical relational truth, R2 for evidence bytes and D1/KV only for\n> bounded reconstructable operational state. Use\n> [`../architecture/IMPLEMENTATION_CONTRACT_v1.1.md`](../architecture/IMPLEMENTATION_CONTRACT_v1.1.md).\n>\n> **Original status:** TRACKED / IN PROGRESS\n> **Original authority:** AGENTS.md DECISION 22 (2026-06-12) — 100% Cloudflare product plane.\n> **Rule:** This is the single tracker for removing Supabase from the product. Update it IN PLACE\n> as services migrate. Do NOT spawn sibling migration docs. Do NOT add new Supabase usage.\n> **Honesty note:** Doctrine = Cloudflare-only. Code = NOT there yet. This doc tracks the gap.\n\n---\n\n## Baseline (measured 2026-06-12)\n\n~71 source files reference Supabase across services + packages (excluding node_modules/dist/tests).\nThe good news: most go through **two client chokepoints**, so this is far less than 71 independent rewrites.\n\n### Chokepoints (migrate these first — everything else funnels through them)\n\n| File                                              | Role                                                                                | Becomes                                                                                        |\n| ------------------------------------------------- | ----------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |\n| `packages/db/src/supabase.ts`                     | `createDbClient` / `createAdminClient` (service-role, schema `hub`, `exec_sql` RPC) | A D1-backed adapter exposing the same surface, OR callers move to D1 bindings                  |\n| `packages/supabase/src/{client,server,native}.ts` | Browser/SSR auth + db client                                                        | DELETE — app auth is already CF Gateway credential auth (DECISION 20); product reads D1-direct |\n| `packages/db/src/index.ts`                        | re-exports db client                                                                | Re-point to D1 adapter                                                                         |\n\n### Access patterns found (what each call actually is)\n\n1. **`createDbClient/createAdminClient(...).from(table).select/insert/update`** — relational reads/writes → **D1** (`env.SPINE_CACHE_DB` or service D1 binding).\n2. **Direct REST `fetch(${SUPABASE_URL}/rest/v1/...)`** (e.g. `services/think/src/tenant-config.ts`) → **D1 query** against `tenant_spine_config` (already partly on D1 — see migration 033).\n3. **`.rpc(\"exec_sql\", ...)`** (raw SQL helper, already `@deprecated`) → **D1 prepared statements** (parameterized). Remove the RPC path.\n4. **pgvector similarity** (memory/knowledge search) → **Vectorize** or **AI Search** (`integratewise-knowledge`).\n5. **Browser auth** (`packages/supabase` client) → **already replaced** by CF Gateway credential auth (DECISION 20). Just remove dead imports.\n\n---\n\n## Migration phases (by blast radius, smallest first)\n\n### Phase 0 — Stop the bleeding (no behavior change)\n\n- [ ] Add `supabase` to the doctrine drift-check ratchet (done — `scripts/check-doctrine.mjs`). New Supabase usage now fails CI.\n- [ ] 🚨 **Rotate** the Supabase service-role key exposed in `IW-handoff-20260611-213600.md` + scrub from `.env`/`.dev.vars` (manual — founder).\n\n### Phase 1 — Already-D1 paths (verify + delete Supabase fallback)\n\nGateway/workspace already read D1-direct. Confirm no Supabase fallback remains.\n\n- [ ] `services/gateway/src/index.ts` (7 refs) — confirm D1-only; drop Supabase fallback.\n- [ ] `services/think/src/tenant-config.ts` (8) — `tenant_spine_config` is on D1 (migration 033) → swap REST fetch → D1.\n- [ ] `services/pipeline/src/index.ts` (14) + `spine/index.ts` (16) — pipeline writes the Spine; confirm D1 partitions (`${domain}_data`) are the only write target.\n\n### Phase 2 — Memory & knowledge (pgvector → Vectorize/AI Search)\n\n- [ ] `services/knowledge/src/{index,iq-hub,memory-consolidator}.ts`, `search/service.ts`, `embedding/storage.ts` — move pgvector → AI Search (`integratewise-knowledge`) / Vectorize.\n- [ ] `services/intelligence/src/memory/morning-context-builder.ts` — read memory from D1/KV/AI Search.\n- [ ] `services/continuity/src/{index,supabase}.ts` — conversational/org/personal memory → D1 + DO SQLite.\n\n### Phase 3 — Reasoning & governance\n\n- [ ] `services/think/src/{cognitive-brain,index}.ts` (70 + 29) — largest single files; cognitive reads → D1/KV/AI Search.\n- [ ] `services/govern/src/proposal.ts`, `services/act/src/index.ts` — proposals/executions → D1 (+ TenantBrainDO already holds approvals/executions).\n- [ ] `services/mcp-connector/src/handlers/tools.ts` (58) + `index.ts` — MCP tool reads → D1/AI Search.\n\n### Phase 4 — Connectors, tenants, billing, workflow, admin\n\n- [ ] `services/connector-sync/src/index.ts` (20), `services/connector/src/token-refresh.ts` — sync cursors/tokens → D1/KV (tokens stay in Nango).\n- [ ] `services/tenants/src/{index,context,oauth-configs}.ts` — tenant/RBAC → D1.\n- [ ] `services/billing/*` (42+18+11) — billing records → D1 (Stripe/Razorpay remain source of truth for payments).\n- [ ] `services/workflow/src/*` (48+others) — workflow state → D1 + DO.\n- [ ] `services/admin/*` — admin reads → D1.\n- [ ] `packages/rbac/src/engine.ts` (9), `packages/lib/src/{audit,cache,neon}.ts` — shared libs → D1/KV.\n\n### Phase 5 — Delete the clients\n\n- [ ] Delete `packages/supabase/*` and `packages/db/src/supabase.ts` once no importers remain.\n- [ ] Remove `SUPABASE_*` from all `wrangler.toml` / `.dev.vars` / `.env`.\n- [ ] Remove `@supabase/supabase-js` from `package.json`s.\n- [ ] Flip the drift-check baseline for `supabase` to 0 (hard-fail on any reintroduction).\n\n---\n\n## Deprecated services note\n\n`services/{normalizer,store,loader,think,act,govern}` are pre-consolidation reference workers (per AGENTS.md). Their Supabase refs are lower priority — confirm they're truly inert before spending effort; the live behavior lives in `pipeline`, `connector`, `intelligence`.\n\n## Definition of done\n\n- `grep -rl \"supabase\" services packages --include=*.ts | grep -v node_modules | grep -v test` → **0**\n- No `SUPABASE_*` vars in any wrangler/env file.\n- `@supabase/supabase-js` absent from all `package.json`.\n- Drift-check `supabase` baseline = 0.\n"}