# D2C OPs — Enterprise Service Operations Platform
## Technical Documentation
**Prepared by:** Chibuye Nsakanya, Service Delivery Manager — D2C Telcare
**Platform Version:** 1.0 | **Date:** May 2026

---

## Table of Contents

1. System Overview
2. Architecture
3. Technology Stack
4. Database Schema & Migrations
5. Role-Based Access Control
6. Module Reference (14 Modules)
7. Email Notification System
8. Authentication & Security
9. Multi-Process (Multi-Tenant) Design
10. Deployment & Setup
11. Seed Data & Default Credentials

---

## 1. System Overview

D2C OPs is a full-stack enterprise service operations platform built for D2C Telcare to manage IT operations across 8 client business processes. It replaces fragmented spreadsheets and email chains with a unified, role-controlled operations hub.

**Core capabilities:**
- Real-time incident management with severity tracking and email escalation
- Downtime logging with automated resolution notifications
- Shift handover management between operations teams
- Ticket tracking across incident, change, access, and report types
- Approval workflows for change and access requests
- Automation rule engine with scheduled and threshold-based triggers
- On-call schedule management
- AI-powered incident root cause analysis (OpenAI GPT-4o)
- Audit logging of all user actions
- Reporting dashboards
- Client-facing notification system

**Supported processes:** Ignite, Sunking, RDG, MobiHive, Momo, Sanlam, MBA, Muzanu

> 📸 **SCREENSHOT:** Dashboard home page showing the stat cards (Total Events, Ongoing, Active Incidents) and the Active Incidents table with the navigation sidebar visible.

---

## 2. Architecture

The platform follows a standard three-tier architecture:

```
[React Frontend]  <-->  [Express/Node.js API]  <-->  [MySQL Database]
     Port 3000               Port 4000
```

**Frontend** — A single-page React application. All routing is client-side. Private routes are protected by JWT token presence in localStorage. A Zustand auth store persists user session and role.

**Backend** — A RESTful Express.js API written in TypeScript. Every route group is isolated in its own router file. Authentication middleware validates the JWT on every protected request. Process isolation is enforced at the query level — all data reads are scoped to the authenticated user's `process_id`.

**Database** — MySQL managed through Knex.js migrations. Eight migrations bring the schema from baseline to production state. A seed file populates processes, users, and test data.

**Background Worker** — A polling worker runs every 60 seconds inside the server process. It evaluates escalation rules, fires threshold-based automation actions, and sends unattended-incident reminder emails (30-minute cutoff, fires once per incident using a `reminder_sent_at` flag).

**Email** — Nodemailer with Gmail SMTP using a lazy singleton transporter (connection pool, `maxConnections: 5`). All bulk notifications use `Promise.all()` for parallel delivery. Events covered: incident created, incident assigned, incident unattended 30 min, incident in progress, incident resolved, downtime started, downtime resolved, handover submitted, handover acknowledged, approval submitted, approval decided, ticket events, account welcome, password reset, email changed.

---

## 3. Technology Stack

| Layer | Technology |
|---|---|
| Frontend framework | React 18 + TypeScript |
| Build tool | Vite |
| Styling | Tailwind CSS (custom design tokens) |
| State management | Zustand (persisted to localStorage) |
| Routing | React Router v6 |
| Backend framework | Express.js + TypeScript |
| Database ORM | Knex.js |
| Database | MySQL 8 |
| Authentication | JWT (jsonwebtoken) — HS256 |
| Password hashing | bcryptjs |
| Email | Nodemailer + Gmail SMTP (STARTTLS port 587) |
| AI insights | OpenAI GPT-4o (falls back to local regex analysis) |
| Runtime | Node.js 18+ |

**Design tokens (Tailwind custom colours):**

| Token | Hex | Usage |
|---|---|---|
| `bg-navy` | #042C53 | Sidebar, primary text, buttons |
| `bg-teal` | #0F6E56 | Primary action buttons |
| `bg-teal-light` | #1D9E75 | Hover states |
| `bg-amber` | #BA7517 | Medium severity, warnings |
| `bg-danger` | #A32D2D | High severity, errors |

