Setting Up Supabase Realtime

Supabase Realtime broadcasts database changes (INSERT, UPDATE, DELETE) to subscribed clients over a WebSocket connection. To enable it:

1. In your Supabase dashboard, go to Database β†’ Replication 2. Enable replication for the tables you want to watch (e.g., `metrics`, `events`, `orders`) 3. Set RLS policies on those tables β€” Supabase Realtime respects RLS, so users only receive changes to rows they're allowed to see

This takes 2 minutes. The hard work is on the frontend β€” handling the stream of changes and updating the UI.

Connecting WeWeb to Supabase Realtime

WeWeb's Supabase plugin supports realtime subscriptions natively. In WeWeb:

1. Go to Plugins β†’ Supabase β†’ your data source 2. Enable "Realtime" on the collection you want to watch 3. WeWeb automatically subscribes to changes and updates bound elements when a change arrives

For a metrics dashboard bound to a `metrics` table: add a Collection bound to the table, enable Realtime, and bind chart/number elements to the collection. When a new metric row is inserted in Supabase, the dashboard updates in under 500ms without any user action.

Building the Dashboard Layout

A typical real-time dashboard has three zones:

**KPI row**: 3–4 large number cards at the top. Each bound to an aggregate (SUM, COUNT, AVG) from a Supabase view. In WeWeb, create a view in Supabase that pre-calculates aggregates and bind the KPI cards to that view's realtime collection.

**Charts**: Line chart for time-series data, bar chart for comparisons, pie for distribution. WeWeb has a built-in Chart component powered by Chart.js. Bind the `data` prop to a Supabase collection ordered by `created_at`.

**Data table**: A sortable, filterable table for the raw events. WeWeb's DataGrid component with search, sort, and pagination. Enable Realtime so new rows appear at the top as they arrive.

Time Range Filtering

Every dashboard needs time range controls. Pattern:

1. Add a Filter Bar component with preset buttons: Last 24h, Last 7d, Last 30d, Custom range
2. Create a page variable `dateRange` with start and end timestamps
3. Pass `dateRange` as a filter to every Supabase collection: `.gte("created_at", dateRange.start).lte("created_at", dateRange.end)`
4. When the user selects a different range, update `dateRange` β€” all collections re-fetch automatically

For custom date ranges, use WeWeb's Date Picker component and bind both inputs to `dateRange.start` and `dateRange.end`.

Row-Level Security for Multi-Tenant Dashboards

For SaaS dashboards where each client sees only their data:

```sql
-- metrics table RLS policy
CREATE POLICY "Users see own org metrics"
ON metrics FOR SELECT
USING (
  org_id IN (
    SELECT org_id FROM memberships
    WHERE user_id = auth.uid()
  )
);
```

This policy means the same dashboard URL works for all clients β€” each sees only their organisation's data. No filtering needed in WeWeb. Supabase enforces it at the database level.

Critical: test this by logging in as users from two different organisations and confirming the data is isolated. An RLS bug in a dashboard is a serious data leak.

Performance Optimisation for Large Datasets

Dashboards with millions of rows slow down quickly if you're running aggregates on raw data.

**Create Supabase views for aggregates**: `CREATE MATERIALIZED VIEW daily_metrics AS SELECT DATE(created_at), COUNT(*), SUM(value) FROM events GROUP BY DATE(created_at)`. Refresh the materialized view hourly via a Supabase Edge Function cron job.

**Use indexes**: Add an index on `(org_id, created_at)` for every table filtered by organisation and time. This turns a 5-second query into a 50ms query.

**Paginate the raw table**: Never load all rows into the dashboard. Use Supabase's `.range(0, 99)` for the data table and let users paginate. This keeps initial load fast regardless of total row count.