swiftops-backend / docs /agent /frontend /FIELD_AGENT_DASHBOARD_API.md
kamau1's picture
updated meta apps and made overview return just the data needed
133af2e

Field Agent Dashboard API - Implementation Summary

Overview

Enhanced the existing GET /api/v1/analytics/user/overview endpoint to support field agent dashboard requirements without creating new endpoints. This maintains consistency with existing RBAC and reduces maintenance overhead.

What Was Built

Enhanced Endpoint: GET /api/v1/analytics/user/overview

URL: /api/v1/analytics/user/overview?limit=50

Query Parameters:

  • limit (optional): Max items in work queue (default: 50, max: 100)

Authorization: Any authenticated user (RBAC filters data automatically)


Response Structure

For Field Agents/Sales Agents (Simplified Response)

Field agents receive a personalized response showing only THEIR work, not organization-wide stats:

{
  "user_info": {
    "id": "uuid",
    "name": "John Doe",
    "email": "john@example.com",
    "role": "field_agent"
  },
  "projects": {
    "total": 3,
    "active": 2
  },
  "my_tickets": {
    "total_assigned": 15,
    "pending": 4,
    "in_progress": 2,
    "completed_this_week": 9
  },
  "my_expenses": {
    "total_amount": 12500.00,
    "pending_approval": 3,
    "pending_amount": 4500.00
  },
  "my_inventory": {
    "items_on_hand": 8
  },
  "my_time": {
    "hours_worked_this_week": 32.5
  },
  "notifications": {
    "unread": 5
  },
  "work_queue": {
    "pending_assignments": [...],
    "total_pending": 4,
    "high_priority": 1,
    "due_today": 2
  },
  "generated_at": "2025-11-27T10:30:00Z"
}

