swiftops-backend / docs /api /dashboards /pm /PM_DASHBOARD_API_REFERENCE.md
kamau1's picture
fix: correct get_db imports and remove duplicate definition
44ca2cd

Project Manager Dashboard - API Reference

Version: 1.0
Last Updated: 2025-11-19
Audience: Frontend Development Team


Overview

This document provides all API endpoints needed to build a comprehensive Project Manager (PM) dashboard. The PM role requires visibility across sales, operations, finance, and resources to orchestrate daily field service operations.

PM Core Responsibilities

  • Convert sales orders to work tickets
  • Assign tickets to field agents
  • Approve expenses and manage finances
  • Track inventory and resources
  • Generate payroll and invoices
  • Monitor team performance

Dashboard Layout Structure

Recommended Sections

  1. Today's Overview - Key metrics at a glance
  2. Financial Snapshot - Cash position and pending payments
  3. Quick Actions - Common PM tasks
  4. Pending Sales Orders - Orders awaiting conversion
  5. Active Tickets - Work in progress
  6. Pending Approvals - Expenses, payroll, invoices
  7. Inventory Status - Stock levels and alerts
  8. Map View - Geographic visualization
  9. Team Status - Agent availability

API Endpoints by Feature

1. Dashboard Overview Statistics

Get Platform Dashboard Stats

GET /api/v1/analytics/platform-admin/dashboard
Authorization: Bearer {token}

Response Fields:

  • users - User statistics (total, active, by role)
  • organizations - Client and contractor counts
  • tickets - Ticket counts by status and type
  • projects - Project statistics
  • assignments - Assignment statistics
  • recent_activity - Latest 10 audit logs
  • system_health - 30-day trends

Use Case: Main dashboard metrics widget


2. Sales Order Management

List Sales Orders

GET /api/v1/sales-orders
Authorization: Bearer {token}

Query Parameters:
- skip (int, default: 0)
- limit (int, default: 50, max: 100)
- project_id (UUID, optional)
- status (string, optional) - "pending", "processed", "cancelled", "duplicate"
- project_region_id (UUID, optional)
- sales_agent_id (UUID, optional)
- from_date (date, optional)
- to_date (date, optional)
- pending_processing (boolean, optional) - Show only pending orders
- customer_phone (string, optional)

Response:

  • items[] - Array of sales orders with computed properties
  • total - Total count
  • skip, limit - Pagination info

Key Fields per Item:

  • id, order_number, customer_name, customer_preferred_package
  • package_price, installation_address_line1, installation_latitude, installation_longitude
  • status, project_title, region_name, sales_agent_name
  • is_pending, has_ticket, can_promote_to_ticket

Get Sales Order Statistics

GET /api/v1/sales-orders/stats
Authorization: Bearer {token}

Query Parameters:
- project_id (UUID, optional)
- project_region_id (UUID, optional)
- sales_agent_id (UUID, optional)

Response: Metrics on orders by status, region, agent

Assign Sales Order to Region

POST /api/v1/sales-orders/{sales_order_id}/assign-region
Authorization: Bearer {token}
Content-Type: application/json

Body:
{
  "project_region_id": "uuid"
}

Promote Sales Order to Ticket (Single)

POST /api/v1/sales-orders/{sales_order_id}/promote
Authorization: Bearer {token}
Content-Type: application/json

Body:
{
  "priority": "normal",
  "scheduled_date": "2025-01-20",
  "scheduled_time_slot": "morning",
  "work_description": "Install fiber",
  "notes": "Customer prefers morning"
}

Response:

  • message, sales_order_id, ticket_id, ticket_name, status

Bulk Promote Sales Orders to Tickets

POST /api/v1/sales-orders/bulk-promote
Authorization: Bearer {token}
Content-Type: application/json

Body:
{
  "sales_order_ids": ["uuid1", "uuid2"],
  "priority": "normal",
  "notes": "Batch promotion"
}

Response:

  • total, successful, failed, errors[], created_ticket_ids[]

3. Ticket Management

List Tickets

GET /api/v1/tickets
Authorization: Bearer {token}

Query Parameters:
- skip (int, default: 0)
- limit (int, default: 50, max: 100)
- project_id (UUID, optional)
- status (enum, optional) - "open", "assigned", "in_progress", "pending_review", "completed", "cancelled"
- ticket_type (enum, optional) - "installation", "support", "infrastructure"
- priority (enum, optional) - "low", "normal", "high", "urgent"
- project_region_id (UUID, optional)
- source (enum, optional) - "sales_order", "incident", "task"
- from_date (date, optional)
- to_date (date, optional)
- is_overdue (boolean, optional)

