Console Admin API
Komplett referanse for Console web-appen (console.impulseai.app) — autentisering, arkitektur og admin-API.
Autentiseringsarkitektur
heading.anchorLabelConsole har fire sikkerhetslag:
| Lag | Mekanisme | Hva sjekkes | Hvor |
|---|---|---|---|
| 1 | Email + passord | Brukerens identitet | Supabase Auth |
| 2 | is_console_admin metadata | At brukeren har admin-rolle | Console middleware |
| 3 | CONSOLE_ALLOWED_EMAILS | At e-posten er i allowlisten | Console middleware |
| 4 | CONSOLE_ADMIN_TOKEN bearer | Console som tjeneste mot API | API bearer auth |
Lag 1-3 beskytter innlogging. Lag 4 beskytter data-henting fra API.
Opprette admin-bruker
heading.anchorLabelI Supabase Dashboard → Authentication → Users → Add User:
- Sett email og passord
- Klikk brukeren → Edit User → User Metadata:
{ "is_console_admin": true }
Alternativt via SQL Editor:
UPDATE auth.usersSET raw_user_meta_data = raw_user_meta_data || '{"is_console_admin": true}'::jsonbWHERE email = 'din-admin@impulseai.app';Admin-brukere per miljoe
heading.anchorLabel| Miljoe | Supabase-prosjekt | |
|---|---|---|
| STG | console-admin-stg@impulseai.app | conxpuqktkeiphnnpfiv |
| PRD | console-admin@impulseai.app | jksqfeutntcvukrisrno |
Klient-autorisasjonsmatrise
heading.anchorLabel| Klient | Klient-auth | Bruker-auth | Scope |
|---|---|---|---|
| iOS/Android | X-API-Key header | Supabase JWT | Egne data (RLS) |
| Console | Bearer CONSOLE_ADMIN_TOKEN | Supabase session cookie | Alle data (admin) |
| Webhooks | Plattform-signatur | Ingen | Skrive (events) |
| Health check | Secret URL-path | Ingen | Kun status |
API middleware-kjede
heading.anchorLabelRequest inn |-- /health/{secret} → Bypass alt (Railway health check) |-- /webhooks/* → Bypass API key (egen signaturverifisering) |-- /admin/* → Bypass API key (egen Bearer token-auth) '-- /api/v1/* → Krev X-API-Key + JWTAPI-autentisering
heading.anchorLabelAlle /admin/monitoring-endepunkter krever Bearer token:
Authorization: Bearer <CONSOLE_ADMIN_TOKEN>- Timing-safe token-sammenligning
- Fritatt fra X-API-Key-krav og global rate limiting
- Returnerer
401ved manglende eller ugyldig token
Environment-variabler
heading.anchorLabelPaakrevd (Console frontend)
heading.anchorLabel| Variabel | Beskrivelse |
|---|---|
NEXT_PUBLIC_SUPABASE_URL | Supabase project URL |
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY | Supabase anon key |
SUPABASE_SECRET_KEY | Supabase service role key (server-only) |
NEXT_PUBLIC_CONSOLE_API_URL | API server URL (f.eks. https://api.impulseai.app) |
CONSOLE_ADMIN_TOKEN | Bearer token for admin-endepunkter |
CONSOLE_ALLOWED_EMAILS | Kommaseparert allowlist for innlogging (Doppler) |
Valgfrie (API-server, aktiverer ekstra features)
heading.anchorLabel| Variabel | Aktiverer |
|---|---|
CONSOLE_SENTRY_API_TOKEN + CONSOLE_SENTRY_ORG + CONSOLE_SENTRY_PROJECT | Sentry error tracking i /errors |
CONSOLE_RAILWAY_API_TOKEN + CONSOLE_RAILWAY_PROJECT_ID | Railway deployments i /deployments |
CONSOLE_VERCEL_API_TOKEN (+ CONSOLE_VERCEL_TEAM_ID) | Web analytics i /web-analytics |
CONSOLE_API_PRODUCTION_URL | Prod API health check i /external-status |
CONSOLE_API_STAGING_URL | Staging API health check i /external-status |
Endepunkter
heading.anchorLabelAlle endepunkter er under /admin/monitoring.
Dashboard & KPI-er
heading.anchorLabelGET /overview
heading.anchorLabelHoeynivaa-metrikker for dashboardet.
Response:
{ "users": { "total": 150, "active_subscriptions": 42 }, "activity": { "impulses_7d": 230, "sessions_7d": 85, "check_ins_7d": 120, "ai_requests_24h": 340 }, "spend": { "current_month": 18.50, "total_requests": 2400 }, "feedback_unread": 3, "timestamp": "2026-03-29T12:00:00Z"}Revenue & oekonomi
heading.anchorLabelGET /revenue?period={7d|30d|90d}
heading.anchorLabelDetaljert revenue- og loennsomhetsanalyse.
| Param | Default | Verdier |
|---|---|---|
period | 30d | 7d, 30d, 90d |
Response:
{ "mrr": 504.00, "arr": 6048.00, "ai_cost": { "total": 45.20, "per_user": 1.08, "by_workload": { "classification": { "requests": 200, "cost": 5.00, "tokens": 50000, "avg_cost": 0.025 }, "guidance": { "requests": 150, "cost": 25.00, "tokens": 300000, "avg_cost": 0.167 } }, "by_day": { "2026-03-28": 1.50, "2026-03-29": 1.20 } }, "gross_margin": 91.0, "subscribers": { "total": 42, "by_tier": { "foundation": { "count": 30, "mrr": 180 }, "mastery": { "count": 12, "mrr": 144 } }, "margin_by_tier": { "foundation": { "mrr": 180, "ai_cost": 20, "margin": 88.9, "count": 30 } } }, "churn": { "count": 2, "rate": 4.8 }, "app_store": { "has_data": true, "gross_revenue": 504.00, "refunds": 0, "net_revenue": 428.40, "transactions": 42, "by_day": { "2026-03-28": 12.00 }, "by_platform": { "ios": { "gross": 504.00, "transactions": 42 } } }, "period": "30d", "timestamp": "2026-03-29T12:00:00Z"}Prediksjoner & runway
heading.anchorLabelGET /predictions
heading.anchorLabelBrukervaekst, churn, revenue-prognoser og cash runway.
Response:
{ "current": { "total_users": 150, "paying_users": 42, "avg_daily_signups": 2.1, "avg_daily_spend": 1.50, "conversion_rate": 28.0, "churn_rate": 4.8 }, "cash_runway": { "balance": 450.00, "daily_burn": 1.50, "runway_days": 300, "runway_date": "2027-01-23", "next_payout": { "date": "2026-05-15", "estimated_amount": 428.40 } }, "forecasts": { "conservative": { "30d": { "users": 160, "paying_users": 44, "mrr": 530, "ai_spend": 48, "margin": 90.9 } }, "realistic": { "30d": { "users": 175, "paying_users": 50, "mrr": 600, "ai_spend": 52, "margin": 91.3 } }, "optimistic": { "30d": { "users": 210, "paying_users": 60, "mrr": 720, "ai_spend": 58, "margin": 91.9 } } }, "rate_limit_headroom": { "current_daily_requests": 340, "tier4_rpm_limit": 4000, "estimated_max_concurrent_users": 1333 }, "trends": { "signups_by_day": { "2026-03-28": 3, "2026-03-29": 2 }, "spend_by_day": { "2026-03-28": 1.50, "2026-03-29": 1.20 } }, "timestamp": "2026-03-29T12:00:00Z"}System-monitorering
heading.anchorLabelGET /ai-health
heading.anchorLabelAI-tjenestens helse: rate limits, forbruk og Anthropic-saldo.
Response:
{ "rate_limits": [ { "model_class": "claude-sonnet-4-20250514", "rpm_limit": 4000, "rpm_remaining": 3990, "rpm_reset_at": "2026-03-29T12:01:00Z", "itpm_limit": 400000, "itpm_remaining": 395000, "itpm_reset_at": "2026-03-29T12:01:00Z", "otpm_limit": 80000, "otpm_remaining": 78000, "otpm_reset_at": "2026-03-29T12:01:00Z" } ], "spend": { "current_month": 45.20, "total_requests": 2400, "total_tokens": 4800000, "by_workload": { "classification": { "requests": 200, "cost": 5.00, "tokens": 50000 } } }, "balance": { "amount_usd": 450.00, "last_updated": "2026-03-29T11:00:00Z" }, "timestamp": "2026-03-29T12:00:00Z"}GET /queue-health
heading.anchorLabelStatus for alle BullMQ-koeeer.
Koeeer: impulse-classification, unified-guidance, session-summary, insights-regeneration, check-in-assessment
Response:
{ "status": "healthy", "queues": [ { "name": "impulse-classification", "waiting": 0, "active": 1, "completed": 500, "failed": 2, "delayed": 0, "status": "healthy" } ], "timestamp": "2026-03-29T12:00:00Z"}En koee er degraded hvis failed > 10.
GET /external-status
heading.anchorLabelHelsesjekk av avhengige tjenester.
Response:
{ "claude": { "status": "operational", "description": "All Systems Operational", "components": [{ "name": "API", "status": "operational" }], "incidents": [] }, "api": { "status": "ok", "redis": true, "timestamp": "2026-03-29T12:00:00Z" }, "api_staging": { "status": "ok", "redis": true, "timestamp": "2026-03-29T12:00:00Z" }, "timestamp": "2026-03-29T12:00:00Z"}GET /errors
heading.anchorLabelSiste feil fra Sentry (krever Sentry-variabler).
Response:
{ "configured": true, "issues": [ { "id": "12345", "title": "TypeError: Cannot read property 'id' of undefined", "culprit": "src/routes/impulses.ts", "level": "error", "count": 3, "first_seen": "2026-03-28T10:00:00Z", "last_seen": "2026-03-29T11:00:00Z", "permalink": "https://sentry.io/issues/12345/" } ], "timestamp": "2026-03-29T12:00:00Z"}GET /deployments
heading.anchorLabelSiste Railway-deployments (krever Railway-variabler).
Response:
{ "configured": true, "deployments": [ { "id": "deploy-123", "status": "SUCCESS", "created_at": "2026-03-29T10:00:00Z", "environment": "production", "service": "im-api", "commit_message": "fix: resolve session timeout", "commit_hash": "abc1234" } ], "timestamp": "2026-03-29T12:00:00Z"}GET /web-analytics
heading.anchorLabelVercel web analytics (krever Vercel-variabler).
Response:
{ "configured": true, "data": {}, "timestamp": "2026-03-29T12:00:00Z"}Brukeradministrasjon
heading.anchorLabelGET /users?tier=&status=&search=&limit=50&offset=0
heading.anchorLabelPaginert brukerliste med soek og filtrering.
| Param | Default | Beskrivelse |
|---|---|---|
tier | all | trial, foundation, mastery, free, all |
status | all | active, cancelled, all |
search | — | Soek i email/display_name (maks 100 tegn) |
limit | 50 | Maks 200 |
offset | 0 | Paginering |
Response:
{ "users": [ { "id": "uuid", "email": "user@example.com", "display_name": "User Name", "subscription_tier": "foundation", "subscription_status": "active", "billing_period": "monthly", "trial_started_at": null, "trial_ends_at": null, "trial_converted": false, "is_partner": false, "created_at": "2026-03-01T10:00:00Z", "updated_at": "2026-03-29T12:00:00Z" } ], "total": 150, "by_tier": { "trial": 50, "foundation": 80, "mastery": 20 }, "timestamp": "2026-03-29T12:00:00Z"}GET /users/:id
heading.anchorLabelKomplett brukerprofil med aktivitet, AI-bruk og admin-notater.
Response:
{ "profile": { "id": "uuid", "email": "user@example.com", "display_name": "User Name", "subscription_tier": "foundation", "subscription_status": "active", "billing_period": "monthly", "trial_started_at": null, "trial_ends_at": null, "trial_converted": false, "is_partner": false, "partner_source": null, "preferred_language": "no", "gender": null, "birth_year": null, "ai_personalization_enabled": true, "created_at": "2026-03-01T10:00:00Z", "updated_at": "2026-03-29T12:00:00Z" }, "auth": { "last_sign_in_at": "2026-03-29T08:00:00Z", "banned_until": null, "email_confirmed_at": "2026-03-01T10:05:00Z" }, "usage": { "total_requests": 120, "total_tokens": 240000, "total_cost": 3.50, "by_workload_type": { "classification": { "requests": 40, "tokens": 20000, "cost": 0.50 }, "guidance": { "requests": 50, "tokens": 150000, "cost": 2.50 } } }, "feedback": [], "activity": [ { "type": "impulse", "id": "uuid", "created_at": "2026-03-29T10:00:00Z", "summary": "Expansion impulse" }, { "type": "session", "id": "uuid", "created_at": "2026-03-29T10:30:00Z", "summary": "Realization session completed" } ], "admin_notes": [], "subscriptions": [ { "platform": "ios", "tier": "foundation", "status": "active", "purchase_date": "2026-03-15", "expires_date": "2026-04-15" } ], "timestamp": "2026-03-29T12:00:00Z"}PATCH /users/:id
heading.anchorLabelOppdater brukerprofil. Kun hvitelistede felt.
Body (alle valgfrie):
{ "display_name": "New Name", "subscription_tier": "mastery", "subscription_status": "active", "billing_period": "annual", "is_partner": true}Oppretter automatisk admin_notes-oppfoering.
POST /users/:id/reset-password
heading.anchorLabelSend passord-reset-lenke.
Response:
{ "success": true, "message": "Password reset link generated", "link": "https://..." }POST /users/:id/suspend
heading.anchorLabelSuspender eller reaktiver bruker.
Body:
{ "action": "suspend", "ban_duration": "876000h" }Response:
{ "success": true, "banned_until": "2126-03-29T12:00:00Z" }POST /users/:id/force-signout
heading.anchorLabelUgyldigjoer alle aktive sesjoner paa tvers av enheter.
Response:
{ "success": true }POST /users/:id/notes
heading.anchorLabelLegg til admin-notat paa bruker.
Body:
{ "note": "User reported login issues", "category": "support" }Kategorier: general, support, tier_change, suspension, password_reset
Response:
{ "note": { "id": "uuid", "note": "...", "category": "support", "created_by": "admin", "created_at": "2026-03-29T12:00:00Z" } }DELETE /users/:id
heading.anchorLabelSoft-delete bruker via Supabase auth.
Body (paakrevd):
{ "confirm": true }Feedback
heading.anchorLabelGET /feedback?limit=50
heading.anchorLabelBrukertilbakemeldinger, sortert nyeste foerst.
| Param | Default | Maks |
|---|---|---|
limit | 50 | 200 |
Response:
{ "items": [ { "id": "uuid", "created_at": "2026-03-29T10:00:00Z", "content": "Great app!", "admin_notes": null, "user_id": "uuid" } ], "total": 25, "unread": 3, "last_7d": 5, "timestamp": "2026-03-29T12:00:00Z"}Innstillinger
heading.anchorLabelGET /settings/:key
heading.anchorLabelLes admin-innstilling.
PUT /settings/:key
heading.anchorLabelOppdater admin-innstilling.
Tillatte noekkler: anthropic_balance, alert_thresholds, slack_webhook_url
Body:
{ "value": 500.00 }Bull Board (koee-dashboard)
heading.anchorLabelURL: /admin/queues/
Interaktivt web-dashboard for BullMQ-koeeer. Beskyttet med samme Bearer token.
Funksjoner:
- Se alle koeeer med jobb-telling
- Inspiser individuelle jobber
- Manuell retry/slett av feilede jobber
- Visuell status (waiting, active, completed, failed, delayed)