---

## 4. Database Schema & Migrations

The database is named `d2c_ops`. Knex manages versioned migrations.

### Migration History

| File | Change |
|---|---|
| `001_initial_schema.js` | Base schema — processes, users, incidents, downtime_events, tickets, notifications, approvals, service_checks, automation_rules, escalation_chains, escalation_tiers, handovers, on_call_schedules, audit_log, activity_log |
| `002_notifications_direction.js` | Adds `direction` column to notifications (ops_to_client) |
| `003_super_admin_role.js` | Adds `super_admin` role enum value to users |
| `004_verification_codes.js` | Creates `verification_codes` table for OTP flows |
| `005_escalation_executions.js` | Creates `escalation_executions` table to track tier firings |
| `006_handover_time.js` | Adds `handover_time` column to handovers |
| `007_ticket_description.js` | Adds `description` column to tickets |
| `008_incident_reminder.js` | Adds `reminder_sent_at` (TIMESTAMP NULL) to incidents for one-shot 30-min unattended email |

### Core Tables

**`processes`** — One row per client business process. All data is scoped to a `process_id`.

**`users`** — Platform users. Columns include `id`, `email`, `name`, `password_hash`, `role`, `process_id`, `is_active`.

**`incidents`** — `id`, `process_id`, `title`, `description`, `severity` (1–4), `status` (open / in_progress / resolved), `assigned_to` (FK → users), `opened_at`, `resolved_at`, `rca`, `reminder_sent_at`.

**`downtime_events`** — `id`, `process_id`, `incident_id` (nullable FK → incidents), `started_at`, `ended_at`, `services_affected` (JSON array), `impact_level` (low / medium / high).

**`tickets`** — `id`, `process_id`, `title`, `description`, `type` (incident / change / access / report), `status` (open / in_progress / closed), `assigned_to`, `created_at`.

**`approvals`** — `id`, `process_id`, `type`, `title`, `description`, `submitted_by`, `reviewed_by`, `status` (pending / approved / rejected), `submitted_at`, `reviewed_at`.

**`handovers`** — `id`, `process_id`, `submitted_by`, `recipient_id`, `shift`, `handover_time`, `open_incidents`, `actions_taken`, `notes`, `acknowledged_at`.

**`escalation_chains`** / **`escalation_tiers`** / **`escalation_executions`** — Three-table structure defining escalation rules: a chain has multiple tiers, each tier fires after a defined delay if the condition is still met. Executions track what has fired.

**`automation_rules`** — `id`, `process_id`, `name`, `trigger_type` (scheduled / threshold / manual), `trigger_config` (JSON), `action_type`, `action_config` (JSON), `is_active`.

**`on_call_schedules`** — `id`, `process_id`, `user_id`, `week_start`, `shift`.

**`audit_log`** — Immutable record of every create/update/delete action: `user_id`, `process_id`, `action`, `entity_type`, `entity_id`, `created_at`.

**`verification_codes`** — OTP codes for registration and password reset: `email`, `code`, `purpose`, `expires_at`, `used`.

---

## 5. Role-Based Access Control

Six roles are defined. Each role inherits the permissions of all roles below it plus its own additions.

| Role | Key Permissions |
|---|---|
| `viewer` | Read-only access to all module data within their process |
| `operator` | + Create & update incidents, submit handovers, create tickets |
| `manager` | + Approve requests, manage automation rules, export data |
| `admin` | + Manage users, delete records |
| `super_admin` | + View all processes (cross-process access, no process filter applied) |
| `client` | View data, receive and send notifications to the ops team |

**Permission check in frontend:**
```typescript
const { can } = useAuthStore();
if (can('create_incident')) { /* show button */ }
```

**Middleware enforcement in backend:**
```typescript
router.post('/', requireRole('operator', 'manager', 'admin'), handler);
```