Response:

  • tickets[] - Array of tickets
  • total, skip, limit

Key Fields per Ticket:

  • id, ticket_name, status, priority, ticket_type
  • work_description, scheduled_date, scheduled_time_slot
  • project_title, region_name, customer_name
  • is_overdue, can_be_assigned

Get Ticket Statistics

GET /api/v1/tickets/stats
Authorization: Bearer {token}

Query Parameters:
- project_id (UUID, optional)
- project_region_id (UUID, optional)

Response:

  • Counts by status, type, priority
  • overdue_tickets, avg_completion_time_hours, completion_rate

Update Ticket

PUT /api/v1/tickets/{ticket_id}
Authorization: Bearer {token}
Content-Type: application/json

Body:
{
  "priority": "urgent",
  "work_description": "Updated description",
  "notes": "Additional notes"
}

Reschedule Ticket

POST /api/v1/tickets/{ticket_id}/reschedule
Authorization: Bearer {token}
Content-Type: application/json

Body:
{
  "scheduled_date": "2025-01-25",
  "scheduled_time_slot": "afternoon",
  "reason": "Customer requested later date"
}

Cancel Ticket

POST /api/v1/tickets/{ticket_id}/cancel
Authorization: Bearer {token}
Content-Type: application/json

Body:
{
  "reason": "Customer cancelled service"
}

4. Ticket Assignment & Dispatch

List Ticket Assignments

GET /api/v1/ticket-assignments
Authorization: Bearer {token}

Query Parameters:
- skip (int, default: 0)
- limit (int, default: 50)
- ticket_id (UUID, optional)
- user_id (UUID, optional)
- status (string, optional)
- project_id (UUID, optional)
- from_date (date, optional)
- to_date (date, optional)

Get Available Agents for Assignment

GET /api/v1/ticket-assignments/available-agents
Authorization: Bearer {token}

Query Parameters:
- ticket_id (UUID, required)

Response: List of agents available to be assigned to the ticket

Assign Ticket to Agent

POST /api/v1/ticket-assignments
Authorization: Bearer {token}
Content-Type: application/json

Body:
{
  "ticket_id": "uuid",
  "user_id": "uuid",
  "notes": "Assigned to John"
}

Reassign Ticket

POST /api/v1/ticket-assignments/{assignment_id}/reassign
Authorization: Bearer {token}
Content-Type: application/json

Body:
{
  "new_user_id": "uuid",
  "reason": "Original agent unavailable"
}

5. Expense Management

List Expenses

GET /api/v1/expenses
Authorization: Bearer {token}

Query Parameters:
- page (int, default: 1)
- page_size (int, default: 50, max: 100)
- ticket_id (UUID, optional)
- assignment_id (UUID, optional)
- approval_status (string, optional) - "pending", "approved", "rejected"
- payment_status (string, optional) - "pending", "paid"
- from_date (date, optional)
- to_date (date, optional)

Response:

  • items[] - Array of expenses
  • total, page, page_size

Key Fields per Expense:

  • id, expense_type, amount, currency
  • description, receipt_url
  • approval_status, payment_status
  • submitted_by_name, approved_by_name

Get Expense Statistics

GET /api/v1/expenses/stats
Authorization: Bearer {token}

Query Parameters:
- ticket_id (UUID, optional)
- assignment_id (UUID, optional)

Response: Total expenses, pending approvals, payment status breakdown

Approve/Reject Expense

POST /api/v1/expenses/{expense_id}/approve
Authorization: Bearer {token}
Content-Type: application/json

Body:
{
  "approved": true,
  "notes": "Approved - receipt verified"
}

Mark Expense as Paid

POST /api/v1/expenses/{expense_id}/mark-paid
Authorization: Bearer {token}
Content-Type: application/json

Body:
{
  "payment_date": "2025-01-20",
  "payment_method": "mobile_money",
  "payment_reference": "TXN123456",
  "notes": "Paid via M-Pesa"
}

6. Financial Management

List Financial Transactions

GET /api/v1/finance
Authorization: Bearer {token}

Query Parameters:
- skip (int, default: 0)
- limit (int, default: 50, max: 100)
- project_id (UUID, optional)
- transaction_type (string, optional) - "inflow", "outflow"
- status (string, optional) - "pending", "approved", "paid", "rejected", "cancelled"
- category (string, optional)
- from_date (date, optional)
- to_date (date, optional)
- pending_approval (boolean, optional)

Get Cash Flow Summary

GET /api/v1/finance/cash-flow/{project_id}
Authorization: Bearer {token}

