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.
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:
- From /organizations on the admin app, click + New organisation.
- Fill the legal entity name, GSTIN, primary contact, state of registration, and pick the operating-model mix (mostly COCO / mixed / FOFO-only).
- Save. The org gets a UUID and an empty schema scope.
- Open the org and click Invite owner. Type the founder's email. They get a magic-link sign-in invite.
- Switch to Branches and create their physical shops. For each one, set the operating model and the four org references (see branches doc).
- 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.
- Open the user's row in /users on the admin app.
- Click Impersonate. Pick read-only (default) or read-write. Type the reason — required, goes into audit.
- You're redirected to app.opticops.in with a banner at the top saying “Impersonating dhravesh@gmail.com (read-only) — End session”.
- Browse anywhere the user can. RLS still applies; you see exactly what they see, no more.
- Click End session when done — banner disappears, you're back to your platform-admin account.
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-deleted | How to restore |
|---|---|
| A customer | Admin → /recovery/customers, search the row, click Restore. |
| An order | Admin → /recovery/orders. Reverting an order also restocks the inventory and reverses payments + accruals if applicable. |
| A SKU | Admin → /recovery/skus. Per-branch inventory rows for the SKU are restored too. |
| A branch | Admin → /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
| Job | Cadence | What it does |
|---|---|---|
| Daily insights generator | 06:30 IST | Generates the previous day's insight (visible at /reports/ai-insights) for every active org. |
| Weekly insights generator | Mon 07:00 IST | Same but for the prior week — deeper read, surfaces trends. |
| Monthly snapshot sealing | 1st of month, 02:00 IST | Captures org_period_snapshots for the previous month. Feeds /reports/trends. |
| Daily-digest email | 08:00 IST | Sends each org owner a 1-page email of yesterday's revenue, low-stock alerts, and recall queue. |
| Customer recall scanner | Daily 09:00 IST | Recomputes 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_logfor 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:
| Sev | Definition | Response |
|---|---|---|
| Sev 1 | Customer-facing app down OR data loss | Page on-call immediately. Status banner up within 15 min. Postmortem within 48h. |
| Sev 2 | Major workflow broken (e.g. new sale failing) for >5% of users | Page on-call. Fix within 4h. Postmortem within 1 week. |
| Sev 3 | Single feature broken or one customer affected | File issue, fix in next sprint. |
| Sev 4 | Cosmetic / nice-to-fix | Backlog, no SLA. |