Architecture. How Plooi folds.
A high-level view of the moving parts — the browser, Supabase, and the AI providers that sit behind each node run.
System overview
Browser (React/Vite)
├─ Canvas UI & node graph
├─ Auth & realtime (Supabase)
├─ Billing UI (Stripe)
└─ Analytics (PostHog)
Supabase (EU / Frankfurt)
├─ Postgres + RLS
├─ Realtime (presence, collaboration)
└─ Edge functions (AI, billing, email, BYOK)
AI providers (BYOK)
├─ Anthropic Claude (text, reasoning)
├─ OpenAI GPT-4o (text, vision)
└─ Google Gemini + Imagen + Veo (text, image, video)Core building blocks
- Node graph as the central data model — nodes, connections, groups.
- Service layer (TypeScript) wraps every call to Supabase, Stripe, and AI providers.
- Edge functions carry the server-side logic — credits, webhooks, BYOK keys, deletion flows.
- RLS enforces row-level access on every table.
auth.uid() = user_idis the rule almost everywhere.
Data flow (AI run)
- User triggers a node run in the canvas.
- Frontend calls the ai-proxy edge function with the user’s auth token.
- The edge function checks credits, pulls the user’s encrypted provider key from
user_api_keys, decrypts it server-side via HKDF-SHA256 + AES-256-GCM, and forwards the request to the provider. - Result is written to the project and rendered back into the canvas. Plaintext key is discarded after the call. Usage is logged to the credit ledger.
BYOK at the architecture layer
Provider keys are encrypted with AES-256-GCM, with a per-row 16-byte salt and 12-byte nonce. The encryption key is derived per-row via HKDF-SHA256 from a master key kept in Supabase Function secrets — a separate store from Postgres.
- Writes go through the
store-api-keyedge function. The browser never writes ciphertext directly. - Reads from the browser hit the
user_api_keys_publicview, which exposes onlyid,service_name,key_hint, andkey_version. The ciphertext column is revoked from theauthenticatedrole. - Decrypts happen only inside
ai-proxy, in memory, for one call at a time. Plaintext never lands in logs, audit trails, Sentry, or backups.
See Bring your own key for the full picture.
Detailed module maps, table layouts, and service references live in
ARCHITECTURE.md and docs/API_REFERENCE.md in the repo.