Admin Guide
This guide is for people in the ADMIN role — system owners who manage users, KPI catalog, settings, and oversight.
What you'll do here
- Provision users + roles (USER / MANAGEMENT / ADMIN / CUSTOMER)
- Configure the KPI catalog (groups, rule types, KPI types, department-KPI mapping)
- Manage countries, departments, holidays
- Assign pending intake tickets
- Configure global app settings (date format, ticket edit window)
- Review the audit log
Sidebar at a glance
The left sidebar lists every admin area. The order is curated; click to navigate:
| Section | What's there |
|---|---|
| Countries | Country list + working-hours config (timezone, workday window, working days) |
| Divisions | Org divisions departments roll up to (parallel to country). Optional; departments without one show as Unassigned in division reports. |
| Departments | Department records linked to a country and, optionally, a division |
| Users | User accounts, roles, department assignment, active/inactive toggle |
| KPI Groups | Top-level KPI categories (e.g. Issue, Internal Control, Uptime) |
| Rule Types | The formula behind each KPI Type (rr, acr, accuracy, submit, project, ic-*, uptime). Usually only admins of admins touch these. |
| KPI Types | Concrete metrics tracked. Each KPI Type picks a Rule Type, sets parameters (SLA minutes, weights, targets), and belongs to a KPI Group. |
| KPI Items | Raw ticket data with import-from-Excel + manual editing. |
| Department KPIs | Which KPI Types are valid for which Departments. |
| Pending Tickets | Intake tickets that arrived with no assigned user — assign or delete. |
| Holidays | Per-country holiday calendar + import-from-Nager-API. |
| General Settings | Global app settings (ticket edit window, date format). |
| Email Templates | Customise the subject + body of the transactional emails (live preview, reset-to-default). |
| Email Log | History of every email the system has tried to send (filterable). |
| Modules | Turn whole feature modules (KPI / Workflow / Asset) on/off at runtime. |
| Audit Log | Read-only history of ticket lifecycle + maintenance events. |
| Data Cleansing | Export-then-delete old tickets / pending intake / audit logs / orphaned attachments past a cutoff. |
| Other KPI Settings | Uptime unit configuration (and, historically, the global settings now on General Settings). |
User management
Roles:
- CUSTOMER — auto-created the first time someone signs in with Google. Can submit intake tickets and chat on their own tickets only. No internal pages.
- USER — agent. Has a Department. Can self-log KPI tickets, handle assigned intake tickets, and view their own profile.
- MANAGEMENT — supervisors. Can view Performance and Monthly reports. No edit access.
- ADMIN — full admin access (sidebar + all settings).
Adding an internal user: Add the user via the Users admin BEFORE they try to sign in. Sign-ins from Google accounts not in the Users table are auto-provisioned as CUSTOMER. To make someone an Agent or Admin, either:
- Create the user row first with their email and role (recommended), or
- Have them sign in, then edit their auto-created CUSTOMER row and change the role.
Department assignment is required for USER role only; MANAGEMENT and ADMIN can be left without one.
Active = false disables sign-in and ticket creation but preserves history. Use this instead of Delete for departing staff.
Join date / End date are the employment span. Setting an End date in the past deactivates the account automatically on save (so you can record a leaver by date instead of flipping the Active toggle); clearing it — or a future date — keeps them active. Join date also drives KPI expectations (e.g. monthly project) from the month they joined.
Delete removes the user and all their tickets — only do this in test environments.
KPI catalog setup
Order matters when bootstrapping a new environment:
- Country → set timezone, workday start/end, working days of the week.
- Division (optional) → create the org divisions departments will roll up to. Skip if you only report by country.
- Department → links to a country; optionally assign a division.
- KPI Group → toggle "contributes to uptime" only for groups whose KPIs feed the Uptime calculation.
- Rule Type → these are pre-seeded; only edit if you understand the formula.
- KPI Type → pick a Rule Type, set parameters:
- For
rr:responseSlaMin,resolutionSlaMin,respWeight,resoWeight. - For
rr-dynamic(Ad Hoc with an extendable, per-ticket resolution deadline):responseSlaMin,resolutionSlaWorkingDays(the default deadline in holiday-aware working days; the agent can raise it per ticket and extend it later),respWeight,resoWeight. Two differences fromrr: the resolution target is a working-day deadline set on each ticket (not a fixed minute SLA), and a ticket is scored in the month it is resolved (closedAt), not the month it was requested — open tickets don't score until they close. Each deadline extension logs a reason and emails the requestor. - For
submit:submitCutoffMin. - For
accuracy:respAccTarget,dataAccTarget,respAccWeight,dataAccWeight. - For
acr: six target percentages + six weights. - For
ic-*:slaWorkingDays,targetDayOfWeek,minFindings(as relevant). availableForIntake: trueexposes the KPI Type on the public intake form.ignoreWorkingDayFilter: truemeans weekend/holiday tickets count without the override.
- For
- Department KPIs → assign each KPI Type to the Departments that should be able to log/select it.
- Other KPI Settings → for Uptime KPI Types, configure unit counts per country.
Countries
The Country form sets per-country defaults used in working-hour math:
- Timezone (IANA name, e.g.
Asia/Jakarta). - Workday Start / End (local time of day, e.g. 10:00-19:00).
- Working Days as comma-separated ISO weekday numbers (1=Mon … 7=Sun). Default
1,2,3,4,5(Mon-Fri).
These settings drive response time, resolution time, uptime windows, and ticket inclusion filters. Change carefully — reports recompute on the next dashboard view but consider the impact on historical scoring.
Divisions
Divisions are an organizational tier parallel to country — both are attributes a department carries, and reports can group departments either way. Use them to mirror your real org chart (e.g. Business Operations, Finance, IT & Business Analytics).
- A division has a name and an optional abbreviation.
- Assign a department to a division on the Departments form (the Division field is optional).
- Set the division's Heads via the Heads button on the division row. A division can have one or more heads. Every head gets manager capabilities over all departments in the division — assign tickets, approve extensions, view performance — exactly like a department manager, but division-wide. (This is independent of the user's role; it works like designating a department manager.)
- Departments with no division roll up under an Unassigned bucket in the division scorecard.
- The division score is the average of its departments — the same roll-up the country score uses — so the two views always reconcile for a given month.
You can adopt divisions gradually: create them here, then assign departments at your own pace. Until a department is assigned, only its country reporting is affected (nothing breaks).
The structure you build here (divisions, heads, departments, managers, user assignments) is shown live to management on the Insights → Org Chart page — it updates automatically as you make changes.
Holidays
The Holidays admin lets you:
- Add/edit/delete holidays for any country.
- Filter the list by country with the radio group.
- Import public holidays from Nager.Date by picking a country + year and clicking Import. The country must have a 2-letter
abbreviation(e.g.ID,US).
Holidays apply to tickets whose country matches.
Pending tickets
Intake tickets submitted without a specific user appear here.
- Pick a user from the destination department's dropdown.
- Click the green check to assign — the user gets an email and the ticket flips to On Progress.
- Click the trash to discard (e.g. spam) — the ticket is permanently deleted.
Once assigned, the ticket lives on the agent's profile and disappears from this list.
Audit log
Path: Admin → Audit Log.
A read-only log of ticket lifecycle events. Filters: action, actor, date range. Columns: When, Who, Action, Entity, Details.
Events captured (v1):
TICKET_INTAKE_SUBMITTED— a customer (or signed-in user) submitted via intake.TICKET_SELF_LOGGED— an agent created via /input.TICKET_ASSIGNED— admin/manager assigned a pending ticket.TICKET_REASSIGNED— a manager/admin moved an already-assigned ticket to a different teammate.TICKET_UPDATED— agent edited a ticket (no status change).TICKET_STATUS_CHANGED— agent moved status forward.TICKET_DELETED— ticket removed (pending-tickets admin or agent's profile).DATA_CLEANSED— an admin ran a Data Cleansing purge (records cutoff + counts removed).
Logs are append-only; nothing here can be edited or deleted from the UI.
Email Templates
Path: Admin → System → Email Templates.
Customise the subject + body of the transactional emails (ticket assigned, closed, rejected, re-opened, deadline-extended, and the verification code) without touching code:
- Pick a template; edit the Subject and Body (HTML). The branded header/footer is fixed (you only edit the message body).
- Insert variables like
{{kpiName}},{{statusUrl}},{{rejectionReason}}from the chips (or type them) — they're highlighted in the body and filled in at send time. Required variables (e.g.{{code}}on the verification email) can't be removed. - Format tidies the HTML indentation; the right/top preview renders with sample data live.
- Save to apply; Reset to default drops your customisation and returns to the built-in template. Templates with no override use the built-in default.
Email Log
Path: Admin → System → Email Log.
A history of every transactional email the system has tried to send: recipient, subject, status (sent / failed, with the error), and time. Filter by status and search by recipient/subject. Shows the latest 200; narrow with the filters for older entries.
Data Cleansing
Path: Admin → System → Data Cleansing. Destructive — read carefully.
Permanently removes old data past a cutoff, after exporting a JSON backup. Choose how many months old, tick the data to remove, Preview (counts only, nothing deleted), then Export & Delete (a JSON backup downloads first):
- Resolved KPI tickets — aged by resolution date (
closedAt); cascade-removes their chat + extension requests and deletes their image attachments. Open tickets are never touched. - Pending / unassigned intake tickets — aged by submitted date.
- Audit log entries — aged by created date.
- Orphaned chat attachments (GCS) — image blobs whose ticket/message is already gone.
Minimum cutoff is 1 month; the run is itself audit-logged. Removing tickets refreshes KPI reports on next view.
Global settings
Other KPI Settings page has:
- Ticket Edit Window (days) — USER-role accounts can only modify tickets dated within this window. ADMIN/MANAGEMENT always bypass.
- Date Format — date-fns format pattern used everywhere in the app (table dates, ticket dates, email dates). Examples:
dd/MM/yyyy,MM/dd/yyyy,yyyy-MM-dd.
Both fields save together when you click Save.
This page also hosts the Uptime Unit table — pairing each Uptime KPI Type with its country and unit count (number of units, e.g. number of stores).
Operational tasks
Backfilling closed tickets
If you have closed tickets pre-dating the response/resolution auto-tracking, run:
npx tsx scripts/backfill-intake-metrics.ts
It will fill in metrics.responseTimeMin, metrics.resolutionTimeMin, closedAt, and firstAgentReplyAt for closed tickets that are missing them, using createdAt, the first agent chat message, and closedAt ?? updatedAt as anchors. Then it rebuilds the KPI reports.
Rebuilding reports
The persisted KPI report tables (DashboardSummary, KpiMonthlySummary) rebuild lazily: a ticket change marks the reports dirty, and the next time someone opens the dashboard / Monthly Report, the system recomputes them — but only if tickets actually changed since the last rebuild (otherwise the view is instant). So daily ticket actions (submit, chat, close, reassign…) stay fast; the recompute cost lands on the next report view. Admin-config saves (KPI types, holidays, etc.) and bulk imports still rebuild in place.
If something looks stale, just open the dashboard (it self-heals on view) or force a rebuild:
POST /api/admin/rebuild-reports
Importing KPI items from Excel
The KPI Items admin has an Import button that accepts an Excel file. Preview the rows first, then run. The preview shows: which rows will create, update, skip, or error. Errors usually mean unmatched user / country / department / KPI Type names — make sure those exist before importing.
Frequently asked
A user can sign in but doesn't have admin access. Check Users page — they're probably CUSTOMER (auto-provisioned). Change their role to ADMIN.
Country deletion fails with "Cannot delete country with existing department associations". Move or delete the dependent Departments first.
Holiday import says "Country has no abbreviation". Edit the Country and set a 2-letter abbreviation. Nager.Date uses ISO country codes.
The audit log has no entries before today. Audit logging started recently; pre-existing tickets aren't retroactively logged. Going forward, every ticket action is captured.
An intake ticket appears stuck in "Pending Tickets" forever. Assign it manually here. Auto-assignment only happens when the customer picked a specific user at submission.