Process isolation in queries:
```typescript
function processFilter(req) {
  return req.user.role === 'super_admin'
    ? {}
    : { 'incidents.process_id': req.user.processId };
}
```

> 📸 **SCREENSHOT:** The Users Management page showing the user list table with role badges, and the role dropdown on the user profile edit page.

---

## 6. Module Reference

### 6.1 Dashboard

**Route:** `/`
**Access:** All roles

The landing page after login. Displays three stat cards at the top: Total Incidents, Active (Ongoing) Incidents, and Total Downtime minutes. Below the stats is a live table of active (non-resolved) incidents with severity badges, status, assignee, and time-open. The "Active Incidents" heading links directly to the full Incidents module.

Admins and super_admins see data aggregated across all processes. All other roles see only their own process data.

> 📸 **SCREENSHOT:** Dashboard with stat cards at the top and the active incidents table below. Show both light and dark mode if possible.

---

### 6.2 Incidents

**Route:** `/incidents`
**Create/Update access:** operator, manager, admin

The core module. Incidents have four statuses: `open`, `in_progress`, `resolved`. Severity runs from Sev 1 (Critical) to Sev 4 (Low).

**Workflow:**
1. Operator or manager creates an incident — all process users receive a "New Incident" email.
2. A manager assigns the incident to an operator — the assignee receives a personal "Assigned to You" email.
3. The incident is marked In Progress — all process users receive an "In Progress" email.
4. If the incident stays `open` and unassigned for 30 minutes, the background worker sends a single "Unattended" reminder email to all process users.
5. The incident is resolved — all process users receive a "Resolved" email with duration.

Each incident card is clickable. The detail modal allows editing the description inline, changing the assignee, adding Root Cause Analysis (RCA), and transitioning the status.

Super admins see a "Process" column in the incidents table showing which client process each incident belongs to.

> 📸 **SCREENSHOT 1:** Incidents list page with severity badges (Sev 1–4) and status badges (open, in_progress, resolved) visible.
> 📸 **SCREENSHOT 2:** The incident detail modal open, showing the description editor, assign-to dropdown, status action buttons, and RCA textarea.
> 📸 **SCREENSHOT 3:** Example of the "New Incident" email received in Gmail.

---

### 6.3 Downtime

**Route:** `/downtime`
**Create access:** operator, manager, admin

Logs service outage events separately from incidents (downtime can exist without a linked incident). Three stat cards: Total Events, Ongoing, Total Downtime (in minutes).

**Fields:** Start time (datetime-local, pre-filled to current local time), Services Affected (comma-separated list, stored as JSON array), Impact Level (low / medium / high).

**Lifecycle:**
- When logged — all process managers and admins receive a "Downtime Reported" email with start time, services, and impact.
- When ended (clicking "End" on an ongoing row) — all process managers and admins receive a "Downtime Resolved" email showing the original start time, end time, and total duration.

Start time pre-fills to local time when the Log Downtime modal opens (refreshed each time the button is clicked, not at page load). All timestamps are stored as UTC ISO strings. The email formatter explicitly includes seconds to distinguish closely-timed events.

> 📸 **SCREENSHOT 1:** Downtime page showing the three stat cards and the events table with Ongoing and Ended rows, impact level badges, and the "End" button.
> 📸 **SCREENSHOT 2:** The Log Downtime modal with the Start Time, Services Affected, and Impact Level fields.
> 📸 **SCREENSHOT 3:** The "Downtime Resolved" email showing Started, Ended, and Duration fields with correct timestamps.

---

### 6.4 Ticketing

**Route:** `/tickets`
**Create access:** Roles with `create_ticket` permission (operator and above)

Four ticket types: Incident, Change, Access, Report. Three statuses: open, in_progress, closed. Tickets can be assigned to any team member at creation time or later via the detail modal.

The list view supports filtering by status. Each row is clickable to open a detail modal where authorised users can reassign or change status.

> 📸 **SCREENSHOT:** Tickets list with type colour badges (red = Incident, blue = Change, amber = Access, grey = Report) and status badges visible.

---

### 6.5 Approvals

