erp-construccion/docs/backend/API-REFERENCE.md

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