Internal · platform admin

The back-office that makes white-glove work.

Customers see app.opticops.in. We see onboarding.opticops.in — a separate Next.js app with its own role gate and impersonation controls, designed for the manual onboarding step that the first 5-10 customers go through.

This page is for the Opticops team and design partners we've given platform-admin access to. Customer users don't have this role and don't see this surface.

Who can access

Only users with the platform_admin role on their JWT can sign in at onboarding.opticops.in. The middleware checks the role at the edge and redirects anyone else to /no-access.

Sign-in is the same Continue-with-Google flow as the customer app — there's no separate password. The platform-admin role is granted by directly editing auth.users.app_metadata.role in Supabase. We intentionally don't expose this as a button: granting platform admin is a 5-minute conversation, not a click.

Onboarding a new organisation

First 5-10 customers are onboarded manually so we can hand- tune the catalogue + branches before they touch the app. The flow:

  1. From /organizations on the admin app, click + New organisation.
  2. Fill the legal entity name, GSTIN, primary contact, state of registration, and pick the operating-model mix (mostly COCO / mixed / FOFO-only).
  3. Save. The org gets a UUID and an empty schema scope.
  4. Open the org and click Invite owner. Type the founder's email. They get a magic-link sign-in invite.
  5. Switch to Branches and create their physical shops. For each one, set the operating model and the four org references (see branches doc).
  6. Hand off — the founder can now sign in and start using the product. We typically pair with them for the first 2-3 sales to make sure the muscle memory builds.

Impersonation

Most support questions need eyes on the customer's actual data. Impersonation lets a platform admin sign in as a specific user in a specific org, scoped to read-only by default.

  1. Open the user's row in /users on the admin app.
  2. Click Impersonate. Pick read-only (default) or read-write. Type the reason — required, goes into audit.
  3. You're redirected to app.opticops.in with a banner at the top saying “Impersonating dhravesh@gmail.com (read-only) — End session”.
  4. Browse anywhere the user can. RLS still applies; you see exactly what they see, no more.
  5. Click End session when done — banner disappears, you're back to your platform-admin account.
Every impersonation start, every action taken during, and the end-session click are logged with timestamps, the impersonator ID, the impersonated user ID, and the typed reason. The org owner of the impersonated user can see this log via Settings → Audit. Trust isn't implicit — we make it auditable.

Data recovery

Soft-deletes are recoverable from the admin app. Hard-deletes need a DBA hand on the Supabase console — they don't happen automatically and we don't expose them through the UI.

What got soft-deletedHow to restore
A customerAdmin → /recovery/customers, search the row, click Restore.
An orderAdmin → /recovery/orders. Reverting an order also restocks the inventory and reverses payments + accruals if applicable.
A SKUAdmin → /recovery/skus. Per-branch inventory rows for the SKU are restored too.
A branchAdmin → /recovery/branches. As noted in the branches doc, re-using the same branch is preferable to creating a fresh one — keeps trend lines continuous.

Cron jobs we run

JobCadenceWhat it does
Daily insights generator06:30 ISTGenerates the previous day's insight (visible at /reports/ai-insights) for every active org.
Weekly insights generatorMon 07:00 ISTSame but for the prior week — deeper read, surfaces trends.
Monthly snapshot sealing1st of month, 02:00 ISTCaptures org_period_snapshots for the previous month. Feeds /reports/trends.
Daily-digest email08:00 ISTSends each org owner a 1-page email of yesterday's revenue, low-stock alerts, and recall queue.
Customer recall scannerDaily 09:00 ISTRecomputes the recall + lapsed + Rx-expiring cohorts on customer records.

All jobs are configured in Inngest and visible in their dashboard. Failures page on the on-call rotation.

Observability surfaces

  • Sentry — every error from the customer app, the admin app, and the AI service. Issues group by stack-trace.
  • PostHog — funnel + cohort analytics on the customer app. “What percentage of new orgs do their first sale within 24h?”
  • Langfuse — every Claude API call, with prompt, response, tokens, and cost. Cross-references with ai_audit_log for per-org cost attribution.
  • Vercel Analytics — page-level traffic + speed.
  • Supabase logs — postgres slow queries, RLS denials, auth events.

Incident response

Sev levels and the runbook live in the internal Notion under Ops / Incident response. The short version:

SevDefinitionResponse
Sev 1Customer-facing app down OR data lossPage on-call immediately. Status banner up within 15 min. Postmortem within 48h.
Sev 2Major workflow broken (e.g. new sale failing) for >5% of usersPage on-call. Fix within 4h. Postmortem within 1 week.
Sev 3Single feature broken or one customer affectedFile issue, fix in next sprint.
Sev 4Cosmetic / nice-to-fixBacklog, no SLA.

Next up

Back to the docs index

Or jump to a customer-facing topic from the left sidebar.