**Route:** `/approvals`
**Approve access:** manager, admin

Approval requests are submitted for change or access actions that require sign-off. Statuses: pending, approved, rejected.

Submitters receive an email when their request is decided. Managers/admins receive an email when a new request is pending.

> 📸 **SCREENSHOT:** Approvals page showing pending requests with the Approve/Reject action buttons.

---

### 6.6 Handovers

**Route:** `/handovers`
**Submit access:** operator and above

Shift handover records between team members. Fields: recipient, shift (morning/afternoon/night), handover time, open incidents summary, actions taken, notes.

When submitted, the recipient receives a handover email. When acknowledged, the original submitter receives a confirmation email.

> 📸 **SCREENSHOT:** Handovers list and the Submit Handover modal with all fields visible.

---

### 6.7 Escalations

**Route:** `/escalations`
**Manage access:** manager, admin

Manages escalation chains — named sequences of tiers that define who gets notified and when during an unresolved incident. Each chain has a name, an optional trigger severity filter, and one or more numbered tiers. Each tier specifies: delay in minutes, notification channel (e.g., email), and an assigned user (with on-call fallback if no user is set).

When a new chain is created, tiers can be added with the "+ Add Tier" option. The background worker polls every 60 seconds and fires tiers that are due. Execution history is stored in `escalation_executions` so each tier fires only once per incident.

Example chain: **"Sev1 Escalation"**
- Tier 1 — Ignite Operator, escalate after 0 min via email
- Tier 2 — Ignite Manager, escalate after 15 min via email

![Escalation Chains list showing the Sev1 Escalation chain with two numbered tiers — Ignite Operator at 0 min and Ignite Manager at 15 min, both via email](Screenshot%202026-05-09%20101002.png)

![New Escalation Chain modal showing Chain Name, Trigger Severity dropdown, and Tier 1 configuration with After (minutes), Channels, and Assigned User fields](Screenshot%202026-05-09%20101018.png)

---

### 6.8 Automation

**Route:** `/automation`
**Manage access:** manager, admin

Rule-based automation engine. Each rule has a name, a trigger, and an action. Rules are listed with their execution count and an Active status badge. The "+ New Rule" button opens the creation modal.

**Trigger types available:**
- **Severity unresolved after N minutes** — fires when an incident of a specified severity remains open beyond a configured time threshold
- **Custom trigger** — configurable for other conditions

**Actions available:**
- **Escalate via chain** — links to an existing escalation chain which then fires its tiers

Example rules in the system:
- *Momo Server down* — Executed 36 times
- *Escalate Sev 1 after 30min* — Executed 2 times
- *Nightly SLA Digest* — Executed 0 times

![Automation Rules page showing three rules (Momo Server down, Escalate Sev 1 after 30min, Nightly SLA Digest) each with Active badge and execution count](Screenshot%202026-05-09%20100833.png)

![New Automation Rule modal showing Rule Name field, Trigger dropdown set to "Severity unresolved after N minutes", Severity set to Sev 1 Critical, After 30 minutes, Action set to "Escalate via chain", and Escalation Chain selector](Screenshot%202026-05-09%20100850.png)

---

### 6.9 Notifications

**Route:** `/notifications`
**Access:** All roles (admins and managers can send; all roles view)

Client Notifications is the ops-to-client broadcast channel. The list displays: Direction badge (To Client), Subject, Sent By, number of Recipients, Bounce count, and Sent At timestamp. The "Send Notification" button opens a compose modal where the user writes a Subject and Message — on submit, the system emails all client stakeholders registered to the process.

Bounce tracking shows how many recipients did not receive the message, allowing admins to identify stale or invalid client email addresses.

![Client Notifications page showing the notifications table with Direction, Subject, Sent By, Recipients, Bounces, and Sent At columns](Screenshot%202026-05-09%20100907.png)

![Send Client Notification modal showing Subject and Message fields with a warning banner: "This will send an email to all client stakeholders in your process"](Screenshot%202026-05-09%20100941.png)

---

### 6.10 AI Insights

