# DIGITs Election Watch
Citizen observation of Nigerian elections — live observer feeds, verified i-Witness
evidence, and accredited DIGEO observer training.
Watching, reading and training require **no account**. Signing in is needed for
exactly two things: commenting on a live feed, and submitting evidence.
---
## Stack
| Layer | Choice |
| ---------------- | ---------------------------------------------------------------- |
| App | TanStack Router + React 19 + Vite 8 (client-rendered SPA) |
| Styling | Tailwind CSS v4, OKLCH design tokens, Sora + Inter |
| Database & auth | Supabase (PostgreSQL, RLS on every table, email + Google OAuth) |
| Realtime | Supabase Realtime (feeds, comments, grid layout, evidence queue) |
| Live video | LiveKit WebRTC — one shared room, adaptive simulcast |
| Evidence storage | Supabase Storage, private bucket, short-lived signed URLs |
| Server secrets | Supabase Edge Functions (`places`, `livekit-token`) |
There is no Node server: the app deploys as static assets. Anything that needs a
secret runs in an Edge Function, so no key ever reaches the browser.
---
## Getting started
```bash
npm install --legacy-peer-deps
npm run dev
```
### Environment
`.env` (never committed) holds the client keys plus the admin credentials the
tooling scripts use:
```dotenv
VITE_SUPABASE_URL=https:// .supabase.co
VITE_SUPABASE_PUBLISHABLE_KEY=
VITE_SUPABASE_PROJECT_ID=
# Tooling only — used by scripts/, never bundled
SUPABASE_PROJECT_ID=
SUPABASE_ACCESS_TOKEN=
# Pushed to Supabase function secrets by `npm run fn:deploy`
GOOGLE_PLACES_API=
LIVEKIT_URL=wss:// .livekit.cloud
LIVEKIT_API_KEY=
LIVEKIT_API_SECRET=
RESEND_API_KEY= # required to send DIGEO email
DIGEO_MAIL_FROM=DIGITs Election Watch
```
Only `VITE_*` variables reach the browser. `GOOGLE_PLACES_ …