Query Parameters:
- from_date (date, optional)
- to_date (date, optional)

Response:

  • Total inflows, outflows, net cash flow
  • Breakdown by category
  • Pending transactions

Create Financial Transaction

POST /api/v1/finance
Authorization: Bearer {token}
Content-Type: application/json

Body:
{
  "project_id": "uuid",
  "transaction_type": "outflow",
  "amount": 50000,
  "currency": "KES",
  "category": "equipment_purchase",
  "description": "Purchased 50 ONTs",
  "transaction_date": "2025-01-20"
}

Approve Transaction

POST /api/v1/finance/{transaction_id}/approve
Authorization: Bearer {token}
Content-Type: application/json

Body:
{
  "notes": "Approved by PM"
}

7. Contractor Invoice Management

List Contractor Invoices

GET /api/v1/invoices
Authorization: Bearer {token}

Query Parameters:
- skip (int, default: 0)
- limit (int, default: 100, max: 500)
- contractor_id (UUID, optional)
- client_id (UUID, optional)
- project_id (UUID, optional)
- status (string, optional) - "draft", "sent", "partially_paid", "paid", "cancelled"
- overdue_only (boolean, optional)
- unpaid_only (boolean, optional)
- latest_versions_only (boolean, default: true)

Response:

  • invoices[] - Array of invoices
  • total, skip, limit

Key Fields per Invoice:

  • id, invoice_number, contractor_name, client_name
  • subtotal_amount, tax_amount, total_amount
  • amount_paid, amount_due
  • status, due_date, is_overdue

Create Contractor Invoice

POST /api/v1/invoices
Authorization: Bearer {token}
Content-Type: application/json

Body:
{
  "contractor_id": "uuid",
  "client_id": "uuid",
  "project_id": "uuid",
  "invoice_date": "2025-01-20",
  "due_date": "2025-02-20",
  "currency": "KES",
  "tax_rate": 16.0,
  "notes": "Monthly invoice"
}

Response: Created invoice with auto-generated invoice number

Add Line Item to Invoice

POST /api/v1/invoices/{invoice_id}/line-items
Authorization: Bearer {token}
Content-Type: application/json

Body:
{
  "line_item_type": "ticket",
  "ticket_id": "uuid",
  "description": "Installation service",
  "quantity": 1,
  "unit_price": 5000,
  "amount": 5000
}

Note: Creates new invoice version

Record Payment

POST /api/v1/invoices/{invoice_id}/payments
Authorization: Bearer {token}
Content-Type: application/json

Body:
{
  "amount": 50000,
  "payment_date": "2025-01-20",
  "payment_method": "bank_transfer",
  "payment_reference": "TXN123456",
  "notes": "Partial payment"
}

Response: Updated invoice with new payment recorded


8. Inventory Management

List Main Office Inventory

GET /api/v1/inventory
Authorization: Bearer {token}

Query Parameters:
- page (int, default: 1)
- page_size (int, default: 50, max: 100)
- project_id (UUID, optional)
- item_type (string, optional) - "tool", "equipment", "consumable", "ppe"
- status (string, optional)
- is_active (boolean, optional)
- search (string, optional)

Response:

  • items[] - Inventory batches
  • total, page, page_size

Key Fields per Item:

  • id, equipment_type, equipment_name, item_type
  • quantity_received, quantity_available, quantity_distributed
  • status, received_date

Create Inventory Batch

POST /api/v1/inventory
Authorization: Bearer {token}
Content-Type: application/json

Body:
{
  "project_id": "uuid",
  "equipment_type": "ONT",
  "equipment_name": "Huawei HG8145V5",
  "item_type": "equipment",
  "quantity_received": 100,
  "received_date": "2025-01-20",
  "supplier_name": "TechSupply Ltd",
  "unit_cost": 2500,
  "currency": "KES"
}

List Regional Distributions

GET /api/v1/inventory/distributions
Authorization: Bearer {token}

Query Parameters:
- page (int, default: 1)
- page_size (int, default: 50)
- project_id (UUID, optional)
- region_id (UUID, optional)
- inventory_id (UUID, optional)
- item_type (string, optional)
- is_active (boolean, optional)

Response: Inventory distributed to regional hubs

Distribute Inventory to Regional Hub

POST /api/v1/inventory/distributions
Authorization: Bearer {token}
Content-Type: application/json

Body:
{
  "inventory_id": "uuid",
  "project_region_id": "uuid",
  "quantity_distributed": 20,
  "distributed_date": "2025-01-20",
  "notes": "Distribution to Nairobi hub"
}