**Route:** `/ai-insights`
**Access:** All roles

Submits incident data to OpenAI GPT-4o for root cause analysis suggestions and recommended remediation steps. Falls back to local regex-based pattern analysis if the OpenAI API key is not configured.

> 📸 **SCREENSHOT NEEDED:** AI Insights page showing an analysed incident with the AI-generated root cause and recommendations panel.

---

### 6.11 On-Call

**Route:** `/oncall`
**Access:** manager, admin to manage; all roles to view

On-Call Scheduling assigns team members to on-call duties by date. The list shows: Date, Person, Role badge (primary / backup / escalation), and Process. The "+ Add Schedule" button opens a modal with Person (dropdown), Role (Primary / Backup / Escalation), and Date (date picker).

Role types:
- **Primary** — first responder for the scheduled date
- **Backup** — called if the primary is unavailable
- **Escalation** — senior contact for critical issues

The on-call schedule integrates with the escalation engine — when a chain tier has no assigned user, the system falls back to the on-call primary for that process on the current date.

![On-Call Scheduling page showing a list with Date, Person, Role (primary/backup/escalation badges), and Process columns across multiple processes](Screenshot%202026-05-09%20101037.png)

![Add On-Call Schedule modal showing Person dropdown, Role dropdown, and Date picker](Screenshot%202026-05-09%20101048.png)

---

### 6.12 Reporting

**Route:** `/reporting`
**Access:** Roles with `export` permission (manager, admin)

Reporting & Export provides three report types, each with its own date range filter and independent CSV and PDF export buttons:

- **Incident Report** — Full export of all incidents with severity, status, assignee, and resolution time. Filtered by opened date.
- **Downtime Summary** — All downtime events with duration, impact level, and affected services. Filtered by start date.
- **Audit Log Export** — Complete audit trail of every sensitive action with user and timestamp. Filtered by date.

The PDF output is a branded D2C OPs report with a navy header bar, "D2C Telcare · D2C OPs Platform · Confidential" footer, and a paginated data table. Super admins see all processes in the export; other roles see only their own process data.

![Reporting & Export page showing three report cards — Incident Report, Downtime Summary, and Audit Log Export — each with date range filters and CSV and PDF download buttons](Screenshot%202026-05-09%20101106.png)

![Generated Incident Report PDF showing columns: ID, Process, Title, Severity, Status, Assignee, Opened At, Resolved At — with data from all 8 processes](Screenshot%202026-05-09%20101130.png)

---

### 6.13 Audit Log

**Route:** `/audit-log`
**Access:** admin, super_admin

Immutable chronological log of every action taken on the platform: who did what, to which record, and when. Actions include user creation, role changes, incident updates, approvals, and deletions.

> 📸 **SCREENSHOT NEEDED:** Audit Log table showing action type, entity, user, and timestamp columns.

---

### 6.14 Activity Feed

**Route:** `/activity`
**Access:** All roles

The Live Activity Feed is a real-time event stream that auto-refreshes every 15 seconds. Events are displayed in the format `entity → action` (e.g., `approval → rejected`, `ticket → create`, `incident → update`) with the acting user's name, the record number, the process, and a relative timestamp (e.g., "2h ago").

Controls at the top: an event type filter dropdown (defaults to "All event types (100)"), a Pause button to stop auto-refresh, and a manual Refresh button. The feed is scoped to the authenticated user's process, except for super admins who see all processes.

![Live Activity Feed showing auto-refresh indicator, event type filter, Pause and Refresh buttons, and a list of events including approval-rejected, approval-create, ticket-create, and incident-update entries with user, record, process, and time ago](Screenshot%202026-05-09%20101149.png)

---

## 7. Email Notification System

All emails are sent from `"D2C OPs Platform" <configured-smtp-user>` using a shared Nodemailer singleton transporter.

