Spaces:
Sleeping
Sleeping
Project Overview Endpoint
Purpose
Single endpoint that replaces 4 separate calls to get complete project structure. Returns project details, regions, roles, subcontractors, and team info based on user permissions.
Replaces:
GET /projects/{id}GET /projects/{id}/regionsGET /projects/{id}/project-rolesGET /projects/{id}/subcontractors
Endpoint
GET /api/v1/projects/{project_id}/overview
Query Params:
refresh(optional):trueto force cache refresh
Cache: 12 hours
Response Structure
For Managers/Admins
{
"project": {
"id": "uuid",
"title": "Project Name",
"project_type": "customer_service",
"status": "active",
"client_id": "uuid",
"client_name": "Client Name",
"contractor_id": "uuid",
"contractor_name": "Contractor Name",
"primary_manager_id": "uuid",
"primary_manager_name": "Manager Name",
"service_type": "ftth",
"planned_start_date": "2025-01-01",
"planned_end_date": "2025-12-31",
"activation_requirements": [...],
"photo_requirements": [...],
"budget": {...},
"is_closed": false,
"created_at": "2025-01-01T00:00:00Z"
},
"regions": [
{
"id": "uuid",
"region_name": "Nairobi West",
"region_code": "NRB-W",
"manager_id": "uuid",
"manager_name": "Regional Manager",
"is_active": true,
"city": "Nairobi",
"latitude": -1.2921,
"longitude": 36.8219
}
],
"roles": [
{
"id": "uuid",
"role_name": "Technician",
"compensation_type": "commission",
"commission_percentage": 15.0,
"base_amount": 500.0,
"is_active": true
}
],
"subcontractors": [
{
"id": "uuid",
"subcontractor_id": "uuid",
"subcontractor_name": "SubCo Ltd",
"scope_description": "Installation work",
"project_region_id": "uuid",
"region_name": "Nairobi West",
"contract_value": 50000.0,
"is_active": true
}
],
"team_summary": {
"total_members": 25,
"by_role": {
"field_agent": 15,
"dispatcher": 3,
"sales_agent": 5,
"project_manager": 2
},
"by_region": {
"Nairobi West": 10,
"Mombasa": 8,
"Project-wide": 7
}
},
"my_involvement": null,
"cached_at": "2025-12-02T10:00:00Z",
"cache_expires_in_seconds": 43200
}
For Field Agents/Sales Agents
{
"project": {
"id": "uuid",
"title": "Project Name",
"project_type": "customer_service",
"status": "active",
"client_name": "Client Name",
"contractor_name": "Contractor Name",
"service_type": "ftth",
"activation_requirements": [...],
"photo_requirements": [...]
},
"regions": [
{
"id": "uuid",
"region_name": "Nairobi West",
"is_active": true,
"city": "Nairobi"
}
],
"roles": null,
"subcontractors": null,
"team_summary": null,
"my_involvement": {
"user_id": "uuid",
"user_name": "John Doe",
"user_email": "john@example.com",
"user_role": "field_agent",
"team_role": "technician",
"project_role_id": "uuid",
"project_role_name": "Senior Technician",
"assigned_region_id": "uuid",
"assigned_region_name": "Nairobi West",
"is_lead": false,
"assigned_at": "2025-01-15T08:00:00Z",
"subcontractor_id": null,
"subcontractor_name": null
},
"cached_at": "2025-12-02T10:00:00Z",
"cache_expires_in_seconds": 43200
}
Frontend Usage
Display Project Overview Page
// Fetch overview
const response = await fetch(`/api/v1/projects/${projectId}/overview`);
const data = await response.json();
// Show project header
showProjectHeader({
title: data.project.title,
status: data.project.status,
client: data.project.client_name,
contractor: data.project.contractor_name
});
// Show regions (all users see all regions)
data.regions.forEach(region => {
const isMyRegion = data.my_involvement?.assigned_region_id === region.id;
renderRegionCard(region, isMyRegion); // Highlight user's region
});
// Role-specific rendering
if (data.my_involvement) {
// Field agent/sales agent view
showMyInvolvement({
role: data.my_involvement.team_role,
region: data.my_involvement.assigned_region_name,
projectRole: data.my_involvement.project_role_name
});
} else {
// Manager/admin view
showRoles(data.roles);
showSubcontractors(data.subcontractors);
showTeamSummary(data.team_summary);
}
Check User's Region Assignment
// Highlight user's assigned region in UI
const myRegionId = data.my_involvement?.assigned_region_id;
data.regions.forEach(region => {
const card = createRegionCard(region);
if (region.id === myRegionId) {
card.classList.add('my-region', 'highlighted');
}
});
Display Requirements (Field Agents)
// Show what photos are required
data.project.photo_requirements.forEach(req => {
console.log(`${req.type}: ${req.min_photos}-${req.max_photos} photos`);
});
// Show activation form fields
data.project.activation_requirements.forEach(field => {
renderFormField({
name: field.field,
label: field.label,
type: field.type,
required: field.required,
options: field.options
});
});
Key Points
- Single call - Replaces 4 separate API calls
- Role-based - Response adapts to user permissions automatically
- Long cache - 12 hours (structure rarely changes)
- All see regions - Everyone sees all regions, UI highlights user's assigned region
- Field agents - See their involvement only, not other team members
- Managers - See complete project structure and team composition
Error Responses
404- Project not found403- User not authorized to access project500- Server error