723 lines
14 KiB
Markdown
723 lines
14 KiB
Markdown
# API Documentation
|
|
|
|
The Romanoff Fire Alarm Management System provides a RESTful API for programmatic access to all data. All API endpoints are prefixed with `/api`.
|
|
|
|
## Base URL
|
|
|
|
```
|
|
http://localhost:5000/api
|
|
```
|
|
|
|
## Response Format
|
|
|
|
All API responses are JSON. Successful responses return the requested data directly. Error responses include appropriate HTTP status codes.
|
|
|
|
## Endpoints
|
|
|
|
### Dashboard Statistics
|
|
|
|
#### Get Dashboard Stats
|
|
|
|
```
|
|
GET /api/stats
|
|
```
|
|
|
|
Returns aggregated statistics for the dashboard.
|
|
|
|
**Response**
|
|
|
|
```json
|
|
{
|
|
"total_jobs": 25,
|
|
"total_budget": 1500000.00,
|
|
"total_labor": 450000.00,
|
|
"total_material": 350000.00,
|
|
"avg_completion": 65.5,
|
|
"completed_jobs": 8,
|
|
"in_progress_jobs": 15,
|
|
"not_started_jobs": 2,
|
|
"vendor_budgets": {
|
|
"Vendor A": 750000.00,
|
|
"Vendor B": 500000.00,
|
|
"Unknown": 250000.00
|
|
},
|
|
"pm_jobs": {
|
|
"John Smith": {
|
|
"count": 10,
|
|
"budget": 600000.00
|
|
},
|
|
"Jane Doe": {
|
|
"count": 8,
|
|
"budget": 500000.00
|
|
}
|
|
},
|
|
"jobs_completion": [
|
|
{
|
|
"id": 1,
|
|
"job_number": "JOB-001",
|
|
"name": "Project Alpha",
|
|
"completion": 75.0,
|
|
"budget": 50000.00,
|
|
"pm_assigned": "John Smith"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Jobs
|
|
|
|
#### List All Jobs
|
|
|
|
```
|
|
GET /api/jobs
|
|
```
|
|
|
|
Returns a list of all jobs.
|
|
|
|
**Response**
|
|
|
|
```json
|
|
[
|
|
{
|
|
"id": 1,
|
|
"job_number": "JOB-001",
|
|
"job_name": "Project Alpha",
|
|
"location": "123 Main St, Raleigh, NC",
|
|
"percent_complete": 0.75,
|
|
"est_starting_qtr": "Q1 2025",
|
|
"fire_alarm_budget": 50000.00,
|
|
"labor_estimate": 20000.00,
|
|
"material_estimate": 15000.00,
|
|
"amount_left_on_contract": 15000.00,
|
|
"pm_assigned": "John Smith",
|
|
"aor": "Region A",
|
|
"fire_vendor": "Vendor A",
|
|
"install_partner": "Partner Inc",
|
|
"ps_or_install": "Install",
|
|
"subcontractor": "Sub Co",
|
|
"pci": "Yes",
|
|
"voip_or_phone": "VoIP",
|
|
"plans": "Approved",
|
|
"notes": "Project notes here",
|
|
"issues": "No major issues",
|
|
"milestone_1": "Permits obtained",
|
|
"milestone_2": "Rough-in complete",
|
|
"milestone_3": null,
|
|
"milestone_4": null,
|
|
"milestone_5": null,
|
|
"milestone_6": null,
|
|
"milestone_7": null,
|
|
"elevator_final": "2025-03-15",
|
|
"pretest": "2025-04-01",
|
|
"final_date": "2025-04-15",
|
|
"co_drop_dead_date": "2025-04-30",
|
|
"number_of_units": 150,
|
|
"sep_club_house": "Yes",
|
|
"created_at": "2025-01-01T00:00:00",
|
|
"updated_at": "2025-01-15T12:30:00"
|
|
}
|
|
]
|
|
```
|
|
|
|
#### Get Single Job
|
|
|
|
```
|
|
GET /api/jobs/<id>
|
|
```
|
|
|
|
Returns a single job by ID.
|
|
|
|
**Parameters**
|
|
|
|
| Name | Type | Description |
|
|
|------|------|-------------|
|
|
| id | integer | Job ID (path parameter) |
|
|
|
|
**Response**
|
|
|
|
Returns a job object (same structure as list item above).
|
|
|
|
**Errors**
|
|
|
|
| Status | Description |
|
|
|--------|-------------|
|
|
| 404 | Job not found |
|
|
|
|
#### Create Job
|
|
|
|
```
|
|
POST /api/jobs
|
|
```
|
|
|
|
Creates a new job.
|
|
|
|
**Request Body**
|
|
|
|
```json
|
|
{
|
|
"job_number": "JOB-002",
|
|
"job_name": "Project Beta",
|
|
"location": "456 Oak Ave, Raleigh, NC",
|
|
"percent_complete": 0,
|
|
"est_starting_qtr": "Q2 2025",
|
|
"fire_alarm_budget": 75000.00,
|
|
"labor_estimate": 30000.00,
|
|
"material_estimate": 25000.00,
|
|
"amount_left_on_contract": 75000.00,
|
|
"pm_assigned": "Jane Doe",
|
|
"aor": "Region B",
|
|
"fire_vendor": "Vendor B",
|
|
"install_partner": "Partner Corp",
|
|
"ps_or_install": "PS",
|
|
"subcontractor": "Sub LLC",
|
|
"pci": "No",
|
|
"voip_or_phone": "Phone",
|
|
"plans": "Pending",
|
|
"notes": "New project",
|
|
"issues": "",
|
|
"milestone_1": "Site survey",
|
|
"number_of_units": 200,
|
|
"sep_club_house": "No",
|
|
"elevator_final": "2025-06-15",
|
|
"pretest": "2025-07-01",
|
|
"final_date": "2025-07-15",
|
|
"co_drop_dead_date": "2025-07-31"
|
|
}
|
|
```
|
|
|
|
**Required Fields**
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| job_number | string | Unique job identifier |
|
|
| job_name | string | Job name/title |
|
|
|
|
**Optional Fields**
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| location | string | Job location address |
|
|
| percent_complete | float | Completion percentage (0.0 - 1.0) |
|
|
| est_starting_qtr | string | Estimated starting quarter |
|
|
| fire_alarm_budget | float | Total fire alarm budget |
|
|
| labor_estimate | float | Labor cost estimate |
|
|
| material_estimate | float | Material cost estimate |
|
|
| amount_left_on_contract | float | Remaining contract amount |
|
|
| pm_assigned | string | Project manager name |
|
|
| aor | string | Area of responsibility |
|
|
| fire_vendor | string | Fire alarm vendor |
|
|
| install_partner | string | Installation partner |
|
|
| ps_or_install | string | PS or Install designation |
|
|
| subcontractor | string | Subcontractor name |
|
|
| pci | string | PCI status |
|
|
| voip_or_phone | string | Communication type |
|
|
| plans | string | Plans status |
|
|
| notes | string | General notes |
|
|
| issues | string | Known issues |
|
|
| milestone_1 - milestone_7 | string | Project milestones |
|
|
| elevator_final | date | Elevator final date (YYYY-MM-DD) |
|
|
| pretest | date | Pretest date (YYYY-MM-DD) |
|
|
| final_date | date | Final date (YYYY-MM-DD) |
|
|
| co_drop_dead_date | date | CO drop dead date (YYYY-MM-DD) |
|
|
| number_of_units | integer | Number of units |
|
|
| sep_club_house | string | Separate club house indicator |
|
|
|
|
**Response**
|
|
|
|
Returns the created job object with status `201 Created`.
|
|
|
|
#### Update Job
|
|
|
|
```
|
|
PUT /api/jobs/<id>
|
|
```
|
|
|
|
Updates an existing job.
|
|
|
|
**Parameters**
|
|
|
|
| Name | Type | Description |
|
|
|------|------|-------------|
|
|
| id | integer | Job ID (path parameter) |
|
|
|
|
**Request Body**
|
|
|
|
Include only the fields you want to update. Same fields as create.
|
|
|
|
```json
|
|
{
|
|
"percent_complete": 0.85,
|
|
"notes": "Updated project notes"
|
|
}
|
|
```
|
|
|
|
**Response**
|
|
|
|
Returns the updated job object.
|
|
|
|
**Errors**
|
|
|
|
| Status | Description |
|
|
|--------|-------------|
|
|
| 404 | Job not found |
|
|
|
|
#### Delete Job
|
|
|
|
```
|
|
DELETE /api/jobs/<id>
|
|
```
|
|
|
|
Deletes a job and all associated phases and materials.
|
|
|
|
**Parameters**
|
|
|
|
| Name | Type | Description |
|
|
|------|------|-------------|
|
|
| id | integer | Job ID (path parameter) |
|
|
|
|
**Response**
|
|
|
|
Returns `204 No Content` on success.
|
|
|
|
**Errors**
|
|
|
|
| Status | Description |
|
|
|--------|-------------|
|
|
| 404 | Job not found |
|
|
|
|
---
|
|
|
|
### Phases
|
|
|
|
#### List Phases for Job
|
|
|
|
```
|
|
GET /api/jobs/<job_id>/phases
|
|
```
|
|
|
|
Returns all phases for a specific job.
|
|
|
|
**Parameters**
|
|
|
|
| Name | Type | Description |
|
|
|------|------|-------------|
|
|
| job_id | integer | Job ID (path parameter) |
|
|
|
|
**Response**
|
|
|
|
```json
|
|
[
|
|
{
|
|
"id": 1,
|
|
"job_id": 1,
|
|
"phase_type": "rough_in",
|
|
"phase_number": 1,
|
|
"points": 500,
|
|
"mobilization_date": "2025-02-01",
|
|
"start_date": "2025-02-05",
|
|
"due_date": "2025-02-28",
|
|
"completion_date": "2025-02-25",
|
|
"men_on_site": 5,
|
|
"completed": true,
|
|
"due_date_met": true,
|
|
"pci_man_hours": 120.5,
|
|
"rer_fire_mgmt_hours": 40.0,
|
|
"rer_fire_mgmt_hours_avl": 50.0
|
|
}
|
|
]
|
|
```
|
|
|
|
#### Create Phase
|
|
|
|
```
|
|
POST /api/jobs/<job_id>/phases
|
|
```
|
|
|
|
Creates a new phase for a job.
|
|
|
|
**Parameters**
|
|
|
|
| Name | Type | Description |
|
|
|------|------|-------------|
|
|
| job_id | integer | Job ID (path parameter) |
|
|
|
|
**Request Body**
|
|
|
|
```json
|
|
{
|
|
"phase_type": "trim",
|
|
"phase_number": 2,
|
|
"points": 300,
|
|
"mobilization_date": "2025-03-01",
|
|
"start_date": "2025-03-05",
|
|
"due_date": "2025-03-31",
|
|
"men_on_site": 4,
|
|
"completed": false,
|
|
"pci_man_hours": 0,
|
|
"rer_fire_mgmt_hours": 0,
|
|
"rer_fire_mgmt_hours_avl": 30.0
|
|
}
|
|
```
|
|
|
|
**Fields**
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| phase_type | string | Phase type: `rough_in`, `trim`, `commissioning`, `final`, `turnover` |
|
|
| phase_number | integer | Phase sequence number |
|
|
| points | integer | Points assigned to phase |
|
|
| mobilization_date | date | Mobilization date (YYYY-MM-DD) |
|
|
| start_date | date | Start date (YYYY-MM-DD) |
|
|
| due_date | date | Due date (YYYY-MM-DD) |
|
|
| completion_date | date | Completion date (YYYY-MM-DD) |
|
|
| men_on_site | integer | Number of workers on site |
|
|
| completed | boolean | Whether phase is complete |
|
|
| due_date_met | boolean | Whether due date was met |
|
|
| pci_man_hours | float | PCI man hours |
|
|
| rer_fire_mgmt_hours | float | RER fire management hours |
|
|
| rer_fire_mgmt_hours_avl | float | RER fire management hours available |
|
|
|
|
**Response**
|
|
|
|
Returns the created phase object with status `201 Created`.
|
|
|
|
**Errors**
|
|
|
|
| Status | Description |
|
|
|--------|-------------|
|
|
| 404 | Job not found |
|
|
|
|
#### Update Phase
|
|
|
|
```
|
|
PUT /api/phases/<phase_id>
|
|
```
|
|
|
|
Updates an existing phase.
|
|
|
|
**Parameters**
|
|
|
|
| Name | Type | Description |
|
|
|------|------|-------------|
|
|
| phase_id | integer | Phase ID (path parameter) |
|
|
|
|
**Request Body**
|
|
|
|
Include only the fields you want to update.
|
|
|
|
```json
|
|
{
|
|
"completed": true,
|
|
"completion_date": "2025-03-28",
|
|
"due_date_met": true
|
|
}
|
|
```
|
|
|
|
**Response**
|
|
|
|
Returns the updated phase object.
|
|
|
|
**Errors**
|
|
|
|
| Status | Description |
|
|
|--------|-------------|
|
|
| 404 | Phase not found |
|
|
|
|
#### Delete Phase
|
|
|
|
```
|
|
DELETE /api/phases/<phase_id>
|
|
```
|
|
|
|
Deletes a phase.
|
|
|
|
**Parameters**
|
|
|
|
| Name | Type | Description |
|
|
|------|------|-------------|
|
|
| phase_id | integer | Phase ID (path parameter) |
|
|
|
|
**Response**
|
|
|
|
Returns `204 No Content` on success.
|
|
|
|
**Errors**
|
|
|
|
| Status | Description |
|
|
|--------|-------------|
|
|
| 404 | Phase not found |
|
|
|
|
---
|
|
|
|
### Materials
|
|
|
|
#### List All Materials
|
|
|
|
```
|
|
GET /api/materials
|
|
```
|
|
|
|
Returns all materials across all jobs.
|
|
|
|
**Response**
|
|
|
|
```json
|
|
[
|
|
{
|
|
"id": 1,
|
|
"job_id": 1,
|
|
"part_number": "FA-SENSOR-001",
|
|
"quantity": 50,
|
|
"ordered": true,
|
|
"received": true,
|
|
"received_qty": 50,
|
|
"received_by": "John Doe",
|
|
"delivered_qty": 45,
|
|
"delivered_to": "Site A - Building 1"
|
|
}
|
|
]
|
|
```
|
|
|
|
#### List Materials for Job
|
|
|
|
```
|
|
GET /api/jobs/<job_id>/materials
|
|
```
|
|
|
|
Returns all materials for a specific job.
|
|
|
|
**Parameters**
|
|
|
|
| Name | Type | Description |
|
|
|------|------|-------------|
|
|
| job_id | integer | Job ID (path parameter) |
|
|
|
|
**Response**
|
|
|
|
Returns an array of material objects (same structure as above).
|
|
|
|
#### Create Material
|
|
|
|
```
|
|
POST /api/jobs/<job_id>/materials
|
|
```
|
|
|
|
Creates a new material record for a job.
|
|
|
|
**Parameters**
|
|
|
|
| Name | Type | Description |
|
|
|------|------|-------------|
|
|
| job_id | integer | Job ID (path parameter) |
|
|
|
|
**Request Body**
|
|
|
|
```json
|
|
{
|
|
"part_number": "FA-PANEL-002",
|
|
"quantity": 10,
|
|
"ordered": false,
|
|
"received": false,
|
|
"received_qty": 0,
|
|
"received_by": "",
|
|
"delivered_qty": 0,
|
|
"delivered_to": ""
|
|
}
|
|
```
|
|
|
|
**Fields**
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| part_number | string | Part/item number |
|
|
| quantity | integer | Quantity needed |
|
|
| ordered | boolean | Whether order has been placed |
|
|
| received | boolean | Whether items have been received |
|
|
| received_qty | integer | Quantity received |
|
|
| received_by | string | Person who received items |
|
|
| delivered_qty | integer | Quantity delivered to site |
|
|
| delivered_to | string | Delivery location |
|
|
|
|
**Response**
|
|
|
|
Returns the created material object with status `201 Created`.
|
|
|
|
**Errors**
|
|
|
|
| Status | Description |
|
|
|--------|-------------|
|
|
| 404 | Job not found |
|
|
|
|
#### Update Material
|
|
|
|
```
|
|
PUT /api/materials/<material_id>
|
|
```
|
|
|
|
Updates an existing material record.
|
|
|
|
**Parameters**
|
|
|
|
| Name | Type | Description |
|
|
|------|------|-------------|
|
|
| material_id | integer | Material ID (path parameter) |
|
|
|
|
**Request Body**
|
|
|
|
Include only the fields you want to update.
|
|
|
|
```json
|
|
{
|
|
"ordered": true,
|
|
"received": true,
|
|
"received_qty": 10,
|
|
"received_by": "Jane Smith"
|
|
}
|
|
```
|
|
|
|
**Response**
|
|
|
|
Returns the updated material object.
|
|
|
|
**Errors**
|
|
|
|
| Status | Description |
|
|
|--------|-------------|
|
|
| 404 | Material not found |
|
|
|
|
#### Delete Material
|
|
|
|
```
|
|
DELETE /api/materials/<material_id>
|
|
```
|
|
|
|
Deletes a material record.
|
|
|
|
**Parameters**
|
|
|
|
| Name | Type | Description |
|
|
|------|------|-------------|
|
|
| material_id | integer | Material ID (path parameter) |
|
|
|
|
**Response**
|
|
|
|
Returns `204 No Content` on success.
|
|
|
|
**Errors**
|
|
|
|
| Status | Description |
|
|
|--------|-------------|
|
|
| 404 | Material not found |
|
|
|
|
---
|
|
|
|
## Data Types
|
|
|
|
### Date Format
|
|
|
|
All dates use ISO 8601 format: `YYYY-MM-DD`
|
|
|
|
Examples:
|
|
- `2025-01-15`
|
|
- `2025-12-31`
|
|
|
|
### DateTime Format
|
|
|
|
All timestamps use ISO 8601 format: `YYYY-MM-DDTHH:MM:SS`
|
|
|
|
Examples:
|
|
- `2025-01-15T14:30:00`
|
|
- `2025-12-31T23:59:59`
|
|
|
|
### Phase Types
|
|
|
|
Valid values for `phase_type`:
|
|
- `rough_in` - Initial rough-in phase
|
|
- `trim` - Trim phase
|
|
- `commissioning` - System commissioning
|
|
- `final` - Final inspection
|
|
- `turnover` - Project turnover
|
|
|
|
---
|
|
|
|
## Error Handling
|
|
|
|
The API uses standard HTTP status codes:
|
|
|
|
| Status | Description |
|
|
|--------|-------------|
|
|
| 200 | Success |
|
|
| 201 | Created |
|
|
| 204 | No Content (successful deletion) |
|
|
| 400 | Bad Request (invalid input) |
|
|
| 404 | Not Found |
|
|
| 500 | Internal Server Error |
|
|
|
|
---
|
|
|
|
## Examples
|
|
|
|
### cURL Examples
|
|
|
|
**Get all jobs:**
|
|
```bash
|
|
curl http://localhost:5000/api/jobs
|
|
```
|
|
|
|
**Create a job:**
|
|
```bash
|
|
curl -X POST http://localhost:5000/api/jobs \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"job_number": "JOB-003", "job_name": "New Project"}'
|
|
```
|
|
|
|
**Update a job:**
|
|
```bash
|
|
curl -X PUT http://localhost:5000/api/jobs/1 \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"percent_complete": 0.5}'
|
|
```
|
|
|
|
**Delete a job:**
|
|
```bash
|
|
curl -X DELETE http://localhost:5000/api/jobs/1
|
|
```
|
|
|
|
### JavaScript Fetch Examples
|
|
|
|
**Get all jobs:**
|
|
```javascript
|
|
const response = await fetch('/api/jobs');
|
|
const jobs = await response.json();
|
|
```
|
|
|
|
**Create a job:**
|
|
```javascript
|
|
const response = await fetch('/api/jobs', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({
|
|
job_number: 'JOB-003',
|
|
job_name: 'New Project'
|
|
})
|
|
});
|
|
const newJob = await response.json();
|
|
```
|
|
|
|
**Update a job:**
|
|
```javascript
|
|
const response = await fetch('/api/jobs/1', {
|
|
method: 'PUT',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ percent_complete: 0.5 })
|
|
});
|
|
const updatedJob = await response.json();
|
|
```
|
|
|
|
**Delete a job:**
|
|
```javascript
|
|
await fetch('/api/jobs/1', { method: 'DELETE' });
|
|
```
|