Multi-tenant SaaS analytics platform
Orbit Analytics
Orbit started as a personal need — every analytics tool was either too expensive, too bloated, or required sending data to a third party. The goal was to build a self-contained, privacy-first analytics engine that a single developer could own and operate. The core challenge was query performance. At scale, aggregating millions of events across arbitrary date ranges and custom dimensions needs careful schema design. I landed on a denormalised event table with a materialised summary layer refreshed on a 5-minute schedule — giving the dashboard sub-100ms response times even for 30-day aggregations across 50k+ daily events.
50k+
Daily Events
avg processed / day
<100ms
Query P95
across 30-day windows
Multi-tenant
Workspaces
full RLS isolation
The Core Challenge
Raw event tables don't query well at scale. A naive COUNT(*) GROUP BY across 30 days of dense event data hits timeout territory quickly. The solution was a two-layer architecture: a write-optimised raw events table using Postgres partitioning by day, plus a materialised summary table refreshed every 5 minutes via a scheduled Supabase Edge Function. The dashboard always reads from the summary layer — raw data is only touched for drill-downs.
-- Incremental summary refresh
INSERT INTO event_summary (workspace_id, event_type, day, total)
SELECT
workspace_id,
event_type,
DATE_TRUNC('day', created_at) AS day,
COUNT(*) AS total
FROM events
WHERE created_at > NOW() - INTERVAL '10 minutes'
GROUP BY 1, 2, 3
ON CONFLICT (workspace_id, event_type, day)
DO UPDATE SET total = event_summary.total + EXCLUDED.total;Multi-tenancy with Row-Level Security
Every workspace is fully isolated at the database level using Postgres Row-Level Security policies. No application-level filtering needed — the database enforces workspace boundaries on every query, making it impossible for one tenant's data to leak into another. This is enforced even in the Supabase client, where the JWT is bound to the workspace ID.

Orbit Analytics funnel analysis view