16 KiB
API Reference - ERP Construccion
Referencia completa de endpoints REST.
Base URL: http://localhost:3000/api/v1
Autenticacion
Todas las rutas (excepto login/register) requieren header:
Authorization: Bearer <access_token>
Auth Endpoints
POST /auth/login
Autenticar usuario.
Request:
{
"email": "user@example.com",
"password": "securePassword123"
}
Response 200:
{
"user": {
"id": "uuid",
"email": "user@example.com",
"firstName": "Juan",
"lastName": "Perez",
"role": "admin"
},
"accessToken": "eyJhbGciOiJIUzI1NiIs...",
"refreshToken": "eyJhbGciOiJIUzI1NiIs...",
"expiresIn": 900
}
Response 401:
{
"error": "Unauthorized",
"message": "Invalid credentials"
}
POST /auth/register
Registrar nuevo usuario.
Request:
{
"email": "nuevo@example.com",
"password": "securePassword123",
"firstName": "Maria",
"lastName": "Lopez",
"tenantId": "tenant-uuid"
}
Response 201:
{
"user": {
"id": "new-uuid",
"email": "nuevo@example.com",
"firstName": "Maria",
"lastName": "Lopez",
"role": "viewer"
},
"accessToken": "...",
"refreshToken": "...",
"expiresIn": 900
}
POST /auth/refresh
Renovar access token.
Request:
{
"refreshToken": "eyJhbGciOiJIUzI1NiIs..."
}
Response 200:
{
"accessToken": "new-access-token",
"refreshToken": "new-refresh-token",
"expiresIn": 900
}
POST /auth/logout
Revocar refresh token.
Request:
{
"refreshToken": "eyJhbGciOiJIUzI1NiIs..."
}
Response 200:
{
"success": true
}
POST /auth/change-password
Cambiar password del usuario autenticado.
Headers:
Authorization: Bearer <access_token>
Request:
{
"currentPassword": "oldPassword123",
"newPassword": "newSecurePassword456"
}
Response 200:
{
"success": true
}
Conceptos Endpoints
GET /conceptos
Listar conceptos con paginacion.
Query Parameters:
| Param | Tipo | Default | Descripcion |
|---|---|---|---|
page |
number | 1 | Pagina actual |
limit |
number | 20 | Items por pagina |
search |
string | - | Buscar por codigo/nombre |
parentId |
uuid | - | Filtrar por padre |
Response 200:
{
"data": [
{
"id": "uuid-1",
"code": "01",
"name": "Preliminares",
"unit": "PZA",
"unitPrice": 0,
"level": 0,
"path": "01",
"isActive": true
},
{
"id": "uuid-2",
"code": "01.01",
"name": "Trazo y nivelacion",
"unit": "M2",
"unitPrice": 25.50,
"level": 1,
"path": "01/01",
"parentId": "uuid-1",
"isActive": true
}
],
"total": 150,
"page": 1,
"limit": 20,
"totalPages": 8
}
GET /conceptos/:id
Obtener concepto por ID.
Response 200:
{
"id": "uuid-1",
"code": "01",
"name": "Preliminares",
"description": "Trabajos preliminares de obra",
"unit": "PZA",
"unitPrice": 0,
"level": 0,
"path": "01",
"isActive": true,
"createdAt": "2025-01-01T00:00:00Z",
"updatedAt": "2025-01-01T00:00:00Z"
}
Response 404:
{
"error": "Not Found",
"message": "Concepto not found"
}
POST /conceptos
Crear nuevo concepto.
Request:
{
"code": "01.02",
"name": "Demoliciones",
"description": "Trabajos de demolicion",
"unit": "M3",
"unitPrice": 150.00,
"parentId": "uuid-1"
}
Response 201:
{
"id": "new-uuid",
"code": "01.02",
"name": "Demoliciones",
"description": "Trabajos de demolicion",
"unit": "M3",
"unitPrice": 150.00,
"level": 1,
"path": "01/02",
"parentId": "uuid-1",
"isActive": true,
"createdAt": "2025-01-15T10:30:00Z"
}
GET /conceptos/tree
Obtener arbol de conceptos.
Query Parameters:
| Param | Tipo | Descripcion |
|---|---|---|
rootId |
uuid | ID del nodo raiz (opcional) |
Response 200:
{
"data": [
{
"id": "uuid-1",
"code": "01",
"name": "Preliminares",
"level": 0,
"children": [
{
"id": "uuid-2",
"code": "01.01",
"name": "Trazo y nivelacion",
"level": 1,
"children": []
},
{
"id": "uuid-3",
"code": "01.02",
"name": "Demoliciones",
"level": 1,
"children": []
}
]
}
]
}
Presupuestos Endpoints
GET /presupuestos
Listar presupuestos.
Query Parameters:
| Param | Tipo | Descripcion |
|---|---|---|
fraccionamientoId |
uuid | Filtrar por proyecto |
status |
string | draft/submitted/approved |
page |
number | Pagina |
limit |
number | Items por pagina |
Response 200:
{
"data": [
{
"id": "uuid-1",
"code": "PPTO-2025-001",
"name": "Presupuesto Casa Tipo A",
"version": 1,
"status": "approved",
"totalAmount": 1500000.00,
"fraccionamiento": {
"id": "frac-uuid",
"name": "Residencial Los Pinos"
},
"approvedAt": "2025-01-10T15:00:00Z"
}
],
"total": 25,
"page": 1,
"limit": 20,
"totalPages": 2
}
GET /presupuestos/:id
Obtener presupuesto con partidas.
Response 200:
{
"id": "uuid-1",
"code": "PPTO-2025-001",
"name": "Presupuesto Casa Tipo A",
"version": 1,
"status": "approved",
"totalAmount": 1500000.00,
"partidas": [
{
"id": "partida-1",
"concepto": {
"id": "concepto-uuid",
"code": "01.01",
"name": "Trazo y nivelacion",
"unit": "M2"
},
"quantity": 120.00,
"unitPrice": 25.50,
"totalAmount": 3060.00
}
],
"fraccionamiento": {
"id": "frac-uuid",
"name": "Residencial Los Pinos"
},
"createdAt": "2025-01-01T00:00:00Z",
"approvedAt": "2025-01-10T15:00:00Z",
"approvedBy": {
"id": "user-uuid",
"firstName": "Juan",
"lastName": "Director"
}
}
POST /presupuestos
Crear presupuesto.
Request:
{
"code": "PPTO-2025-002",
"name": "Presupuesto Casa Tipo B",
"fraccionamientoId": "frac-uuid"
}
Response 201:
{
"id": "new-uuid",
"code": "PPTO-2025-002",
"name": "Presupuesto Casa Tipo B",
"version": 1,
"status": "draft",
"totalAmount": 0,
"fraccionamientoId": "frac-uuid",
"createdAt": "2025-01-15T10:30:00Z"
}
POST /presupuestos/:id/partidas
Agregar partida a presupuesto.
Request:
{
"conceptoId": "concepto-uuid",
"quantity": 100.00,
"unitPrice": 25.50
}
Response 201:
{
"id": "partida-uuid",
"presupuestoId": "presupuesto-uuid",
"conceptoId": "concepto-uuid",
"quantity": 100.00,
"unitPrice": 25.50,
"totalAmount": 2550.00
}
POST /presupuestos/:id/approve
Aprobar presupuesto.
Response 200:
{
"id": "presupuesto-uuid",
"status": "approved",
"approvedAt": "2025-01-15T12:00:00Z",
"approvedById": "user-uuid"
}
POST /presupuestos/:id/version
Crear nueva version del presupuesto.
Response 201:
{
"id": "new-version-uuid",
"code": "PPTO-2025-001",
"name": "Presupuesto Casa Tipo A",
"version": 2,
"status": "draft",
"totalAmount": 1500000.00,
"partidas": [...]
}
Avances Endpoints
GET /avances
Listar avances de obra.
Query Parameters:
| Param | Tipo | Descripcion |
|---|---|---|
loteId |
uuid | Filtrar por lote |
departamentoId |
uuid | Filtrar por departamento |
status |
string | captured/reviewed/approved/rejected |
dateFrom |
date | Fecha desde |
dateTo |
date | Fecha hasta |
Response 200:
{
"data": [
{
"id": "avance-uuid",
"lote": {
"id": "lote-uuid",
"number": "L-001"
},
"concepto": {
"id": "concepto-uuid",
"code": "02.01",
"name": "Cimentacion",
"unit": "M3"
},
"quantity": 15.50,
"progressDate": "2025-01-15",
"status": "approved",
"capturedBy": {
"firstName": "Pedro",
"lastName": "Residente"
}
}
],
"total": 150,
"page": 1,
"limit": 20,
"totalPages": 8
}
POST /avances
Registrar avance de obra.
Request:
{
"loteId": "lote-uuid",
"conceptoId": "concepto-uuid",
"quantity": 15.50,
"progressDate": "2025-01-15",
"notes": "Cimentacion completada"
}
Response 201:
{
"id": "new-avance-uuid",
"loteId": "lote-uuid",
"conceptoId": "concepto-uuid",
"quantity": 15.50,
"progressDate": "2025-01-15",
"status": "captured",
"capturedById": "user-uuid",
"notes": "Cimentacion completada",
"createdAt": "2025-01-15T14:30:00Z"
}
POST /avances/:id/fotos
Agregar foto a avance.
Request (multipart/form-data):
file: <archivo imagen>
description: "Vista frontal de cimentacion"
latitude: 20.123456
longitude: -99.654321
Response 201:
{
"id": "foto-uuid",
"avanceObraId": "avance-uuid",
"fileName": "IMG_20250115_143000.jpg",
"filePath": "/uploads/avances/2025/01/IMG_20250115_143000.jpg",
"fileSize": 2048576,
"mimeType": "image/jpeg",
"latitude": 20.123456,
"longitude": -99.654321,
"description": "Vista frontal de cimentacion",
"takenAt": "2025-01-15T14:30:00Z"
}
POST /avances/:id/review
Revisar avance (workflow).
Response 200:
{
"id": "avance-uuid",
"status": "reviewed",
"reviewedAt": "2025-01-15T16:00:00Z",
"reviewedById": "supervisor-uuid"
}
POST /avances/:id/approve
Aprobar avance (workflow).
Response 200:
{
"id": "avance-uuid",
"status": "approved",
"approvedAt": "2025-01-15T17:00:00Z",
"approvedById": "manager-uuid"
}
POST /avances/:id/reject
Rechazar avance (workflow).
Request:
{
"reason": "Cantidad incorrecta, verificar medicion"
}
Response 200:
{
"id": "avance-uuid",
"status": "rejected",
"rejectedAt": "2025-01-15T16:30:00Z",
"rejectedById": "supervisor-uuid",
"rejectionReason": "Cantidad incorrecta, verificar medicion"
}
Bitacora Endpoints
GET /bitacora/:fraccionamientoId
Obtener entradas de bitacora.
Query Parameters:
| Param | Tipo | Descripcion |
|---|---|---|
dateFrom |
date | Fecha desde |
dateTo |
date | Fecha hasta |
Response 200:
{
"data": [
{
"id": "bitacora-uuid",
"entryNumber": 125,
"entryDate": "2025-01-15",
"weather": "Soleado",
"temperature": 28.5,
"workersCount": 45,
"activities": "Colado de cimentacion lotes 15-20",
"incidents": "Ninguno",
"observations": "Se requiere mas cemento para manana",
"createdBy": {
"firstName": "Pedro",
"lastName": "Residente"
}
}
],
"total": 125,
"page": 1,
"limit": 20,
"totalPages": 7
}
POST /bitacora
Crear entrada de bitacora.
Request:
{
"fraccionamientoId": "frac-uuid",
"entryDate": "2025-01-15",
"weather": "Soleado",
"temperature": 28.5,
"workersCount": 45,
"activities": "Colado de cimentacion lotes 15-20",
"incidents": "Ninguno",
"observations": "Se requiere mas cemento para manana"
}
Response 201:
{
"id": "new-bitacora-uuid",
"entryNumber": 126,
"entryDate": "2025-01-15",
"weather": "Soleado",
"temperature": 28.5,
"workersCount": 45,
"activities": "Colado de cimentacion lotes 15-20",
"createdById": "user-uuid",
"createdAt": "2025-01-15T18:00:00Z"
}
Estimaciones Endpoints
GET /estimaciones
Listar estimaciones.
Query Parameters:
| Param | Tipo | Descripcion |
|---|---|---|
contratoId |
uuid | Filtrar por contrato |
status |
string | draft/submitted/reviewed/approved/rejected |
Response 200:
{
"data": [
{
"id": "est-uuid",
"number": 5,
"periodStart": "2025-01-01",
"periodEnd": "2025-01-15",
"status": "approved",
"subtotal": 500000.00,
"iva": 80000.00,
"retentions": 25000.00,
"amortization": 10000.00,
"totalAmount": 545000.00,
"contrato": {
"id": "contrato-uuid",
"number": "CTR-2025-001"
}
}
],
"total": 5,
"page": 1,
"limit": 20,
"totalPages": 1
}
GET /estimaciones/:id
Obtener estimacion con detalles.
Response 200:
{
"id": "est-uuid",
"number": 5,
"periodStart": "2025-01-01",
"periodEnd": "2025-01-15",
"status": "approved",
"subtotal": 500000.00,
"iva": 80000.00,
"retentions": 25000.00,
"amortization": 10000.00,
"totalAmount": 545000.00,
"conceptos": [
{
"id": "est-concepto-uuid",
"concepto": {
"code": "02.01",
"name": "Cimentacion",
"unit": "M3"
},
"contractQuantity": 1000.00,
"previousQuantity": 400.00,
"currentQuantity": 150.00,
"accumulatedQuantity": 550.00,
"pendingQuantity": 450.00,
"unitPrice": 1200.00,
"currentAmount": 180000.00,
"accumulatedAmount": 660000.00,
"generadores": [
{
"description": "Lotes 15-20",
"length": 10.00,
"width": 5.00,
"height": 0.30,
"quantity": 6,
"partial": 90.00
}
]
}
],
"workflow": [
{
"fromStatus": "draft",
"toStatus": "submitted",
"changedAt": "2025-01-16T10:00:00Z",
"changedBy": {
"firstName": "Pedro",
"lastName": "Residente"
}
}
]
}
POST /estimaciones
Crear estimacion.
Request:
{
"contratoId": "contrato-uuid",
"periodStart": "2025-01-16",
"periodEnd": "2025-01-31"
}
Response 201:
{
"id": "new-est-uuid",
"number": 6,
"contratoId": "contrato-uuid",
"periodStart": "2025-01-16",
"periodEnd": "2025-01-31",
"status": "draft",
"subtotal": 0,
"totalAmount": 0,
"createdAt": "2025-01-16T09:00:00Z"
}
POST /estimaciones/:id/conceptos
Agregar concepto a estimacion.
Request:
{
"conceptoId": "concepto-uuid",
"contractQuantity": 1000.00,
"currentQuantity": 150.00,
"unitPrice": 1200.00
}
Response 201:
{
"id": "new-est-concepto-uuid",
"estimacionId": "est-uuid",
"conceptoId": "concepto-uuid",
"contractQuantity": 1000.00,
"previousQuantity": 550.00,
"currentQuantity": 150.00,
"accumulatedQuantity": 700.00,
"pendingQuantity": 300.00,
"unitPrice": 1200.00,
"currentAmount": 180000.00,
"accumulatedAmount": 840000.00
}
POST /estimaciones/:id/submit
Enviar estimacion para revision.
Response 200:
{
"id": "est-uuid",
"status": "submitted",
"submittedAt": "2025-01-20T10:00:00Z",
"submittedById": "user-uuid"
}
POST /estimaciones/:id/approve
Aprobar estimacion.
Response 200:
{
"id": "est-uuid",
"status": "approved",
"approvedAt": "2025-01-21T15:00:00Z",
"approvedById": "director-uuid"
}
Codigos de Error
| Codigo | Descripcion |
|---|---|
| 400 | Bad Request - Datos invalidos |
| 401 | Unauthorized - Token invalido o expirado |
| 403 | Forbidden - Sin permisos |
| 404 | Not Found - Recurso no encontrado |
| 409 | Conflict - Conflicto (ej: duplicado) |
| 422 | Unprocessable Entity - Validacion fallida |
| 500 | Internal Server Error |
Formato de Error
{
"error": "Bad Request",
"message": "Validation failed",
"details": [
{
"field": "email",
"message": "Invalid email format"
}
]
}
Rate Limiting
| Tipo | Limite |
|---|---|
| Login | 5 requests/min por IP |
| API General | 100 requests/min por usuario |
| Uploads | 10 requests/min por usuario |
Headers de respuesta:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1610000000
Ultima actualizacion: 2025-12-12