Spaces:
Sleeping
Sleeping
fix: correct get_db imports and remove duplicate definition
Browse files- docs/api/dashboards/pm/PM_DASHBOARD_API_REFERENCE.md +1054 -0
- docs/api/dashboards/pm/PM_DASHBOARD_DESIGN_GUIDE.md +604 -0
- docs/api/dashboards/pm/QUICK_REFERENCE.md +303 -0
- docs/api/dashboards/pm/README.md +376 -0
- docs/hflogs/runtimeerror.txt +109 -626
- src/app/api/v1/expenses.py +1 -2
- src/app/api/v1/incident_reports.py +1 -2
- src/app/api/v1/progress_reports.py +1 -2
- tests/integration/test_auth_audit_logs.py +1 -1
- tests/integration/test_password_reset.py +1 -1
docs/api/dashboards/pm/PM_DASHBOARD_API_REFERENCE.md
ADDED
|
@@ -0,0 +1,1054 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Project Manager Dashboard - API Reference
|
| 2 |
+
|
| 3 |
+
**Version:** 1.0
|
| 4 |
+
**Last Updated:** 2025-11-19
|
| 5 |
+
**Audience:** Frontend Development Team
|
| 6 |
+
|
| 7 |
+
---
|
| 8 |
+
|
| 9 |
+
## Overview
|
| 10 |
+
|
| 11 |
+
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.
|
| 12 |
+
|
| 13 |
+
### PM Core Responsibilities
|
| 14 |
+
- Convert sales orders to work tickets
|
| 15 |
+
- Assign tickets to field agents
|
| 16 |
+
- Approve expenses and manage finances
|
| 17 |
+
- Track inventory and resources
|
| 18 |
+
- Generate payroll and invoices
|
| 19 |
+
- Monitor team performance
|
| 20 |
+
|
| 21 |
+
---
|
| 22 |
+
|
| 23 |
+
## Dashboard Layout Structure
|
| 24 |
+
|
| 25 |
+
### Recommended Sections
|
| 26 |
+
|
| 27 |
+
1. **Today's Overview** - Key metrics at a glance
|
| 28 |
+
2. **Financial Snapshot** - Cash position and pending payments
|
| 29 |
+
3. **Quick Actions** - Common PM tasks
|
| 30 |
+
4. **Pending Sales Orders** - Orders awaiting conversion
|
| 31 |
+
5. **Active Tickets** - Work in progress
|
| 32 |
+
6. **Pending Approvals** - Expenses, payroll, invoices
|
| 33 |
+
7. **Inventory Status** - Stock levels and alerts
|
| 34 |
+
8. **Map View** - Geographic visualization
|
| 35 |
+
9. **Team Status** - Agent availability
|
| 36 |
+
|
| 37 |
+
---
|
| 38 |
+
|
| 39 |
+
## API Endpoints by Feature
|
| 40 |
+
|
| 41 |
+
### 1. Dashboard Overview Statistics
|
| 42 |
+
|
| 43 |
+
#### Get Platform Dashboard Stats
|
| 44 |
+
```
|
| 45 |
+
GET /api/v1/analytics/platform-admin/dashboard
|
| 46 |
+
Authorization: Bearer {token}
|
| 47 |
+
```
|
| 48 |
+
|
| 49 |
+
**Response Fields:**
|
| 50 |
+
- `users` - User statistics (total, active, by role)
|
| 51 |
+
- `organizations` - Client and contractor counts
|
| 52 |
+
- `tickets` - Ticket counts by status and type
|
| 53 |
+
- `projects` - Project statistics
|
| 54 |
+
- `assignments` - Assignment statistics
|
| 55 |
+
- `recent_activity` - Latest 10 audit logs
|
| 56 |
+
- `system_health` - 30-day trends
|
| 57 |
+
|
| 58 |
+
**Use Case:** Main dashboard metrics widget
|
| 59 |
+
|
| 60 |
+
---
|
| 61 |
+
|
| 62 |
+
### 2. Sales Order Management
|
| 63 |
+
|
| 64 |
+
#### List Sales Orders
|
| 65 |
+
```
|
| 66 |
+
GET /api/v1/sales-orders
|
| 67 |
+
Authorization: Bearer {token}
|
| 68 |
+
|
| 69 |
+
Query Parameters:
|
| 70 |
+
- skip (int, default: 0)
|
| 71 |
+
- limit (int, default: 50, max: 100)
|
| 72 |
+
- project_id (UUID, optional)
|
| 73 |
+
- status (string, optional) - "pending", "processed", "cancelled", "duplicate"
|
| 74 |
+
- project_region_id (UUID, optional)
|
| 75 |
+
- sales_agent_id (UUID, optional)
|
| 76 |
+
- from_date (date, optional)
|
| 77 |
+
- to_date (date, optional)
|
| 78 |
+
- pending_processing (boolean, optional) - Show only pending orders
|
| 79 |
+
- customer_phone (string, optional)
|
| 80 |
+
```
|
| 81 |
+
|
| 82 |
+
**Response:**
|
| 83 |
+
- `items[]` - Array of sales orders with computed properties
|
| 84 |
+
- `total` - Total count
|
| 85 |
+
- `skip`, `limit` - Pagination info
|
| 86 |
+
|
| 87 |
+
**Key Fields per Item:**
|
| 88 |
+
- `id`, `order_number`, `customer_name`, `customer_preferred_package`
|
| 89 |
+
- `package_price`, `installation_address_line1`, `installation_latitude`, `installation_longitude`
|
| 90 |
+
- `status`, `project_title`, `region_name`, `sales_agent_name`
|
| 91 |
+
- `is_pending`, `has_ticket`, `can_promote_to_ticket`
|
| 92 |
+
|
| 93 |
+
#### Get Sales Order Statistics
|
| 94 |
+
```
|
| 95 |
+
GET /api/v1/sales-orders/stats
|
| 96 |
+
Authorization: Bearer {token}
|
| 97 |
+
|
| 98 |
+
Query Parameters:
|
| 99 |
+
- project_id (UUID, optional)
|
| 100 |
+
- project_region_id (UUID, optional)
|
| 101 |
+
- sales_agent_id (UUID, optional)
|
| 102 |
+
```
|
| 103 |
+
|
| 104 |
+
**Response:** Metrics on orders by status, region, agent
|
| 105 |
+
|
| 106 |
+
#### Assign Sales Order to Region
|
| 107 |
+
```
|
| 108 |
+
POST /api/v1/sales-orders/{sales_order_id}/assign-region
|
| 109 |
+
Authorization: Bearer {token}
|
| 110 |
+
Content-Type: application/json
|
| 111 |
+
|
| 112 |
+
Body:
|
| 113 |
+
{
|
| 114 |
+
"project_region_id": "uuid"
|
| 115 |
+
}
|
| 116 |
+
```
|
| 117 |
+
|
| 118 |
+
#### Promote Sales Order to Ticket (Single)
|
| 119 |
+
```
|
| 120 |
+
POST /api/v1/sales-orders/{sales_order_id}/promote
|
| 121 |
+
Authorization: Bearer {token}
|
| 122 |
+
Content-Type: application/json
|
| 123 |
+
|
| 124 |
+
Body:
|
| 125 |
+
{
|
| 126 |
+
"priority": "normal",
|
| 127 |
+
"scheduled_date": "2025-01-20",
|
| 128 |
+
"scheduled_time_slot": "morning",
|
| 129 |
+
"work_description": "Install fiber",
|
| 130 |
+
"notes": "Customer prefers morning"
|
| 131 |
+
}
|
| 132 |
+
```
|
| 133 |
+
|
| 134 |
+
**Response:**
|
| 135 |
+
- `message`, `sales_order_id`, `ticket_id`, `ticket_name`, `status`
|
| 136 |
+
|
| 137 |
+
#### Bulk Promote Sales Orders to Tickets
|
| 138 |
+
```
|
| 139 |
+
POST /api/v1/sales-orders/bulk-promote
|
| 140 |
+
Authorization: Bearer {token}
|
| 141 |
+
Content-Type: application/json
|
| 142 |
+
|
| 143 |
+
Body:
|
| 144 |
+
{
|
| 145 |
+
"sales_order_ids": ["uuid1", "uuid2"],
|
| 146 |
+
"priority": "normal",
|
| 147 |
+
"notes": "Batch promotion"
|
| 148 |
+
}
|
| 149 |
+
```
|
| 150 |
+
|
| 151 |
+
**Response:**
|
| 152 |
+
- `total`, `successful`, `failed`, `errors[]`, `created_ticket_ids[]`
|
| 153 |
+
|
| 154 |
+
---
|
| 155 |
+
|
| 156 |
+
### 3. Ticket Management
|
| 157 |
+
|
| 158 |
+
#### List Tickets
|
| 159 |
+
```
|
| 160 |
+
GET /api/v1/tickets
|
| 161 |
+
Authorization: Bearer {token}
|
| 162 |
+
|
| 163 |
+
Query Parameters:
|
| 164 |
+
- skip (int, default: 0)
|
| 165 |
+
- limit (int, default: 50, max: 100)
|
| 166 |
+
- project_id (UUID, optional)
|
| 167 |
+
- status (enum, optional) - "open", "assigned", "in_progress", "pending_review", "completed", "cancelled"
|
| 168 |
+
- ticket_type (enum, optional) - "installation", "support", "infrastructure"
|
| 169 |
+
- priority (enum, optional) - "low", "normal", "high", "urgent"
|
| 170 |
+
- project_region_id (UUID, optional)
|
| 171 |
+
- source (enum, optional) - "sales_order", "incident", "task"
|
| 172 |
+
- from_date (date, optional)
|
| 173 |
+
- to_date (date, optional)
|
| 174 |
+
- is_overdue (boolean, optional)
|
| 175 |
+
```
|
| 176 |
+
|
| 177 |
+
**Response:**
|
| 178 |
+
- `tickets[]` - Array of tickets
|
| 179 |
+
- `total`, `skip`, `limit`
|
| 180 |
+
|
| 181 |
+
**Key Fields per Ticket:**
|
| 182 |
+
- `id`, `ticket_name`, `status`, `priority`, `ticket_type`
|
| 183 |
+
- `work_description`, `scheduled_date`, `scheduled_time_slot`
|
| 184 |
+
- `project_title`, `region_name`, `customer_name`
|
| 185 |
+
- `is_overdue`, `can_be_assigned`
|
| 186 |
+
|
| 187 |
+
#### Get Ticket Statistics
|
| 188 |
+
```
|
| 189 |
+
GET /api/v1/tickets/stats
|
| 190 |
+
Authorization: Bearer {token}
|
| 191 |
+
|
| 192 |
+
Query Parameters:
|
| 193 |
+
- project_id (UUID, optional)
|
| 194 |
+
- project_region_id (UUID, optional)
|
| 195 |
+
```
|
| 196 |
+
|
| 197 |
+
**Response:**
|
| 198 |
+
- Counts by status, type, priority
|
| 199 |
+
- `overdue_tickets`, `avg_completion_time_hours`, `completion_rate`
|
| 200 |
+
|
| 201 |
+
#### Update Ticket
|
| 202 |
+
```
|
| 203 |
+
PUT /api/v1/tickets/{ticket_id}
|
| 204 |
+
Authorization: Bearer {token}
|
| 205 |
+
Content-Type: application/json
|
| 206 |
+
|
| 207 |
+
Body:
|
| 208 |
+
{
|
| 209 |
+
"priority": "urgent",
|
| 210 |
+
"work_description": "Updated description",
|
| 211 |
+
"notes": "Additional notes"
|
| 212 |
+
}
|
| 213 |
+
```
|
| 214 |
+
|
| 215 |
+
#### Reschedule Ticket
|
| 216 |
+
```
|
| 217 |
+
POST /api/v1/tickets/{ticket_id}/reschedule
|
| 218 |
+
Authorization: Bearer {token}
|
| 219 |
+
Content-Type: application/json
|
| 220 |
+
|
| 221 |
+
Body:
|
| 222 |
+
{
|
| 223 |
+
"scheduled_date": "2025-01-25",
|
| 224 |
+
"scheduled_time_slot": "afternoon",
|
| 225 |
+
"reason": "Customer requested later date"
|
| 226 |
+
}
|
| 227 |
+
```
|
| 228 |
+
|
| 229 |
+
#### Cancel Ticket
|
| 230 |
+
```
|
| 231 |
+
POST /api/v1/tickets/{ticket_id}/cancel
|
| 232 |
+
Authorization: Bearer {token}
|
| 233 |
+
Content-Type: application/json
|
| 234 |
+
|
| 235 |
+
Body:
|
| 236 |
+
{
|
| 237 |
+
"reason": "Customer cancelled service"
|
| 238 |
+
}
|
| 239 |
+
```
|
| 240 |
+
|
| 241 |
+
---
|
| 242 |
+
|
| 243 |
+
### 4. Ticket Assignment & Dispatch
|
| 244 |
+
|
| 245 |
+
#### List Ticket Assignments
|
| 246 |
+
```
|
| 247 |
+
GET /api/v1/ticket-assignments
|
| 248 |
+
Authorization: Bearer {token}
|
| 249 |
+
|
| 250 |
+
Query Parameters:
|
| 251 |
+
- skip (int, default: 0)
|
| 252 |
+
- limit (int, default: 50)
|
| 253 |
+
- ticket_id (UUID, optional)
|
| 254 |
+
- user_id (UUID, optional)
|
| 255 |
+
- status (string, optional)
|
| 256 |
+
- project_id (UUID, optional)
|
| 257 |
+
- from_date (date, optional)
|
| 258 |
+
- to_date (date, optional)
|
| 259 |
+
```
|
| 260 |
+
|
| 261 |
+
#### Get Available Agents for Assignment
|
| 262 |
+
```
|
| 263 |
+
GET /api/v1/ticket-assignments/available-agents
|
| 264 |
+
Authorization: Bearer {token}
|
| 265 |
+
|
| 266 |
+
Query Parameters:
|
| 267 |
+
- ticket_id (UUID, required)
|
| 268 |
+
```
|
| 269 |
+
|
| 270 |
+
**Response:** List of agents available to be assigned to the ticket
|
| 271 |
+
|
| 272 |
+
#### Assign Ticket to Agent
|
| 273 |
+
```
|
| 274 |
+
POST /api/v1/ticket-assignments
|
| 275 |
+
Authorization: Bearer {token}
|
| 276 |
+
Content-Type: application/json
|
| 277 |
+
|
| 278 |
+
Body:
|
| 279 |
+
{
|
| 280 |
+
"ticket_id": "uuid",
|
| 281 |
+
"user_id": "uuid",
|
| 282 |
+
"notes": "Assigned to John"
|
| 283 |
+
}
|
| 284 |
+
```
|
| 285 |
+
|
| 286 |
+
#### Reassign Ticket
|
| 287 |
+
```
|
| 288 |
+
POST /api/v1/ticket-assignments/{assignment_id}/reassign
|
| 289 |
+
Authorization: Bearer {token}
|
| 290 |
+
Content-Type: application/json
|
| 291 |
+
|
| 292 |
+
Body:
|
| 293 |
+
{
|
| 294 |
+
"new_user_id": "uuid",
|
| 295 |
+
"reason": "Original agent unavailable"
|
| 296 |
+
}
|
| 297 |
+
```
|
| 298 |
+
|
| 299 |
+
---
|
| 300 |
+
|
| 301 |
+
### 5. Expense Management
|
| 302 |
+
|
| 303 |
+
#### List Expenses
|
| 304 |
+
```
|
| 305 |
+
GET /api/v1/expenses
|
| 306 |
+
Authorization: Bearer {token}
|
| 307 |
+
|
| 308 |
+
Query Parameters:
|
| 309 |
+
- page (int, default: 1)
|
| 310 |
+
- page_size (int, default: 50, max: 100)
|
| 311 |
+
- ticket_id (UUID, optional)
|
| 312 |
+
- assignment_id (UUID, optional)
|
| 313 |
+
- approval_status (string, optional) - "pending", "approved", "rejected"
|
| 314 |
+
- payment_status (string, optional) - "pending", "paid"
|
| 315 |
+
- from_date (date, optional)
|
| 316 |
+
- to_date (date, optional)
|
| 317 |
+
```
|
| 318 |
+
|
| 319 |
+
**Response:**
|
| 320 |
+
- `items[]` - Array of expenses
|
| 321 |
+
- `total`, `page`, `page_size`
|
| 322 |
+
|
| 323 |
+
**Key Fields per Expense:**
|
| 324 |
+
- `id`, `expense_type`, `amount`, `currency`
|
| 325 |
+
- `description`, `receipt_url`
|
| 326 |
+
- `approval_status`, `payment_status`
|
| 327 |
+
- `submitted_by_name`, `approved_by_name`
|
| 328 |
+
|
| 329 |
+
#### Get Expense Statistics
|
| 330 |
+
```
|
| 331 |
+
GET /api/v1/expenses/stats
|
| 332 |
+
Authorization: Bearer {token}
|
| 333 |
+
|
| 334 |
+
Query Parameters:
|
| 335 |
+
- ticket_id (UUID, optional)
|
| 336 |
+
- assignment_id (UUID, optional)
|
| 337 |
+
```
|
| 338 |
+
|
| 339 |
+
**Response:** Total expenses, pending approvals, payment status breakdown
|
| 340 |
+
|
| 341 |
+
#### Approve/Reject Expense
|
| 342 |
+
```
|
| 343 |
+
POST /api/v1/expenses/{expense_id}/approve
|
| 344 |
+
Authorization: Bearer {token}
|
| 345 |
+
Content-Type: application/json
|
| 346 |
+
|
| 347 |
+
Body:
|
| 348 |
+
{
|
| 349 |
+
"approved": true,
|
| 350 |
+
"notes": "Approved - receipt verified"
|
| 351 |
+
}
|
| 352 |
+
```
|
| 353 |
+
|
| 354 |
+
#### Mark Expense as Paid
|
| 355 |
+
```
|
| 356 |
+
POST /api/v1/expenses/{expense_id}/mark-paid
|
| 357 |
+
Authorization: Bearer {token}
|
| 358 |
+
Content-Type: application/json
|
| 359 |
+
|
| 360 |
+
Body:
|
| 361 |
+
{
|
| 362 |
+
"payment_date": "2025-01-20",
|
| 363 |
+
"payment_method": "mobile_money",
|
| 364 |
+
"payment_reference": "TXN123456",
|
| 365 |
+
"notes": "Paid via M-Pesa"
|
| 366 |
+
}
|
| 367 |
+
```
|
| 368 |
+
|
| 369 |
+
---
|
| 370 |
+
|
| 371 |
+
### 6. Financial Management
|
| 372 |
+
|
| 373 |
+
#### List Financial Transactions
|
| 374 |
+
```
|
| 375 |
+
GET /api/v1/finance
|
| 376 |
+
Authorization: Bearer {token}
|
| 377 |
+
|
| 378 |
+
Query Parameters:
|
| 379 |
+
- skip (int, default: 0)
|
| 380 |
+
- limit (int, default: 50, max: 100)
|
| 381 |
+
- project_id (UUID, optional)
|
| 382 |
+
- transaction_type (string, optional) - "inflow", "outflow"
|
| 383 |
+
- status (string, optional) - "pending", "approved", "paid", "rejected", "cancelled"
|
| 384 |
+
- category (string, optional)
|
| 385 |
+
- from_date (date, optional)
|
| 386 |
+
- to_date (date, optional)
|
| 387 |
+
- pending_approval (boolean, optional)
|
| 388 |
+
```
|
| 389 |
+
|
| 390 |
+
#### Get Cash Flow Summary
|
| 391 |
+
```
|
| 392 |
+
GET /api/v1/finance/cash-flow/{project_id}
|
| 393 |
+
Authorization: Bearer {token}
|
| 394 |
+
|
| 395 |
+
Query Parameters:
|
| 396 |
+
- from_date (date, optional)
|
| 397 |
+
- to_date (date, optional)
|
| 398 |
+
```
|
| 399 |
+
|
| 400 |
+
**Response:**
|
| 401 |
+
- Total inflows, outflows, net cash flow
|
| 402 |
+
- Breakdown by category
|
| 403 |
+
- Pending transactions
|
| 404 |
+
|
| 405 |
+
#### Create Financial Transaction
|
| 406 |
+
```
|
| 407 |
+
POST /api/v1/finance
|
| 408 |
+
Authorization: Bearer {token}
|
| 409 |
+
Content-Type: application/json
|
| 410 |
+
|
| 411 |
+
Body:
|
| 412 |
+
{
|
| 413 |
+
"project_id": "uuid",
|
| 414 |
+
"transaction_type": "outflow",
|
| 415 |
+
"amount": 50000,
|
| 416 |
+
"currency": "KES",
|
| 417 |
+
"category": "equipment_purchase",
|
| 418 |
+
"description": "Purchased 50 ONTs",
|
| 419 |
+
"transaction_date": "2025-01-20"
|
| 420 |
+
}
|
| 421 |
+
```
|
| 422 |
+
|
| 423 |
+
#### Approve Transaction
|
| 424 |
+
```
|
| 425 |
+
POST /api/v1/finance/{transaction_id}/approve
|
| 426 |
+
Authorization: Bearer {token}
|
| 427 |
+
Content-Type: application/json
|
| 428 |
+
|
| 429 |
+
Body:
|
| 430 |
+
{
|
| 431 |
+
"notes": "Approved by PM"
|
| 432 |
+
}
|
| 433 |
+
```
|
| 434 |
+
|
| 435 |
+
---
|
| 436 |
+
|
| 437 |
+
### 7. Contractor Invoice Management
|
| 438 |
+
|
| 439 |
+
#### List Contractor Invoices
|
| 440 |
+
```
|
| 441 |
+
GET /api/v1/invoices
|
| 442 |
+
Authorization: Bearer {token}
|
| 443 |
+
|
| 444 |
+
Query Parameters:
|
| 445 |
+
- skip (int, default: 0)
|
| 446 |
+
- limit (int, default: 100, max: 500)
|
| 447 |
+
- contractor_id (UUID, optional)
|
| 448 |
+
- client_id (UUID, optional)
|
| 449 |
+
- project_id (UUID, optional)
|
| 450 |
+
- status (string, optional) - "draft", "sent", "partially_paid", "paid", "cancelled"
|
| 451 |
+
- overdue_only (boolean, optional)
|
| 452 |
+
- unpaid_only (boolean, optional)
|
| 453 |
+
- latest_versions_only (boolean, default: true)
|
| 454 |
+
```
|
| 455 |
+
|
| 456 |
+
**Response:**
|
| 457 |
+
- `invoices[]` - Array of invoices
|
| 458 |
+
- `total`, `skip`, `limit`
|
| 459 |
+
|
| 460 |
+
**Key Fields per Invoice:**
|
| 461 |
+
- `id`, `invoice_number`, `contractor_name`, `client_name`
|
| 462 |
+
- `subtotal_amount`, `tax_amount`, `total_amount`
|
| 463 |
+
- `amount_paid`, `amount_due`
|
| 464 |
+
- `status`, `due_date`, `is_overdue`
|
| 465 |
+
|
| 466 |
+
#### Create Contractor Invoice
|
| 467 |
+
```
|
| 468 |
+
POST /api/v1/invoices
|
| 469 |
+
Authorization: Bearer {token}
|
| 470 |
+
Content-Type: application/json
|
| 471 |
+
|
| 472 |
+
Body:
|
| 473 |
+
{
|
| 474 |
+
"contractor_id": "uuid",
|
| 475 |
+
"client_id": "uuid",
|
| 476 |
+
"project_id": "uuid",
|
| 477 |
+
"invoice_date": "2025-01-20",
|
| 478 |
+
"due_date": "2025-02-20",
|
| 479 |
+
"currency": "KES",
|
| 480 |
+
"tax_rate": 16.0,
|
| 481 |
+
"notes": "Monthly invoice"
|
| 482 |
+
}
|
| 483 |
+
```
|
| 484 |
+
|
| 485 |
+
**Response:** Created invoice with auto-generated invoice number
|
| 486 |
+
|
| 487 |
+
#### Add Line Item to Invoice
|
| 488 |
+
```
|
| 489 |
+
POST /api/v1/invoices/{invoice_id}/line-items
|
| 490 |
+
Authorization: Bearer {token}
|
| 491 |
+
Content-Type: application/json
|
| 492 |
+
|
| 493 |
+
Body:
|
| 494 |
+
{
|
| 495 |
+
"line_item_type": "ticket",
|
| 496 |
+
"ticket_id": "uuid",
|
| 497 |
+
"description": "Installation service",
|
| 498 |
+
"quantity": 1,
|
| 499 |
+
"unit_price": 5000,
|
| 500 |
+
"amount": 5000
|
| 501 |
+
}
|
| 502 |
+
```
|
| 503 |
+
|
| 504 |
+
**Note:** Creates new invoice version
|
| 505 |
+
|
| 506 |
+
#### Record Payment
|
| 507 |
+
```
|
| 508 |
+
POST /api/v1/invoices/{invoice_id}/payments
|
| 509 |
+
Authorization: Bearer {token}
|
| 510 |
+
Content-Type: application/json
|
| 511 |
+
|
| 512 |
+
Body:
|
| 513 |
+
{
|
| 514 |
+
"amount": 50000,
|
| 515 |
+
"payment_date": "2025-01-20",
|
| 516 |
+
"payment_method": "bank_transfer",
|
| 517 |
+
"payment_reference": "TXN123456",
|
| 518 |
+
"notes": "Partial payment"
|
| 519 |
+
}
|
| 520 |
+
```
|
| 521 |
+
|
| 522 |
+
**Response:** Updated invoice with new payment recorded
|
| 523 |
+
|
| 524 |
+
---
|
| 525 |
+
|
| 526 |
+
### 8. Inventory Management
|
| 527 |
+
|
| 528 |
+
#### List Main Office Inventory
|
| 529 |
+
```
|
| 530 |
+
GET /api/v1/inventory
|
| 531 |
+
Authorization: Bearer {token}
|
| 532 |
+
|
| 533 |
+
Query Parameters:
|
| 534 |
+
- page (int, default: 1)
|
| 535 |
+
- page_size (int, default: 50, max: 100)
|
| 536 |
+
- project_id (UUID, optional)
|
| 537 |
+
- item_type (string, optional) - "tool", "equipment", "consumable", "ppe"
|
| 538 |
+
- status (string, optional)
|
| 539 |
+
- is_active (boolean, optional)
|
| 540 |
+
- search (string, optional)
|
| 541 |
+
```
|
| 542 |
+
|
| 543 |
+
**Response:**
|
| 544 |
+
- `items[]` - Inventory batches
|
| 545 |
+
- `total`, `page`, `page_size`
|
| 546 |
+
|
| 547 |
+
**Key Fields per Item:**
|
| 548 |
+
- `id`, `equipment_type`, `equipment_name`, `item_type`
|
| 549 |
+
- `quantity_received`, `quantity_available`, `quantity_distributed`
|
| 550 |
+
- `status`, `received_date`
|
| 551 |
+
|
| 552 |
+
#### Create Inventory Batch
|
| 553 |
+
```
|
| 554 |
+
POST /api/v1/inventory
|
| 555 |
+
Authorization: Bearer {token}
|
| 556 |
+
Content-Type: application/json
|
| 557 |
+
|
| 558 |
+
Body:
|
| 559 |
+
{
|
| 560 |
+
"project_id": "uuid",
|
| 561 |
+
"equipment_type": "ONT",
|
| 562 |
+
"equipment_name": "Huawei HG8145V5",
|
| 563 |
+
"item_type": "equipment",
|
| 564 |
+
"quantity_received": 100,
|
| 565 |
+
"received_date": "2025-01-20",
|
| 566 |
+
"supplier_name": "TechSupply Ltd",
|
| 567 |
+
"unit_cost": 2500,
|
| 568 |
+
"currency": "KES"
|
| 569 |
+
}
|
| 570 |
+
```
|
| 571 |
+
|
| 572 |
+
#### List Regional Distributions
|
| 573 |
+
```
|
| 574 |
+
GET /api/v1/inventory/distributions
|
| 575 |
+
Authorization: Bearer {token}
|
| 576 |
+
|
| 577 |
+
Query Parameters:
|
| 578 |
+
- page (int, default: 1)
|
| 579 |
+
- page_size (int, default: 50)
|
| 580 |
+
- project_id (UUID, optional)
|
| 581 |
+
- region_id (UUID, optional)
|
| 582 |
+
- inventory_id (UUID, optional)
|
| 583 |
+
- item_type (string, optional)
|
| 584 |
+
- is_active (boolean, optional)
|
| 585 |
+
```
|
| 586 |
+
|
| 587 |
+
**Response:** Inventory distributed to regional hubs
|
| 588 |
+
|
| 589 |
+
#### Distribute Inventory to Regional Hub
|
| 590 |
+
```
|
| 591 |
+
POST /api/v1/inventory/distributions
|
| 592 |
+
Authorization: Bearer {token}
|
| 593 |
+
Content-Type: application/json
|
| 594 |
+
|
| 595 |
+
Body:
|
| 596 |
+
{
|
| 597 |
+
"inventory_id": "uuid",
|
| 598 |
+
"project_region_id": "uuid",
|
| 599 |
+
"quantity_distributed": 20,
|
| 600 |
+
"distributed_date": "2025-01-20",
|
| 601 |
+
"notes": "Distribution to Nairobi hub"
|
| 602 |
+
}
|
| 603 |
+
```
|
| 604 |
+
|
| 605 |
+
#### List Inventory Assignments (Issued to Agents)
|
| 606 |
+
```
|
| 607 |
+
GET /api/v1/inventory/assignments
|
| 608 |
+
Authorization: Bearer {token}
|
| 609 |
+
|
| 610 |
+
Query Parameters:
|
| 611 |
+
- page (int, default: 1)
|
| 612 |
+
- page_size (int, default: 50)
|
| 613 |
+
- user_id (UUID, optional)
|
| 614 |
+
- region_id (UUID, optional)
|
| 615 |
+
- status (string, optional)
|
| 616 |
+
- is_returned (boolean, optional)
|
| 617 |
+
- ticket_id (UUID, optional)
|
| 618 |
+
```
|
| 619 |
+
|
| 620 |
+
**Response:** Equipment issued to field agents
|
| 621 |
+
|
| 622 |
+
---
|
| 623 |
+
|
| 624 |
+
### 9. Payroll Management
|
| 625 |
+
|
| 626 |
+
#### List Payroll Records
|
| 627 |
+
```
|
| 628 |
+
GET /api/v1/payroll
|
| 629 |
+
Authorization: Bearer {token}
|
| 630 |
+
|
| 631 |
+
Query Parameters:
|
| 632 |
+
- skip (int, default: 0)
|
| 633 |
+
- limit (int, default: 50, max: 100)
|
| 634 |
+
- user_id (UUID, optional)
|
| 635 |
+
- project_id (UUID, optional)
|
| 636 |
+
- period_start (date, optional)
|
| 637 |
+
- period_end (date, optional)
|
| 638 |
+
- status (string, optional)
|
| 639 |
+
```
|
| 640 |
+
|
| 641 |
+
**Response:**
|
| 642 |
+
- `items[]` - Payroll records
|
| 643 |
+
- `total`, `skip`, `limit`
|
| 644 |
+
|
| 645 |
+
**Key Fields per Record:**
|
| 646 |
+
- `id`, `user_name`, `period_start`, `period_end`
|
| 647 |
+
- `total_earnings`, `deductions`, `net_pay`
|
| 648 |
+
- `status`, `payment_status`
|
| 649 |
+
|
| 650 |
+
#### Generate Payroll
|
| 651 |
+
```
|
| 652 |
+
POST /api/v1/payroll/generate
|
| 653 |
+
Authorization: Bearer {token}
|
| 654 |
+
Content-Type: application/json
|
| 655 |
+
|
| 656 |
+
Body:
|
| 657 |
+
{
|
| 658 |
+
"project_id": "uuid",
|
| 659 |
+
"period_start": "2025-01-01",
|
| 660 |
+
"period_end": "2025-01-31",
|
| 661 |
+
"user_ids": ["uuid1", "uuid2"]
|
| 662 |
+
}
|
| 663 |
+
```
|
| 664 |
+
|
| 665 |
+
**Response:** Generated payroll records
|
| 666 |
+
|
| 667 |
+
#### Approve Payroll
|
| 668 |
+
```
|
| 669 |
+
POST /api/v1/payroll/{payroll_id}/approve
|
| 670 |
+
Authorization: Bearer {token}
|
| 671 |
+
Content-Type: application/json
|
| 672 |
+
|
| 673 |
+
Body:
|
| 674 |
+
{
|
| 675 |
+
"notes": "Approved for payment"
|
| 676 |
+
}
|
| 677 |
+
```
|
| 678 |
+
|
| 679 |
+
---
|
| 680 |
+
|
| 681 |
+
### 10. Timesheet Management
|
| 682 |
+
|
| 683 |
+
#### List Timesheets
|
| 684 |
+
```
|
| 685 |
+
GET /api/v1/timesheets
|
| 686 |
+
Authorization: Bearer {token}
|
| 687 |
+
|
| 688 |
+
Query Parameters:
|
| 689 |
+
- skip (int, default: 0)
|
| 690 |
+
- limit (int, default: 50, max: 100)
|
| 691 |
+
- user_id (UUID, optional)
|
| 692 |
+
- project_id (UUID, optional)
|
| 693 |
+
- from_date (date, optional)
|
| 694 |
+
- to_date (date, optional)
|
| 695 |
+
- status (string, optional) - "present", "absent", "on_leave", "sick_leave", "half_day"
|
| 696 |
+
```
|
| 697 |
+
|
| 698 |
+
#### Get Timesheet Statistics
|
| 699 |
+
```
|
| 700 |
+
GET /api/v1/timesheets/stats
|
| 701 |
+
Authorization: Bearer {token}
|
| 702 |
+
|
| 703 |
+
Query Parameters:
|
| 704 |
+
- user_id (UUID, optional)
|
| 705 |
+
- project_id (UUID, optional)
|
| 706 |
+
- from_date (date, optional)
|
| 707 |
+
- to_date (date, optional)
|
| 708 |
+
```
|
| 709 |
+
|
| 710 |
+
**Response:** Attendance metrics, days worked, absences
|
| 711 |
+
|
| 712 |
+
---
|
| 713 |
+
|
| 714 |
+
### 11. User Management
|
| 715 |
+
|
| 716 |
+
#### List Users
|
| 717 |
+
```
|
| 718 |
+
GET /api/v1/users
|
| 719 |
+
Authorization: Bearer {token}
|
| 720 |
+
|
| 721 |
+
Query Parameters:
|
| 722 |
+
- skip (int, default: 0)
|
| 723 |
+
- limit (int, default: 50, max: 100)
|
| 724 |
+
- role (string, optional)
|
| 725 |
+
- client_id (UUID, optional)
|
| 726 |
+
- contractor_id (UUID, optional)
|
| 727 |
+
- is_active (boolean, optional)
|
| 728 |
+
- status (string, optional)
|
| 729 |
+
- search (string, optional)
|
| 730 |
+
```
|
| 731 |
+
|
| 732 |
+
**Response:**
|
| 733 |
+
- `users[]` - Array of users
|
| 734 |
+
- `total`, `skip`, `limit`
|
| 735 |
+
|
| 736 |
+
#### Search Users
|
| 737 |
+
```
|
| 738 |
+
GET /api/v1/users/search
|
| 739 |
+
Authorization: Bearer {token}
|
| 740 |
+
|
| 741 |
+
Query Parameters:
|
| 742 |
+
- q (string, required) - Search query
|
| 743 |
+
- role (string, optional)
|
| 744 |
+
- limit (int, default: 20)
|
| 745 |
+
```
|
| 746 |
+
|
| 747 |
+
**Response:** Matching users (useful for assignment dropdowns)
|
| 748 |
+
|
| 749 |
+
#### Invite New User
|
| 750 |
+
```
|
| 751 |
+
POST /api/v1/invitations
|
| 752 |
+
Authorization: Bearer {token}
|
| 753 |
+
Content-Type: application/json
|
| 754 |
+
|
| 755 |
+
Body:
|
| 756 |
+
{
|
| 757 |
+
"email": "john@example.com",
|
| 758 |
+
"name": "John Doe",
|
| 759 |
+
"phone": "+254712345678",
|
| 760 |
+
"role": "field_agent",
|
| 761 |
+
"contractor_id": "uuid"
|
| 762 |
+
}
|
| 763 |
+
```
|
| 764 |
+
|
| 765 |
+
---
|
| 766 |
+
|
| 767 |
+
### 12. Map & Location Services
|
| 768 |
+
|
| 769 |
+
#### Get Map Entities
|
| 770 |
+
```
|
| 771 |
+
GET /api/v1/map/entities
|
| 772 |
+
Authorization: Bearer {token}
|
| 773 |
+
|
| 774 |
+
Query Parameters:
|
| 775 |
+
- project_id (UUID, required)
|
| 776 |
+
- entity_types (array, optional) - ["customers", "tickets", "sales_orders", "agents", "regions"]
|
| 777 |
+
- status (string, optional)
|
| 778 |
+
```
|
| 779 |
+
|
| 780 |
+
**Response:**
|
| 781 |
+
- `customers[]` - Customer locations
|
| 782 |
+
- `tickets[]` - Ticket locations
|
| 783 |
+
- `sales_orders[]` - Sales order locations
|
| 784 |
+
- `agents[]` - Agent current locations
|
| 785 |
+
- `regions[]` - Regional hub locations
|
| 786 |
+
|
| 787 |
+
**Use Case:** Render all entities on map view
|
| 788 |
+
|
| 789 |
+
#### Get Regional Hub Locations
|
| 790 |
+
```
|
| 791 |
+
GET /api/v1/map/regions/{project_id}
|
| 792 |
+
Authorization: Bearer {token}
|
| 793 |
+
|
| 794 |
+
Query Parameters:
|
| 795 |
+
- include_inactive (boolean, default: false)
|
| 796 |
+
```
|
| 797 |
+
|
| 798 |
+
**Response:** Regional hubs with coordinates, coverage radius, active tickets/agents count
|
| 799 |
+
|
| 800 |
+
#### Get Journey Details
|
| 801 |
+
```
|
| 802 |
+
GET /api/v1/map/journey/{assignment_id}
|
| 803 |
+
Authorization: Bearer {token}
|
| 804 |
+
```
|
| 805 |
+
|
| 806 |
+
**Response:**
|
| 807 |
+
- Timeline (start, arrival, completion times)
|
| 808 |
+
- GPS breadcrumb trail (array of coordinates with timestamps)
|
| 809 |
+
- Journey statistics (distance, duration, speed)
|
| 810 |
+
- Location information
|
| 811 |
+
|
| 812 |
+
**Use Case:** Track agent movement during work assignment
|
| 813 |
+
|
| 814 |
+
#### Find Nearest Regional Hub
|
| 815 |
+
```
|
| 816 |
+
GET /api/v1/map/nearest-region
|
| 817 |
+
Authorization: Bearer {token}
|
| 818 |
+
|
| 819 |
+
Query Parameters:
|
| 820 |
+
- project_id (UUID, required)
|
| 821 |
+
- latitude (float, required)
|
| 822 |
+
- longitude (float, required)
|
| 823 |
+
- max_distance_km (float, optional)
|
| 824 |
+
```
|
| 825 |
+
|
| 826 |
+
**Response:** Nearest regional hub with distance
|
| 827 |
+
|
| 828 |
+
---
|
| 829 |
+
|
| 830 |
+
### 13. Task Management
|
| 831 |
+
|
| 832 |
+
#### List Tasks
|
| 833 |
+
```
|
| 834 |
+
GET /api/v1/tasks
|
| 835 |
+
Authorization: Bearer {token}
|
| 836 |
+
|
| 837 |
+
Query Parameters:
|
| 838 |
+
- skip (int, default: 0)
|
| 839 |
+
- limit (int, default: 50, max: 100)
|
| 840 |
+
- project_id (UUID, optional)
|
| 841 |
+
- status (string, optional) - "pending", "assigned", "in_progress", "completed", "cancelled", "blocked"
|
| 842 |
+
- assigned_to (UUID, optional)
|
| 843 |
+
- priority (string, optional)
|
| 844 |
+
- from_date (date, optional)
|
| 845 |
+
- to_date (date, optional)
|
| 846 |
+
```
|
| 847 |
+
|
| 848 |
+
#### Create Task
|
| 849 |
+
```
|
| 850 |
+
POST /api/v1/tasks
|
| 851 |
+
Authorization: Bearer {token}
|
| 852 |
+
Content-Type: application/json
|
| 853 |
+
|
| 854 |
+
Body:
|
| 855 |
+
{
|
| 856 |
+
"project_id": "uuid",
|
| 857 |
+
"task_type": "installation",
|
| 858 |
+
"title": "Install fiber cable",
|
| 859 |
+
"description": "Install cable from pole A to B",
|
| 860 |
+
"priority": "high",
|
| 861 |
+
"due_date": "2025-01-25",
|
| 862 |
+
"assigned_to": "uuid"
|
| 863 |
+
}
|
| 864 |
+
```
|
| 865 |
+
|
| 866 |
+
---
|
| 867 |
+
|
| 868 |
+
### 14. Customer Management
|
| 869 |
+
|
| 870 |
+
#### List Customers
|
| 871 |
+
```
|
| 872 |
+
GET /api/v1/customers
|
| 873 |
+
Authorization: Bearer {token}
|
| 874 |
+
|
| 875 |
+
Query Parameters:
|
| 876 |
+
- skip (int, default: 0)
|
| 877 |
+
- limit (int, default: 50, max: 100)
|
| 878 |
+
- client_id (UUID, optional)
|
| 879 |
+
- search (string, optional)
|
| 880 |
+
- phone (string, optional)
|
| 881 |
+
```
|
| 882 |
+
|
| 883 |
+
#### Get Customer Details
|
| 884 |
+
```
|
| 885 |
+
GET /api/v1/customers/{customer_id}
|
| 886 |
+
Authorization: Bearer {token}
|
| 887 |
+
```
|
| 888 |
+
|
| 889 |
+
**Response:** Customer profile with all related data (subscriptions, tickets, sales orders)
|
| 890 |
+
|
| 891 |
+
---
|
| 892 |
+
|
| 893 |
+
### 15. Notifications
|
| 894 |
+
|
| 895 |
+
#### List Notifications
|
| 896 |
+
```
|
| 897 |
+
GET /api/v1/notifications
|
| 898 |
+
Authorization: Bearer {token}
|
| 899 |
+
|
| 900 |
+
Query Parameters:
|
| 901 |
+
- skip (int, default: 0)
|
| 902 |
+
- limit (int, default: 50)
|
| 903 |
+
- is_read (boolean, optional)
|
| 904 |
+
- type (string, optional)
|
| 905 |
+
```
|
| 906 |
+
|
| 907 |
+
#### Get Unread Count
|
| 908 |
+
```
|
| 909 |
+
GET /api/v1/notifications/unread-count
|
| 910 |
+
Authorization: Bearer {token}
|
| 911 |
+
```
|
| 912 |
+
|
| 913 |
+
**Response:** `{ "count": 5 }`
|
| 914 |
+
|
| 915 |
+
#### Mark Notification as Read
|
| 916 |
+
```
|
| 917 |
+
PUT /api/v1/notifications/{notification_id}/read
|
| 918 |
+
Authorization: Bearer {token}
|
| 919 |
+
```
|
| 920 |
+
|
| 921 |
+
---
|
| 922 |
+
|
| 923 |
+
## Authentication
|
| 924 |
+
|
| 925 |
+
All endpoints require Bearer token authentication:
|
| 926 |
+
|
| 927 |
+
```
|
| 928 |
+
Authorization: Bearer {access_token}
|
| 929 |
+
```
|
| 930 |
+
|
| 931 |
+
**Token Refresh:**
|
| 932 |
+
```
|
| 933 |
+
POST /api/v1/auth/refresh
|
| 934 |
+
Content-Type: application/json
|
| 935 |
+
|
| 936 |
+
Body:
|
| 937 |
+
{
|
| 938 |
+
"refresh_token": "your_refresh_token"
|
| 939 |
+
}
|
| 940 |
+
```
|
| 941 |
+
|
| 942 |
+
**Response:**
|
| 943 |
+
```json
|
| 944 |
+
{
|
| 945 |
+
"access_token": "new_access_token",
|
| 946 |
+
"refresh_token": "new_refresh_token",
|
| 947 |
+
"token_type": "bearer",
|
| 948 |
+
"expires_in": 3600
|
| 949 |
+
}
|
| 950 |
+
```
|
| 951 |
+
|
| 952 |
+
---
|
| 953 |
+
|
| 954 |
+
## Error Handling
|
| 955 |
+
|
| 956 |
+
All endpoints follow standard HTTP status codes:
|
| 957 |
+
|
| 958 |
+
- `200 OK` - Success
|
| 959 |
+
- `201 Created` - Resource created
|
| 960 |
+
- `204 No Content` - Success with no response body
|
| 961 |
+
- `400 Bad Request` - Invalid input
|
| 962 |
+
- `401 Unauthorized` - Missing or invalid token
|
| 963 |
+
- `403 Forbidden` - Insufficient permissions
|
| 964 |
+
- `404 Not Found` - Resource not found
|
| 965 |
+
- `409 Conflict` - Duplicate or conflicting resource
|
| 966 |
+
- `422 Unprocessable Entity` - Validation error
|
| 967 |
+
- `500 Internal Server Error` - Server error
|
| 968 |
+
|
| 969 |
+
**Error Response Format:**
|
| 970 |
+
```json
|
| 971 |
+
{
|
| 972 |
+
"detail": "Error message here"
|
| 973 |
+
}
|
| 974 |
+
```
|
| 975 |
+
|
| 976 |
+
---
|
| 977 |
+
|
| 978 |
+
## Pagination
|
| 979 |
+
|
| 980 |
+
List endpoints use offset-based pagination:
|
| 981 |
+
|
| 982 |
+
**Request:**
|
| 983 |
+
- `skip` - Number of items to skip (default: 0)
|
| 984 |
+
- `limit` - Number of items to return (default: 50, max varies by endpoint)
|
| 985 |
+
|
| 986 |
+
**Response:**
|
| 987 |
+
- `items[]` or `users[]` or similar - Array of results
|
| 988 |
+
- `total` - Total count of items
|
| 989 |
+
- `skip` - Current offset
|
| 990 |
+
- `limit` - Current limit
|
| 991 |
+
|
| 992 |
+
---
|
| 993 |
+
|
| 994 |
+
## Date/Time Formats
|
| 995 |
+
|
| 996 |
+
- **Dates:** ISO 8601 format `YYYY-MM-DD` (e.g., `2025-01-20`)
|
| 997 |
+
- **DateTimes:** ISO 8601 with timezone `YYYY-MM-DDTHH:MM:SSZ` (e.g., `2025-01-20T14:30:00Z`)
|
| 998 |
+
- **Time Slots:** `"morning"`, `"afternoon"`, `"evening"`, `"any"`
|
| 999 |
+
|
| 1000 |
+
---
|
| 1001 |
+
|
| 1002 |
+
## Filtering Best Practices
|
| 1003 |
+
|
| 1004 |
+
1. **Combine filters** - Most list endpoints support multiple filters simultaneously
|
| 1005 |
+
2. **Use pagination** - Always paginate large result sets
|
| 1006 |
+
3. **Cache where appropriate** - Dashboard stats can be cached for 1-5 minutes
|
| 1007 |
+
4. **Real-time updates** - Use polling or WebSockets for live data (tickets, assignments)
|
| 1008 |
+
|
| 1009 |
+
---
|
| 1010 |
+
|
| 1011 |
+
## Common UI Patterns
|
| 1012 |
+
|
| 1013 |
+
### Dashboard Widgets
|
| 1014 |
+
- Fetch stats on page load
|
| 1015 |
+
- Refresh every 30-60 seconds for live data
|
| 1016 |
+
- Show loading skeletons during fetch
|
| 1017 |
+
|
| 1018 |
+
### List Views
|
| 1019 |
+
- Implement infinite scroll or traditional pagination
|
| 1020 |
+
- Add filters in sidebar or top bar
|
| 1021 |
+
- Show total count and current range
|
| 1022 |
+
|
| 1023 |
+
### Map Views
|
| 1024 |
+
- Lazy load entities based on viewport
|
| 1025 |
+
- Cluster markers when zoomed out
|
| 1026 |
+
- Show details on marker click
|
| 1027 |
+
|
| 1028 |
+
### Approval Workflows
|
| 1029 |
+
- Show pending count badge
|
| 1030 |
+
- Provide bulk approve/reject actions
|
| 1031 |
+
- Confirm destructive actions (reject, cancel)
|
| 1032 |
+
|
| 1033 |
+
---
|
| 1034 |
+
|
| 1035 |
+
## Performance Recommendations
|
| 1036 |
+
|
| 1037 |
+
1. **Lazy load** - Don't fetch all data at once
|
| 1038 |
+
2. **Debounce searches** - Wait 300ms before searching
|
| 1039 |
+
3. **Cache reference data** - Roles, statuses, regions rarely change
|
| 1040 |
+
4. **Optimize map rendering** - Use clustering for large datasets
|
| 1041 |
+
5. **Batch operations** - Use bulk endpoints when available
|
| 1042 |
+
|
| 1043 |
+
---
|
| 1044 |
+
|
| 1045 |
+
## Support & Questions
|
| 1046 |
+
|
| 1047 |
+
For API questions or issues:
|
| 1048 |
+
- Backend Team Lead: [Contact Info]
|
| 1049 |
+
- API Documentation: `/api/v1/docs` (Swagger UI)
|
| 1050 |
+
- Base URL: `https://api.swiftops.example.com`
|
| 1051 |
+
|
| 1052 |
+
---
|
| 1053 |
+
|
| 1054 |
+
**End of Document**
|
docs/api/dashboards/pm/PM_DASHBOARD_DESIGN_GUIDE.md
ADDED
|
@@ -0,0 +1,604 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Project Manager Dashboard - Design & UX Guide
|
| 2 |
+
|
| 3 |
+
**Version:** 1.0
|
| 4 |
+
**Last Updated:** 2025-11-19
|
| 5 |
+
**Audience:** Frontend Development Team, UI/UX Designers
|
| 6 |
+
|
| 7 |
+
---
|
| 8 |
+
|
| 9 |
+
## Executive Summary
|
| 10 |
+
|
| 11 |
+
The Project Manager (PM) dashboard is the command center for daily field service operations. It provides real-time visibility across sales, operations, finance, and resources, enabling PMs to orchestrate work efficiently.
|
| 12 |
+
|
| 13 |
+
### Key Design Principles
|
| 14 |
+
|
| 15 |
+
1. **Information at a Glance** - Critical metrics visible without scrolling
|
| 16 |
+
2. **Action-Oriented** - Every metric has a corresponding action
|
| 17 |
+
3. **Context-Aware** - Show relevant data based on time, location, status
|
| 18 |
+
4. **Progressive Disclosure** - Summary → Details → Actions
|
| 19 |
+
5. **Real-Time Updates** - Live data for time-sensitive operations
|
| 20 |
+
|
| 21 |
+
---
|
| 22 |
+
|
| 23 |
+
## User Persona: The Project Manager
|
| 24 |
+
|
| 25 |
+
### Daily Workflow
|
| 26 |
+
|
| 27 |
+
**Morning (8:00 AM - 10:00 AM)**
|
| 28 |
+
- Review overnight sales orders
|
| 29 |
+
- Check today's scheduled tickets
|
| 30 |
+
- Approve pending expenses from yesterday
|
| 31 |
+
- Assign unassigned tickets to field agents
|
| 32 |
+
- Check inventory levels
|
| 33 |
+
|
| 34 |
+
**Midday (10:00 AM - 2:00 PM)**
|
| 35 |
+
- Monitor active tickets in progress
|
| 36 |
+
- Handle reassignments (agent issues, emergencies)
|
| 37 |
+
- Approve expense claims as they come in
|
| 38 |
+
- Respond to customer escalations
|
| 39 |
+
- Track agent locations on map
|
| 40 |
+
|
| 41 |
+
**Afternoon (2:00 PM - 5:00 PM)**
|
| 42 |
+
- Review completed tickets
|
| 43 |
+
- Generate invoices for completed work
|
| 44 |
+
- Process payroll for the period
|
| 45 |
+
- Plan tomorrow's assignments
|
| 46 |
+
- Review financial position
|
| 47 |
+
|
| 48 |
+
### Pain Points to Solve
|
| 49 |
+
|
| 50 |
+
❌ **Too many clicks** - Accessing critical info requires navigation
|
| 51 |
+
❌ **No overview** - Can't see overall status at a glance
|
| 52 |
+
❌ **Manual tracking** - Spreadsheets for inventory, assignments
|
| 53 |
+
❌ **Delayed approvals** - Expenses pile up, agents wait for payment
|
| 54 |
+
❌ **Poor visibility** - Don't know where agents are or what they're doing
|
| 55 |
+
|
| 56 |
+
---
|
| 57 |
+
|
| 58 |
+
## Dashboard Layout
|
| 59 |
+
|
| 60 |
+
### Recommended Structure
|
| 61 |
+
|
| 62 |
+
```
|
| 63 |
+
┌─────────────────────────────────────────────────────────────────┐
|
| 64 |
+
│ HEADER: SwiftOps | PM Dashboard | [Notifications] [Profile] │
|
| 65 |
+
├─────────────────────────────────────────────────────────────────┤
|
| 66 |
+
│ │
|
| 67 |
+
│ ┌─────────────────────────────────────────────────────────┐ │
|
| 68 |
+
│ │ TODAY'S OVERVIEW (4 metric cards) │ │
|
| 69 |
+
│ │ [Open Tickets] [Active Agents] [Overdue] [Pending $] │ │
|
| 70 |
+
│ └─────────────────────────────────────────────────────────┘ │
|
| 71 |
+
│ │
|
| 72 |
+
│ ┌─────────────────────────────────────────────────────────┐ │
|
| 73 |
+
│ │ FINANCIAL SNAPSHOT (1 card, 4 metrics) │ │
|
| 74 |
+
│ │ Cash | Pending Expenses | Unpaid Invoices | Payroll │ │
|
| 75 |
+
│ └─────────────────────────────────────────────────────────┘ │
|
| 76 |
+
│ │
|
| 77 |
+
│ ┌─────────────────────────────────────────────────────────┐ │
|
| 78 |
+
│ │ QUICK ACTIONS (6 buttons) │ │
|
| 79 |
+
│ │ [Assign Tickets] [Approve Expenses] [Add Inventory] │ │
|
| 80 |
+
│ │ [Generate Payroll] [Create Invoice] [Add User] │ │
|
| 81 |
+
│ └─────────────────────────────────────────────────────────┘ │
|
| 82 |
+
│ │
|
| 83 |
+
│ ┌───────────────────────────┬─────────────────────────────┐ │
|
| 84 |
+
│ │ PENDING SALES ORDERS │ INVENTORY STATUS │ │
|
| 85 |
+
│ │ (List with actions) │ (Stock levels + alerts) │ │
|
| 86 |
+
│ │ │ │ │
|
| 87 |
+
│ │ 15 orders pending │ ONTs: 45 ⚠️ Low │ │
|
| 88 |
+
│ │ [View All] [Bulk Assign] │ Routers: 120 ✓ │ │
|
| 89 |
+
│ └───────────────────────────┴─────────────────────────────┘ │
|
| 90 |
+
│ │
|
| 91 |
+
│ ┌─────────────────────────────────────────────────────────┐ │
|
| 92 |
+
│ │ ACTIVE TICKETS MAP │ │
|
| 93 |
+
│ │ (Interactive map showing tickets, agents, regions) │ │
|
| 94 |
+
│ │ [Full Screen] [Filters] │ │
|
| 95 |
+
│ └─────────────────────────────────────────────────────────┘ │
|
| 96 |
+
│ │
|
| 97 |
+
│ ┌───────────────────────────┬─────────────────────────────┐ │
|
| 98 |
+
│ │ PENDING APPROVALS │ TEAM STATUS │ │
|
| 99 |
+
│ │ (Expenses, Payroll) │ (Agent availability) │ │
|
| 100 |
+
│ └───────────────────────────┴─────────────────────────────┘ │
|
| 101 |
+
│ │
|
| 102 |
+
└─────────────────────────────────────────────────────────────────┘
|
| 103 |
+
```
|
| 104 |
+
|
| 105 |
+
---
|
| 106 |
+
|
| 107 |
+
## Component Specifications
|
| 108 |
+
|
| 109 |
+
### 1. Today's Overview Cards
|
| 110 |
+
|
| 111 |
+
**Purpose:** At-a-glance metrics for daily operations
|
| 112 |
+
|
| 113 |
+
**Layout:** 4 cards in a row (responsive: 2x2 on tablet, stacked on mobile)
|
| 114 |
+
|
| 115 |
+
**Card 1: Open Tickets**
|
| 116 |
+
- **Primary Metric:** Count of unassigned tickets
|
| 117 |
+
- **Secondary Info:** "12 need assignment"
|
| 118 |
+
- **Action:** Click → Navigate to tickets page with filter `status=open`
|
| 119 |
+
- **Visual:** Orange/amber color if > 10, green if < 5
|
| 120 |
+
- **API:** `GET /tickets/stats`
|
| 121 |
+
|
| 122 |
+
**Card 2: Active Agents**
|
| 123 |
+
- **Primary Metric:** Count of agents currently working
|
| 124 |
+
- **Secondary Info:** "8 out of 25 agents"
|
| 125 |
+
- **Action:** Click → Navigate to team page
|
| 126 |
+
- **Visual:** Progress bar showing utilization
|
| 127 |
+
- **API:** `GET /ticket-assignments?status=in_progress` (count unique users)
|
| 128 |
+
|
| 129 |
+
**Card 3: Overdue Tickets**
|
| 130 |
+
- **Primary Metric:** Count of overdue tickets
|
| 131 |
+
- **Secondary Info:** "3 past SLA"
|
| 132 |
+
- **Action:** Click → Navigate to tickets page with filter `is_overdue=true`
|
| 133 |
+
- **Visual:** Red color if > 0, green if 0
|
| 134 |
+
- **API:** `GET /tickets/stats` (overdue_tickets field)
|
| 135 |
+
|
| 136 |
+
**Card 4: Pending Expenses**
|
| 137 |
+
- **Primary Metric:** Count of pending expense approvals
|
| 138 |
+
- **Secondary Info:** "KES 25,000 total"
|
| 139 |
+
- **Action:** Click → Navigate to expenses page with filter `approval_status=pending`
|
| 140 |
+
- **Visual:** Badge with count
|
| 141 |
+
- **API:** `GET /expenses/stats`
|
| 142 |
+
|
| 143 |
+
### 2. Financial Snapshot Card
|
| 144 |
+
|
| 145 |
+
**Purpose:** Quick view of financial position
|
| 146 |
+
|
| 147 |
+
**Layout:** Single card with 4 metrics in a row
|
| 148 |
+
|
| 149 |
+
**Metrics:**
|
| 150 |
+
1. **Cash Position** - Current available funds
|
| 151 |
+
2. **Pending Expenses** - Awaiting approval
|
| 152 |
+
3. **Unpaid Invoices** - Owed to contractors
|
| 153 |
+
4. **Payroll Due** - Upcoming payroll obligations
|
| 154 |
+
|
| 155 |
+
**Data Sources:**
|
| 156 |
+
- `GET /finance/cash-flow/{project_id}`
|
| 157 |
+
- `GET /expenses/stats`
|
| 158 |
+
- `GET /invoices?unpaid_only=true`
|
| 159 |
+
- `GET /payroll?status=approved&payment_status=pending`
|
| 160 |
+
|
| 161 |
+
**Visual Design:**
|
| 162 |
+
- Green for positive cash flow
|
| 163 |
+
- Amber for low cash warnings
|
| 164 |
+
- Red for negative/critical
|
| 165 |
+
|
| 166 |
+
### 3. Quick Actions Bar
|
| 167 |
+
|
| 168 |
+
**Purpose:** One-click access to common PM tasks
|
| 169 |
+
|
| 170 |
+
**Layout:** 6 buttons in 2 rows (responsive: 3x2 on tablet, stacked on mobile)
|
| 171 |
+
|
| 172 |
+
**Buttons:**
|
| 173 |
+
1. **Assign Tickets** → Opens ticket assignment modal
|
| 174 |
+
2. **Approve Expenses** → Opens expense approval queue
|
| 175 |
+
3. **Add Inventory** → Opens inventory creation form
|
| 176 |
+
4. **Generate Payroll** → Opens payroll generation wizard
|
| 177 |
+
5. **Create Invoice** → Opens invoice creation form
|
| 178 |
+
6. **Add User** → Opens user invitation form
|
| 179 |
+
|
| 180 |
+
**Design:**
|
| 181 |
+
- Icon + Label
|
| 182 |
+
- Hover state shows tooltip with description
|
| 183 |
+
- Disabled state if no pending items (e.g., "Approve Expenses" disabled if none pending)
|
| 184 |
+
|
| 185 |
+
### 4. Pending Sales Orders Widget
|
| 186 |
+
|
| 187 |
+
**Purpose:** Convert sales orders to work tickets
|
| 188 |
+
|
| 189 |
+
**Layout:** List view with inline actions
|
| 190 |
+
|
| 191 |
+
**Display:**
|
| 192 |
+
- Show top 5 pending orders
|
| 193 |
+
- Each row: Customer name, package, location, price
|
| 194 |
+
- Actions per row: [Assign Region] [Convert to Ticket]
|
| 195 |
+
- Footer: "15 total" + [View All] [Bulk Convert]
|
| 196 |
+
|
| 197 |
+
**API:** `GET /sales-orders?pending_processing=true&limit=5`
|
| 198 |
+
|
| 199 |
+
**Interactions:**
|
| 200 |
+
- **Assign Region** → Opens region selector dropdown
|
| 201 |
+
- **Convert to Ticket** → Opens ticket creation modal (pre-filled with order data)
|
| 202 |
+
- **Bulk Convert** → Opens multi-select modal for batch conversion
|
| 203 |
+
|
| 204 |
+
**Visual Indicators:**
|
| 205 |
+
- ⚠️ No region assigned
|
| 206 |
+
- ⚠️ No location coordinates
|
| 207 |
+
- ✓ Ready to convert
|
| 208 |
+
|
| 209 |
+
### 5. Inventory Status Widget
|
| 210 |
+
|
| 211 |
+
**Purpose:** Monitor stock levels and prevent shortages
|
| 212 |
+
|
| 213 |
+
**Layout:** Compact list with progress bars
|
| 214 |
+
|
| 215 |
+
**Display:**
|
| 216 |
+
- Equipment type + quantity + status indicator
|
| 217 |
+
- Progress bar showing available vs. total
|
| 218 |
+
- Alert icon for low stock (< 20% remaining)
|
| 219 |
+
|
| 220 |
+
**Example:**
|
| 221 |
+
```
|
| 222 |
+
ONTs: [████░░░░░░] 45 / 200 ⚠️ Low
|
| 223 |
+
Routers: [████████░░] 120 / 150 ✓
|
| 224 |
+
Cables: [██████████] 200 / 200 ✓
|
| 225 |
+
```
|
| 226 |
+
|
| 227 |
+
**API:** `GET /inventory?project_id={id}`
|
| 228 |
+
|
| 229 |
+
**Actions:**
|
| 230 |
+
- [Distribute to Hubs] → Opens distribution modal
|
| 231 |
+
- [Add Stock] → Opens inventory creation form
|
| 232 |
+
|
| 233 |
+
**Alert Thresholds:**
|
| 234 |
+
- Red: < 10% remaining
|
| 235 |
+
- Amber: < 20% remaining
|
| 236 |
+
- Green: > 20% remaining
|
| 237 |
+
|
| 238 |
+
### 6. Active Tickets Map
|
| 239 |
+
|
| 240 |
+
**Purpose:** Geographic visualization of operations
|
| 241 |
+
|
| 242 |
+
**Layout:** Interactive map (Google Maps, Mapbox, or Leaflet)
|
| 243 |
+
|
| 244 |
+
**Map Layers:**
|
| 245 |
+
1. **Regional Hubs** - Blue markers with coverage circles
|
| 246 |
+
2. **Open Tickets** - Red markers
|
| 247 |
+
3. **In-Progress Tickets** - Yellow markers
|
| 248 |
+
4. **Completed Tickets** - Green markers
|
| 249 |
+
5. **Field Agents** - Agent icons with real-time location
|
| 250 |
+
6. **Sales Orders** - Purple markers (pending installation sites)
|
| 251 |
+
|
| 252 |
+
**API:** `GET /map/entities?project_id={id}&entity_types=tickets,agents,regions,sales_orders`
|
| 253 |
+
|
| 254 |
+
**Interactions:**
|
| 255 |
+
- Click marker → Show popup with entity details
|
| 256 |
+
- Click agent → Show current assignment + journey trail
|
| 257 |
+
- Filter by entity type (toggle layers)
|
| 258 |
+
- [Full Screen] button → Expand to full page
|
| 259 |
+
|
| 260 |
+
**Performance:**
|
| 261 |
+
- Use marker clustering for > 50 markers
|
| 262 |
+
- Lazy load markers based on viewport
|
| 263 |
+
- Update agent positions every 30 seconds
|
| 264 |
+
|
| 265 |
+
### 7. Pending Approvals Widget
|
| 266 |
+
|
| 267 |
+
**Purpose:** Queue of items requiring PM approval
|
| 268 |
+
|
| 269 |
+
**Layout:** Tabbed interface or segmented list
|
| 270 |
+
|
| 271 |
+
**Tabs:**
|
| 272 |
+
1. **Expenses** (count badge)
|
| 273 |
+
2. **Payroll** (count badge)
|
| 274 |
+
3. **Invoices** (count badge)
|
| 275 |
+
|
| 276 |
+
**Display per Tab:**
|
| 277 |
+
- List of pending items (top 5)
|
| 278 |
+
- Each row: Submitter, amount, date, [Approve] [Reject]
|
| 279 |
+
- Footer: "12 total" + [View All]
|
| 280 |
+
|
| 281 |
+
**APIs:**
|
| 282 |
+
- `GET /expenses?approval_status=pending&limit=5`
|
| 283 |
+
- `GET /payroll?status=pending&limit=5`
|
| 284 |
+
- `GET /invoices?status=draft&limit=5`
|
| 285 |
+
|
| 286 |
+
**Bulk Actions:**
|
| 287 |
+
- [Approve All] - Approve all visible items
|
| 288 |
+
- [Review Queue] - Navigate to full approval page
|
| 289 |
+
|
| 290 |
+
### 8. Team Status Widget
|
| 291 |
+
|
| 292 |
+
**Purpose:** Monitor agent availability and workload
|
| 293 |
+
|
| 294 |
+
**Layout:** List or grid of agents
|
| 295 |
+
|
| 296 |
+
**Display:**
|
| 297 |
+
- Agent name + photo
|
| 298 |
+
- Current status (Available, On Job, Off Duty)
|
| 299 |
+
- Current assignment (if any)
|
| 300 |
+
- Location (region/area)
|
| 301 |
+
|
| 302 |
+
**API:** `GET /users?role=field_agent&is_active=true`
|
| 303 |
+
|
| 304 |
+
**Status Indicators:**
|
| 305 |
+
- 🟢 Available - No active assignment
|
| 306 |
+
- 🟡 On Job - Has active assignment
|
| 307 |
+
- 🔴 Off Duty - Not working today
|
| 308 |
+
- ⚫ Offline - No recent location update
|
| 309 |
+
|
| 310 |
+
**Interactions:**
|
| 311 |
+
- Click agent → View profile + assignment history
|
| 312 |
+
- Filter by status, region
|
| 313 |
+
|
| 314 |
+
---
|
| 315 |
+
|
| 316 |
+
## User Flows
|
| 317 |
+
|
| 318 |
+
### Flow 1: Morning Routine - Review & Assign
|
| 319 |
+
|
| 320 |
+
1. **PM logs in** → Dashboard loads
|
| 321 |
+
2. **Sees "12 Open Tickets"** → Clicks card
|
| 322 |
+
3. **Tickets page opens** → Filtered to `status=open`
|
| 323 |
+
4. **Reviews first ticket** → Clicks "Assign"
|
| 324 |
+
5. **Assignment modal opens** → Shows available agents
|
| 325 |
+
6. **Selects agent** → Clicks "Assign"
|
| 326 |
+
7. **Ticket assigned** → Notification sent to agent
|
| 327 |
+
8. **Returns to dashboard** → Counter updates to "11 Open Tickets"
|
| 328 |
+
|
| 329 |
+
**API Sequence:**
|
| 330 |
+
```
|
| 331 |
+
1. GET /tickets/stats
|
| 332 |
+
2. GET /tickets?status=open
|
| 333 |
+
3. GET /ticket-assignments/available-agents?ticket_id={id}
|
| 334 |
+
4. POST /ticket-assignments
|
| 335 |
+
5. GET /tickets/stats (refresh)
|
| 336 |
+
```
|
| 337 |
+
|
| 338 |
+
### Flow 2: Convert Sales Order to Ticket
|
| 339 |
+
|
| 340 |
+
1. **PM sees "15 Pending Sales Orders"** → Reviews list
|
| 341 |
+
2. **Clicks "Convert to Ticket"** on an order
|
| 342 |
+
3. **Modal opens** → Pre-filled with order data
|
| 343 |
+
4. **Selects priority, schedule** → Clicks "Create Ticket"
|
| 344 |
+
5. **Ticket created** → Order marked as processed
|
| 345 |
+
6. **Dashboard updates** → "14 Pending Sales Orders"
|
| 346 |
+
|
| 347 |
+
**API Sequence:**
|
| 348 |
+
```
|
| 349 |
+
1. GET /sales-orders?pending_processing=true
|
| 350 |
+
2. POST /sales-orders/{id}/promote
|
| 351 |
+
3. GET /sales-orders?pending_processing=true (refresh)
|
| 352 |
+
```
|
| 353 |
+
|
| 354 |
+
### Flow 3: Approve Expenses
|
| 355 |
+
|
| 356 |
+
1. **PM sees "5 Pending Expenses"** → Clicks widget
|
| 357 |
+
2. **Expense approval page opens**
|
| 358 |
+
3. **Reviews first expense** → Checks receipt, location
|
| 359 |
+
4. **Clicks "Approve"** → Adds approval note
|
| 360 |
+
5. **Expense approved** → Agent notified
|
| 361 |
+
6. **Returns to dashboard** → "4 Pending Expenses"
|
| 362 |
+
|
| 363 |
+
**API Sequence:**
|
| 364 |
+
```
|
| 365 |
+
1. GET /expenses?approval_status=pending
|
| 366 |
+
2. POST /expenses/{id}/approve
|
| 367 |
+
3. GET /expenses/stats (refresh)
|
| 368 |
+
```
|
| 369 |
+
|
| 370 |
+
### Flow 4: Distribute Inventory
|
| 371 |
+
|
| 372 |
+
1. **PM sees "ONTs: 45 ⚠️ Low"** → Clicks "Distribute to Hubs"
|
| 373 |
+
2. **Distribution modal opens** → Shows main office stock
|
| 374 |
+
3. **Selects region, quantity** → Clicks "Distribute"
|
| 375 |
+
4. **Inventory distributed** → Hub stock updated
|
| 376 |
+
5. **Dashboard updates** → "ONTs: 25 ⚠️ Low" (main office)
|
| 377 |
+
|
| 378 |
+
**API Sequence:**
|
| 379 |
+
```
|
| 380 |
+
1. GET /inventory?project_id={id}
|
| 381 |
+
2. POST /inventory/distributions
|
| 382 |
+
3. GET /inventory?project_id={id} (refresh)
|
| 383 |
+
```
|
| 384 |
+
|
| 385 |
+
### Flow 5: Track Agent on Map
|
| 386 |
+
|
| 387 |
+
1. **PM clicks agent marker on map**
|
| 388 |
+
2. **Popup shows** → Agent name, current assignment, status
|
| 389 |
+
3. **Clicks "View Journey"**
|
| 390 |
+
4. **Journey details load** → GPS breadcrumb trail displayed
|
| 391 |
+
5. **PM sees** → Start time, arrival time, current location
|
| 392 |
+
|
| 393 |
+
**API Sequence:**
|
| 394 |
+
```
|
| 395 |
+
1. GET /map/entities?entity_types=agents
|
| 396 |
+
2. GET /map/journey/{assignment_id}
|
| 397 |
+
```
|
| 398 |
+
|
| 399 |
+
---
|
| 400 |
+
|
| 401 |
+
## Data Refresh Strategy
|
| 402 |
+
|
| 403 |
+
### Real-Time Updates (Every 10-30 seconds)
|
| 404 |
+
- Active ticket assignments
|
| 405 |
+
- Agent locations on map
|
| 406 |
+
- Pending approvals count
|
| 407 |
+
|
| 408 |
+
### Periodic Refresh (Every 1-5 minutes)
|
| 409 |
+
- Dashboard statistics
|
| 410 |
+
- Inventory levels
|
| 411 |
+
- Financial metrics
|
| 412 |
+
|
| 413 |
+
### On-Demand Refresh
|
| 414 |
+
- After user action (assign ticket, approve expense)
|
| 415 |
+
- Manual refresh button
|
| 416 |
+
- Page focus/visibility change
|
| 417 |
+
|
| 418 |
+
### Implementation Options
|
| 419 |
+
|
| 420 |
+
**Option 1: Polling**
|
| 421 |
+
```javascript
|
| 422 |
+
// Refresh dashboard stats every 60 seconds
|
| 423 |
+
setInterval(() => {
|
| 424 |
+
fetchDashboardStats();
|
| 425 |
+
}, 60000);
|
| 426 |
+
```
|
| 427 |
+
|
| 428 |
+
**Option 2: WebSockets** (Future Enhancement)
|
| 429 |
+
```javascript
|
| 430 |
+
// Real-time updates via WebSocket
|
| 431 |
+
socket.on('ticket_assigned', (data) => {
|
| 432 |
+
updateDashboardStats();
|
| 433 |
+
});
|
| 434 |
+
```
|
| 435 |
+
|
| 436 |
+
**Option 3: Server-Sent Events** (Future Enhancement)
|
| 437 |
+
```javascript
|
| 438 |
+
// One-way real-time updates
|
| 439 |
+
const eventSource = new EventSource('/api/v1/notifications/stream');
|
| 440 |
+
eventSource.onmessage = (event) => {
|
| 441 |
+
handleUpdate(event.data);
|
| 442 |
+
};
|
| 443 |
+
```
|
| 444 |
+
|
| 445 |
+
---
|
| 446 |
+
|
| 447 |
+
## Responsive Design
|
| 448 |
+
|
| 449 |
+
### Desktop (> 1200px)
|
| 450 |
+
- Full dashboard layout as shown
|
| 451 |
+
- All widgets visible
|
| 452 |
+
- Map at comfortable size (400-600px height)
|
| 453 |
+
|
| 454 |
+
### Tablet (768px - 1200px)
|
| 455 |
+
- 2-column layout for metric cards
|
| 456 |
+
- Stacked widgets (sales orders above inventory)
|
| 457 |
+
- Collapsible sidebar for filters
|
| 458 |
+
|
| 459 |
+
### Mobile (< 768px)
|
| 460 |
+
- Single column layout
|
| 461 |
+
- Metric cards stacked
|
| 462 |
+
- Map hidden by default (accessible via tab)
|
| 463 |
+
- Bottom navigation for quick actions
|
| 464 |
+
|
| 465 |
+
---
|
| 466 |
+
|
| 467 |
+
## Accessibility
|
| 468 |
+
|
| 469 |
+
### Keyboard Navigation
|
| 470 |
+
- All actions accessible via keyboard
|
| 471 |
+
- Tab order follows visual hierarchy
|
| 472 |
+
- Escape key closes modals
|
| 473 |
+
|
| 474 |
+
### Screen Readers
|
| 475 |
+
- Proper ARIA labels on all interactive elements
|
| 476 |
+
- Status announcements for updates
|
| 477 |
+
- Descriptive button labels
|
| 478 |
+
|
| 479 |
+
### Color Contrast
|
| 480 |
+
- WCAG AA compliance minimum
|
| 481 |
+
- Don't rely solely on color for status (use icons too)
|
| 482 |
+
|
| 483 |
+
### Focus Management
|
| 484 |
+
- Clear focus indicators
|
| 485 |
+
- Focus trap in modals
|
| 486 |
+
- Return focus after modal close
|
| 487 |
+
|
| 488 |
+
---
|
| 489 |
+
|
| 490 |
+
## Performance Optimization
|
| 491 |
+
|
| 492 |
+
### Initial Load
|
| 493 |
+
- Lazy load below-the-fold widgets
|
| 494 |
+
- Skeleton screens during fetch
|
| 495 |
+
- Critical CSS inline
|
| 496 |
+
|
| 497 |
+
### Data Fetching
|
| 498 |
+
- Parallel API calls where possible
|
| 499 |
+
- Cache reference data (roles, statuses)
|
| 500 |
+
- Debounce search inputs (300ms)
|
| 501 |
+
|
| 502 |
+
### Map Rendering
|
| 503 |
+
- Marker clustering for > 50 markers
|
| 504 |
+
- Viewport-based loading
|
| 505 |
+
- Throttle zoom/pan events
|
| 506 |
+
|
| 507 |
+
### Bundle Size
|
| 508 |
+
- Code splitting by route
|
| 509 |
+
- Lazy load heavy components (map, charts)
|
| 510 |
+
- Tree shaking unused code
|
| 511 |
+
|
| 512 |
+
---
|
| 513 |
+
|
| 514 |
+
## Error Handling
|
| 515 |
+
|
| 516 |
+
### Network Errors
|
| 517 |
+
- Show toast notification
|
| 518 |
+
- Retry button for failed requests
|
| 519 |
+
- Offline indicator
|
| 520 |
+
|
| 521 |
+
### API Errors
|
| 522 |
+
- Display user-friendly error messages
|
| 523 |
+
- Log errors for debugging
|
| 524 |
+
- Fallback to cached data if available
|
| 525 |
+
|
| 526 |
+
### Empty States
|
| 527 |
+
- "No pending sales orders" with illustration
|
| 528 |
+
- "All tickets assigned" success message
|
| 529 |
+
- "No expenses to approve" with helpful tip
|
| 530 |
+
|
| 531 |
+
---
|
| 532 |
+
|
| 533 |
+
## Testing Recommendations
|
| 534 |
+
|
| 535 |
+
### Unit Tests
|
| 536 |
+
- Component rendering
|
| 537 |
+
- User interactions (clicks, form submissions)
|
| 538 |
+
- Data transformations
|
| 539 |
+
|
| 540 |
+
### Integration Tests
|
| 541 |
+
- API call sequences
|
| 542 |
+
- State management
|
| 543 |
+
- Navigation flows
|
| 544 |
+
|
| 545 |
+
### E2E Tests
|
| 546 |
+
- Critical user flows (assign ticket, approve expense)
|
| 547 |
+
- Cross-browser compatibility
|
| 548 |
+
- Mobile responsiveness
|
| 549 |
+
|
| 550 |
+
---
|
| 551 |
+
|
| 552 |
+
## Future Enhancements
|
| 553 |
+
|
| 554 |
+
### Phase 2 Features
|
| 555 |
+
- Real-time notifications (WebSockets)
|
| 556 |
+
- Advanced analytics (charts, trends)
|
| 557 |
+
- Customizable dashboard (drag-and-drop widgets)
|
| 558 |
+
- Export reports (PDF, Excel)
|
| 559 |
+
|
| 560 |
+
### Phase 3 Features
|
| 561 |
+
- AI-powered assignment recommendations
|
| 562 |
+
- Predictive inventory alerts
|
| 563 |
+
- Automated expense approval rules
|
| 564 |
+
- Voice commands for mobile
|
| 565 |
+
|
| 566 |
+
---
|
| 567 |
+
|
| 568 |
+
## Design Assets
|
| 569 |
+
|
| 570 |
+
### Color Palette
|
| 571 |
+
- **Primary:** #1976D2 (Blue)
|
| 572 |
+
- **Success:** #4CAF50 (Green)
|
| 573 |
+
- **Warning:** #FF9800 (Amber)
|
| 574 |
+
- **Error:** #F44336 (Red)
|
| 575 |
+
- **Info:** #2196F3 (Light Blue)
|
| 576 |
+
|
| 577 |
+
### Typography
|
| 578 |
+
- **Headings:** Inter, Roboto, or system font
|
| 579 |
+
- **Body:** Same as headings
|
| 580 |
+
- **Monospace:** Courier New (for IDs, codes)
|
| 581 |
+
|
| 582 |
+
### Icons
|
| 583 |
+
- Use consistent icon library (Material Icons, Feather, or Heroicons)
|
| 584 |
+
- 24px for buttons, 16px for inline icons
|
| 585 |
+
|
| 586 |
+
### Spacing
|
| 587 |
+
- Base unit: 8px
|
| 588 |
+
- Small: 8px, Medium: 16px, Large: 24px, XL: 32px
|
| 589 |
+
|
| 590 |
+
---
|
| 591 |
+
|
| 592 |
+
## Questions & Support
|
| 593 |
+
|
| 594 |
+
For design questions:
|
| 595 |
+
- UI/UX Lead: [Contact Info]
|
| 596 |
+
- Design System: [Link to Figma/Storybook]
|
| 597 |
+
|
| 598 |
+
For technical questions:
|
| 599 |
+
- See `PM_DASHBOARD_API_REFERENCE.md`
|
| 600 |
+
- Backend Team: [Contact Info]
|
| 601 |
+
|
| 602 |
+
---
|
| 603 |
+
|
| 604 |
+
**End of Document**
|
docs/api/dashboards/pm/QUICK_REFERENCE.md
ADDED
|
@@ -0,0 +1,303 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# PM Dashboard - Quick Reference
|
| 2 |
+
|
| 3 |
+
**Quick lookup for common PM operations**
|
| 4 |
+
|
| 5 |
+
---
|
| 6 |
+
|
| 7 |
+
## 🎯 Dashboard Overview
|
| 8 |
+
|
| 9 |
+
```
|
| 10 |
+
GET /api/v1/analytics/platform-admin/dashboard
|
| 11 |
+
→ All dashboard statistics in one call
|
| 12 |
+
```
|
| 13 |
+
|
| 14 |
+
---
|
| 15 |
+
|
| 16 |
+
## 📋 Sales Orders
|
| 17 |
+
|
| 18 |
+
| Action | Endpoint | Method |
|
| 19 |
+
|--------|----------|--------|
|
| 20 |
+
| List pending orders | `/sales-orders?pending_processing=true` | GET |
|
| 21 |
+
| Get stats | `/sales-orders/stats` | GET |
|
| 22 |
+
| Assign to region | `/sales-orders/{id}/assign-region` | POST |
|
| 23 |
+
| Convert to ticket | `/sales-orders/{id}/promote` | POST |
|
| 24 |
+
| Bulk convert | `/sales-orders/bulk-promote` | POST |
|
| 25 |
+
|
| 26 |
+
---
|
| 27 |
+
|
| 28 |
+
## 🎫 Tickets
|
| 29 |
+
|
| 30 |
+
| Action | Endpoint | Method |
|
| 31 |
+
|--------|----------|--------|
|
| 32 |
+
| List all tickets | `/tickets` | GET |
|
| 33 |
+
| Get stats | `/tickets/stats` | GET |
|
| 34 |
+
| Get open tickets | `/tickets?status=open` | GET |
|
| 35 |
+
| Get overdue | `/tickets?is_overdue=true` | GET |
|
| 36 |
+
| Update ticket | `/tickets/{id}` | PUT |
|
| 37 |
+
| Reschedule | `/tickets/{id}/reschedule` | POST |
|
| 38 |
+
| Cancel | `/tickets/{id}/cancel` | POST |
|
| 39 |
+
|
| 40 |
+
**Common Filters:**
|
| 41 |
+
- `status`: open, assigned, in_progress, pending_review, completed, cancelled
|
| 42 |
+
- `priority`: low, normal, high, urgent
|
| 43 |
+
- `ticket_type`: installation, support, infrastructure
|
| 44 |
+
- `project_region_id`: Filter by region
|
| 45 |
+
|
| 46 |
+
---
|
| 47 |
+
|
| 48 |
+
## 👥 Ticket Assignments
|
| 49 |
+
|
| 50 |
+
| Action | Endpoint | Method |
|
| 51 |
+
|--------|----------|--------|
|
| 52 |
+
| List assignments | `/ticket-assignments` | GET |
|
| 53 |
+
| Get available agents | `/ticket-assignments/available-agents?ticket_id={id}` | GET |
|
| 54 |
+
| Assign ticket | `/ticket-assignments` | POST |
|
| 55 |
+
| Reassign | `/ticket-assignments/{id}/reassign` | POST |
|
| 56 |
+
|
| 57 |
+
---
|
| 58 |
+
|
| 59 |
+
## 💰 Expenses
|
| 60 |
+
|
| 61 |
+
| Action | Endpoint | Method |
|
| 62 |
+
|--------|----------|--------|
|
| 63 |
+
| List expenses | `/expenses` | GET |
|
| 64 |
+
| Get stats | `/expenses/stats` | GET |
|
| 65 |
+
| Get pending | `/expenses?approval_status=pending` | GET |
|
| 66 |
+
| Approve/Reject | `/expenses/{id}/approve` | POST |
|
| 67 |
+
| Mark paid | `/expenses/{id}/mark-paid` | POST |
|
| 68 |
+
|
| 69 |
+
---
|
| 70 |
+
|
| 71 |
+
## 💵 Finance
|
| 72 |
+
|
| 73 |
+
| Action | Endpoint | Method |
|
| 74 |
+
|--------|----------|--------|
|
| 75 |
+
| List transactions | `/finance` | GET |
|
| 76 |
+
| Get cash flow | `/finance/cash-flow/{project_id}` | GET |
|
| 77 |
+
| Create transaction | `/finance` | POST |
|
| 78 |
+
| Approve | `/finance/{id}/approve` | POST |
|
| 79 |
+
|
| 80 |
+
---
|
| 81 |
+
|
| 82 |
+
## 📄 Contractor Invoices
|
| 83 |
+
|
| 84 |
+
| Action | Endpoint | Method |
|
| 85 |
+
|--------|----------|--------|
|
| 86 |
+
| List invoices | `/invoices` | GET |
|
| 87 |
+
| Get unpaid | `/invoices?unpaid_only=true` | GET |
|
| 88 |
+
| Create invoice | `/invoices` | POST |
|
| 89 |
+
| Add line item | `/invoices/{id}/line-items` | POST |
|
| 90 |
+
| Record payment | `/invoices/{id}/payments` | POST |
|
| 91 |
+
| Change status | `/invoices/{id}/status` | POST |
|
| 92 |
+
|
| 93 |
+
---
|
| 94 |
+
|
| 95 |
+
## 📦 Inventory
|
| 96 |
+
|
| 97 |
+
| Action | Endpoint | Method |
|
| 98 |
+
|--------|----------|--------|
|
| 99 |
+
| List main office | `/inventory` | GET |
|
| 100 |
+
| Create batch | `/inventory` | POST |
|
| 101 |
+
| List distributions | `/inventory/distributions` | GET |
|
| 102 |
+
| Distribute to hub | `/inventory/distributions` | POST |
|
| 103 |
+
| List assignments | `/inventory/assignments` | GET |
|
| 104 |
+
|
| 105 |
+
---
|
| 106 |
+
|
| 107 |
+
## 💼 Payroll
|
| 108 |
+
|
| 109 |
+
| Action | Endpoint | Method |
|
| 110 |
+
|--------|----------|--------|
|
| 111 |
+
| List payroll | `/payroll` | GET |
|
| 112 |
+
| Generate | `/payroll/generate` | POST |
|
| 113 |
+
| Approve | `/payroll/{id}/approve` | POST |
|
| 114 |
+
|
| 115 |
+
---
|
| 116 |
+
|
| 117 |
+
## 🗓️ Timesheets
|
| 118 |
+
|
| 119 |
+
| Action | Endpoint | Method |
|
| 120 |
+
|--------|----------|--------|
|
| 121 |
+
| List timesheets | `/timesheets` | GET |
|
| 122 |
+
| Get stats | `/timesheets/stats` | GET |
|
| 123 |
+
|
| 124 |
+
---
|
| 125 |
+
|
| 126 |
+
## 👤 Users
|
| 127 |
+
|
| 128 |
+
| Action | Endpoint | Method |
|
| 129 |
+
|--------|----------|--------|
|
| 130 |
+
| List users | `/users` | GET |
|
| 131 |
+
| Search | `/users/search?q={query}` | GET |
|
| 132 |
+
| Invite | `/invitations` | POST |
|
| 133 |
+
|
| 134 |
+
---
|
| 135 |
+
|
| 136 |
+
## 🗺️ Map & Location
|
| 137 |
+
|
| 138 |
+
| Action | Endpoint | Method |
|
| 139 |
+
|--------|----------|--------|
|
| 140 |
+
| Get all map entities | `/map/entities?project_id={id}` | GET |
|
| 141 |
+
| Get regional hubs | `/map/regions/{project_id}` | GET |
|
| 142 |
+
| Get journey details | `/map/journey/{assignment_id}` | GET |
|
| 143 |
+
| Find nearest hub | `/map/nearest-region` | GET |
|
| 144 |
+
|
| 145 |
+
---
|
| 146 |
+
|
| 147 |
+
## 🔔 Notifications
|
| 148 |
+
|
| 149 |
+
| Action | Endpoint | Method |
|
| 150 |
+
|--------|----------|--------|
|
| 151 |
+
| List notifications | `/notifications` | GET |
|
| 152 |
+
| Get unread count | `/notifications/unread-count` | GET |
|
| 153 |
+
| Mark as read | `/notifications/{id}/read` | PUT |
|
| 154 |
+
|
| 155 |
+
---
|
| 156 |
+
|
| 157 |
+
## 🔐 Authentication
|
| 158 |
+
|
| 159 |
+
```
|
| 160 |
+
POST /api/v1/auth/refresh
|
| 161 |
+
Body: { "refresh_token": "..." }
|
| 162 |
+
→ Returns new access_token
|
| 163 |
+
```
|
| 164 |
+
|
| 165 |
+
**All requests require:**
|
| 166 |
+
```
|
| 167 |
+
Authorization: Bearer {access_token}
|
| 168 |
+
```
|
| 169 |
+
|
| 170 |
+
---
|
| 171 |
+
|
| 172 |
+
## 📊 Common Response Patterns
|
| 173 |
+
|
| 174 |
+
### List Response
|
| 175 |
+
```json
|
| 176 |
+
{
|
| 177 |
+
"items": [...],
|
| 178 |
+
"total": 150,
|
| 179 |
+
"skip": 0,
|
| 180 |
+
"limit": 50
|
| 181 |
+
}
|
| 182 |
+
```
|
| 183 |
+
|
| 184 |
+
### Stats Response
|
| 185 |
+
```json
|
| 186 |
+
{
|
| 187 |
+
"total": 150,
|
| 188 |
+
"by_status": { "open": 20, "completed": 80 },
|
| 189 |
+
"by_type": { "installation": 100, "support": 50 }
|
| 190 |
+
}
|
| 191 |
+
```
|
| 192 |
+
|
| 193 |
+
### Error Response
|
| 194 |
+
```json
|
| 195 |
+
{
|
| 196 |
+
"detail": "Error message"
|
| 197 |
+
}
|
| 198 |
+
```
|
| 199 |
+
|
| 200 |
+
---
|
| 201 |
+
|
| 202 |
+
## ⚡ Quick Workflows
|
| 203 |
+
|
| 204 |
+
### Assign a Ticket
|
| 205 |
+
```
|
| 206 |
+
1. GET /ticket-assignments/available-agents?ticket_id={id}
|
| 207 |
+
2. POST /ticket-assignments
|
| 208 |
+
Body: { "ticket_id": "...", "user_id": "..." }
|
| 209 |
+
```
|
| 210 |
+
|
| 211 |
+
### Convert Sales Order to Ticket
|
| 212 |
+
```
|
| 213 |
+
1. GET /sales-orders?pending_processing=true
|
| 214 |
+
2. POST /sales-orders/{id}/promote
|
| 215 |
+
Body: { "priority": "normal", "scheduled_date": "..." }
|
| 216 |
+
```
|
| 217 |
+
|
| 218 |
+
### Approve Expense
|
| 219 |
+
```
|
| 220 |
+
1. GET /expenses?approval_status=pending
|
| 221 |
+
2. POST /expenses/{id}/approve
|
| 222 |
+
Body: { "approved": true, "notes": "..." }
|
| 223 |
+
```
|
| 224 |
+
|
| 225 |
+
### Distribute Inventory
|
| 226 |
+
```
|
| 227 |
+
1. GET /inventory?project_id={id}
|
| 228 |
+
2. POST /inventory/distributions
|
| 229 |
+
Body: { "inventory_id": "...", "project_region_id": "...", "quantity_distributed": 20 }
|
| 230 |
+
```
|
| 231 |
+
|
| 232 |
+
### Generate Payroll
|
| 233 |
+
```
|
| 234 |
+
1. GET /timesheets?from_date=...&to_date=...
|
| 235 |
+
2. POST /payroll/generate
|
| 236 |
+
Body: { "project_id": "...", "period_start": "...", "period_end": "..." }
|
| 237 |
+
```
|
| 238 |
+
|
| 239 |
+
---
|
| 240 |
+
|
| 241 |
+
## 🎨 Status Values
|
| 242 |
+
|
| 243 |
+
### Ticket Status
|
| 244 |
+
- `open` - Not assigned
|
| 245 |
+
- `assigned` - Assigned to agent
|
| 246 |
+
- `in_progress` - Agent working on it
|
| 247 |
+
- `pending_review` - Awaiting review
|
| 248 |
+
- `completed` - Done
|
| 249 |
+
- `cancelled` - Cancelled
|
| 250 |
+
|
| 251 |
+
### Sales Order Status
|
| 252 |
+
- `pending` - Awaiting processing
|
| 253 |
+
- `processed` - Converted to ticket
|
| 254 |
+
- `cancelled` - Cancelled
|
| 255 |
+
- `duplicate` - Marked as duplicate
|
| 256 |
+
|
| 257 |
+
### Expense Approval Status
|
| 258 |
+
- `pending` - Awaiting approval
|
| 259 |
+
- `approved` - Approved
|
| 260 |
+
- `rejected` - Rejected
|
| 261 |
+
|
| 262 |
+
### Payment Status
|
| 263 |
+
- `pending` - Not paid
|
| 264 |
+
- `paid` - Paid
|
| 265 |
+
|
| 266 |
+
---
|
| 267 |
+
|
| 268 |
+
## 📅 Date Formats
|
| 269 |
+
|
| 270 |
+
- **Date:** `YYYY-MM-DD` (e.g., `2025-01-20`)
|
| 271 |
+
- **DateTime:** `YYYY-MM-DDTHH:MM:SSZ` (e.g., `2025-01-20T14:30:00Z`)
|
| 272 |
+
- **Time Slots:** `morning`, `afternoon`, `evening`, `any`
|
| 273 |
+
|
| 274 |
+
---
|
| 275 |
+
|
| 276 |
+
## 🔢 Pagination
|
| 277 |
+
|
| 278 |
+
Default: `skip=0&limit=50`
|
| 279 |
+
|
| 280 |
+
Example: `/tickets?skip=0&limit=50`
|
| 281 |
+
|
| 282 |
+
---
|
| 283 |
+
|
| 284 |
+
## 🎯 Priority Levels
|
| 285 |
+
|
| 286 |
+
- `low` - Can wait
|
| 287 |
+
- `normal` - Standard priority
|
| 288 |
+
- `high` - Important
|
| 289 |
+
- `urgent` - Immediate attention
|
| 290 |
+
|
| 291 |
+
---
|
| 292 |
+
|
| 293 |
+
## 📱 Base URL
|
| 294 |
+
|
| 295 |
+
```
|
| 296 |
+
https://api.swiftops.example.com/api/v1
|
| 297 |
+
```
|
| 298 |
+
|
| 299 |
+
---
|
| 300 |
+
|
| 301 |
+
**For detailed documentation, see:**
|
| 302 |
+
- `PM_DASHBOARD_API_REFERENCE.md` - Full API details
|
| 303 |
+
- `PM_DASHBOARD_DESIGN_GUIDE.md` - UX and design specs
|
docs/api/dashboards/pm/README.md
ADDED
|
@@ -0,0 +1,376 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Project Manager Dashboard Documentation
|
| 2 |
+
|
| 3 |
+
**Complete documentation package for building the PM dashboard**
|
| 4 |
+
|
| 5 |
+
---
|
| 6 |
+
|
| 7 |
+
## 📚 Documentation Overview
|
| 8 |
+
|
| 9 |
+
This directory contains comprehensive documentation for implementing the Project Manager (PM) dashboard in the SwiftOps platform.
|
| 10 |
+
|
| 11 |
+
### Documents in This Package
|
| 12 |
+
|
| 13 |
+
1. **[PM_DASHBOARD_API_REFERENCE.md](./PM_DASHBOARD_API_REFERENCE.md)** ⭐ **START HERE**
|
| 14 |
+
- Complete API endpoint reference
|
| 15 |
+
- Request/response formats
|
| 16 |
+
- Query parameters and filters
|
| 17 |
+
- Authentication and error handling
|
| 18 |
+
- **Audience:** Frontend developers
|
| 19 |
+
|
| 20 |
+
2. **[PM_DASHBOARD_DESIGN_GUIDE.md](./PM_DASHBOARD_DESIGN_GUIDE.md)**
|
| 21 |
+
- Dashboard layout and structure
|
| 22 |
+
- Component specifications
|
| 23 |
+
- User flows and interactions
|
| 24 |
+
- Responsive design guidelines
|
| 25 |
+
- **Audience:** UI/UX designers, frontend developers
|
| 26 |
+
|
| 27 |
+
3. **[QUICK_REFERENCE.md](./QUICK_REFERENCE.md)**
|
| 28 |
+
- Cheat sheet for common operations
|
| 29 |
+
- Quick endpoint lookup
|
| 30 |
+
- Common workflows
|
| 31 |
+
- Status values and formats
|
| 32 |
+
- **Audience:** All team members
|
| 33 |
+
|
| 34 |
+
---
|
| 35 |
+
|
| 36 |
+
## 🎯 What is the PM Dashboard?
|
| 37 |
+
|
| 38 |
+
The Project Manager dashboard is the **command center** for daily field service operations. It provides:
|
| 39 |
+
|
| 40 |
+
- **Real-time visibility** across sales, operations, finance, and resources
|
| 41 |
+
- **Action-oriented interface** for quick decision-making
|
| 42 |
+
- **Geographic visualization** of field operations
|
| 43 |
+
- **Approval workflows** for expenses, payroll, and invoices
|
| 44 |
+
- **Resource management** for inventory and team allocation
|
| 45 |
+
|
| 46 |
+
### Key Capabilities
|
| 47 |
+
|
| 48 |
+
✅ Convert sales orders to work tickets
|
| 49 |
+
✅ Assign tickets to field agents
|
| 50 |
+
✅ Approve expenses and track payments
|
| 51 |
+
✅ Monitor inventory levels and distributions
|
| 52 |
+
✅ Generate payroll and contractor invoices
|
| 53 |
+
✅ Track agent locations and journeys on map
|
| 54 |
+
✅ View real-time operational metrics
|
| 55 |
+
|
| 56 |
+
---
|
| 57 |
+
|
| 58 |
+
## 🚀 Getting Started
|
| 59 |
+
|
| 60 |
+
### For Frontend Developers
|
| 61 |
+
|
| 62 |
+
1. **Read the API Reference** - [PM_DASHBOARD_API_REFERENCE.md](./PM_DASHBOARD_API_REFERENCE.md)
|
| 63 |
+
- Understand available endpoints
|
| 64 |
+
- Review request/response formats
|
| 65 |
+
- Note authentication requirements
|
| 66 |
+
|
| 67 |
+
2. **Review the Design Guide** - [PM_DASHBOARD_DESIGN_GUIDE.md](./PM_DASHBOARD_DESIGN_GUIDE.md)
|
| 68 |
+
- Understand dashboard layout
|
| 69 |
+
- Review component specifications
|
| 70 |
+
- Study user flows
|
| 71 |
+
|
| 72 |
+
3. **Use the Quick Reference** - [QUICK_REFERENCE.md](./QUICK_REFERENCE.md)
|
| 73 |
+
- Keep handy during development
|
| 74 |
+
- Quick endpoint lookup
|
| 75 |
+
- Common workflow patterns
|
| 76 |
+
|
| 77 |
+
### For UI/UX Designers
|
| 78 |
+
|
| 79 |
+
1. **Start with Design Guide** - [PM_DASHBOARD_DESIGN_GUIDE.md](./PM_DASHBOARD_DESIGN_GUIDE.md)
|
| 80 |
+
- Dashboard structure and layout
|
| 81 |
+
- Component specifications
|
| 82 |
+
- User personas and workflows
|
| 83 |
+
|
| 84 |
+
2. **Reference API capabilities** - [PM_DASHBOARD_API_REFERENCE.md](./PM_DASHBOARD_API_REFERENCE.md)
|
| 85 |
+
- Understand data availability
|
| 86 |
+
- Review filtering options
|
| 87 |
+
- Note computed fields
|
| 88 |
+
|
| 89 |
+
### For Project Managers
|
| 90 |
+
|
| 91 |
+
1. **Review Quick Reference** - [QUICK_REFERENCE.md](./QUICK_REFERENCE.md)
|
| 92 |
+
- Understand dashboard capabilities
|
| 93 |
+
- Review common workflows
|
| 94 |
+
- Provide feedback on priorities
|
| 95 |
+
|
| 96 |
+
---
|
| 97 |
+
|
| 98 |
+
## 📊 Dashboard Sections
|
| 99 |
+
|
| 100 |
+
### 1. Today's Overview
|
| 101 |
+
- Open tickets count
|
| 102 |
+
- Active agents count
|
| 103 |
+
- Overdue tickets alert
|
| 104 |
+
- Pending expenses count
|
| 105 |
+
|
| 106 |
+
### 2. Financial Snapshot
|
| 107 |
+
- Cash position
|
| 108 |
+
- Pending expenses
|
| 109 |
+
- Unpaid invoices
|
| 110 |
+
- Payroll obligations
|
| 111 |
+
|
| 112 |
+
### 3. Quick Actions
|
| 113 |
+
- Assign tickets
|
| 114 |
+
- Approve expenses
|
| 115 |
+
- Add inventory
|
| 116 |
+
- Generate payroll
|
| 117 |
+
- Create invoices
|
| 118 |
+
- Add users
|
| 119 |
+
|
| 120 |
+
### 4. Pending Sales Orders
|
| 121 |
+
- List of orders awaiting conversion
|
| 122 |
+
- Inline actions (assign region, convert to ticket)
|
| 123 |
+
- Bulk conversion capability
|
| 124 |
+
|
| 125 |
+
### 5. Active Tickets Map
|
| 126 |
+
- Geographic visualization
|
| 127 |
+
- Real-time agent locations
|
| 128 |
+
- Journey tracking
|
| 129 |
+
- Multi-layer filtering
|
| 130 |
+
|
| 131 |
+
### 6. Inventory Status
|
| 132 |
+
- Stock levels by equipment type
|
| 133 |
+
- Low stock alerts
|
| 134 |
+
- Distribution management
|
| 135 |
+
|
| 136 |
+
### 7. Pending Approvals
|
| 137 |
+
- Expenses awaiting approval
|
| 138 |
+
- Payroll pending review
|
| 139 |
+
- Draft invoices
|
| 140 |
+
|
| 141 |
+
### 8. Team Status
|
| 142 |
+
- Agent availability
|
| 143 |
+
- Current assignments
|
| 144 |
+
- Location tracking
|
| 145 |
+
|
| 146 |
+
---
|
| 147 |
+
|
| 148 |
+
## 🔑 Key API Endpoints
|
| 149 |
+
|
| 150 |
+
### Dashboard Stats
|
| 151 |
+
```
|
| 152 |
+
GET /api/v1/analytics/platform-admin/dashboard
|
| 153 |
+
```
|
| 154 |
+
|
| 155 |
+
### Sales Orders
|
| 156 |
+
```
|
| 157 |
+
GET /api/v1/sales-orders?pending_processing=true
|
| 158 |
+
POST /api/v1/sales-orders/{id}/promote
|
| 159 |
+
```
|
| 160 |
+
|
| 161 |
+
### Tickets
|
| 162 |
+
```
|
| 163 |
+
GET /api/v1/tickets?status=open
|
| 164 |
+
GET /api/v1/tickets/stats
|
| 165 |
+
POST /api/v1/ticket-assignments
|
| 166 |
+
```
|
| 167 |
+
|
| 168 |
+
### Expenses
|
| 169 |
+
```
|
| 170 |
+
GET /api/v1/expenses?approval_status=pending
|
| 171 |
+
POST /api/v1/expenses/{id}/approve
|
| 172 |
+
```
|
| 173 |
+
|
| 174 |
+
### Map
|
| 175 |
+
```
|
| 176 |
+
GET /api/v1/map/entities?project_id={id}
|
| 177 |
+
GET /api/v1/map/journey/{assignment_id}
|
| 178 |
+
```
|
| 179 |
+
|
| 180 |
+
**See [QUICK_REFERENCE.md](./QUICK_REFERENCE.md) for complete list**
|
| 181 |
+
|
| 182 |
+
---
|
| 183 |
+
|
| 184 |
+
## 🎨 Design Principles
|
| 185 |
+
|
| 186 |
+
1. **Information at a Glance** - Critical metrics visible without scrolling
|
| 187 |
+
2. **Action-Oriented** - Every metric has a corresponding action button
|
| 188 |
+
3. **Context-Aware** - Show relevant data based on time, location, status
|
| 189 |
+
4. **Progressive Disclosure** - Summary → Details ��� Actions
|
| 190 |
+
5. **Real-Time Updates** - Live data for time-sensitive operations
|
| 191 |
+
|
| 192 |
+
---
|
| 193 |
+
|
| 194 |
+
## 🔄 Data Refresh Strategy
|
| 195 |
+
|
| 196 |
+
### Real-Time (10-30 seconds)
|
| 197 |
+
- Active ticket assignments
|
| 198 |
+
- Agent locations on map
|
| 199 |
+
- Pending approvals count
|
| 200 |
+
|
| 201 |
+
### Periodic (1-5 minutes)
|
| 202 |
+
- Dashboard statistics
|
| 203 |
+
- Inventory levels
|
| 204 |
+
- Financial metrics
|
| 205 |
+
|
| 206 |
+
### On-Demand
|
| 207 |
+
- After user actions
|
| 208 |
+
- Manual refresh button
|
| 209 |
+
- Page focus change
|
| 210 |
+
|
| 211 |
+
---
|
| 212 |
+
|
| 213 |
+
## 📱 Responsive Design
|
| 214 |
+
|
| 215 |
+
### Desktop (> 1200px)
|
| 216 |
+
- Full dashboard layout
|
| 217 |
+
- All widgets visible
|
| 218 |
+
- Comfortable map size
|
| 219 |
+
|
| 220 |
+
### Tablet (768px - 1200px)
|
| 221 |
+
- 2-column layout
|
| 222 |
+
- Stacked widgets
|
| 223 |
+
- Collapsible filters
|
| 224 |
+
|
| 225 |
+
### Mobile (< 768px)
|
| 226 |
+
- Single column
|
| 227 |
+
- Stacked cards
|
| 228 |
+
- Bottom navigation
|
| 229 |
+
- Map accessible via tab
|
| 230 |
+
|
| 231 |
+
---
|
| 232 |
+
|
| 233 |
+
## 🔐 Authentication
|
| 234 |
+
|
| 235 |
+
All API requests require Bearer token authentication:
|
| 236 |
+
|
| 237 |
+
```
|
| 238 |
+
Authorization: Bearer {access_token}
|
| 239 |
+
```
|
| 240 |
+
|
| 241 |
+
**Token Refresh:**
|
| 242 |
+
```
|
| 243 |
+
POST /api/v1/auth/refresh
|
| 244 |
+
Body: { "refresh_token": "your_refresh_token" }
|
| 245 |
+
```
|
| 246 |
+
|
| 247 |
+
**See API Reference for details**
|
| 248 |
+
|
| 249 |
+
---
|
| 250 |
+
|
| 251 |
+
## ⚡ Performance Tips
|
| 252 |
+
|
| 253 |
+
1. **Lazy load** below-the-fold widgets
|
| 254 |
+
2. **Debounce** search inputs (300ms)
|
| 255 |
+
3. **Cache** reference data (roles, statuses, regions)
|
| 256 |
+
4. **Cluster** map markers when > 50 items
|
| 257 |
+
5. **Parallel** API calls where possible
|
| 258 |
+
6. **Skeleton screens** during data fetch
|
| 259 |
+
|
| 260 |
+
---
|
| 261 |
+
|
| 262 |
+
## 🧪 Testing Recommendations
|
| 263 |
+
|
| 264 |
+
### Unit Tests
|
| 265 |
+
- Component rendering
|
| 266 |
+
- User interactions
|
| 267 |
+
- Data transformations
|
| 268 |
+
|
| 269 |
+
### Integration Tests
|
| 270 |
+
- API call sequences
|
| 271 |
+
- State management
|
| 272 |
+
- Navigation flows
|
| 273 |
+
|
| 274 |
+
### E2E Tests
|
| 275 |
+
- Critical workflows (assign ticket, approve expense)
|
| 276 |
+
- Cross-browser compatibility
|
| 277 |
+
- Mobile responsiveness
|
| 278 |
+
|
| 279 |
+
---
|
| 280 |
+
|
| 281 |
+
## 📋 Implementation Checklist
|
| 282 |
+
|
| 283 |
+
### Phase 1: Core Dashboard
|
| 284 |
+
- [ ] Dashboard layout structure
|
| 285 |
+
- [ ] Today's overview cards
|
| 286 |
+
- [ ] Financial snapshot widget
|
| 287 |
+
- [ ] Quick actions bar
|
| 288 |
+
- [ ] Authentication integration
|
| 289 |
+
|
| 290 |
+
### Phase 2: Operations
|
| 291 |
+
- [ ] Pending sales orders widget
|
| 292 |
+
- [ ] Ticket list and assignment
|
| 293 |
+
- [ ] Expense approval workflow
|
| 294 |
+
- [ ] Inventory status widget
|
| 295 |
+
|
| 296 |
+
### Phase 3: Advanced Features
|
| 297 |
+
- [ ] Interactive map view
|
| 298 |
+
- [ ] Journey tracking
|
| 299 |
+
- [ ] Payroll generation
|
| 300 |
+
- [ ] Invoice management
|
| 301 |
+
|
| 302 |
+
### Phase 4: Polish
|
| 303 |
+
- [ ] Real-time updates
|
| 304 |
+
- [ ] Responsive design
|
| 305 |
+
- [ ] Error handling
|
| 306 |
+
- [ ] Performance optimization
|
| 307 |
+
|
| 308 |
+
---
|
| 309 |
+
|
| 310 |
+
## 🐛 Troubleshooting
|
| 311 |
+
|
| 312 |
+
### Common Issues
|
| 313 |
+
|
| 314 |
+
**Issue:** API returns 401 Unauthorized
|
| 315 |
+
**Solution:** Check token expiration, refresh if needed
|
| 316 |
+
|
| 317 |
+
**Issue:** Dashboard stats not loading
|
| 318 |
+
**Solution:** Verify user has PM role and project access
|
| 319 |
+
|
| 320 |
+
**Issue:** Map markers not showing
|
| 321 |
+
**Solution:** Check entity_types parameter and data availability
|
| 322 |
+
|
| 323 |
+
**Issue:** Slow performance
|
| 324 |
+
**Solution:** Implement lazy loading, reduce API call frequency
|
| 325 |
+
|
| 326 |
+
---
|
| 327 |
+
|
| 328 |
+
## 📞 Support & Resources
|
| 329 |
+
|
| 330 |
+
### Documentation
|
| 331 |
+
- **API Docs:** `/api/v1/docs` (Swagger UI)
|
| 332 |
+
- **Base URL:** `https://api.swiftops.example.com`
|
| 333 |
+
|
| 334 |
+
### Team Contacts
|
| 335 |
+
- **Backend Team:** [Contact Info]
|
| 336 |
+
- **Frontend Team:** [Contact Info]
|
| 337 |
+
- **UI/UX Team:** [Contact Info]
|
| 338 |
+
- **Product Manager:** [Contact Info]
|
| 339 |
+
|
| 340 |
+
### Related Documentation
|
| 341 |
+
- User Role Documentation: `/docs/api/user-profile/APP_MANAGEMENT_SYSTEM.md`
|
| 342 |
+
- Authentication Guide: `/docs/AUTH_API_COMPLETE.md`
|
| 343 |
+
- Finance API: `/docs/FINANCE_MANAGEMENT_IMPLEMENTATION.md`
|
| 344 |
+
|
| 345 |
+
---
|
| 346 |
+
|
| 347 |
+
## 🔄 Version History
|
| 348 |
+
|
| 349 |
+
### Version 1.0 (2025-11-19)
|
| 350 |
+
- Initial documentation release
|
| 351 |
+
- Complete API reference
|
| 352 |
+
- Design guide
|
| 353 |
+
- Quick reference
|
| 354 |
+
|
| 355 |
+
---
|
| 356 |
+
|
| 357 |
+
## 📝 Contributing
|
| 358 |
+
|
| 359 |
+
Found an issue or have suggestions?
|
| 360 |
+
|
| 361 |
+
1. Check existing documentation
|
| 362 |
+
2. Contact backend team lead
|
| 363 |
+
3. Submit feedback with specific examples
|
| 364 |
+
4. Include API endpoint and expected behavior
|
| 365 |
+
|
| 366 |
+
---
|
| 367 |
+
|
| 368 |
+
## 📄 License
|
| 369 |
+
|
| 370 |
+
Internal documentation for SwiftOps platform development team.
|
| 371 |
+
|
| 372 |
+
---
|
| 373 |
+
|
| 374 |
+
**Last Updated:** 2025-11-19
|
| 375 |
+
**Maintained By:** SwiftOps Backend Team
|
| 376 |
+
**Status:** Active Development
|
docs/hflogs/runtimeerror.txt
CHANGED
|
@@ -1,627 +1,110 @@
|
|
| 1 |
-
===== Application Startup at 2025-11-
|
| 2 |
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
|
| 102 |
-
|
| 103 |
-
|
| 104 |
-
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
|
| 110 |
-
|
| 111 |
-
INFO: 10.16.32.101:21895 - "GET /health HTTP/1.1" 200 OK
|
| 112 |
-
INFO: 10.16.42.67:42642 - "GET /health HTTP/1.1" 200 OK
|
| 113 |
-
INFO: 10.16.2.183:24496 - "GET /health HTTP/1.1" 200 OK
|
| 114 |
-
INFO: 10.16.2.183:3350 - "GET /health HTTP/1.1" 200 OK
|
| 115 |
-
INFO: 10.16.4.177:2901 - "GET /health HTTP/1.1" 200 OK
|
| 116 |
-
INFO: 10.16.2.183:35947 - "GET /health HTTP/1.1" 200 OK
|
| 117 |
-
INFO: 10.16.24.73:34289 - "GET /health HTTP/1.1" 200 OK
|
| 118 |
-
INFO: 10.16.2.183:1049 - "GET /health HTTP/1.1" 200 OK
|
| 119 |
-
INFO: 10.16.4.177:35653 - "GET /health HTTP/1.1" 200 OK
|
| 120 |
-
INFO: 10.16.2.183:51150 - "GET /health HTTP/1.1" 200 OK
|
| 121 |
-
INFO: 10.16.4.177:43279 - "GET /health HTTP/1.1" 200 OK
|
| 122 |
-
INFO: 10.16.42.67:11310 - "GET /health HTTP/1.1" 200 OK
|
| 123 |
-
INFO: 10.16.24.73:35037 - "GET /health HTTP/1.1" 200 OK
|
| 124 |
-
INFO: 10.16.24.73:54078 - "GET /health HTTP/1.1" 200 OK
|
| 125 |
-
INFO: 10.16.2.183:9083 - "GET /health HTTP/1.1" 200 OK
|
| 126 |
-
INFO: 10.16.2.183:45466 - "GET /health HTTP/1.1" 200 OK
|
| 127 |
-
INFO: 10.16.2.183:8925 - "GET /health HTTP/1.1" 200 OK
|
| 128 |
-
INFO: 10.16.42.67:43405 - "GET /health HTTP/1.1" 200 OK
|
| 129 |
-
INFO: 10.16.42.67:26416 - "GET /health HTTP/1.1" 200 OK
|
| 130 |
-
INFO: 10.16.24.73:51168 - "GET /health HTTP/1.1" 200 OK
|
| 131 |
-
INFO: 10.16.4.177:23684 - "GET /health HTTP/1.1" 200 OK
|
| 132 |
-
INFO: 10.16.42.67:45875 - "GET /health HTTP/1.1" 200 OK
|
| 133 |
-
INFO: 10.16.42.67:26455 - "GET /health HTTP/1.1" 200 OK
|
| 134 |
-
INFO: 10.16.24.73:1362 - "GET /api/v1/auth/me HTTP/1.1" 200 OK
|
| 135 |
-
INFO: 10.16.24.73:1362 - "GET /api/v1/users?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 136 |
-
INFO: 10.16.24.73:25500 - "GET /api/v1/contractors?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 137 |
-
INFO: 10.16.42.67:23487 - "GET /api/v1/clients?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 138 |
-
INFO: 10.16.2.183:24873 - "GET /health HTTP/1.1" 200 OK
|
| 139 |
-
INFO: 10.16.4.177:28689 - "GET /api/v1/audit-logs?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 140 |
-
INFO: 10.16.2.183:28579 - "GET /health HTTP/1.1" 200 OK
|
| 141 |
-
INFO: 10.16.42.67:52849 - "GET /health HTTP/1.1" 200 OK
|
| 142 |
-
INFO: 10.16.42.67:62755 - "GET /health HTTP/1.1" 200 OK
|
| 143 |
-
INFO: 10.16.24.73:28385 - "GET /health HTTP/1.1" 200 OK
|
| 144 |
-
INFO: 10.16.42.67:31797 - "GET /health HTTP/1.1" 200 OK
|
| 145 |
-
INFO: 10.16.2.183:39394 - "GET /health HTTP/1.1" 200 OK
|
| 146 |
-
INFO: 10.16.42.67:24134 - "GET /health HTTP/1.1" 200 OK
|
| 147 |
-
INFO: 10.16.24.73:36305 - "GET /health HTTP/1.1" 200 OK
|
| 148 |
-
INFO: 10.16.42.67:52657 - "GET /health HTTP/1.1" 200 OK
|
| 149 |
-
INFO: 10.16.2.183:20544 - "GET /health HTTP/1.1" 200 OK
|
| 150 |
-
INFO: 10.16.2.183:4596 - "GET /health HTTP/1.1" 200 OK
|
| 151 |
-
INFO: 10.16.24.73:39932 - "GET /health HTTP/1.1" 200 OK
|
| 152 |
-
INFO: 10.16.2.183:33709 - "GET /health HTTP/1.1" 200 OK
|
| 153 |
-
INFO: 10.16.4.177:11790 - "GET /health HTTP/1.1" 200 OK
|
| 154 |
-
INFO: 10.16.32.101:34312 - "GET /health HTTP/1.1" 200 OK
|
| 155 |
-
INFO: 10.16.42.67:1313 - "GET /health HTTP/1.1" 200 OK
|
| 156 |
-
INFO: 10.16.24.73:63949 - "GET /health HTTP/1.1" 200 OK
|
| 157 |
-
INFO: 10.16.4.177:5892 - "GET /health HTTP/1.1" 200 OK
|
| 158 |
-
INFO: 10.16.2.183:25020 - "GET /health HTTP/1.1" 200 OK
|
| 159 |
-
INFO: 10.16.2.183:31384 - "GET /health HTTP/1.1" 200 OK
|
| 160 |
-
INFO: 10.16.32.101:52843 - "GET /health HTTP/1.1" 200 OK
|
| 161 |
-
INFO: 10.16.32.101:52843 - "GET /health HTTP/1.1" 200 OK
|
| 162 |
-
INFO: 10.16.32.101:23243 - "GET /health HTTP/1.1" 200 OK
|
| 163 |
-
INFO: 10.16.4.177:46110 - "GET /health HTTP/1.1" 200 OK
|
| 164 |
-
INFO: 10.16.24.73:4614 - "GET /health HTTP/1.1" 200 OK
|
| 165 |
-
INFO: 10.16.24.73:31206 - "GET /health HTTP/1.1" 200 OK
|
| 166 |
-
INFO: 10.16.32.101:30230 - "GET /health HTTP/1.1" 200 OK
|
| 167 |
-
INFO: 10.16.42.67:53286 - "GET /health HTTP/1.1" 200 OK
|
| 168 |
-
INFO: 10.16.4.177:10592 - "GET /health HTTP/1.1" 200 OK
|
| 169 |
-
INFO: 10.16.42.67:31196 - "GET /health HTTP/1.1" 200 OK
|
| 170 |
-
INFO: 10.16.2.183:30179 - "GET /health HTTP/1.1" 200 OK
|
| 171 |
-
INFO: 10.16.4.177:13538 - "GET /health HTTP/1.1" 200 OK
|
| 172 |
-
INFO: 10.16.42.67:33157 - "GET /health HTTP/1.1" 200 OK
|
| 173 |
-
INFO: 10.16.24.73:46396 - "GET /health HTTP/1.1" 200 OK
|
| 174 |
-
INFO: 10.16.2.183:1408 - "GET /api/v1/auth/me/preferences/available-apps HTTP/1.1" 403 Forbidden
|
| 175 |
-
INFO: 10.16.4.177:56761 - "GET /health HTTP/1.1" 200 OK
|
| 176 |
-
INFO: 10.16.4.177:46932 - "GET /health HTTP/1.1" 200 OK
|
| 177 |
-
INFO: 10.16.42.67:59371 - "GET /health HTTP/1.1" 200 OK
|
| 178 |
-
INFO: 10.16.2.183:24702 - "GET /health HTTP/1.1" 200 OK
|
| 179 |
-
INFO: 10.16.42.67:44719 - "GET /health HTTP/1.1" 200 OK
|
| 180 |
-
INFO: 10.16.24.73:31374 - "GET /health HTTP/1.1" 200 OK
|
| 181 |
-
INFO: 10.16.2.183:21887 - "GET /health HTTP/1.1" 200 OK
|
| 182 |
-
INFO: 10.16.24.73:2894 - "GET /health HTTP/1.1" 200 OK
|
| 183 |
-
INFO: 10.16.4.177:45637 - "GET /health HTTP/1.1" 200 OK
|
| 184 |
-
INFO: 10.16.24.73:28334 - "GET /health HTTP/1.1" 200 OK
|
| 185 |
-
INFO: 10.16.24.73:45702 - "GET / HTTP/1.1" 200 OK
|
| 186 |
-
INFO: 10.16.42.67:46200 - "GET /health HTTP/1.1" 200 OK
|
| 187 |
-
INFO: 10.16.42.67:26422 - "GET /health HTTP/1.1" 200 OK
|
| 188 |
-
INFO: 2025-11-18T19:55:46 - app.core.supabase_auth: Session refreshed successfully
|
| 189 |
-
INFO: 2025-11-18T19:55:47 - app.api.v1.auth: ✅ Token refreshed successfully for: lewiskimaru01@gmail.com
|
| 190 |
-
INFO: 10.16.42.67:42821 - "POST /api/v1/auth/refresh-token HTTP/1.1" 200 OK
|
| 191 |
-
INFO: 10.16.42.67:45316 - "GET /health HTTP/1.1" 200 OK
|
| 192 |
-
INFO: 10.16.4.177:52344 - "GET /health HTTP/1.1" 200 OK
|
| 193 |
-
INFO: 10.16.24.73:26923 - "GET /health HTTP/1.1" 200 OK
|
| 194 |
-
INFO: 10.16.2.183:10006 - "GET /health HTTP/1.1" 200 OK
|
| 195 |
-
INFO: 10.16.42.67:28896 - "GET /health HTTP/1.1" 200 OK
|
| 196 |
-
INFO: 10.16.24.73:11808 - "GET /health HTTP/1.1" 200 OK
|
| 197 |
-
INFO: 10.16.4.177:25799 - "GET /health HTTP/1.1" 200 OK
|
| 198 |
-
INFO: 10.16.24.73:61041 - "GET /health HTTP/1.1" 200 OK
|
| 199 |
-
INFO: 10.16.24.73:3530 - "GET /health HTTP/1.1" 200 OK
|
| 200 |
-
INFO: 10.16.4.177:46326 - "GET /health HTTP/1.1" 200 OK
|
| 201 |
-
INFO: 10.16.24.73:6918 - "GET /health HTTP/1.1" 200 OK
|
| 202 |
-
INFO: 10.16.4.177:35282 - "GET /health HTTP/1.1" 200 OK
|
| 203 |
-
INFO: 10.16.4.177:12323 - "GET /health HTTP/1.1" 200 OK
|
| 204 |
-
INFO: 10.16.42.67:3473 - "GET /health HTTP/1.1" 200 OK
|
| 205 |
-
INFO: 10.16.24.73:36480 - "GET /health HTTP/1.1" 200 OK
|
| 206 |
-
INFO: 10.16.2.183:25507 - "GET /health HTTP/1.1" 200 OK
|
| 207 |
-
INFO: 10.16.24.73:17019 - "GET /health HTTP/1.1" 200 OK
|
| 208 |
-
INFO: 10.16.2.183:25230 - "GET /health HTTP/1.1" 200 OK
|
| 209 |
-
INFO: 10.16.42.67:40643 - "GET /health HTTP/1.1" 200 OK
|
| 210 |
-
INFO: 10.16.4.177:56906 - "GET /health HTTP/1.1" 200 OK
|
| 211 |
-
INFO: 10.16.4.177:43249 - "GET /health HTTP/1.1" 200 OK
|
| 212 |
-
INFO: 10.16.24.73:23472 - "GET /health HTTP/1.1" 200 OK
|
| 213 |
-
INFO: 10.16.24.73:35057 - "GET /health HTTP/1.1" 200 OK
|
| 214 |
-
INFO: 10.16.17.175:56973 - "GET /health HTTP/1.1" 200 OK
|
| 215 |
-
ERROR: 2025-11-18T19:56:11 - app.core.supabase_auth: Get user error: invalid JWT: unable to parse or verify signature, token has invalid claims: token is expired
|
| 216 |
-
WARNING: 2025-11-18T19:56:11 - app.api.deps: Invalid or expired token
|
| 217 |
-
ERROR: 2025-11-18T19:56:12 - app.core.supabase_auth: Get user error: invalid JWT: unable to parse or verify signature, token has invalid claims: token is expired
|
| 218 |
-
WARNING: 2025-11-18T19:56:12 - app.api.deps: Invalid or expired token
|
| 219 |
-
INFO: 10.16.42.67:21176 - "GET /api/v1/contractors?skip=0&limit=50 HTTP/1.1" 401 Unauthorized
|
| 220 |
-
INFO: 10.16.4.177:10227 - "GET /api/v1/clients?skip=0&limit=50 HTTP/1.1" 401 Unauthorized
|
| 221 |
-
INFO: 10.16.4.177:58943 - "GET /health HTTP/1.1" 200 OK
|
| 222 |
-
INFO: 10.16.42.67:10300 - "GET /health HTTP/1.1" 200 OK
|
| 223 |
-
INFO: 10.16.4.177:58943 - "GET /api/v1/contractors?skip=0&limit=50 HTTP/1.1" 200 OK
|
| 224 |
-
INFO: 10.16.4.177:10227 - "GET /api/v1/clients?skip=0&limit=50 HTTP/1.1" 200 OK
|
| 225 |
-
INFO: 10.16.2.183:57778 - "GET /health HTTP/1.1" 200 OK
|
| 226 |
-
INFO: 10.16.2.183:41718 - "GET /health HTTP/1.1" 200 OK
|
| 227 |
-
INFO: 10.16.17.175:58682 - "GET /health HTTP/1.1" 200 OK
|
| 228 |
-
INFO: 10.16.24.73:14242 - "GET /health HTTP/1.1" 200 OK
|
| 229 |
-
INFO: 10.16.42.67:50622 - "GET /health HTTP/1.1" 200 OK
|
| 230 |
-
INFO: 10.16.24.73:32216 - "GET /health HTTP/1.1" 200 OK
|
| 231 |
-
INFO: 10.16.42.67:64263 - "GET /health HTTP/1.1" 200 OK
|
| 232 |
-
INFO: 10.16.4.177:56807 - "GET /health HTTP/1.1" 200 OK
|
| 233 |
-
INFO: 10.16.2.183:65229 - "GET /health HTTP/1.1" 200 OK
|
| 234 |
-
INFO: 10.16.2.183:21119 - "GET /health HTTP/1.1" 200 OK
|
| 235 |
-
INFO: 10.16.24.73:54186 - "GET /health HTTP/1.1" 200 OK
|
| 236 |
-
INFO: 10.16.4.177:9018 - "GET /health HTTP/1.1" 200 OK
|
| 237 |
-
INFO: 10.16.42.67:25163 - "GET /health HTTP/1.1" 200 OK
|
| 238 |
-
INFO: 10.16.2.183:30343 - "GET /health HTTP/1.1" 200 OK
|
| 239 |
-
INFO: 10.16.4.177:53427 - "GET /health HTTP/1.1" 200 OK
|
| 240 |
-
INFO: 10.16.4.177:53427 - "GET /api/v1/auth/me HTTP/1.1" 200 OK
|
| 241 |
-
INFO: 10.16.4.177:53427 - "GET /api/v1/clients?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 242 |
-
INFO: 10.16.17.175:29023 - "GET /api/v1/contractors?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 243 |
-
INFO: 10.16.4.177:59479 - "GET /api/v1/users?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 244 |
-
INFO: 10.16.17.175:29023 - "GET /api/v1/audit-logs?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 245 |
-
INFO: 10.16.4.177:31683 - "GET /health HTTP/1.1" 200 OK
|
| 246 |
-
INFO: 10.16.24.73:62343 - "GET /api/v1/users?skip=0&limit=50 HTTP/1.1" 200 OK
|
| 247 |
-
INFO: 10.16.4.177:13211 - "GET /api/v1/audit-logs?skip=0&limit=50 HTTP/1.1" 200 OK
|
| 248 |
-
INFO: 10.16.2.183:47811 - "GET /health HTTP/1.1" 200 OK
|
| 249 |
-
INFO: 10.16.42.67:9644 - "GET /health HTTP/1.1" 200 OK
|
| 250 |
-
INFO: 10.16.4.177:45860 - "GET /health HTTP/1.1" 200 OK
|
| 251 |
-
INFO: 10.16.42.67:45768 - "GET /health HTTP/1.1" 200 OK
|
| 252 |
-
INFO: 10.16.4.177:63910 - "GET /health HTTP/1.1" 200 OK
|
| 253 |
-
INFO: 10.16.24.73:28357 - "GET /api/v1/auth/me HTTP/1.1" 200 OK
|
| 254 |
-
INFO: 10.16.42.67:1230 - "GET /health HTTP/1.1" 200 OK
|
| 255 |
-
INFO: 10.16.4.177:21445 - "GET /api/v1/auth/me/preferences HTTP/1.1" 200 OK
|
| 256 |
-
INFO: 10.16.24.73:50132 - "GET /api/v1/auth/me/preferences/available-apps HTTP/1.1" 200 OK
|
| 257 |
-
INFO: 10.16.42.67:1230 - "GET /api/v1/audit-logs?skip=0&limit=50 HTTP/1.1" 200 OK
|
| 258 |
-
INFO: 10.16.4.177:43720 - "GET /health HTTP/1.1" 200 OK
|
| 259 |
-
INFO: 10.16.4.177:56844 - "GET /health HTTP/1.1" 200 OK
|
| 260 |
-
INFO: 10.16.4.177:3583 - "GET /health HTTP/1.1" 200 OK
|
| 261 |
-
INFO: 10.16.24.73:10758 - "GET /health HTTP/1.1" 200 OK
|
| 262 |
-
INFO: 10.16.4.177:59687 - "GET /health HTTP/1.1" 200 OK
|
| 263 |
-
INFO: 10.16.24.73:10221 - "GET /health HTTP/1.1" 200 OK
|
| 264 |
-
INFO: 10.16.24.73:50998 - "GET /health HTTP/1.1" 200 OK
|
| 265 |
-
INFO: 10.16.4.177:13202 - "GET /health HTTP/1.1" 200 OK
|
| 266 |
-
INFO: 10.16.2.183:31672 - "GET /health HTTP/1.1" 200 OK
|
| 267 |
-
INFO: 10.16.17.175:20301 - "GET /health HTTP/1.1" 200 OK
|
| 268 |
-
INFO: 10.16.4.177:13530 - "GET /health HTTP/1.1" 200 OK
|
| 269 |
-
INFO: 10.16.2.183:46734 - "GET /health HTTP/1.1" 200 OK
|
| 270 |
-
INFO: 10.16.4.177:24139 - "GET /health HTTP/1.1" 200 OK
|
| 271 |
-
INFO: 10.16.17.175:36330 - "GET /health HTTP/1.1" 200 OK
|
| 272 |
-
INFO: 10.16.2.183:1526 - "GET /health HTTP/1.1" 200 OK
|
| 273 |
-
INFO: 10.16.4.177:46414 - "GET /health HTTP/1.1" 200 OK
|
| 274 |
-
INFO: 10.16.42.67:42359 - "GET /health HTTP/1.1" 200 OK
|
| 275 |
-
INFO: 10.16.42.67:27906 - "GET /health HTTP/1.1" 200 OK
|
| 276 |
-
INFO: 10.16.42.67:15813 - "GET /health HTTP/1.1" 200 OK
|
| 277 |
-
INFO: 10.16.42.67:46955 - "GET /health HTTP/1.1" 200 OK
|
| 278 |
-
INFO: 10.16.42.67:65132 - "GET /health HTTP/1.1" 200 OK
|
| 279 |
-
INFO: 10.16.42.67:31438 - "GET /health HTTP/1.1" 200 OK
|
| 280 |
-
INFO: 10.16.42.67:30436 - "GET /health HTTP/1.1" 200 OK
|
| 281 |
-
INFO: 10.16.2.183:33655 - "GET /health HTTP/1.1" 200 OK
|
| 282 |
-
INFO: 10.16.42.67:63505 - "GET /health HTTP/1.1" 200 OK
|
| 283 |
-
INFO: 10.16.42.67:31088 - "GET /health HTTP/1.1" 200 OK
|
| 284 |
-
INFO: 10.16.2.183:38008 - "GET /api/v1/contractors?skip=0&limit=50 HTTP/1.1" 200 OK
|
| 285 |
-
INFO: 10.16.4.177:62441 - "GET /api/v1/clients?skip=0&limit=50 HTTP/1.1" 200 OK
|
| 286 |
-
INFO: 10.16.17.175:36193 - "GET /health HTTP/1.1" 200 OK
|
| 287 |
-
INFO: 10.16.17.175:44411 - "GET /api/v1/users?skip=0&limit=50 HTTP/1.1" 200 OK
|
| 288 |
-
INFO: 10.16.2.183:29830 - "GET /health HTTP/1.1" 200 OK
|
| 289 |
-
INFO: 10.16.2.183:60280 - "GET /api/v1/users?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 290 |
-
INFO: 10.16.24.73:28744 - "GET /api/v1/contractors?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 291 |
-
INFO: 10.16.4.177:29046 - "GET /api/v1/clients?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 292 |
-
INFO: 10.16.2.183:60280 - "GET /api/v1/audit-logs?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 293 |
-
INFO: 10.16.2.183:54610 - "GET /health HTTP/1.1" 200 OK
|
| 294 |
-
INFO: 10.16.24.73:13586 - "GET /health HTTP/1.1" 200 OK
|
| 295 |
-
INFO: 10.16.2.183:55737 - "GET /health HTTP/1.1" 200 OK
|
| 296 |
-
INFO: 10.16.24.73:63158 - "GET /health HTTP/1.1" 200 OK
|
| 297 |
-
INFO: 10.16.4.177:13754 - "GET /health HTTP/1.1" 200 OK
|
| 298 |
-
INFO: 10.16.24.73:30613 - "GET /health HTTP/1.1" 200 OK
|
| 299 |
-
INFO: 10.16.4.177:29811 - "GET /health HTTP/1.1" 200 OK
|
| 300 |
-
INFO: 10.16.2.183:33733 - "GET /health HTTP/1.1" 200 OK
|
| 301 |
-
INFO: 10.16.2.183:33983 - "GET /health HTTP/1.1" 200 OK
|
| 302 |
-
INFO: 10.16.24.73:22716 - "GET /health HTTP/1.1" 200 OK
|
| 303 |
-
INFO: 10.16.2.183:42607 - "GET /health HTTP/1.1" 200 OK
|
| 304 |
-
INFO: 10.16.2.183:28296 - "GET /health HTTP/1.1" 200 OK
|
| 305 |
-
INFO: 10.16.42.67:2829 - "GET /health HTTP/1.1" 200 OK
|
| 306 |
-
INFO: 10.16.24.73:45531 - "GET /health HTTP/1.1" 200 OK
|
| 307 |
-
INFO: 10.16.42.67:44633 - "GET /health HTTP/1.1" 200 OK
|
| 308 |
-
INFO: 10.16.24.73:47194 - "GET /health HTTP/1.1" 200 OK
|
| 309 |
-
INFO: 2025-11-18T20:23:08 - app.core.supabase_auth: User signed in successfully: lewiskimaru01@gmail.com
|
| 310 |
-
INFO: 2025-11-18T20:23:10 - app.services.audit_service: Audit log created: login on auth by lewiskimaru01@gmail.com
|
| 311 |
-
INFO: 2025-11-18T20:23:10 - app.api.v1.auth: User logged in successfully: lewiskimaru01@gmail.com
|
| 312 |
-
INFO: 10.16.42.67:36053 - "POST /api/v1/auth/login HTTP/1.1" 200 OK
|
| 313 |
-
INFO: 10.16.2.183:50123 - "GET /api/v1/auth/me HTTP/1.1" 200 OK
|
| 314 |
-
INFO: 10.16.2.183:50123 - "GET /api/v1/clients?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 315 |
-
INFO: 10.16.4.177:35016 - "GET /api/v1/contractors?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 316 |
-
INFO: 10.16.4.177:50387 - "GET /api/v1/users?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 317 |
-
INFO: 10.16.4.177:50387 - "GET /api/v1/audit-logs?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 318 |
-
INFO: 10.16.24.73:39787 - "GET /health HTTP/1.1" 200 OK
|
| 319 |
-
INFO: 10.16.42.67:7567 - "GET /health HTTP/1.1" 200 OK
|
| 320 |
-
INFO: 10.16.42.67:38182 - "GET /health HTTP/1.1" 200 OK
|
| 321 |
-
INFO: 10.16.2.183:18679 - "GET /health HTTP/1.1" 200 OK
|
| 322 |
-
INFO: 10.16.42.67:25826 - "GET /health HTTP/1.1" 200 OK
|
| 323 |
-
INFO: 10.16.42.67:38562 - "GET /health HTTP/1.1" 200 OK
|
| 324 |
-
INFO: 10.16.24.73:40955 - "GET /health HTTP/1.1" 200 OK
|
| 325 |
-
INFO: 10.16.2.183:7240 - "GET /health HTTP/1.1" 200 OK
|
| 326 |
-
INFO: 10.16.4.177:1198 - "GET /health HTTP/1.1" 200 OK
|
| 327 |
-
INFO: 10.16.4.177:26804 - "GET /health HTTP/1.1" 200 OK
|
| 328 |
-
INFO: 10.16.24.73:25835 - "GET /health HTTP/1.1" 200 OK
|
| 329 |
-
INFO: 10.16.24.73:58339 - "GET /health HTTP/1.1" 200 OK
|
| 330 |
-
INFO: 10.16.4.177:4533 - "GET /health HTTP/1.1" 200 OK
|
| 331 |
-
INFO: 10.16.24.73:61483 - "GET /health HTTP/1.1" 200 OK
|
| 332 |
-
INFO: 10.16.4.177:20828 - "GET /health HTTP/1.1" 200 OK
|
| 333 |
-
INFO: 10.16.24.73:58786 - "GET /health HTTP/1.1" 200 OK
|
| 334 |
-
INFO: 10.16.2.183:18946 - "GET /health HTTP/1.1" 200 OK
|
| 335 |
-
INFO: 10.16.24.73:35647 - "GET /health HTTP/1.1" 200 OK
|
| 336 |
-
INFO: 10.16.2.183:1081 - "GET /health HTTP/1.1" 200 OK
|
| 337 |
-
INFO: 10.16.4.177:52734 - "GET /health HTTP/1.1" 200 OK
|
| 338 |
-
INFO: 10.16.24.73:2465 - "GET /health HTTP/1.1" 200 OK
|
| 339 |
-
INFO: 10.16.42.67:59547 - "GET /health HTTP/1.1" 200 OK
|
| 340 |
-
INFO: 10.16.42.67:14987 - "GET /health HTTP/1.1" 200 OK
|
| 341 |
-
INFO: 10.16.2.183:8051 - "GET /health HTTP/1.1" 200 OK
|
| 342 |
-
INFO: 10.16.2.183:52270 - "GET /health HTTP/1.1" 200 OK
|
| 343 |
-
INFO: 10.16.2.183:52799 - "GET /health HTTP/1.1" 200 OK
|
| 344 |
-
INFO: 10.16.42.67:23702 - "GET /health HTTP/1.1" 200 OK
|
| 345 |
-
INFO: 10.16.24.73:24357 - "GET /health HTTP/1.1" 200 OK
|
| 346 |
-
INFO: 10.16.42.67:58261 - "GET /health HTTP/1.1" 200 OK
|
| 347 |
-
INFO: 10.16.24.73:51569 - "GET /health HTTP/1.1" 200 OK
|
| 348 |
-
INFO: 10.16.24.73:32527 - "GET /health HTTP/1.1" 200 OK
|
| 349 |
-
INFO: 10.16.2.183:1599 - "GET /health HTTP/1.1" 200 OK
|
| 350 |
-
INFO: 10.16.24.73:12838 - "GET /health HTTP/1.1" 200 OK
|
| 351 |
-
INFO: 10.16.2.183:15752 - "GET /health HTTP/1.1" 200 OK
|
| 352 |
-
INFO: 10.16.2.183:36166 - "GET /health HTTP/1.1" 200 OK
|
| 353 |
-
INFO: 10.16.24.73:39485 - "GET /health HTTP/1.1" 200 OK
|
| 354 |
-
INFO: 10.16.4.177:65051 - "GET /health HTTP/1.1" 200 OK
|
| 355 |
-
INFO: 10.16.2.183:34587 - "GET /health HTTP/1.1" 200 OK
|
| 356 |
-
INFO: 10.16.2.183:13415 - "GET /api/v1/users?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 357 |
-
INFO: 10.16.42.67:3804 - "GET /api/v1/contractors?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 358 |
-
INFO: 10.16.4.177:9240 - "GET /health HTTP/1.1" 200 OK
|
| 359 |
-
INFO: 10.16.2.183:50707 - "GET /api/v1/clients?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 360 |
-
INFO: 10.16.2.183:13415 - "GET /api/v1/contractors?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 361 |
-
INFO: 10.16.4.177:26930 - "GET /api/v1/users?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 362 |
-
INFO: 10.16.42.67:3804 - "GET /api/v1/clients?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 363 |
-
INFO: 10.16.2.183:13415 - "GET /api/v1/audit-logs?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 364 |
-
INFO: 10.16.24.73:3887 - "GET /api/v1/contractors?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 365 |
-
INFO: 10.16.2.183:50707 - "GET /api/v1/users?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 366 |
-
INFO: 10.16.42.67:3804 - "GET /api/v1/clients?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 367 |
-
INFO: 10.16.2.183:13415 - "GET /api/v1/contractors?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 368 |
-
INFO: 10.16.24.73:3887 - "GET /api/v1/users?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 369 |
-
INFO: 10.16.2.183:50707 - "GET /api/v1/clients?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 370 |
-
INFO: 10.16.2.183:50707 - "GET /api/v1/contractors?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 371 |
-
INFO: 10.16.2.183:45066 - "GET /api/v1/users?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 372 |
-
INFO: 10.16.24.73:51559 - "GET /api/v1/clients?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 373 |
-
INFO: 10.16.2.183:50707 - "GET /api/v1/contractors?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 374 |
-
INFO: 10.16.42.67:46099 - "GET /api/v1/users?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 375 |
-
INFO: 10.16.2.183:45066 - "GET /api/v1/clients?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 376 |
-
INFO: 10.16.42.67:47734 - "GET /api/v1/contractors?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 377 |
-
INFO: 10.16.42.67:46099 - "GET /api/v1/users?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 378 |
-
INFO: 10.16.42.67:2643 - "GET /api/v1/clients?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 379 |
-
INFO: 10.16.24.73:56243 - "GET /health HTTP/1.1" 200 OK
|
| 380 |
-
INFO: 10.16.42.67:8311 - "GET /health HTTP/1.1" 200 OK
|
| 381 |
-
INFO: 10.16.42.67:41171 - "GET /health HTTP/1.1" 200 OK
|
| 382 |
-
INFO: 10.16.24.73:5179 - "GET /api/v1/auth/me HTTP/1.1" 200 OK
|
| 383 |
-
INFO: 10.16.42.67:49760 - "GET /api/v1/clients?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 384 |
-
INFO: 10.16.4.177:4968 - "GET /api/v1/users?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 385 |
-
INFO: 10.16.4.177:6371 - "GET /api/v1/contractors?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 386 |
-
INFO: 10.16.24.73:63807 - "GET /health HTTP/1.1" 200 OK
|
| 387 |
-
INFO: 10.16.24.73:7825 - "GET /health HTTP/1.1" 200 OK
|
| 388 |
-
INFO: 10.16.42.67:41712 - "GET /health HTTP/1.1" 200 OK
|
| 389 |
-
INFO: 10.16.24.73:59247 - "GET /health HTTP/1.1" 200 OK
|
| 390 |
-
INFO: 10.16.4.177:8578 - "GET /health HTTP/1.1" 200 OK
|
| 391 |
-
INFO: 10.16.4.177:15840 - "GET /health HTTP/1.1" 200 OK
|
| 392 |
-
INFO: 10.16.2.183:55237 - "GET /health HTTP/1.1" 200 OK
|
| 393 |
-
INFO: 10.16.2.183:1281 - "GET /health HTTP/1.1" 200 OK
|
| 394 |
-
INFO: 10.16.4.177:55913 - "GET /health HTTP/1.1" 200 OK
|
| 395 |
-
INFO: 10.16.4.177:23927 - "GET /health HTTP/1.1" 200 OK
|
| 396 |
-
INFO: 10.16.2.183:39887 - "GET /health HTTP/1.1" 200 OK
|
| 397 |
-
INFO: 10.16.42.67:47296 - "GET /health HTTP/1.1" 200 OK
|
| 398 |
-
ERROR: 2025-11-18T20:57:44 - app.core.supabase_auth: Get user error: invalid JWT: unable to parse or verify signature, token has invalid claims: token is expired
|
| 399 |
-
WARNING: 2025-11-18T20:57:44 - app.api.deps: Invalid or expired token
|
| 400 |
-
INFO: 10.16.42.67:18104 - "GET /health HTTP/1.1" 200 OK
|
| 401 |
-
INFO: 10.16.24.73:54913 - "GET /health HTTP/1.1" 200 OK
|
| 402 |
-
INFO: 10.16.2.183:52230 - "GET /health HTTP/1.1" 200 OK
|
| 403 |
-
INFO: 10.16.24.73:15341 - "GET /health HTTP/1.1" 200 OK
|
| 404 |
-
INFO: 10.16.24.73:62813 - "GET /health HTTP/1.1" 200 OK
|
| 405 |
-
INFO: 10.16.2.183:54376 - "GET /health HTTP/1.1" 200 OK
|
| 406 |
-
INFO: 10.16.2.183:25092 - "GET /health HTTP/1.1" 200 OK
|
| 407 |
-
INFO: 10.16.2.183:2732 - "GET /health HTTP/1.1" 200 OK
|
| 408 |
-
INFO: 10.16.4.177:54053 - "GET /health HTTP/1.1" 200 OK
|
| 409 |
-
INFO: 10.16.42.67:1458 - "GET /health HTTP/1.1" 200 OK
|
| 410 |
-
INFO: 10.16.2.183:1970 - "GET /health HTTP/1.1" 200 OK
|
| 411 |
-
INFO: 10.16.2.183:39171 - "GET /health HTTP/1.1" 200 OK
|
| 412 |
-
INFO: 10.16.2.183:31631 - "GET /health HTTP/1.1" 200 OK
|
| 413 |
-
INFO: 2025-11-18T20:57:58 - app.core.supabase_auth: Session refreshed successfully
|
| 414 |
-
INFO: 2025-11-18T20:57:58 - app.api.v1.auth: ✅ Token refreshed successfully for: lewiskimaru01@gmail.com
|
| 415 |
-
INFO: 10.16.2.183:46306 - "GET /health HTTP/1.1" 200 OK
|
| 416 |
-
INFO: 10.16.2.183:57772 - "GET /health HTTP/1.1" 200 OK
|
| 417 |
-
INFO: 10.16.2.183:16281 - "GET /health HTTP/1.1" 200 OK
|
| 418 |
-
INFO: 10.16.42.67:28690 - "GET /health HTTP/1.1" 200 OK
|
| 419 |
-
INFO: 10.16.24.73:61506 - "GET /health HTTP/1.1" 200 OK
|
| 420 |
-
INFO: 10.16.32.101:49923 - "GET /health HTTP/1.1" 200 OK
|
| 421 |
-
INFO: 10.16.42.67:54183 - "GET /health HTTP/1.1" 200 OK
|
| 422 |
-
INFO: 10.16.42.67:54878 - "GET /health HTTP/1.1" 200 OK
|
| 423 |
-
INFO: 10.16.42.67:7134 - "GET /health HTTP/1.1" 200 OK
|
| 424 |
-
INFO: 10.16.32.101:26991 - "GET /health HTTP/1.1" 200 OK
|
| 425 |
-
INFO: 10.16.32.101:35984 - "GET /health HTTP/1.1" 200 OK
|
| 426 |
-
INFO: 10.16.24.73:23627 - "GET /health HTTP/1.1" 200 OK
|
| 427 |
-
INFO: 10.16.2.183:60025 - "GET /health HTTP/1.1" 200 OK
|
| 428 |
-
INFO: 10.16.32.101:21380 - "GET /health HTTP/1.1" 200 OK
|
| 429 |
-
INFO: 10.16.42.67:7066 - "GET /health HTTP/1.1" 200 OK
|
| 430 |
-
INFO: 10.16.2.183:19222 - "GET /health HTTP/1.1" 200 OK
|
| 431 |
-
INFO: 10.16.32.101:39468 - "GET /health HTTP/1.1" 200 OK
|
| 432 |
-
INFO: 10.16.2.183:38508 - "GET /health HTTP/1.1" 200 OK
|
| 433 |
-
INFO: 10.16.4.177:36127 - "GET /health HTTP/1.1" 200 OK
|
| 434 |
-
INFO: 10.16.24.73:47417 - "GET /health HTTP/1.1" 200 OK
|
| 435 |
-
INFO: 10.16.2.183:48815 - "GET /health HTTP/1.1" 200 OK
|
| 436 |
-
INFO: 10.16.4.177:47884 - "GET /health HTTP/1.1" 200 OK
|
| 437 |
-
INFO: 10.16.24.73:6357 - "GET /health HTTP/1.1" 200 OK
|
| 438 |
-
INFO: 10.16.32.101:3181 - "GET /api/v1/auth/me HTTP/1.1" 200 OK
|
| 439 |
-
INFO: 10.16.2.183:21053 - "GET /health HTTP/1.1" 200 OK
|
| 440 |
-
INFO: 10.16.24.73:25442 - "GET /api/v1/auth/me/preferences HTTP/1.1" 200 OK
|
| 441 |
-
INFO: 10.16.2.183:28211 - "GET /api/v1/auth/me/preferences/available-apps HTTP/1.1" 200 OK
|
| 442 |
-
INFO: 10.16.32.101:3181 - "GET /api/v1/users?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 443 |
-
INFO: 10.16.2.183:21053 - "GET /api/v1/contractors?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 444 |
-
INFO: 10.16.24.73:46513 - "GET /api/v1/clients?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 445 |
-
INFO: 10.16.4.177:26166 - "GET /api/v1/audit-logs?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 446 |
-
INFO: 10.16.42.67:26501 - "GET /health HTTP/1.1" 200 OK
|
| 447 |
-
INFO: 10.16.42.67:58512 - "GET /health HTTP/1.1" 200 OK
|
| 448 |
-
INFO: 10.16.2.183:22407 - "GET /health HTTP/1.1" 200 OK
|
| 449 |
-
INFO: 10.16.2.183:17473 - "GET /health HTTP/1.1" 200 OK
|
| 450 |
-
INFO: 2025-11-18T20:59:43 - app.core.supabase_auth: User signed in successfully: lewiskimaru01@gmail.com
|
| 451 |
-
INFO: 2025-11-18T20:59:45 - app.services.audit_service: Audit log created: login on auth by lewiskimaru01@gmail.com
|
| 452 |
-
INFO: 2025-11-18T20:59:45 - app.api.v1.auth: User logged in successfully: lewiskimaru01@gmail.com
|
| 453 |
-
INFO: 10.16.42.67:33772 - "POST /api/v1/auth/login HTTP/1.1" 200 OK
|
| 454 |
-
INFO: 10.16.42.67:33772 - "GET /api/v1/auth/me HTTP/1.1" 200 OK
|
| 455 |
-
INFO: 10.16.42.67:33772 - "GET /api/v1/contractors?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 456 |
-
INFO: 10.16.24.73:8023 - "GET /api/v1/clients?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 457 |
-
INFO: 10.16.4.177:35710 - "GET /api/v1/users?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 458 |
-
INFO: 10.16.42.67:33772 - "GET /health HTTP/1.1" 200 OK
|
| 459 |
-
INFO: 10.16.42.67:32061 - "GET /api/v1/audit-logs?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 460 |
-
INFO: 10.16.24.73:12751 - "GET /health HTTP/1.1" 200 OK
|
| 461 |
-
INFO: 10.16.24.73:39562 - "GET /health HTTP/1.1" 200 OK
|
| 462 |
-
INFO: 10.16.2.183:28946 - "GET /health HTTP/1.1" 200 OK
|
| 463 |
-
INFO: 10.16.24.73:61189 - "GET /health HTTP/1.1" 200 OK
|
| 464 |
-
INFO: 10.16.4.177:1872 - "GET /health HTTP/1.1" 200 OK
|
| 465 |
-
INFO: 10.16.42.67:2928 - "GET /health HTTP/1.1" 200 OK
|
| 466 |
-
INFO: 10.16.24.73:6668 - "GET /health HTTP/1.1" 200 OK
|
| 467 |
-
INFO: 10.16.2.183:9599 - "GET /health HTTP/1.1" 200 OK
|
| 468 |
-
INFO: 10.16.42.67:17623 - "GET /health HTTP/1.1" 200 OK
|
| 469 |
-
INFO: 10.16.42.67:14762 - "GET /health HTTP/1.1" 200 OK
|
| 470 |
-
INFO: 10.16.24.73:43216 - "GET /health HTTP/1.1" 200 OK
|
| 471 |
-
INFO: 10.16.42.67:17685 - "GET /health HTTP/1.1" 200 OK
|
| 472 |
-
INFO: 10.16.24.73:48382 - "GET /health HTTP/1.1" 200 OK
|
| 473 |
-
INFO: 10.16.4.177:2652 - "GET /health HTTP/1.1" 200 OK
|
| 474 |
-
INFO: 10.16.24.73:53262 - "GET /health HTTP/1.1" 200 OK
|
| 475 |
-
INFO: 10.16.42.67:47692 - "GET /health HTTP/1.1" 200 OK
|
| 476 |
-
INFO: 10.16.4.177:64326 - "GET /health HTTP/1.1" 200 OK
|
| 477 |
-
INFO: 10.16.42.67:7307 - "GET /health HTTP/1.1" 200 OK
|
| 478 |
-
INFO: 10.16.2.183:25534 - "GET /health HTTP/1.1" 200 OK
|
| 479 |
-
INFO: 10.16.42.67:52068 - "GET /api/v1/auth/me HTTP/1.1" 200 OK
|
| 480 |
-
INFO: 10.16.2.183:19931 - "GET /api/v1/auth/me/preferences HTTP/1.1" 200 OK
|
| 481 |
-
INFO: 10.16.4.177:4433 - "GET /api/v1/auth/me/preferences/available-apps HTTP/1.1" 200 OK
|
| 482 |
-
INFO: 10.16.42.67:52068 - "GET /api/v1/users?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 483 |
-
INFO: 10.16.2.183:25534 - "GET /api/v1/contractors?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 484 |
-
INFO: 10.16.4.177:4433 - "GET /health HTTP/1.1" 200 OK
|
| 485 |
-
INFO: 10.16.4.177:37222 - "GET /api/v1/clients?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 486 |
-
INFO: 10.16.42.67:12340 - "GET /api/v1/audit-logs?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 487 |
-
INFO: 10.16.2.183:17646 - "GET /health HTTP/1.1" 200 OK
|
| 488 |
-
INFO: 10.16.4.177:56071 - "GET /health HTTP/1.1" 200 OK
|
| 489 |
-
INFO: 10.16.24.73:3415 - "GET /health HTTP/1.1" 200 OK
|
| 490 |
-
INFO: 10.16.2.183:49486 - "GET /health HTTP/1.1" 200 OK
|
| 491 |
-
INFO: 10.16.2.183:49486 - "GET /health HTTP/1.1" 200 OK
|
| 492 |
-
INFO: 10.16.42.67:2060 - "GET /health HTTP/1.1" 200 OK
|
| 493 |
-
INFO: 10.16.4.177:63825 - "GET /health HTTP/1.1" 200 OK
|
| 494 |
-
INFO: 10.16.4.177:37926 - "GET /health HTTP/1.1" 200 OK
|
| 495 |
-
INFO: 10.16.24.73:28604 - "GET /health HTTP/1.1" 200 OK
|
| 496 |
-
ERROR: 2025-11-19T04:37:19 - app.core.supabase_auth: Session refresh error: Invalid Refresh Token: Already Used
|
| 497 |
-
ERROR: 2025-11-19T04:37:19 - app.api.v1.auth: ❌ Token refresh error: Invalid Refresh Token: Already Used
|
| 498 |
-
ERROR: 2025-11-19T04:37:19 - app.core.supabase_auth: Get user error: invalid JWT: unable to parse or verify signature, token has invalid claims: token is expired
|
| 499 |
-
WARNING: 2025-11-19T04:37:19 - app.api.deps: Invalid or expired token
|
| 500 |
-
ERROR: 2025-11-19T04:37:20 - app.core.supabase_auth: Get user error: invalid JWT: unable to parse or verify signature, token has invalid claims: token is expired
|
| 501 |
-
WARNING: 2025-11-19T04:37:20 - app.api.deps: Invalid or expired token
|
| 502 |
-
ERROR: 2025-11-19T04:37:20 - app.core.supabase_auth: Get user error: invalid JWT: unable to parse or verify signature, token has invalid claims: token is expired
|
| 503 |
-
WARNING: 2025-11-19T04:37:20 - app.api.deps: Invalid or expired token
|
| 504 |
-
INFO: 10.16.24.73:33660 - "POST /api/v1/auth/refresh-token HTTP/1.1" 401 Unauthorized
|
| 505 |
-
INFO: 10.16.24.73:34541 - "GET /api/v1/auth/me/preferences HTTP/1.1" 401 Unauthorized
|
| 506 |
-
INFO: 10.16.32.101:40596 - "GET /api/v1/auth/me HTTP/1.1" 401 Unauthorized
|
| 507 |
-
INFO: 10.16.2.183:34221 - "GET /api/v1/auth/me/preferences/available-apps HTTP/1.1" 401 Unauthorized
|
| 508 |
-
INFO: 10.16.42.67:8059 - "GET /health HTTP/1.1" 200 OK
|
| 509 |
-
INFO: 10.16.2.183:48493 - "GET /health HTTP/1.1" 200 OK
|
| 510 |
-
INFO: 10.16.32.101:9358 - "GET /health HTTP/1.1" 200 OK
|
| 511 |
-
INFO: 10.16.32.101:9358 - "GET /health HTTP/1.1" 200 OK
|
| 512 |
-
INFO: 10.16.2.183:8594 - "GET /health HTTP/1.1" 200 OK
|
| 513 |
-
INFO: 10.16.24.73:57651 - "GET /health HTTP/1.1" 200 OK
|
| 514 |
-
INFO: 2025-11-19T04:40:11 - app.core.supabase_auth: User signed in successfully: lewiskimaru01@gmail.com
|
| 515 |
-
INFO: 2025-11-19T04:40:12 - app.services.audit_service: Audit log created: login on auth by lewiskimaru01@gmail.com
|
| 516 |
-
INFO: 2025-11-19T04:40:12 - app.api.v1.auth: User logged in successfully: lewiskimaru01@gmail.com
|
| 517 |
-
INFO: 10.16.2.183:6394 - "POST /api/v1/auth/login HTTP/1.1" 200 OK
|
| 518 |
-
INFO: 10.16.2.183:6394 - "GET /api/v1/auth/me HTTP/1.1" 200 OK
|
| 519 |
-
INFO: 10.16.2.183:6394 - "GET /api/v1/clients?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 520 |
-
INFO: 10.16.24.73:42530 - "GET /api/v1/contractors?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 521 |
-
INFO: 10.16.32.101:33933 - "GET /api/v1/users?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 522 |
-
INFO: 10.16.32.101:33933 - "GET /api/v1/audit-logs?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 523 |
-
INFO: 10.16.2.183:26743 - "GET /health HTTP/1.1" 200 OK
|
| 524 |
-
INFO: 10.16.24.73:42664 - "GET /health HTTP/1.1" 200 OK
|
| 525 |
-
INFO: 10.16.24.73:15309 - "GET /api/v1/auth/me HTTP/1.1" 200 OK
|
| 526 |
-
INFO: 10.16.32.101:35036 - "GET /api/v1/auth/me/preferences/available-apps HTTP/1.1" 200 OK
|
| 527 |
-
INFO: 10.16.2.183:43122 - "GET /api/v1/auth/me/preferences HTTP/1.1" 200 OK
|
| 528 |
-
INFO: 10.16.2.183:16243 - "GET /api/v1/clients?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 529 |
-
INFO: 10.16.32.101:52836 - "GET /api/v1/contractors?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 530 |
-
INFO: 10.16.42.67:1154 - "GET /api/v1/users?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 531 |
-
INFO: 10.16.24.73:12930 - "GET /api/v1/audit-logs?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 532 |
-
INFO: 10.16.32.101:58437 - "GET /health HTTP/1.1" 200 OK
|
| 533 |
-
INFO: 2025-11-19T04:42:58 - app.core.supabase_auth: Session refreshed successfully
|
| 534 |
-
INFO: 2025-11-19T04:42:59 - app.api.v1.auth: ✅ Token refreshed successfully for: lewiskimaru01@gmail.com
|
| 535 |
-
INFO: 10.16.29.62:60594 - "POST /api/v1/auth/refresh-token HTTP/1.1" 200 OK
|
| 536 |
-
ERROR: 2025-11-19T04:42:59 - app.core.supabase_auth: Get user error: invalid JWT: unable to parse or verify signature, token has invalid claims: token is expired
|
| 537 |
-
WARNING: 2025-11-19T04:42:59 - app.api.deps: Invalid or expired token
|
| 538 |
-
ERROR: 2025-11-19T04:42:59 - app.core.supabase_auth: Get user error: invalid JWT: unable to parse or verify signature, token has invalid claims: token is expired
|
| 539 |
-
WARNING: 2025-11-19T04:42:59 - app.api.deps: Invalid or expired token
|
| 540 |
-
ERROR: 2025-11-19T04:42:59 - app.core.supabase_auth: Get user error: invalid JWT: unable to parse or verify signature, token has invalid claims: token is expired
|
| 541 |
-
WARNING: 2025-11-19T04:42:59 - app.api.deps: Invalid or expired token
|
| 542 |
-
INFO: 10.16.2.183:39737 - "GET /api/v1/auth/me/preferences HTTP/1.1" 401 Unauthorized
|
| 543 |
-
INFO: 10.16.24.73:1491 - "GET /api/v1/auth/me HTTP/1.1" 401 Unauthorized
|
| 544 |
-
INFO: 10.16.29.62:12374 - "GET /api/v1/auth/me/preferences/available-apps HTTP/1.1" 401 Unauthorized
|
| 545 |
-
INFO: 10.16.24.73:1491 - "GET /health HTTP/1.1" 200 OK
|
| 546 |
-
INFO: 2025-11-19T04:43:30 - app.core.supabase_auth: User signed in successfully: lewiskimaru01@gmail.com
|
| 547 |
-
INFO: 2025-11-19T04:43:32 - app.services.audit_service: Audit log created: login on auth by lewiskimaru01@gmail.com
|
| 548 |
-
INFO: 2025-11-19T04:43:32 - app.api.v1.auth: User logged in successfully: lewiskimaru01@gmail.com
|
| 549 |
-
INFO: 10.16.2.183:44311 - "POST /api/v1/auth/login HTTP/1.1" 200 OK
|
| 550 |
-
INFO: 10.16.24.73:33537 - "GET /api/v1/auth/me HTTP/1.1" 200 OK
|
| 551 |
-
INFO: 10.16.24.73:33537 - "GET /api/v1/clients?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 552 |
-
INFO: 10.16.29.62:37849 - "GET /api/v1/contractors?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 553 |
-
INFO: 10.16.32.101:29195 - "GET /api/v1/users?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 554 |
-
INFO: 10.16.32.101:29195 - "GET /api/v1/audit-logs?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 555 |
-
INFO: 10.16.32.101:28157 - "GET /api/v1/auth/me HTTP/1.1" 200 OK
|
| 556 |
-
INFO: 10.16.32.101:30477 - "GET /health HTTP/1.1" 200 OK
|
| 557 |
-
INFO: 10.16.29.62:51264 - "GET /api/v1/auth/me/preferences HTTP/1.1" 200 OK
|
| 558 |
-
INFO: 10.16.32.101:32205 - "GET /api/v1/auth/me/preferences/available-apps HTTP/1.1" 200 OK
|
| 559 |
-
INFO: 10.16.29.62:17615 - "GET /api/v1/clients?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 560 |
-
INFO: 10.16.42.67:6702 - "GET /api/v1/contractors?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 561 |
-
INFO: 10.16.42.67:4910 - "GET /api/v1/users?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 562 |
-
INFO: 10.16.42.67:4910 - "GET /api/v1/audit-logs?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 563 |
-
INFO: 10.16.42.67:44047 - "GET /api/v1/clients?skip=0&limit=50 HTTP/1.1" 200 OK
|
| 564 |
-
INFO: 10.16.24.73:16591 - "GET /api/v1/contractors?skip=0&limit=50 HTTP/1.1" 200 OK
|
| 565 |
-
INFO: 10.16.32.101:58521 - "GET /health HTTP/1.1" 200 OK
|
| 566 |
-
INFO: 10.16.24.73:34404 - "GET /api/v1/users?skip=0&limit=50 HTTP/1.1" 200 OK
|
| 567 |
-
INFO: 10.16.24.73:44278 - "GET /api/v1/audit-logs?skip=0&limit=50 HTTP/1.1" 200 OK
|
| 568 |
-
INFO: 10.16.42.67:50328 - "GET /health HTTP/1.1" 200 OK
|
| 569 |
-
INFO: 10.16.42.67:10442 - "GET /health HTTP/1.1" 200 OK
|
| 570 |
-
INFO: 10.16.29.62:10878 - "GET /api/v1/auth/me/preferences HTTP/1.1" 200 OK
|
| 571 |
-
INFO: 10.16.32.101:46692 - "GET /api/v1/auth/me HTTP/1.1" 200 OK
|
| 572 |
-
INFO: 10.16.2.183:1137 - "GET /health HTTP/1.1" 200 OK
|
| 573 |
-
INFO: 10.16.32.101:25681 - "GET /api/v1/auth/me/preferences/available-apps HTTP/1.1" 200 OK
|
| 574 |
-
INFO: 10.16.24.73:64236 - "GET /api/v1/clients?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 575 |
-
INFO: 10.16.2.183:39926 - "GET /api/v1/users?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 576 |
-
INFO: 10.16.24.73:39456 - "GET /api/v1/contractors?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 577 |
-
INFO: 10.16.2.183:39926 - "GET /api/v1/audit-logs?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 578 |
-
INFO: 10.16.32.101:60235 - "GET /health HTTP/1.1" 200 OK
|
| 579 |
-
INFO: 10.16.32.101:11361 - "GET /health HTTP/1.1" 200 OK
|
| 580 |
-
INFO: 10.16.32.101:22289 - "GET /health HTTP/1.1" 200 OK
|
| 581 |
-
INFO: 10.16.24.73:14015 - "GET /health HTTP/1.1" 200 OK
|
| 582 |
-
INFO: 10.16.42.67:18436 - "GET /health HTTP/1.1" 200 OK
|
| 583 |
-
INFO: 10.16.32.101:55877 - "GET /health HTTP/1.1" 200 OK
|
| 584 |
-
INFO: 10.16.24.73:52870 - "GET /health HTTP/1.1" 200 OK
|
| 585 |
-
INFO: 2025-11-19T05:10:14 - app.core.supabase_auth: Session refreshed successfully
|
| 586 |
-
INFO: 2025-11-19T05:10:16 - app.api.v1.auth: ✅ Token refreshed successfully for: kamirujoel2000@gmail.com
|
| 587 |
-
INFO: 10.16.42.67:60173 - "POST /api/v1/auth/refresh-token HTTP/1.1" 200 OK
|
| 588 |
-
ERROR: 2025-11-19T05:10:16 - app.core.supabase_auth: Get user error: invalid JWT: unable to parse or verify signature, token has invalid claims: token is expired
|
| 589 |
-
WARNING: 2025-11-19T05:10:16 - app.api.deps: Invalid or expired token
|
| 590 |
-
ERROR: 2025-11-19T05:10:16 - app.core.supabase_auth: Get user error: invalid JWT: unable to parse or verify signature, token has invalid claims: token is expired
|
| 591 |
-
WARNING: 2025-11-19T05:10:16 - app.api.deps: Invalid or expired token
|
| 592 |
-
ERROR: 2025-11-19T05:10:17 - app.core.supabase_auth: Get user error: invalid JWT: unable to parse or verify signature, token has invalid claims: token is expired
|
| 593 |
-
WARNING: 2025-11-19T05:10:17 - app.api.deps: Invalid or expired token
|
| 594 |
-
INFO: 10.16.24.73:7288 - "GET /api/v1/auth/me HTTP/1.1" 401 Unauthorized
|
| 595 |
-
ERROR: 2025-11-19T05:10:17 - app.core.supabase_auth: Get user error: invalid JWT: unable to parse or verify signature, token has invalid claims: token is expired
|
| 596 |
-
WARNING: 2025-11-19T05:10:17 - app.api.deps: Invalid or expired token
|
| 597 |
-
INFO: 10.16.2.183:16465 - "GET /api/v1/clients?skip=0&limit=100 HTTP/1.1" 401 Unauthorized
|
| 598 |
-
INFO: 10.16.2.183:62132 - "GET /api/v1/users?skip=0&limit=100 HTTP/1.1" 401 Unauthorized
|
| 599 |
-
INFO: 10.16.2.183:47393 - "GET /api/v1/contractors?skip=0&limit=100 HTTP/1.1" 401 Unauthorized
|
| 600 |
-
INFO: 10.16.42.67:57285 - "GET /health HTTP/1.1" 200 OK
|
| 601 |
-
INFO: 2025-11-19T07:30:23 - app.core.supabase_auth: Session refreshed successfully
|
| 602 |
-
INFO: 2025-11-19T07:30:25 - app.api.v1.auth: ✅ Token refreshed successfully for: lewiskimaru01@gmail.com
|
| 603 |
-
INFO: 10.16.42.67:51262 - "POST /api/v1/auth/refresh-token HTTP/1.1" 200 OK
|
| 604 |
-
ERROR: 2025-11-19T07:30:26 - app.core.supabase_auth: Get user error: invalid JWT: unable to parse or verify signature, token has invalid claims: token is expired
|
| 605 |
-
WARNING: 2025-11-19T07:30:26 - app.api.deps: Invalid or expired token
|
| 606 |
-
ERROR: 2025-11-19T07:30:26 - app.core.supabase_auth: Get user error: invalid JWT: unable to parse or verify signature, token has invalid claims: token is expired
|
| 607 |
-
WARNING: 2025-11-19T07:30:26 - app.api.deps: Invalid or expired token
|
| 608 |
-
ERROR: 2025-11-19T07:30:26 - app.core.supabase_auth: Get user error: invalid JWT: unable to parse or verify signature, token has invalid claims: token is expired
|
| 609 |
-
WARNING: 2025-11-19T07:30:26 - app.api.deps: Invalid or expired token
|
| 610 |
-
INFO: 10.16.2.183:13623 - "GET /api/v1/auth/me HTTP/1.1" 401 Unauthorized
|
| 611 |
-
INFO: 10.16.32.101:65493 - "GET /api/v1/auth/me/preferences/available-apps HTTP/1.1" 401 Unauthorized
|
| 612 |
-
INFO: 10.16.32.101:63769 - "GET /api/v1/auth/me/preferences HTTP/1.1" 401 Unauthorized
|
| 613 |
-
INFO: 2025-11-19T07:30:49 - app.core.supabase_auth: User signed in successfully: lewiskimaru01@gmail.com
|
| 614 |
-
INFO: 2025-11-19T07:30:52 - app.services.audit_service: Audit log created: login on auth by lewiskimaru01@gmail.com
|
| 615 |
-
INFO: 2025-11-19T07:30:52 - app.api.v1.auth: User logged in successfully: lewiskimaru01@gmail.com
|
| 616 |
-
INFO: 10.16.2.183:60486 - "POST /api/v1/auth/login HTTP/1.1" 200 OK
|
| 617 |
-
INFO: 10.16.24.73:55086 - "GET /api/v1/auth/me HTTP/1.1" 200 OK
|
| 618 |
-
INFO: 10.16.32.101:27054 - "GET /api/v1/contractors?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 619 |
-
INFO: 10.16.42.67:5575 - "GET /api/v1/clients?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 620 |
-
INFO: 10.16.32.101:16146 - "GET /api/v1/users?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 621 |
-
INFO: 10.16.2.183:56271 - "GET /api/v1/audit-logs?skip=0&limit=20 HTTP/1.1" 200 OK
|
| 622 |
-
INFO: 10.16.32.101:35137 - "GET /health HTTP/1.1" 200 OK
|
| 623 |
-
INFO: 10.16.24.73:29699 - "GET /health HTTP/1.1" 200 OK
|
| 624 |
-
INFO: 10.16.2.183:8281 - "GET /health HTTP/1.1" 200 OK
|
| 625 |
-
INFO: 10.16.2.183:34724 - "GET /health HTTP/1.1" 200 OK
|
| 626 |
-
INFO: 10.16.2.183:44681 - "GET /health HTTP/1.1" 200 OK
|
| 627 |
-
INFO: 10.16.2.183:43318 - "GET /health HTTP/1.1" 200 OK
|
|
|
|
| 1 |
+
===== Application Startup at 2025-11-19 10:47:20 =====
|
| 2 |
|
| 3 |
+
Traceback (most recent call last):
|
| 4 |
+
File "/usr/local/bin/uvicorn", line 8, in <module>
|
| 5 |
+
sys.exit(main())
|
| 6 |
+
^^^^^^
|
| 7 |
+
File "/usr/local/lib/python3.11/site-packages/click/core.py", line 1485, in __call__
|
| 8 |
+
return self.main(*args, **kwargs)
|
| 9 |
+
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| 10 |
+
File "/usr/local/lib/python3.11/site-packages/click/core.py", line 1406, in main
|
| 11 |
+
rv = self.invoke(ctx)
|
| 12 |
+
^^^^^^^^^^^^^^^^
|
| 13 |
+
File "/usr/local/lib/python3.11/site-packages/click/core.py", line 1269, in invoke
|
| 14 |
+
return ctx.invoke(self.callback, **ctx.params)
|
| 15 |
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| 16 |
+
File "/usr/local/lib/python3.11/site-packages/click/core.py", line 824, in invoke
|
| 17 |
+
return callback(*args, **kwargs)
|
| 18 |
+
^^^^^^^^^^^^^^^^^^^^^^^^^
|
| 19 |
+
File "/usr/local/lib/python3.11/site-packages/uvicorn/main.py", line 416, in main
|
| 20 |
+
run(
|
| 21 |
+
File "/usr/local/lib/python3.11/site-packages/uvicorn/main.py", line 587, in run
|
| 22 |
+
server.run()
|
| 23 |
+
File "/usr/local/lib/python3.11/site-packages/uvicorn/server.py", line 61, in run
|
| 24 |
+
return asyncio.run(self.serve(sockets=sockets))
|
| 25 |
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| 26 |
+
File "/usr/local/lib/python3.11/asyncio/runners.py", line 190, in run
|
| 27 |
+
return runner.run(main)
|
| 28 |
+
^^^^^^^^^^^^^^^^
|
| 29 |
+
File "/usr/local/lib/python3.11/asyncio/runners.py", line 118, in run
|
| 30 |
+
return self._loop.run_until_complete(task)
|
| 31 |
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| 32 |
+
File "uvloop/loop.pyx", line 1518, in uvloop.loop.Loop.run_until_complete
|
| 33 |
+
File "/usr/local/lib/python3.11/site-packages/uvicorn/server.py", line 68, in serve
|
| 34 |
+
config.load()
|
| 35 |
+
File "/usr/local/lib/python3.11/site-packages/uvicorn/config.py", line 467, in load
|
| 36 |
+
self.loaded_app = import_from_string(self.app)
|
| 37 |
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| 38 |
+
File "/usr/local/lib/python3.11/site-packages/uvicorn/importer.py", line 21, in import_from_string
|
| 39 |
+
module = importlib.import_module(module_str)
|
| 40 |
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| 41 |
+
File "/usr/local/lib/python3.11/importlib/__init__.py", line 126, in import_module
|
| 42 |
+
return _bootstrap._gcd_import(name[level:], package, level)
|
| 43 |
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| 44 |
+
File "<frozen importlib._bootstrap>", line 1204, in _gcd_import
|
| 45 |
+
File "<frozen importlib._bootstrap>", line 1176, in _find_and_load
|
| 46 |
+
File "<frozen importlib._bootstrap>", line 1147, in _find_and_load_unlocked
|
| 47 |
+
File "<frozen importlib._bootstrap>", line 690, in _load_unlocked
|
| 48 |
+
File "<frozen importlib._bootstrap_external>", line 940, in exec_module
|
| 49 |
+
File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
|
| 50 |
+
File "/app/src/app/main.py", line 141, in <module>
|
| 51 |
+
from app.api.v1.router import api_router
|
| 52 |
+
File "/app/src/app/api/v1/router.py", line 5, in <module>
|
| 53 |
+
from app.api.v1 import (
|
| 54 |
+
File "/app/src/app/api/v1/expenses.py", line 18, in <module>
|
| 55 |
+
from app.core.database import get_db
|
| 56 |
+
ImportError: cannot import name 'get_db' from 'app.core.database' (/app/src/app/core/database.py)
|
| 57 |
+
Traceback (most recent call last):
|
| 58 |
+
File "/usr/local/bin/uvicorn", line 8, in <module>
|
| 59 |
+
sys.exit(main())
|
| 60 |
+
^^^^^^
|
| 61 |
+
File "/usr/local/lib/python3.11/site-packages/click/core.py", line 1485, in __call__
|
| 62 |
+
return self.main(*args, **kwargs)
|
| 63 |
+
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| 64 |
+
File "/usr/local/lib/python3.11/site-packages/click/core.py", line 1406, in main
|
| 65 |
+
rv = self.invoke(ctx)
|
| 66 |
+
^^^^^^^^^^^^^^^^
|
| 67 |
+
File "/usr/local/lib/python3.11/site-packages/click/core.py", line 1269, in invoke
|
| 68 |
+
return ctx.invoke(self.callback, **ctx.params)
|
| 69 |
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| 70 |
+
File "/usr/local/lib/python3.11/site-packages/click/core.py", line 824, in invoke
|
| 71 |
+
return callback(*args, **kwargs)
|
| 72 |
+
^^^^^^^^^^^^^^^^^^^^^^^^^
|
| 73 |
+
File "/usr/local/lib/python3.11/site-packages/uvicorn/main.py", line 416, in main
|
| 74 |
+
run(
|
| 75 |
+
File "/usr/local/lib/python3.11/site-packages/uvicorn/main.py", line 587, in run
|
| 76 |
+
server.run()
|
| 77 |
+
File "/usr/local/lib/python3.11/site-packages/uvicorn/server.py", line 61, in run
|
| 78 |
+
return asyncio.run(self.serve(sockets=sockets))
|
| 79 |
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| 80 |
+
File "/usr/local/lib/python3.11/asyncio/runners.py", line 190, in run
|
| 81 |
+
return runner.run(main)
|
| 82 |
+
^^^^^^^^^^^^^^^^
|
| 83 |
+
File "/usr/local/lib/python3.11/asyncio/runners.py", line 118, in run
|
| 84 |
+
return self._loop.run_until_complete(task)
|
| 85 |
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| 86 |
+
File "uvloop/loop.pyx", line 1518, in uvloop.loop.Loop.run_until_complete
|
| 87 |
+
File "/usr/local/lib/python3.11/site-packages/uvicorn/server.py", line 68, in serve
|
| 88 |
+
config.load()
|
| 89 |
+
File "/usr/local/lib/python3.11/site-packages/uvicorn/config.py", line 467, in load
|
| 90 |
+
self.loaded_app = import_from_string(self.app)
|
| 91 |
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| 92 |
+
File "/usr/local/lib/python3.11/site-packages/uvicorn/importer.py", line 21, in import_from_string
|
| 93 |
+
module = importlib.import_module(module_str)
|
| 94 |
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| 95 |
+
File "/usr/local/lib/python3.11/importlib/__init__.py", line 126, in import_module
|
| 96 |
+
return _bootstrap._gcd_import(name[level:], package, level)
|
| 97 |
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| 98 |
+
File "<frozen importlib._bootstrap>", line 1204, in _gcd_import
|
| 99 |
+
File "<frozen importlib._bootstrap>", line 1176, in _find_and_load
|
| 100 |
+
File "<frozen importlib._bootstrap>", line 1147, in _find_and_load_unlocked
|
| 101 |
+
File "<frozen importlib._bootstrap>", line 690, in _load_unlocked
|
| 102 |
+
File "<frozen importlib._bootstrap_external>", line 940, in exec_module
|
| 103 |
+
File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
|
| 104 |
+
File "/app/src/app/main.py", line 141, in <module>
|
| 105 |
+
from app.api.v1.router import api_router
|
| 106 |
+
File "/app/src/app/api/v1/router.py", line 5, in <module>
|
| 107 |
+
from app.api.v1 import (
|
| 108 |
+
File "/app/src/app/api/v1/expenses.py", line 18, in <module>
|
| 109 |
+
from app.core.database import get_db
|
| 110 |
+
ImportError: cannot import name 'get_db' from 'app.core.database' (/app/src/app/core/database.py)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/app/api/v1/expenses.py
CHANGED
|
@@ -15,8 +15,7 @@ from sqlalchemy.orm import Session
|
|
| 15 |
from typing import Optional, List
|
| 16 |
from uuid import UUID
|
| 17 |
|
| 18 |
-
from app.
|
| 19 |
-
from app.core.auth import get_current_user
|
| 20 |
from app.models.user import User
|
| 21 |
from app.schemas.ticket_expense import (
|
| 22 |
TicketExpenseCreate,
|
|
|
|
| 15 |
from typing import Optional, List
|
| 16 |
from uuid import UUID
|
| 17 |
|
| 18 |
+
from app.api.deps import get_db, get_current_user
|
|
|
|
| 19 |
from app.models.user import User
|
| 20 |
from app.schemas.ticket_expense import (
|
| 21 |
TicketExpenseCreate,
|
src/app/api/v1/incident_reports.py
CHANGED
|
@@ -13,8 +13,7 @@ from sqlalchemy.orm import Session
|
|
| 13 |
from typing import List, Optional
|
| 14 |
from uuid import UUID
|
| 15 |
|
| 16 |
-
from app.
|
| 17 |
-
from app.core.auth import get_current_user
|
| 18 |
from app.models.user import User
|
| 19 |
from app.schemas.ticket_progress import (
|
| 20 |
TicketIncidentReportCreate,
|
|
|
|
| 13 |
from typing import List, Optional
|
| 14 |
from uuid import UUID
|
| 15 |
|
| 16 |
+
from app.api.deps import get_db, get_current_user
|
|
|
|
| 17 |
from app.models.user import User
|
| 18 |
from app.schemas.ticket_progress import (
|
| 19 |
TicketIncidentReportCreate,
|
src/app/api/v1/progress_reports.py
CHANGED
|
@@ -14,8 +14,7 @@ from sqlalchemy.orm import Session
|
|
| 14 |
from typing import List, Optional
|
| 15 |
from uuid import UUID
|
| 16 |
|
| 17 |
-
from app.
|
| 18 |
-
from app.core.auth import get_current_user
|
| 19 |
from app.models.user import User
|
| 20 |
from app.schemas.ticket_progress import (
|
| 21 |
TicketProgressReportCreate,
|
|
|
|
| 14 |
from typing import List, Optional
|
| 15 |
from uuid import UUID
|
| 16 |
|
| 17 |
+
from app.api.deps import get_db, get_current_user
|
|
|
|
| 18 |
from app.models.user import User
|
| 19 |
from app.schemas.ticket_progress import (
|
| 20 |
TicketProgressReportCreate,
|
tests/integration/test_auth_audit_logs.py
CHANGED
|
@@ -18,7 +18,7 @@ from sqlalchemy.orm import Session
|
|
| 18 |
from fastapi.testclient import TestClient
|
| 19 |
|
| 20 |
from app.main import app
|
| 21 |
-
from app.
|
| 22 |
from app.models.user import User
|
| 23 |
from app.models.audit_log import AuditLog
|
| 24 |
from app.services.password_reset_service import PasswordResetService
|
|
|
|
| 18 |
from fastapi.testclient import TestClient
|
| 19 |
|
| 20 |
from app.main import app
|
| 21 |
+
from app.api.deps import get_db
|
| 22 |
from app.models.user import User
|
| 23 |
from app.models.audit_log import AuditLog
|
| 24 |
from app.services.password_reset_service import PasswordResetService
|
tests/integration/test_password_reset.py
CHANGED
|
@@ -16,7 +16,7 @@ from sqlalchemy.orm import Session
|
|
| 16 |
from fastapi.testclient import TestClient
|
| 17 |
|
| 18 |
from app.main import app
|
| 19 |
-
from app.
|
| 20 |
from app.models.user import User
|
| 21 |
from app.models.invitation import UserInvitation
|
| 22 |
from app.models.audit_log import AuditLog
|
|
|
|
| 16 |
from fastapi.testclient import TestClient
|
| 17 |
|
| 18 |
from app.main import app
|
| 19 |
+
from app.api.deps import get_db
|
| 20 |
from app.models.user import User
|
| 21 |
from app.models.invitation import UserInvitation
|
| 22 |
from app.models.audit_log import AuditLog
|