List Inventory Assignments (Issued to Agents)

GET /api/v1/inventory/assignments
Authorization: Bearer {token}

Query Parameters:
- page (int, default: 1)
- page_size (int, default: 50)
- user_id (UUID, optional)
- region_id (UUID, optional)
- status (string, optional)
- is_returned (boolean, optional)
- ticket_id (UUID, optional)

Response: Equipment issued to field agents


9. Payroll Management

List Payroll Records

GET /api/v1/payroll
Authorization: Bearer {token}

Query Parameters:
- skip (int, default: 0)
- limit (int, default: 50, max: 100)
- user_id (UUID, optional)
- project_id (UUID, optional)
- period_start (date, optional)
- period_end (date, optional)
- status (string, optional)

Response:

  • items[] - Payroll records
  • total, skip, limit

Key Fields per Record:

  • id, user_name, period_start, period_end
  • total_earnings, deductions, net_pay
  • status, payment_status

Generate Payroll

POST /api/v1/payroll/generate
Authorization: Bearer {token}
Content-Type: application/json

Body:
{
  "project_id": "uuid",
  "period_start": "2025-01-01",
  "period_end": "2025-01-31",
  "user_ids": ["uuid1", "uuid2"]
}

Response: Generated payroll records

Approve Payroll

POST /api/v1/payroll/{payroll_id}/approve
Authorization: Bearer {token}
Content-Type: application/json

Body:
{
  "notes": "Approved for payment"
}

10. Timesheet Management

List Timesheets

GET /api/v1/timesheets
Authorization: Bearer {token}

Query Parameters:
- skip (int, default: 0)
- limit (int, default: 50, max: 100)
- user_id (UUID, optional)
- project_id (UUID, optional)
- from_date (date, optional)
- to_date (date, optional)
- status (string, optional) - "present", "absent", "on_leave", "sick_leave", "half_day"

Get Timesheet Statistics

GET /api/v1/timesheets/stats
Authorization: Bearer {token}

Query Parameters:
- user_id (UUID, optional)
- project_id (UUID, optional)
- from_date (date, optional)
- to_date (date, optional)

Response: Attendance metrics, days worked, absences


11. User Management

List Users

GET /api/v1/users
Authorization: Bearer {token}

Query Parameters:
- skip (int, default: 0)
- limit (int, default: 50, max: 100)
- role (string, optional)
- client_id (UUID, optional)
- contractor_id (UUID, optional)
- is_active (boolean, optional)
- status (string, optional)
- search (string, optional)

Response:

  • users[] - Array of users
  • total, skip, limit

Search Users

GET /api/v1/users/search
Authorization: Bearer {token}

Query Parameters:
- q (string, required) - Search query
- role (string, optional)
- limit (int, default: 20)

Response: Matching users (useful for assignment dropdowns)

Invite New User

POST /api/v1/invitations
Authorization: Bearer {token}
Content-Type: application/json

Body:
{
  "email": "john@example.com",
  "name": "John Doe",
  "phone": "+254712345678",
  "role": "field_agent",
  "contractor_id": "uuid"
}

12. Map & Location Services

Get Map Entities

GET /api/v1/map/entities
Authorization: Bearer {token}

Query Parameters:
- project_id (UUID, required)
- entity_types (array, optional) - ["customers", "tickets", "sales_orders", "agents", "regions"]
- status (string, optional)

Response:

  • customers[] - Customer locations
  • tickets[] - Ticket locations
  • sales_orders[] - Sales order locations
  • agents[] - Agent current locations
  • regions[] - Regional hub locations

Use Case: Render all entities on map view

Get Regional Hub Locations

GET /api/v1/map/regions/{project_id}
Authorization: Bearer {token}

Query Parameters:
- include_inactive (boolean, default: false)

Response: Regional hubs with coordinates, coverage radius, active tickets/agents count

Get Journey Details

GET /api/v1/map/journey/{assignment_id}
Authorization: Bearer {token}

Response:

  • Timeline (start, arrival, completion times)
  • GPS breadcrumb trail (array of coordinates with timestamps)
  • Journey statistics (distance, duration, speed)
  • Location information

Use Case: Track agent movement during work assignment

Find Nearest Regional Hub

GET /api/v1/map/nearest-region
Authorization: Bearer {token}

Query Parameters:
- project_id (UUID, required)
- latitude (float, required)
- longitude (float, required)
- max_distance_km (float, optional)

Response: Nearest regional hub with distance


13. Task Management

List Tasks

GET /api/v1/tasks
Authorization: Bearer {token}