Key Differences from Manager Response:

  • βœ… my_tickets - Only tickets assigned to ME (not all project tickets)
  • βœ… my_expenses - Only MY expenses (not team expenses)
  • βœ… my_inventory - Only items I have (not warehouse inventory)
  • βœ… my_time - MY hours worked
  • βœ… work_queue - MY pending assignments
  • ❌ No team stats (don't manage team)
  • ❌ No sales_orders (not relevant)
  • ❌ No organization-wide inventory value

Metrics Explained:

  • my_tickets.total_assigned: All tickets ever assigned to me
  • my_tickets.pending: Tickets with status "assigned" (not started)
  • my_tickets.in_progress: Tickets with status "en_route" or "in_progress"
  • my_tickets.completed_this_week: Completed this ISO week (Monday-Sunday)
  • my_expenses.total_amount: Sum of all MY expenses (approved + pending)
  • my_expenses.pending_approval: Count of MY unapproved expenses
  • my_expenses.pending_amount: Sum of MY unapproved expenses
  • my_inventory.items_on_hand: Equipment I collected but haven't returned/installed
  • my_time.hours_worked_this_week: Hours from MY timesheets (ISO week)

For Managers/Admins (Full Response)

Managers receive organization-wide stats:

{
  "user_info": {...},
  "projects": {...},
  "team": {
    "total_members": 25
  },
  "tickets": {
    "total": 150,
    "open": 45,
    "in_progress": 30
  },
  "expenses": {
    "total_amount": 250000.00,
    "pending_approval": 15
  },
  "sales_orders": {
    "total": 80,
    "pending": 20
  },
  "inventory": {
    "total_value": 500000.00,
    "active_assignments": 45
  },
  "notifications": {...},
  "generated_at": "..."
}

Work Queue Structure (Field Agents Only)

"work_queue": {
  "pending_assignments": [
    {
      "assignment_id": "uuid",
      "ticket_id": "uuid",
      "ticket_title": "Install fiber at Westlands Office",
      "ticket_number": "TKT-2024-001",
      "project_id": "uuid",
      "project_title": "Nairobi Fiber Rollout",
      "client_name": "Airtel Kenya",
      "status": "assigned",
      "priority": "high",
      "due_date": "2025-11-28T00:00:00Z",
      "execution_order": 1,
      "assigned_at": "2025-11-27T08:00:00Z"
    }
  ],
  "total_pending": 4,
  "high_priority": 1,
  "due_today": 2
}

Work Queue Details:

  • Shows ALL pending assignments across ALL projects
  • Sorted by: execution_order (if set) β†’ assigned_at (oldest first)
  • Includes assignments with status: assigned, en_route, in_progress
  • Limited to max 4 items per field agent (business rule)
  • No location data included (not all tickets have locations)

Frontend Implementation Guide

1. Global Dashboard (Root /)

Fetch Overview:

const response = await fetch('/api/v1/analytics/user/overview?limit=50', {
  headers: { 'Authorization': `Bearer ${token}` }
});
const data = await response.json();

Display Summary Cards:

// Field agent response has simplified structure
const { my_tickets, my_expenses, my_inventory, my_time } = data;

<Card title="Hours This Week">
  {my_time.hours_worked_this_week} hrs
</Card>

<Card title="Pending Expenses">
  KES {my_expenses.pending_amount.toLocaleString()}
</Card>

<Card title="Inventory On Hand">
  {my_inventory.items_on_hand} items
</Card>

<Card title="Completed This Week">
  {my_tickets.completed_this_week} tickets
</Card>

Display Work Queue:

const workQueue = data.work_queue;

<WorkQueue>
  <Header>
    Pending Work: {workQueue.total_pending}
    (High Priority: {workQueue.high_priority}, Due Today: {workQueue.due_today})
  </Header>
  
  {workQueue.pending_assignments.map(assignment => (
    <WorkItem key={assignment.assignment_id}>
      <Badge>{assignment.execution_order || 'β€”'}</Badge>
      <Title>{assignment.ticket_title}</Title>
      <Subtitle>{assignment.project_title} β€’ {assignment.client_name}</Subtitle>
      <Meta>
        <Priority>{assignment.priority}</Priority>
        <DueDate>{assignment.due_date}</DueDate>
      </Meta>
    </WorkItem>
  ))}
</WorkQueue>

2. Project List

Use Existing Endpoint:

const response = await fetch('/api/v1/projects', {
  headers: { 'Authorization': `Bearer ${token}` }
});
const projects = await response.json();

No changes needed - RBAC automatically filters to show only projects the field agent is assigned to via ProjectTeam.

3. Project Dashboard

Use Existing Endpoint:

const response = await fetch(`/api/v1/projects/${projectId}/dashboard`, {
  headers: { 'Authorization': `Bearer ${token}` }
});
const dashboard = await response.json();

No changes needed - Already returns project-scoped stats with proper authorization.


Technical Details

Database Queries

Field Agent Stats:

  • Timesheet: SUM(hours_worked) WHERE user_id = current_user AND work_date >= week_start
  • Expenses: SUM(total_cost) WHERE user_id = current_user AND is_approved = false
  • Inventory: COUNT(*) WHERE user_id = current_user AND is_returned = false AND installed_at IS NULL
  • Tickets: COUNT(*) WHERE user_id = current_user AND status = 'completed' AND ended_at >= week_start

Work Queue:

SELECT ta.*, t.*, p.*, c.*
FROM ticket_assignments ta
JOIN tickets t ON ta.ticket_id = t.id
JOIN projects p ON t.project_id = p.id
JOIN clients c ON p.client_id = c.id
WHERE ta.user_id = :user_id
  AND ta.status IN ('assigned', 'en_route', 'in_progress')
  AND ta.ended_at IS NULL
  AND ta.deleted_at IS NULL
ORDER BY ta.execution_order ASC NULLS LAST, ta.assigned_at ASC
LIMIT :limit

Performance Considerations

  • Caching: Not cached (real-time data needed for work queue)
  • Query Optimization: Uses joins with joinedload to avoid N+1 queries
  • Limit: Max 100 items in work queue (business rule: max 4 active assignments)
  • ISO Week: Monday = start of week (Python's date.weekday())

Authorization

  • RBAC: Existing role-based access control applies
  • Data Filtering: Queries automatically filter by user_id = current_user.id
  • Project Access: Field agents only see projects they're assigned to via ProjectTeam

Testing

Manual Test (cURL)

# Login as field agent
curl -X POST http://localhost:8000/api/v1/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email": "agent@example.com", "password": "password"}'

# Get overview
curl http://localhost:8000/api/v1/analytics/user/overview?limit=50 \
  -H "Authorization: Bearer YOUR_TOKEN"

Expected Response

Field agents should see:

  • field_agent_stats object with 4 metrics
  • work_queue object with pending assignments
  • All other standard fields

Non-field-agent roles should NOT see:

  • field_agent_stats (null/undefined)
  • work_queue (null/undefined)

Migration Notes

No Breaking Changes

  • Existing endpoints unchanged
  • New fields only added for field_agent/sales_agent roles
  • Other roles receive same response as before

Frontend Migration Path

  1. Update API client to handle new optional fields
  2. Create field agent dashboard components
  3. Reuse existing project list/dashboard components
  4. Test with field agent user account

Questions?

Contact backend team or check:

  • Service: src/app/services/dashboard_service.py
  • Endpoint: src/app/api/v1/analytics.py
  • Models: src/app/models/ticket_assignment.py, src/app/models/timesheet.py