Architecture Overview
Flow runs on a Supabase-only backend: a single stack of PostgreSQL (with RLS), Edge Functions (Deno/TypeScript), Realtime, and Storage. No microservices, no multiple databases, no message queues — all business logic lives either in the database or in Edge Functions called via HTTP.
Architectural decision — 2026-03-29
Flow migrated from Node.js microservices + MongoDB + Redis + Elasticsearch to Supabase-only. Motivation: eliminate dual-database inconsistency, cut operational costs to near zero, simplify deployment. Legacy microservice code still exists in
backend/but is not used or touched — it will be archived in alegacy/microservicesbranch once fully decoupled.Full design spec: Supabase-only Migration Design
Tech Stack
| Layer | Technology |
|---|---|
| Mobile | Flutter · Dart · Riverpod · GoRouter · Supabase Flutter SDK |
| Web | Next.js 16 · React 19 · TypeScript · Tailwind CSS 4 · TanStack Query |
| API | Supabase PostgREST (auto-generated from Postgres schema) + custom Edge Functions |
| Database | PostgreSQL with Row Level Security on every table |
| Geospatial | PostGIS (geo_point column) |
| Search | pg_trgm for native fuzzy matching in Postgres |
| Realtime | Supabase Realtime (Postgres changes subscriptions + broadcast) |
| Auth | Supabase Auth (email/password, JWT auto-refresh) |
| Push | Firebase Cloud Messaging, triggered from Edge Functions |
| Resend API for critical notifications | |
| AI/ML | Custom Edge Functions (recommendations, matchmaking, moderation) |
Core Components
Database
Postgres with ~30 main tables (profiles, events, venues, chats, connections, crews, badges, notifications, recommendations_cache, etc.). RLS on every table: no API layer needs to re-verify authorization — the database rejects unauthorized queries directly based on auth.uid().
Details: Database Schema
Edge Functions
Seven Edge Functions in Deno/TypeScript handle logic that cannot live purely in SQL: push/email notifications, recommendation scoring, matchmaking, content moderation, XP/badge assignment.
| Function | Trigger | Purpose |
|---|---|---|
send-notification | INSERT on notifications | FCM push + Resend email |
process-rsvp | Change on event_attendees | XP, cache invalidation, badge |
compute-recommendations | Cron (6h) / on-demand | Event scoring |
compute-matchmaking | On-demand | People scoring |
moderate-content | INSERT on messages/comments | Keyword filter + flag |
compute-connection-depth | INSERT on event_attendees | Friendship tier |
evaluate-badges | Called from process-rsvp | Badge criteria check |
Details: API Reference
Clients
- Admin Portal (
web/): multi-role dashboard (admin, vendor, moderator) in Next.js 16. Server Components for SSR, TanStack Query for mutations. - Mobile App (
flow_mobile/): Flutter iOS + Android. Riverpod for state management, GoRouter for navigation, Supabase Flutter SDK for data layer.
Both clients talk directly to Supabase — no intermediate API gateway, no custom serialization, TypeScript/Dart types auto-generated from the schema.
What Does NOT Exist (by design)
- ❌ No custom API gateway (Express, Fastify, etc.)
- ❌ No message broker (RabbitMQ, Kafka, etc.)
- ❌ No secondary database (MongoDB, DynamoDB, etc.)
- ❌ No custom cache layer (Redis, Memcached) — Postgres suffices, with materialized views where performance is needed
- ❌ No separate search engine —
pg_trgmhandles fuzzy matching for current use cases
These choices are reversible — but any new technology addition must be justified by a real measured problem, not anticipated.
Related
- Supabase-only Migration Design — full decision spec
- technical-architecture — detailed component breakdown
- 1-event-bus — infra improvement proposals, each with cost/benefit analysis