backend/
│
├── app/
│ ├── main.py # FastAPI entrypoint
│ │
│ ├── api/ # Route layer
│ │ ├── routes.py
│ │ ├── jobs.py
│ │ ├── detections.py
│ │ ├── estimation.py
│ │ └── health.py
│ │
│ ├── core/ # Core configs
│ │ ├── config.py
│ │ ├── logging.py
│ │ ├── security.py
│ │ └── exceptions.py
│ │
│ ├── db/ # Database layer
│ │ ├── database.py
│ │ ├── models.py
│ │ └── migrations/
│ │
│ ├── schemas/ # Pydantic schemas
│ │ ├── job.py
│ │ ├── detection.py
│ │ ├── estimation.py
│ │ └── common.py
│ │
│ ├── services/ # Business logic
│ │ ├── job_service.py
│ │ ├── detection_service.py
│ │ ├── estimation_service.py
│ │ ├── storage_service.py
│ │ └── health_service.py
│ │
│ ├── messaging/ # RabbitMQ integration
│ │ ├── connection.py
│ │ ├── publisher.py # Publish job.created
│ │ ├── consumer.py # Consume job.completed/failed
│ │ └── handlers.py # Result message handlers
│ │
│ ├── repositories/ # DB abstraction layer
│ │ ├── job_repository.py
│ │ ├── detection_repository.py
│ │ └── base.py
│ │
│ └── utils/
│ ├── file_utils.py
│ └── validators.py
│
├── tests/
│ ├── test_jobs.py
│ ├── test_estimation.py
│ └── test_messaging.py
│
├── Dockerfile
├── docker-compose.yml
├── requirements.txt
├── Makefile
└── .env.dev
This document defines the REST API contract for the Blueprint AI Backend.
Responsibilities:
- Accept blueprint uploads
- Manage job lifecycle
- Communicate with AI via RabbitMQ
- Store image URLs (original + annotated)
- Expose detection and estimation data to frontend
Base URL:
/api/v1
All timestamps: ISO 8601 (UTC) All IDs: UUID v4 All responses: application/json
{
"data": {},
"message": "Optional message"
}{
"error": "ERROR_CODE",
"message": "Human readable explanation",
"details": {}
}PENDING → QUEUED → PROCESSING → COMPLETED
↘ FAILED
POST /jobs
Content-Type: multipart/form-data
Field:
- file (PDF | PNG | JPG)
Optional metadata:
{
"project_name": "Residential Layout A",
"confidence_threshold": 0.25
}{
"data": {
"job_id": "uuid",
"status": "PENDING",
"original_image_url": "https://storage/original/uuid.png",
"created_at": "2026-02-22T10:25:41Z"
}
}Backend Actions:
- Store original image in object storage
- Insert DB record
- Publish job message to RabbitMQ
- Update status → QUEUED
GET /jobs/{job_id}
{
"data": {
"job_id": "uuid",
"status": "PROCESSING",
"original_image_url": "https://storage/original/uuid.png",
"progress": 55
}
}{
"data": {
"job_id": "uuid",
"status": "COMPLETED",
"original_image_url": "https://storage/original/uuid.png",
"annotated_image_url": "https://storage/annotated/uuid.png",
"image_size": {
"width": 2480,
"height": 3508
},
"symbol_counts": {
"valve": 12,
"pump": 4
},
"total_detections": 16,
"completed_at": "2026-02-22T10:26:09Z"
}
}GET /jobs/{job_id}/detections
{
"data": {
"job_id": "uuid",
"original_image_url": "https://storage/original/uuid.png",
"annotated_image_url": "https://storage/annotated/uuid.png",
"image_size": {
"width": 2480,
"height": 3508
},
"detections": [
{
"label": "valve",
"confidence": 0.91,
"bbox": {
"x1": 100,
"y1": 200,
"x2": 180,
"y2": 280
}
}
]
}
}Purpose:
- original_image_url → base render
- annotated_image_url → preview render
- detections → dynamic frontend drawing
GET /jobs/{job_id}/estimation
{
"data": {
"job_id": "uuid",
"total_symbols": 16,
"material_breakdown": [
{
"symbol": "valve",
"count": 12,
"unit_cost": 1500,
"total_cost": 18000
}
],
"grand_total_cost": 38000
}
}GET /health
{
"data": {
"status": "healthy",
"services": {
"database": "connected",
"rabbitmq": "connected"
}
}
}End of Backend REST API Specification