# 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: ```http Authorization: Bearer ``` --- ## Auth Endpoints ### POST /auth/login Autenticar usuario. **Request:** ```json { "email": "user@example.com", "password": "securePassword123" } ``` **Response 200:** ```json { "user": { "id": "uuid", "email": "user@example.com", "firstName": "Juan", "lastName": "Perez", "role": "admin" }, "accessToken": "eyJhbGciOiJIUzI1NiIs...", "refreshToken": "eyJhbGciOiJIUzI1NiIs...", "expiresIn": 900 } ``` **Response 401:** ```json { "error": "Unauthorized", "message": "Invalid credentials" } ``` --- ### POST /auth/register Registrar nuevo usuario. **Request:** ```json { "email": "nuevo@example.com", "password": "securePassword123", "firstName": "Maria", "lastName": "Lopez", "tenantId": "tenant-uuid" } ``` **Response 201:** ```json { "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:** ```json { "refreshToken": "eyJhbGciOiJIUzI1NiIs..." } ``` **Response 200:** ```json { "accessToken": "new-access-token", "refreshToken": "new-refresh-token", "expiresIn": 900 } ``` --- ### POST /auth/logout Revocar refresh token. **Request:** ```json { "refreshToken": "eyJhbGciOiJIUzI1NiIs..." } ``` **Response 200:** ```json { "success": true } ``` --- ### POST /auth/change-password Cambiar password del usuario autenticado. **Headers:** ``` Authorization: Bearer ``` **Request:** ```json { "currentPassword": "oldPassword123", "newPassword": "newSecurePassword456" } ``` **Response 200:** ```json { "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:** ```json { "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:** ```json { "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:** ```json { "error": "Not Found", "message": "Concepto not found" } ``` --- ### POST /conceptos Crear nuevo concepto. **Request:** ```json { "code": "01.02", "name": "Demoliciones", "description": "Trabajos de demolicion", "unit": "M3", "unitPrice": 150.00, "parentId": "uuid-1" } ``` **Response 201:** ```json { "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:** ```json { "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:** ```json { "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:** ```json { "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:** ```json { "code": "PPTO-2025-002", "name": "Presupuesto Casa Tipo B", "fraccionamientoId": "frac-uuid" } ``` **Response 201:** ```json { "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:** ```json { "conceptoId": "concepto-uuid", "quantity": 100.00, "unitPrice": 25.50 } ``` **Response 201:** ```json { "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:** ```json { "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:** ```json { "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:** ```json { "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:** ```json { "loteId": "lote-uuid", "conceptoId": "concepto-uuid", "quantity": 15.50, "progressDate": "2025-01-15", "notes": "Cimentacion completada" } ``` **Response 201:** ```json { "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: description: "Vista frontal de cimentacion" latitude: 20.123456 longitude: -99.654321 ``` **Response 201:** ```json { "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:** ```json { "id": "avance-uuid", "status": "reviewed", "reviewedAt": "2025-01-15T16:00:00Z", "reviewedById": "supervisor-uuid" } ``` --- ### POST /avances/:id/approve Aprobar avance (workflow). **Response 200:** ```json { "id": "avance-uuid", "status": "approved", "approvedAt": "2025-01-15T17:00:00Z", "approvedById": "manager-uuid" } ``` --- ### POST /avances/:id/reject Rechazar avance (workflow). **Request:** ```json { "reason": "Cantidad incorrecta, verificar medicion" } ``` **Response 200:** ```json { "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:** ```json { "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:** ```json { "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:** ```json { "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:** ```json { "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:** ```json { "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:** ```json { "contratoId": "contrato-uuid", "periodStart": "2025-01-16", "periodEnd": "2025-01-31" } ``` **Response 201:** ```json { "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:** ```json { "conceptoId": "concepto-uuid", "contractQuantity": 1000.00, "currentQuantity": 150.00, "unitPrice": 1200.00 } ``` **Response 201:** ```json { "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:** ```json { "id": "est-uuid", "status": "submitted", "submittedAt": "2025-01-20T10:00:00Z", "submittedById": "user-uuid" } ``` --- ### POST /estimaciones/:id/approve Aprobar estimacion. **Response 200:** ```json { "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 ```json { "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