Query Parameters:
- skip (int, default: 0)
- limit (int, default: 50, max: 100)
- project_id (UUID, optional)
- status (string, optional) - "pending", "assigned", "in_progress", "completed", "cancelled", "blocked"
- assigned_to (UUID, optional)
- priority (string, optional)
- from_date (date, optional)
- to_date (date, optional)

Create Task

POST /api/v1/tasks
Authorization: Bearer {token}
Content-Type: application/json

Body:
{
  "project_id": "uuid",
  "task_type": "installation",
  "title": "Install fiber cable",
  "description": "Install cable from pole A to B",
  "priority": "high",
  "due_date": "2025-01-25",
  "assigned_to": "uuid"
}

14. Customer Management

List Customers

GET /api/v1/customers
Authorization: Bearer {token}

Query Parameters:
- skip (int, default: 0)
- limit (int, default: 50, max: 100)
- client_id (UUID, optional)
- search (string, optional)
- phone (string, optional)

Get Customer Details

GET /api/v1/customers/{customer_id}
Authorization: Bearer {token}

Response: Customer profile with all related data (subscriptions, tickets, sales orders)


15. Notifications

List Notifications

GET /api/v1/notifications
Authorization: Bearer {token}

Query Parameters:
- skip (int, default: 0)
- limit (int, default: 50)
- is_read (boolean, optional)
- type (string, optional)

Get Unread Count

GET /api/v1/notifications/unread-count
Authorization: Bearer {token}

Response: { "count": 5 }

Mark Notification as Read

PUT /api/v1/notifications/{notification_id}/read
Authorization: Bearer {token}

Authentication

All endpoints require Bearer token authentication:

Authorization: Bearer {access_token}

Token Refresh:

POST /api/v1/auth/refresh
Content-Type: application/json

Body:
{
  "refresh_token": "your_refresh_token"
}

Response:

{
  "access_token": "new_access_token",
  "refresh_token": "new_refresh_token",
  "token_type": "bearer",
  "expires_in": 3600
}

Error Handling

All endpoints follow standard HTTP status codes:

  • 200 OK - Success
  • 201 Created - Resource created
  • 204 No Content - Success with no response body
  • 400 Bad Request - Invalid input
  • 401 Unauthorized - Missing or invalid token
  • 403 Forbidden - Insufficient permissions
  • 404 Not Found - Resource not found
  • 409 Conflict - Duplicate or conflicting resource
  • 422 Unprocessable Entity - Validation error
  • 500 Internal Server Error - Server error

Error Response Format:

{
  "detail": "Error message here"
}

Pagination

List endpoints use offset-based pagination:

Request:

  • skip - Number of items to skip (default: 0)
  • limit - Number of items to return (default: 50, max varies by endpoint)

Response:

  • items[] or users[] or similar - Array of results
  • total - Total count of items
  • skip - Current offset
  • limit - Current limit

Date/Time Formats

  • Dates: ISO 8601 format YYYY-MM-DD (e.g., 2025-01-20)
  • DateTimes: ISO 8601 with timezone YYYY-MM-DDTHH:MM:SSZ (e.g., 2025-01-20T14:30:00Z)
  • Time Slots: "morning", "afternoon", "evening", "any"

Filtering Best Practices

  1. Combine filters - Most list endpoints support multiple filters simultaneously
  2. Use pagination - Always paginate large result sets
  3. Cache where appropriate - Dashboard stats can be cached for 1-5 minutes
  4. Real-time updates - Use polling or WebSockets for live data (tickets, assignments)

Common UI Patterns

Dashboard Widgets

  • Fetch stats on page load
  • Refresh every 30-60 seconds for live data
  • Show loading skeletons during fetch

List Views

  • Implement infinite scroll or traditional pagination
  • Add filters in sidebar or top bar
  • Show total count and current range

Map Views

  • Lazy load entities based on viewport
  • Cluster markers when zoomed out
  • Show details on marker click

Approval Workflows

  • Show pending count badge
  • Provide bulk approve/reject actions
  • Confirm destructive actions (reject, cancel)

Performance Recommendations

  1. Lazy load - Don't fetch all data at once
  2. Debounce searches - Wait 300ms before searching
  3. Cache reference data - Roles, statuses, regions rarely change
  4. Optimize map rendering - Use clustering for large datasets
  5. Batch operations - Use bulk endpoints when available

Support & Questions

For API questions or issues:

  • Backend Team Lead: [Contact Info]
  • API Documentation: /api/v1/docs (Swagger UI)
  • Base URL: https://api.swiftops.example.com

End of Document