### Performance Design
- **Lazy singleton** — the transporter is created once on first send, not per email.
- **Connection pool** — `pool: true`, `maxConnections: 5` keeps SMTP connections alive between sends.
- **Parallel bulk sends** — `Promise.all()` fires all emails in a batch simultaneously.
- **TLS auto-detect** — `secure: port === 465` (port 587 uses STARTTLS, port 465 uses direct TLS).

### Email Event Matrix

| Event | Recipient | Trigger |
|---|---|---|
| Incident Created | All process users | POST /incidents |
| Incident Assigned | Assignee only (targeted) | PATCH /incidents/:id — assigned_to changes |
| Incident Unattended | All process users | Background worker — open 30+ min, no reminder sent yet |
| Incident In Progress | All process users | PATCH — status → in_progress |
| Incident Resolved | All process users | PATCH — status → resolved |
| Downtime Reported | Process managers & admins | POST /downtime |
| Downtime Resolved | Process managers & admins | PATCH /downtime/:id — ended_at set |
| Handover Submitted | Recipient | POST /handovers |
| Handover Acknowledged | Submitter | PATCH /handovers/:id — acknowledged |
| Approval Submitted | Managers & admins | POST /approvals |
| Approval Decided | Submitter | PATCH /approvals/:id |
| Welcome Email | New user | POST /users (admin creates account) |
| Password Reset OTP | Requesting user | POST /auth/forgot-password |
| Email Changed | Old & new address | PATCH /users/:id/email |

> 📸 **SCREENSHOT:** Show the "Incident Resolved" email template in Gmail, displaying the incident title, severity badge, assignee, and resolution duration.

---

## 8. Authentication & Security

### Registration & Login Flow

1. User submits email for verification → server generates a 6-digit OTP, stores in `verification_codes`, sends via email.
2. User submits OTP + chosen password → server validates OTP (15-minute expiry), hashes password with bcrypt, creates the user record.
3. Login → server validates credentials, issues a signed JWT containing `userId`, `processId`, `role`, `processSlug`.
4. Frontend stores JWT in localStorage under the Zustand auth store key (`d2c-ops-auth`).
5. All API requests include `Authorization: Bearer <token>` header.
6. `authenticate` middleware on every protected route validates and decodes the token on each request.

### Security Controls
- Passwords hashed with bcrypt (salt rounds: 10)
- JWT signed with HS256, configurable secret via `JWT_SECRET` env var
- All routes except `/auth/login`, `/auth/register`, `/auth/verify-code`, `/auth/forgot-password` require a valid JWT
- Role enforcement via `requireRole(...allowedRoles)` middleware — returns 403 if role not in allowed list
- Process isolation — all data queries include `process_id` filter matching the authenticated user's process, except super_admin which bypasses the filter
- OTP codes are single-use (`used` flag) and expire after 15 minutes

> 📸 **SCREENSHOT 1:** The Login page with email/password fields and the D2C OPs branding header.
> 📸 **SCREENSHOT 2:** The Register page showing the email verification step (OTP entry screen).
> 📸 **SCREENSHOT 3:** The Forgot Password page.

---

## 9. Multi-Process (Multi-Tenant) Design

Each client business process (Ignite, Sunking, RDG, etc.) is a separate row in the `processes` table. Every data table (incidents, tickets, downtime_events, etc.) has a `process_id` foreign key.

**Data isolation rule:** Every API query that reads or writes operational data is filtered by `process_id` derived from the authenticated user's JWT payload. No user can read or modify another process's data unless they hold the `super_admin` role.

**Super admin view:** The super admin account (`admin@d2ctelcare.com`) bypasses the process filter on all list endpoints, sees a "Process" column in relevant tables, and can manage users across all processes.

**Process slug:** Each process has a URL-friendly slug (e.g., `momo`, `ignite`) stored in the JWT and used for process-specific routing and display.

---

## 10. Deployment & Setup

### Prerequisites
- Node.js 18+
- MySQL 8+
- Gmail account with an App Password (for SMTP)
- OpenAI API key (optional, for AI insights)

### Environment Variables (`server/.env`)

