# Platform Admin Frontend Development Guide
**Last Updated:** November 17, 2025
**Target Audience:** Frontend Developers
**Backend Version:** SwiftOps v1.0
---
## Table of Contents
1. [Overview](#overview)
2. [Authentication & Authorization](#authentication--authorization)
3. [Dashboard & Analytics](#dashboard--analytics)
4. [Organization Management](#organization-management)
5. [User Management](#user-management)
6. [System Monitoring](#system-monitoring)
7. [Audit Logs](#audit-logs)
8. [Complete API Reference](#complete-api-reference)
9. [UI/UX Recommendations](#uiux-recommendations)
10. [Error Handling](#error-handling)
---
## Overview
### What is a Platform Admin?
**Platform Admin** is the highest-level administrative role with full system access. They manage:
- **Organizations** (Clients & Contractors)
- **Platform-wide settings**
- **System health monitoring**
- **Audit logs and compliance**
- **Billing and usage metrics** (planned)
**Key Responsibilities:**
- Create and manage client organizations (telecom operators)
- Create and manage contractor organizations (field service providers)
- Monitor platform usage across all organizations
- View comprehensive audit trails
- Manage platform-wide configurations
- Access all system data for oversight
**Authorization Level:**
```javascript
{
role: "platform_admin",
permissions: ["*"], // All permissions
access_scope: "global" // Access to all organizations and projects
}
```
---
## Authentication & Authorization
### 1. Registration Flow
Platform admins register through a secure 2-step OTP verification process.
**Step 1: Request OTP**
```http
POST /api/v1/auth/send-admin-otp
Content-Type: application/json
{
"email": "admin@swiftops.com",
"first_name": "John",
"last_name": "Doe",
"phone": "+254700123456"
}
```
**Response:**
```json
{
"message": "✅ Registration request received! An OTP code has been sent to admin@swiftops.com..."
}
```
**Step 2: Complete Registration**
```http
POST /api/v1/auth/register
Content-Type: application/json
{
"email": "admin@swiftops.com",
"first_name": "John",
"last_name": "Doe",
"phone": "+254700123456",
"password": "SecurePassword123!",
"otp_code": "613281"
}
```
**Response:**
```json
{
"message": "✅ Platform admin account created successfully!",
"user_id": "uuid-here"
}
```
### 2. Login
```http
POST /api/v1/auth/login
Content-Type: application/json
{
"email": "admin@swiftops.com",
"password": "SecurePassword123!"
}
```
**Response:**
```json
{
"access_token": "eyJhbGciOiJIUzI1NiIs...",
"token_type": "bearer",
"user": {
"id": "uuid",
"email": "admin@swiftops.com",
"first_name": "John",
"last_name": "Doe",
"role": "platform_admin",
"is_active": true,
"phone": "+254700123456"
}
}
```
### 3. Authentication Headers
All subsequent requests must include:
```http
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
```
### 4. Get Current User
```http
GET /api/v1/auth/me
Authorization: Bearer {token}
```
**Response:**
```json
{
"id": "uuid",
"email": "admin@swiftops.com",
"role": "platform_admin",
"first_name": "John",
"last_name": "Doe",
"is_active": true,
"created_at": "2025-11-17T10:00:00Z"
}
```
---
## Dashboard & Analytics
### Dashboard Overview Page
The platform admin dashboard should display high-level metrics and system health.
#### 1. System-Wide Statistics
**Endpoint:** `GET /api/v1/tickets/stats`
```http
GET /api/v1/tickets/stats
Authorization: Bearer {token}
```
**Response:**
```json
{
"total_tickets": 1500,
"by_status": {
"open": 120,
"assigned": 350,
"in_progress": 280,
"completed": 700,
"cancelled": 50
},
"by_type": {
"installation": 800,
"support": 500,
"infrastructure": 200
},
"by_priority": {
"urgent": 45,
"high": 200,
"normal": 900,
"low": 355
},
"overdue_tickets": 25,
"sla_violations": 12,
"avg_completion_time_hours": 18.5,
"completion_rate": 0.87
}
```
**UI Component Suggestion:**
```jsx
// Dashboard Overview Cards
```
#### 2. Organization Metrics
**Clients Overview:**
```http
GET /api/v1/clients?limit=100
Authorization: Bearer {token}
```
**Response:**
```json
[
{
"id": "uuid",
"name": "Airtel Kenya",
"industry": "Telecommunications",
"is_active": true,
"default_sla_days": 3,
"created_at": "2025-01-01T00:00:00Z",
"main_email": "contact@airtel.co.ke",
"main_phone": "+254700000000"
}
]
```
**Contractors Overview:**
```http
GET /api/v1/contractors?limit=100
Authorization: Bearer {token}
```
**Response:**
```json
[
{
"id": "uuid",
"name": "TechInstall Ltd",
"competencies": ["FTTH", "Fixed Wireless", "Fiber Splicing"],
"is_active": true,
"onboarding_status": "completed",
"created_at": "2025-01-15T00:00:00Z",
"main_email": "info@techinstall.co.ke"
}
]
```
**UI Component Suggestion:**
```jsx
// Organizations Summary
Clients
{clients.length} Active
{clients.map(client => (
{client.name}
{client.industry}
))}
Contractors
{contractors.length} Active
{/* Similar list for contractors */}
```
#### 3. Active Projects
```http
GET /api/v1/projects?is_active=true&limit=100
Authorization: Bearer {token}
```
**Response:**
```json
[
{
"id": "uuid",
"title": "Nairobi FTTH Expansion",
"client_id": "uuid",
"contractor_id": "uuid",
"client_name": "Airtel Kenya",
"contractor_name": "TechInstall Ltd",
"status": "active",
"start_date": "2025-01-01",
"end_date": "2025-12-31",
"total_tickets": 500,
"completed_tickets": 320
}
]
```
**UI Component Suggestion:**
```jsx
// Active Projects Table
(
)},
{ key: "status", label: "Status" }
]}
data={projects}
/>
```
#### 4. Recent Activity Feed
```http
GET /api/v1/audit-logs?limit=20
Authorization: Bearer {token}
```
**Response:**
```json
[
{
"id": "uuid",
"action": "create",
"entity_type": "client",
"description": "Client organization created: Safaricom Ltd",
"user_email": "admin@swiftops.com",
"created_at": "2025-11-17T10:30:00Z",
"ip_address": "192.168.1.1"
}
]
```
---
## Organization Management
### 1. Create Client Organization
**Purpose:** Onboard new telecom operators or clients to the platform.
**Endpoint:**
```http
POST /api/v1/clients
Authorization: Bearer {token}
Content-Type: application/json
{
"name": "Safaricom Kenya",
"description": "Leading telecommunications provider in Kenya",
"industry": "Telecommunications",
"main_email": "contact@safaricom.co.ke",
"main_phone": "+254700000000",
"website": "https://safaricom.co.ke",
"default_sla_days": 3
}
```
**Response:**
```json
{
"id": "uuid",
"name": "Safaricom Kenya",
"description": "Leading telecommunications provider in Kenya",
"industry": "Telecommunications",
"main_email": "contact@safaricom.co.ke",
"main_phone": "+254700000000",
"website": "https://safaricom.co.ke",
"is_active": true,
"default_sla_days": 3,
"created_at": "2025-11-17T10:00:00Z",
"updated_at": "2025-11-17T10:00:00Z"
}
```
**Validation Rules:**
- `name`: Required, unique, 3-100 characters
- `industry`: Optional, suggested values: "Telecommunications", "Utilities", "ISP", "Construction"
- `main_email`: Required, unique, valid email format
- `main_phone`: Optional, valid phone format
- `default_sla_days`: Optional, integer 1-30, defaults to 3
**UI Form Fields:**
```jsx
```
### 2. List Clients
**Endpoint:**
```http
GET /api/v1/clients?skip=0&limit=100&is_active=true
Authorization: Bearer {token}
```
**Query Parameters:**
- `skip`: Number of records to skip (pagination), default: 0
- `limit`: Max records to return (1-100), default: 100
- `is_active`: Filter by active status (optional)
**Response:** Array of client objects (see Create Client response for structure)
**UI Component:**
```jsx
// Clients List/Table View
+ New Client} />
(
)},
{ key: "created_at", label: "Created", render: (row) => (
formatDate(row.created_at)
)},
{ key: "actions", label: "", render: (row) => (
)}
]}
data={clients}
pagination={{
page: currentPage,
pageSize: 100,
total: totalClients,
onPageChange: setCurrentPage
}}
/>
```
### 3. View Client Details
**Endpoint:**
```http
GET /api/v1/clients/{client_id}
Authorization: Bearer {token}
```
**Response:** Single client object
**UI Page Structure:**
```jsx
// Client Details Page
Edit,
]}
/>
- Email
- {client.main_email}
- Phone
- {client.main_phone}
- Website
- {client.website}
- Default SLA
- {client.default_sla_days} days
- Status
- Created
- {formatDate(client.created_at)}
{/* List projects associated with this client */}
{/* List users belonging to this client organization */}
{/* Audit logs for this client */}
```
### 4. Update Client
**Endpoint:**
```http
PUT /api/v1/clients/{client_id}
Authorization: Bearer {token}
Content-Type: application/json
{
"description": "Updated description",
"is_active": true,
"default_sla_days": 5,
"main_phone": "+254711222333"
}
```
**Response:** Updated client object
**Note:** Only include fields you want to update. Name and email cannot be changed after creation.
### 5. Deactivate Client
**Endpoint:**
```http
DELETE /api/v1/clients/{client_id}
Authorization: Bearer {token}
```
**Response:**
```json
{
"message": "Client soft-deleted successfully"
}
```
**Note:** This performs a soft delete (sets `deleted_at` timestamp). The client is hidden from default queries but data is retained.
### 6. Create Contractor Organization
**Purpose:** Onboard field service contractors who will execute work for clients.
**Endpoint:**
```http
POST /api/v1/contractors
Authorization: Bearer {token}
Content-Type: application/json
{
"name": "FieldTech Solutions",
"description": "Professional FTTH installation services",
"website": "https://fieldtech.co.ke",
"main_email": "ops@fieldtech.co.ke",
"main_phone": "+254722333444",
"competencies": ["FTTH", "Fixed Wireless", "Fiber Splicing", "FTTB"]
}
```
**Response:**
```json
{
"id": "uuid",
"name": "FieldTech Solutions",
"description": "Professional FTTH installation services",
"website": "https://fieldtech.co.ke",
"main_email": "ops@fieldtech.co.ke",
"main_phone": "+254722333444",
"is_active": true,
"competencies": ["FTTH", "Fixed Wireless", "Fiber Splicing", "FTTB"],
"onboarding_status": "started",
"onboarding_completed_at": null,
"created_at": "2025-11-17T10:00:00Z",
"updated_at": "2025-11-17T10:00:00Z"
}
```
**Validation Rules:**
- `name`: Required, unique, 3-100 characters
- `competencies`: Required array, available options:
- "FTTH" (Fiber to the Home)
- "FTTB" (Fiber to the Building)
- "Fixed Wireless"
- "Fiber Splicing"
- "Infrastructure"
- "Maintenance"
- "Support"
**UI Form Fields:**
```jsx
```
### 7. List Contractors
**Endpoint:**
```http
GET /api/v1/contractors?skip=0&limit=100&is_active=true
Authorization: Bearer {token}
```
**Query Parameters:** Same as clients
**Response:** Array of contractor objects
### 8. View Contractor Details
**Endpoint:**
```http
GET /api/v1/contractors/{contractor_id}
Authorization: Bearer {token}
```
**Response:** Single contractor object
### 9. Update Contractor
**Endpoint:**
```http
PUT /api/v1/contractors/{contractor_id}
Authorization: Bearer {token}
Content-Type: application/json
{
"description": "Updated description",
"is_active": true,
"competencies": ["FTTH", "Fixed Wireless", "Fiber Splicing", "FTTB"],
"onboarding_status": "completed"
}
```
**Response:** Updated contractor object
**Note:** Setting `onboarding_status` to `"completed"` automatically sets `onboarding_completed_at` timestamp.
**Onboarding Status Values:**
- `"started"` - Initial state
- `"documents_pending"` - Awaiting compliance documents
- `"training"` - Undergoing training
- `"completed"` - Fully onboarded, ready for work
---
## User Management
### 1. List All Users
**Endpoint:**
```http
GET /api/v1/users?skip=0&limit=100&role=field_agent
Authorization: Bearer {token}
```
**Query Parameters:**
- `skip`: Pagination offset
- `limit`: Max records (1-100)
- `role`: Filter by role (optional)
- `platform_admin`
- `client_admin`
- `contractor_admin`
- `project_manager`
- `dispatcher`
- `field_agent`
- `sales_agent`
- `sales_manager`
- `is_active`: Filter by active status (optional)
- `client_id`: Filter by client organization (optional)
- `contractor_id`: Filter by contractor organization (optional)
**Response:**
```json
[
{
"id": "uuid",
"email": "agent@example.com",
"first_name": "John",
"last_name": "Doe",
"role": "field_agent",
"is_active": true,
"phone": "+254700123456",
"client_id": null,
"contractor_id": "uuid",
"created_at": "2025-11-17T10:00:00Z"
}
]
```
### 2. View User Details
**Endpoint:**
```http
GET /api/v1/users/{user_id}
Authorization: Bearer {token}
```
**Response:** Single user object
### 3. Invite New User
**Endpoint:**
```http
POST /api/v1/invitations
Authorization: Bearer {token}
Content-Type: application/json
{
"email": "newuser@example.com",
"first_name": "Jane",
"last_name": "Smith",
"role": "project_manager",
"client_id": "uuid",
"notification_channel": "email"
}
```
**Response:**
```json
{
"id": "uuid",
"email": "newuser@example.com",
"role": "project_manager",
"status": "pending",
"expires_at": "2025-11-24T10:00:00Z",
"created_at": "2025-11-17T10:00:00Z"
}
```
**Notification Channels:**
- `"email"` - Send invitation via email
- `"whatsapp"` - Send invitation via WhatsApp (default, saves email credits)
- `"both"` - Send via both channels
### 4. Update User
**Endpoint:**
```http
PUT /api/v1/users/{user_id}
Authorization: Bearer {token}
Content-Type: application/json
{
"first_name": "Jane",
"last_name": "Smith",
"phone": "+254711222333",
"is_active": true
}
```
**Response:** Updated user object
### 5. Change User Role
**Endpoint:**
```http
PUT /api/v1/users/{user_id}/role
Authorization: Bearer {token}
Content-Type: application/json
{
"role": "dispatcher",
"reason": "Promoted due to excellent performance"
}
```
**Response:**
```json
{
"message": "User role updated successfully",
"user": { /* updated user object */ }
}
```
**Note:** Role changes are logged in audit trail with reason.
### 6. Deactivate User
**Endpoint:**
```http
POST /api/v1/users/{user_id}/deactivate
Authorization: Bearer {token}
Content-Type: application/json
{
"reason": "Employee left the company"
}
```
**Response:**
```json
{
"message": "User deactivated successfully"
}
```
---
## System Monitoring
### 1. Assignment Statistics
**Endpoint:**
```http
GET /api/v1/assignments/stats?project_id={uuid}
Authorization: Bearer {token}
```
**Response:**
```json
{
"total_assignments": 500,
"active_assignments": 120,
"completed_assignments": 350,
"dropped_assignments": 20,
"rejected_assignments": 10,
"avg_travel_time_minutes": 45.5,
"avg_work_time_minutes": 120.3,
"avg_journey_distance_km": 15.2
}
```
**UI Component:**
```jsx
```
### 2. Timesheet Statistics
**Endpoint:**
```http
GET /api/v1/timesheets/stats?start_date=2025-11-01&end_date=2025-11-30
Authorization: Bearer {token}
```
**Query Parameters:**
- `start_date`: Start date (required, YYYY-MM-DD)
- `end_date`: End date (required, YYYY-MM-DD)
- `user_id`: Filter by specific user (optional)
- `project_id`: Filter by specific project (optional)
**Response:**
```json
{
"total_days": 30,
"present_days": 25,
"absent_days": 3,
"on_leave_days": 2,
"sick_leave_days": 0,
"attendance_rate": 83.33,
"absence_rate": 10.0,
"total_hours_worked": 200.5,
"average_hours_per_day": 8.02,
"total_tickets_completed": 150,
"average_tickets_per_day": 6.0
}
```
### 3. Notification Statistics
**Endpoint:**
```http
GET /api/v1/notifications/stats
Authorization: Bearer {token}
```
**Response:**
```json
{
"total": 500,
"unread": 45,
"read": 455,
"by_type": {
"ticket_assigned": 200,
"ticket_completed": 150,
"payment_received": 50,
"system_alert": 100
},
"by_channel": {
"in_app": 500,
"email": 300,
"whatsapp": 200
}
}
```
### 4. Export Data
Platform admins can export data for all organizations.
**Tickets Export:**
```http
GET /api/v1/export/tickets?project_id={uuid}&format=csv
Authorization: Bearer {token}
```
**Response:** CSV file download
**Available Export Endpoints:**
- `/api/v1/export/tickets` - All tickets
- `/api/v1/export/customers` - All customers
- `/api/v1/export/sales-orders` - All sales orders
- `/api/v1/export/agents` - All field agents
- `/api/v1/export/subscriptions` - All subscriptions
**Query Parameters:**
- `format`: `csv` or `excel` (default: `csv`)
- `project_id`: Filter by project (optional)
- `start_date`: Filter by date range (optional)
- `end_date`: Filter by date range (optional)
---
## Audit Logs
### 1. View Audit Logs
**Endpoint:**
```http
GET /api/v1/audit-logs?skip=0&limit=100&action=create
Authorization: Bearer {token}
```
**Query Parameters:**
- `skip`: Pagination offset
- `limit`: Max records (1-100)
- `action`: Filter by action type (optional)
- `create`, `update`, `delete`
- `login`, `logout`, `login_failed`
- `register`, `password_change`
- `status_change`, `role_change`
- `entity_type`: Filter by entity (optional)
- `user`, `client`, `contractor`, `project`, `ticket`
- `user_id`: Filter by user who performed action (optional)
- `start_date`: Filter by date range (optional)
- `end_date`: Filter by date range (optional)
**Response:**
```json
[
{
"id": "uuid",
"user_id": "uuid",
"user_email": "admin@swiftops.com",
"user_role": "platform_admin",
"action": "create",
"entity_type": "client",
"entity_id": "uuid",
"description": "Client organization created: Safaricom Ltd by platform_admin",
"changes": {
"new": {
"name": "Safaricom Ltd",
"industry": "Telecommunications"
}
},
"ip_address": "192.168.1.1",
"user_agent": "Mozilla/5.0...",
"created_at": "2025-11-17T10:30:00Z"
}
]
```
### 2. View Audit Logs for Specific Entity
**Endpoint:**
```http
GET /api/v1/audit-logs/entity/{entity_type}/{entity_id}
Authorization: Bearer {token}
```
**Example:**
```http
GET /api/v1/audit-logs/entity/client/uuid-here
```
**Response:** Array of audit log objects filtered for that entity
### 3. View Audit Logs for Specific User
**Endpoint:**
```http
GET /api/v1/audit-logs/user/{user_id}
Authorization: Bearer {token}
```
**Response:** Array of audit log objects for that user's actions
**UI Component:**
```jsx
// Audit Log Table
(
formatDateTime(row.created_at)
)},
{ key: "user_email", label: "User" },
{ key: "action", label: "Action", render: (row) => (
{row.action}
)},
{ key: "entity_type", label: "Entity" },
{ key: "description", label: "Description" },
{ key: "ip_address", label: "IP Address" },
{ key: "actions", label: "", render: (row) => (
)}
]}
data={auditLogs}
pagination={true}
/>
// Audit Log Detail Modal
setDetailsOpen(false)}>
Audit Log Details
- Action
- {selectedLog.action}
- User
- {selectedLog.user_email} ({selectedLog.user_role})
- Entity
- {selectedLog.entity_type} - {selectedLog.entity_id}
- Timestamp
- {formatDateTime(selectedLog.created_at)}
- IP Address
- {selectedLog.ip_address}
- User Agent
- {selectedLog.user_agent}
- Description
- {selectedLog.description}
{selectedLog.changes && (
<>
- Changes
-
{JSON.stringify(selectedLog.changes, null, 2)}
>
)}
```
### 4. Export Audit Logs
**Endpoint:**
```http
POST /api/v1/audit-logs/export
Authorization: Bearer {token}
Content-Type: application/json
{
"start_date": "2025-11-01",
"end_date": "2025-11-30",
"format": "csv"
}
```
**Response:** CSV file download with all audit logs in date range
---
## Complete API Reference
### Authentication Endpoints
| Method | Endpoint | Description |
|--------|----------|-------------|
| POST | `/api/v1/auth/send-admin-otp` | Request OTP for admin registration |
| POST | `/api/v1/auth/register` | Complete admin registration with OTP |
| POST | `/api/v1/auth/login` | Login and get access token |
| POST | `/api/v1/auth/logout` | Logout (invalidate token) |
| GET | `/api/v1/auth/me` | Get current user info |
| PUT | `/api/v1/auth/me` | Update current user profile |
| POST | `/api/v1/auth/change-password` | Change password |
| POST | `/api/v1/auth/forgot-password` | Request password reset |
| POST | `/api/v1/auth/reset-password` | Reset password with token |
### Client Management Endpoints
| Method | Endpoint | Description |
|--------|----------|-------------|
| POST | `/api/v1/clients` | Create new client organization |
| GET | `/api/v1/clients` | List all clients (paginated) |
| GET | `/api/v1/clients/{client_id}` | Get client details |
| PUT | `/api/v1/clients/{client_id}` | Update client |
| DELETE | `/api/v1/clients/{client_id}` | Deactivate client (soft delete) |
### Contractor Management Endpoints
| Method | Endpoint | Description |
|--------|----------|-------------|
| POST | `/api/v1/contractors` | Create new contractor organization |
| GET | `/api/v1/contractors` | List all contractors (paginated) |
| GET | `/api/v1/contractors/{contractor_id}` | Get contractor details |
| PUT | `/api/v1/contractors/{contractor_id}` | Update contractor |
| DELETE | `/api/v1/contractors/{contractor_id}` | Deactivate contractor (soft delete) |
### User Management Endpoints
| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | `/api/v1/users` | List all users (paginated) |
| GET | `/api/v1/users/{user_id}` | Get user details |
| PUT | `/api/v1/users/{user_id}` | Update user |
| PUT | `/api/v1/users/{user_id}/role` | Change user role |
| POST | `/api/v1/users/{user_id}/deactivate` | Deactivate user |
| POST | `/api/v1/users/{user_id}/activate` | Activate user |
### Invitation Endpoints
| Method | Endpoint | Description |
|--------|----------|-------------|
| POST | `/api/v1/invitations` | Create user invitation |
| GET | `/api/v1/invitations` | List all invitations |
| GET | `/api/v1/invitations/{invitation_id}` | Get invitation details |
| POST | `/api/v1/invitations/{invitation_id}/resend` | Resend invitation |
| DELETE | `/api/v1/invitations/{invitation_id}` | Cancel invitation |
### Project Endpoints
| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | `/api/v1/projects` | List all projects |
| GET | `/api/v1/projects/{project_id}` | Get project details |
| POST | `/api/v1/projects` | Create project (as client/contractor) |
| PUT | `/api/v1/projects/{project_id}` | Update project |
| DELETE | `/api/v1/projects/{project_id}` | Delete project |
### Ticket Endpoints
| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | `/api/v1/tickets` | List all tickets |
| GET | `/api/v1/tickets/{ticket_id}` | Get ticket details |
| GET | `/api/v1/tickets/stats` | Get ticket analytics |
| PUT | `/api/v1/tickets/{ticket_id}` | Update ticket |
| DELETE | `/api/v1/tickets/{ticket_id}` | Delete ticket |
### Assignment Endpoints
| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | `/api/v1/assignments/stats` | Get assignment statistics |
| GET | `/api/v1/tickets/{ticket_id}/assignments` | Get ticket assignments |
### Timesheet Endpoints
| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | `/api/v1/timesheets` | List timesheets |
| GET | `/api/v1/timesheets/stats` | Get timesheet statistics |
### Finance Endpoints
| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | `/api/v1/contractor-invoices` | List contractor invoices |
| GET | `/api/v1/contractor-invoices/{invoice_id}` | Get invoice details |
| POST | `/api/v1/contractor-invoices` | Create invoice |
| PUT | `/api/v1/contractor-invoices/{invoice_id}` | Update invoice |
| POST | `/api/v1/contractor-invoices/{invoice_id}/payments` | Record payment |
### Audit Log Endpoints
| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | `/api/v1/audit-logs` | List all audit logs (paginated) |
| GET | `/api/v1/audit-logs/user/{user_id}` | Get logs for specific user |
| GET | `/api/v1/audit-logs/entity/{entity_type}/{entity_id}` | Get logs for specific entity |
| POST | `/api/v1/audit-logs/export` | Export audit logs to CSV |
### Export Endpoints
| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | `/api/v1/export/tickets` | Export tickets to CSV/Excel |
| GET | `/api/v1/export/customers` | Export customers to CSV/Excel |
| GET | `/api/v1/export/sales-orders` | Export sales orders to CSV/Excel |
| GET | `/api/v1/export/agents` | Export field agents to CSV/Excel |
| GET | `/api/v1/export/subscriptions` | Export subscriptions to CSV/Excel |
### Notification Endpoints
| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | `/api/v1/notifications` | List user notifications |
| GET | `/api/v1/notifications/stats` | Get notification statistics |
| GET | `/api/v1/notifications/unread-count` | Get unread count (for badge) |
| PUT | `/api/v1/notifications/{notification_id}/read` | Mark notification as read |
| PUT | `/api/v1/notifications/mark-all-read` | Mark all as read |
---
## UI/UX Recommendations
### Page Structure
**1. Dashboard (Home Page)**
```
┌─────────────────────────────────────────────────────┐
│ Platform Admin Dashboard │
├─────────────────────────────────────────────────────┤
│ │
│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │ 1.5K │ │ 320 │ │ 87% │ │ 12 │ │
│ │Ticket│ │ Active│ │ SLA │ │Alert │ │
│ └──────┘ └──────┘ └──────┘ └──────┘ │
│ │
│ ┌──────────────────────┐ ┌──────────────────────┐ │
│ │ Clients │ │ Contractors │ │
│ │ ==================== │ │ ==================== │ │
│ │ • Airtel Kenya │ │ • TechInstall Ltd │ │
│ │ • Safaricom │ │ • FieldTech Co │ │
│ │ • Zuku │ │ • NetConnect Pro │ │
│ └──────────────────────┘ └──────────────────────┘ │
│ │
│ ┌───────────────────────────────────────────────┐ │
│ │ Active Projects │ │
│ │ ============================================= │ │
│ │ Nairobi FTTH Expansion [████████░░] 80% │ │
│ │ Mombasa Fixed Wireless [█████░░░░░] 50% │ │
│ └───────────────────────────────────────────────┘ │
│ │
│ ┌───────────────────────────────────────────────┐ │
│ │ Recent Activity │ │
│ │ ============================================= │ │
│ │ 10:30 - Client "Safaricom" created │ │
│ │ 10:15 - User role changed: John → Dispatcher │ │
│ │ 09:45 - Project "Nairobi FTTH" completed │ │
│ └───────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────┘
```
**2. Organizations Page**
```
┌─────────────────────────────────────────────────────┐
│ Organizations [Clients] [Contractors] │
│ [+ New Client] │
├─────────────────────────────────────────────────────┤
│ │
│ 🔍 Search: [________________] Filters: [v] │
│ │
│ ┌─────────────────────────────────────────────────┐│
│ │ Name │ Industry │ Status │ Created ││
│ │──────────────┼───────────┼────────┼───────────││
│ │ Airtel Kenya │ Telecom │ Active │ Jan 2025 ││
│ │ Safaricom │ Telecom │ Active │ Feb 2025 ││
│ │ Zuku │ ISP │ Active │ Mar 2025 ││
│ └─────────────────────────────────────────────────┘│
│ │
│ Showing 3 of 15 clients [1] [2] [3] > │
└─────────────────────────────────────────────────────┘
```
**3. Users Page**
```
┌─────────────────────────────────────────────────────┐
│ Users [+ Invite] │
├─────────────────────────────────────────────────────┤
│ │
│ Filters: Role: [All ▼] Organization: [All ▼] │
│ Status: [Active ▼] │
│ │
│ ┌─────────────────────────────────────────────────┐│
│ │ Name │ Email │ Role │ Org ││
│ │───────────┼──────────────┼───────────┼─────────││
│ │ John Doe │ john@ex.com │ Agent │ Tech Ltd││
│ │ Jane Smith│ jane@ex.com │ Dispatcher│ Tech Ltd││
│ └─────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────┘
```
**4. Audit Logs Page**
```
┌─────────────────────────────────────────────────────┐
│ Audit Logs [Export CSV] │
├─────────────────────────────────────────────────────┤
│ │
│ Filters: Action: [All ▼] Entity: [All ▼] │
│ Date Range: [2025-11-01] to [2025-11-30] │
│ │
│ ┌─────────────────────────────────────────────────┐│
│ │ Time │ User │ Action │ Entity │ IP ││
│ │────────┼─────────────┼────────┼────────┼───────││
│ │ 10:30 │ admin@... │ CREATE │ Client │ 192...││
│ │ 10:15 │ admin@... │ UPDATE │ User │ 192...││
│ └─────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────┘
```
### Navigation Structure
**Sidebar Menu:**
```
SwiftOps
─────────────
🏠 Dashboard
📊 Analytics
Organizations
─────────────
🏢 Clients
🔧 Contractors
Users & Access
─────────────
👥 Users
📨 Invitations
Operations
─────────────
📋 Projects
🎫 Tickets
📦 Inventory
Finance
─────────────
💰 Invoices
💳 Payments
System
─────────────
📜 Audit Logs
⚙️ Settings
📤 Exports
```
### Color Scheme
**Status Colors:**
- Active/Success: `#10b981` (Green)
- Pending/Warning: `#f59e0b` (Amber)
- Inactive/Error: `#ef4444` (Red)
- Info: `#3b82f6` (Blue)
**Role Colors:**
- Platform Admin: `#8b5cf6` (Purple)
- Client Admin: `#3b82f6` (Blue)
- Contractor Admin: `#10b981` (Green)
- Manager: `#f59e0b` (Amber)
- Agent: `#6b7280` (Gray)
### Responsive Design
**Breakpoints:**
- Mobile: < 640px
- Tablet: 640px - 1024px
- Desktop: > 1024px
**Mobile Considerations:**
- Collapsible sidebar menu
- Stacked card layouts
- Horizontal scrolling for tables
- Bottom navigation bar for key actions
---
## Error Handling
### HTTP Status Codes
| Code | Meaning | Action |
|------|---------|--------|
| 200 | Success | Display data |
| 201 | Created | Show success message, redirect |
| 400 | Bad Request | Show validation errors |
| 401 | Unauthorized | Redirect to login |
| 403 | Forbidden | Show "Access denied" message |
| 404 | Not Found | Show "Resource not found" |
| 409 | Conflict | Show "Already exists" error |
| 500 | Server Error | Show generic error, report to support |
### Error Response Format
```json
{
"detail": "Email already registered"
}
```
Or for validation errors:
```json
{
"detail": [
{
"loc": ["body", "email"],
"msg": "field required",
"type": "value_error.missing"
}
]
}
```
### Error Handling Example
```javascript
// API Service with Error Handling
async function createClient(clientData) {
try {
const response = await fetch('/api/v1/clients', {
method: 'POST',
headers: {
'Authorization': `Bearer ${getAccessToken()}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(clientData)
});
if (!response.ok) {
if (response.status === 401) {
// Token expired, redirect to login
redirectToLogin();
return;
}
if (response.status === 409) {
// Conflict - client already exists
const error = await response.json();
showError(error.detail);
return;
}
if (response.status === 400) {
// Validation errors
const errors = await response.json();
showValidationErrors(errors.detail);
return;
}
// Generic error
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const client = await response.json();
showSuccess('Client created successfully!');
return client;
} catch (error) {
console.error('Error creating client:', error);
showError('Failed to create client. Please try again.');
}
}
// Show error notification
function showError(message) {
// Use your notification system
toast.error(message);
}
// Show success notification
function showSuccess(message) {
toast.success(message);
}
// Show validation errors
function showValidationErrors(errors) {
if (Array.isArray(errors)) {
errors.forEach(error => {
const field = error.loc[error.loc.length - 1];
toast.error(`${field}: ${error.msg}`);
});
} else {
showError(errors);
}
}
```
### Token Refresh Strategy
```javascript
// Intercept 401 responses and refresh token
async function fetchWithAuth(url, options = {}) {
const token = getAccessToken();
const response = await fetch(url, {
...options,
headers: {
...options.headers,
'Authorization': `Bearer ${token}`
}
});
if (response.status === 401) {
// Try to refresh token
const refreshed = await refreshAccessToken();
if (refreshed) {
// Retry original request with new token
const newToken = getAccessToken();
return fetch(url, {
...options,
headers: {
...options.headers,
'Authorization': `Bearer ${newToken}`
}
});
} else {
// Refresh failed, redirect to login
redirectToLogin();
throw new Error('Session expired');
}
}
return response;
}
async function refreshAccessToken() {
try {
const refreshToken = getRefreshToken();
const response = await fetch('/api/v1/auth/refresh-token', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ refresh_token: refreshToken })
});
if (response.ok) {
const data = await response.json();
setAccessToken(data.access_token);
return true;
}
return false;
} catch (error) {
console.error('Token refresh failed:', error);
return false;
}
}
```
---
## Implementation Checklist
### Phase 1: Core Setup
- [ ] Setup authentication (login/register)
- [ ] Implement token storage and refresh
- [ ] Create API service layer
- [ ] Setup error handling
### Phase 2: Dashboard
- [ ] Create dashboard layout
- [ ] Implement statistics cards
- [ ] Add organization summary widgets
- [ ] Add recent activity feed
### Phase 3: Organization Management
- [ ] Create clients list page
- [ ] Implement create client form
- [ ] Create client details page
- [ ] Implement client update/delete
- [ ] Create contractors list page
- [ ] Implement create contractor form
- [ ] Create contractor details page
- [ ] Implement contractor update/delete
### Phase 4: User Management
- [ ] Create users list page
- [ ] Implement user invitation form
- [ ] Create user details page
- [ ] Implement user update/deactivate
- [ ] Add role change functionality
### Phase 5: Monitoring & Logs
- [ ] Create audit logs page
- [ ] Implement log filtering
- [ ] Add export functionality
- [ ] Create system monitoring dashboard
### Phase 6: Polish
- [ ] Add loading states
- [ ] Implement pagination
- [ ] Add search functionality
- [ ] Optimize performance
- [ ] Add accessibility features
- [ ] Write unit tests
---
## Best Practices
### 1. State Management
```javascript
// Use React Context or Redux for global state
const AuthContext = React.createContext();
export function AuthProvider({ children }) {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
// Check if user is logged in on mount
const checkAuth = async () => {
const token = getAccessToken();
if (token) {
const userData = await fetchCurrentUser();
setUser(userData);
}
setLoading(false);
};
checkAuth();
}, []);
return (
{children}
);
}
```
### 2. API Client
```javascript
// Create a centralized API client
class ApiClient {
constructor(baseURL) {
this.baseURL = baseURL;
}
async request(endpoint, options = {}) {
const url = `${this.baseURL}${endpoint}`;
const token = getAccessToken();
const config = {
...options,
headers: {
'Content-Type': 'application/json',
...options.headers,
...(token && { 'Authorization': `Bearer ${token}` })
}
};
const response = await fetch(url, config);
if (!response.ok) {
throw await this.handleError(response);
}
return response.json();
}
async handleError(response) {
const error = await response.json();
return new Error(error.detail || 'An error occurred');
}
// Convenience methods
get(endpoint, options) {
return this.request(endpoint, { ...options, method: 'GET' });
}
post(endpoint, data, options) {
return this.request(endpoint, {
...options,
method: 'POST',
body: JSON.stringify(data)
});
}
put(endpoint, data, options) {
return this.request(endpoint, {
...options,
method: 'PUT',
body: JSON.stringify(data)
});
}
delete(endpoint, options) {
return this.request(endpoint, { ...options, method: 'DELETE' });
}
}
const api = new ApiClient('http://localhost:8000/api/v1');
export default api;
```
### 3. Custom Hooks
```javascript
// useClients hook
function useClients(filters = {}) {
const [clients, setClients] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchClients = async () => {
try {
setLoading(true);
const data = await api.get('/clients', { params: filters });
setClients(data);
} catch (err) {
setError(err);
} finally {
setLoading(false);
}
};
fetchClients();
}, [JSON.stringify(filters)]);
return { clients, loading, error };
}
// Usage
function ClientsPage() {
const { clients, loading, error } = useClients({ is_active: true });
if (loading) return ;
if (error) return ;
return ;
}
```
### 4. Performance Optimization
```javascript
// Debounce search input
function useDebounce(value, delay) {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const timer = setTimeout(() => {
setDebouncedValue(value);
}, delay);
return () => clearTimeout(timer);
}, [value, delay]);
return debouncedValue;
}
// Usage
function SearchableList() {
const [searchTerm, setSearchTerm] = useState('');
const debouncedSearch = useDebounce(searchTerm, 500);
const { data } = useSearch(debouncedSearch);
return (
<>
setSearchTerm(e.target.value)}
/>
>
);
}
```
---
## Support & Resources
**Backend Documentation:**
- API Docs: `http://localhost:8000/api/docs` (Swagger UI)
- ReDoc: `http://localhost:8000/api/redoc`
- Health Check: `http://localhost:8000/health`
**Related Documentation:**
- User Management: `/docs/USER_MANAGEMENT_IMPLEMENTATION.md`
- Organizations API: `/docs/dev/ORGANIZATIONS_API_GUIDE.md`
- Auth API: `/docs/dev/AUTH_API_GUIDE.md`
- Audit Logging: `/docs/agent/PASSWORD_RESET_COMPLETE.md`
**Contact:**
- Backend Team: backend@swiftops.com
- Technical Support: support@swiftops.com
---
**Document Version:** 1.0
**Last Updated:** November 17, 2025
**Maintained By:** SwiftOps Backend Team