Unified analytics dashboard pulling revenue (RevenueCat, Adapty), ad spend (Meta Ads, Apple Search Ads), attribution (AppsFlyer) and user (Amplitude) metrics into one place. Next.js 15 + Supabase + Vercel.
- Every provider has an adapter (
src/lib/providers/*) implementing one interface:connect/ensureToken/fetchMetrics. - Adapters normalize each source into a single
metricstimeseries table (provider, app_id, metric_key, date, value, dimensions). - Charts only ever read from
metrics— they never call a provider API. Fresh data is pulled by the per-chart Refresh button and a daily 09:00 Vercel Cron, both routed through one sync orchestrator. This keeps us inside tight provider rate limits (RevenueCat 15/min, AppsFlyer 24/day…). - Provider secrets and OAuth tokens are AES-256-GCM encrypted before they touch Supabase. Decryption happens only in server route handlers.
npm install- Create a project at supabase.com.
- Run the migration: open the SQL editor and paste
supabase/migrations/0001_init.sql(orsupabase db pushwith the CLI). - Create team members under Authentication → Users (email + password). There is no public signup — this is an internal tool.
Copy .env.example to .env.local and fill in:
cp .env.example .env.local
# generate the encryption key + cron secret:
node -e "console.log('CREDENTIALS_ENCRYPTION_KEY=' + require('crypto').randomBytes(32).toString('base64'))"
node -e "console.log('CRON_SECRET=' + require('crypto').randomBytes(24).toString('hex'))"Provider API keys are not env vars — they are entered in the in-app Settings page and stored encrypted.
npm run dev # http://localhost:3000- Push to a Git repo and import into Vercel.
- Add every variable from
.env.examplein Project → Settings → Environment Variables (setNEXT_PUBLIC_APP_URLto the production URL). - The daily cron is declared in
vercel.json(0 9 * * *→/api/cron/sync). Vercel sendsAuthorization: Bearer $CRON_SECRETautomatically.
Open Settings and pick a source. Each card lists where to get its credentials. Highlights:
| Provider | Auth | Note |
|---|---|---|
| RevenueCat | OAuth (PKCE) or sk_ key |
OAuth client is registered via support@revenuecat.com; the V2 secret key is a drop-in fallback. |
| Adapty | Secret API Key | App Settings → SDK and API keys. |
| Meta Ads | OAuth + long-lived token | Business app + ads_read (App Review for accounts you don't own). |
| Apple Search Ads | OAuth client-credentials (ES256 JWT) | EC P-256 private key in PKCS8 PEM; resolves orgId via /acls. |
| AppsFlyer | API V2 Token | Master API must be enabled; token must be regenerated after 2026-03-10. |
| Amplitude | API Key + Secret (Basic) | Pick US vs EU data residency. |
OAuth redirect URI to register with each provider:
https://<your-app>/api/oauth/<provider>/callback.
npm run dev # dev server
npm run build # production build
npm run typecheck # tsc --noEmit