```
DATABASE_URL=mysql://root:password@localhost:3306/d2c_ops
JWT_SECRET=your-secret-key
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=your-gmail@gmail.com
SMTP_PASS=your-app-password
OPENAI_API_KEY=sk-...
```

### Local Setup Steps

```bash
# 1. Install all dependencies
npm run install:all

# 2. Create the database
mysql -u root -p -e "CREATE DATABASE d2c_ops;"

# 3. Run migrations
cd server && npm run migrate

# 4. Seed initial data (processes, users, test accounts)
npm run seed

# 5. Start backend (port 4000)
npm run dev

# 6. Start frontend in a second terminal (port 3000)
cd ../client && npm run dev
```

### Production Build

```bash
# Build frontend static files
cd client && npm run build

# Build backend
cd server && npm run build

# Start production server
node dist/server/src/index.js
```

---

## 11. Seed Data & Default Credentials

The seed file creates 8 processes and the following accounts:

| Role | Email | Password |
|---|---|---|
| Super Admin | admin@d2ctelcare.com | Admin@D2C2026 |
| Ignite Operator | ops.ignite@d2ctelcare.com | Operator@123 |
| Ignite Manager | mgr.ignite@d2ctelcare.com | Operator@123 |
| Sunking Operator | ops.sunking@d2ctelcare.com | Operator@123 |
| Client Stakeholder | stakeholder@ignite.com | Client@123 |

> Change all default passwords before any production or demonstration use.

---

## Summary Screenshot Checklist

| # | Status | Location | What to Capture |
|---|---|---|---|
| 1 | NEEDED | Dashboard | Stat cards + Active Incidents table + sidebar |
| 2 | NEEDED | Incidents list | Severity and status badges across all values |
| 3 | NEEDED | Incident detail modal | Description editor, assign dropdown, RCA field, status buttons |
| 4 | NEEDED | Incident email | "New Incident" email in Gmail |
| 5 | NEEDED | Incident email | "Resolved" email with duration |
| 6 | NEEDED | Downtime page | Stat cards + events table with ongoing and ended rows |
| 7 | NEEDED | Log Downtime modal | Start time, services, impact fields |
| 8 | NEEDED | Downtime email | "Resolved" email showing correct start, end, and duration |
| 9 | NEEDED | Tickets page | Type colour badges and status filters |
| 10 | NEEDED | Approvals page | Pending requests with approve/reject buttons |
| 11 | NEEDED | Handovers page | Submit modal with all fields |
| 12 | DONE | Escalations — chain list | Sev1 Escalation with Tier 1 (0 min) and Tier 2 (15 min) |
| 13 | DONE | Escalations — new chain modal | Chain Name, Trigger Severity, Tier configuration |
| 14 | DONE | Automation — rules list | Three rules with Active badges and execution counts |
| 15 | DONE | Automation — new rule modal | Trigger, Severity, After minutes, Action, Chain dropdown |
| 16 | DONE | Notifications — list | Direction, Subject, Sent By, Recipients, Bounces, Sent At |
| 17 | DONE | Notifications — compose modal | Subject and Message fields, stakeholder warning |
| 18 | NEEDED | AI Insights | Analysis result with recommendations panel |
| 19 | DONE | On-Call — schedule list | Date, Person, Role badges (primary/backup/escalation), Process |
| 20 | DONE | On-Call — add schedule modal | Person, Role, Date fields |
| 21 | DONE | Reporting — export page | Three report cards with date filters and CSV/PDF buttons |
| 22 | DONE | Reporting — PDF output | Generated Incident Report with all columns and process data |
| 23 | NEEDED | Audit Log | Action, entity, user, timestamp columns |
| 24 | DONE | Activity Feed | Auto-refresh, event type filter, event list with entity→action format |
| 25 | NEEDED | Users page | User list with role badges |
| 26 | NEEDED | Login page | Login form with D2C OPs branding |
| 27 | NEEDED | Register/OTP page | Email verification step |
| 28 | NEEDED | Dark mode | Any page showing dark mode theme |

---

*D2C OPs Platform — D2C Telcare — Confidential*
