workspace/projects/erp-suite/apps/verticales/construccion/docs/api/openapi.yaml
Adrian Flores Cortes 7ed5c5ab45
Some checks are pending
CI Pipeline / changes (push) Waiting to run
CI Pipeline / core (push) Blocked by required conditions
CI Pipeline / trading-backend (push) Blocked by required conditions
CI Pipeline / trading-data-service (push) Blocked by required conditions
CI Pipeline / trading-frontend (push) Blocked by required conditions
CI Pipeline / erp-core (push) Blocked by required conditions
CI Pipeline / erp-mecanicas (push) Blocked by required conditions
CI Pipeline / gamilit-backend (push) Blocked by required conditions
CI Pipeline / gamilit-frontend (push) Blocked by required conditions
changes on project erp-suite documentation
2025-12-12 08:18:01 -06:00

948 lines
22 KiB
YAML

openapi: 3.0.3
info:
title: ERP Construccion API
description: |
API REST para sistema de administracion de obra e INFONAVIT.
## Autenticacion
La API utiliza JWT Bearer tokens. Incluir el header:
```
Authorization: Bearer <access_token>
```
## Multi-tenancy
Todas las operaciones estan aisladas por tenant_id.
El tenant se determina automaticamente desde el JWT.
## Paginacion
Los endpoints de listado soportan paginacion:
- `page`: Numero de pagina (default: 1)
- `limit`: Items por pagina (default: 20, max: 100)
version: 1.0.0
contact:
name: ERP Construccion Team
email: dev@construccion.local
servers:
- url: http://localhost:3000/api/v1
description: Development
- url: https://api.construccion.example.com/api/v1
description: Production
tags:
- name: Auth
description: Autenticacion y autorizacion
- name: Conceptos
description: Catalogo de conceptos de obra
- name: Presupuestos
description: Presupuestos de obra
- name: Avances
description: Control de avances fisicos
- name: Bitacora
description: Bitacora de obra
- name: Estimaciones
description: Estimaciones periodicas
paths:
/auth/login:
post:
tags: [Auth]
summary: Login de usuario
operationId: login
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/LoginRequest'
responses:
'200':
description: Login exitoso
content:
application/json:
schema:
$ref: '#/components/schemas/AuthResponse'
'401':
$ref: '#/components/responses/Unauthorized'
/auth/register:
post:
tags: [Auth]
summary: Registro de usuario
operationId: register
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/RegisterRequest'
responses:
'201':
description: Usuario registrado
content:
application/json:
schema:
$ref: '#/components/schemas/AuthResponse'
'400':
$ref: '#/components/responses/BadRequest'
/auth/refresh:
post:
tags: [Auth]
summary: Renovar access token
operationId: refreshToken
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/RefreshTokenRequest'
responses:
'200':
description: Tokens renovados
content:
application/json:
schema:
$ref: '#/components/schemas/AuthResponse'
'401':
$ref: '#/components/responses/Unauthorized'
/auth/logout:
post:
tags: [Auth]
summary: Logout (revocar refresh token)
operationId: logout
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/RefreshTokenRequest'
responses:
'204':
description: Logout exitoso
/conceptos:
get:
tags: [Conceptos]
summary: Listar conceptos
operationId: listConceptos
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/PageParam'
- $ref: '#/components/parameters/LimitParam'
responses:
'200':
description: Lista de conceptos
content:
application/json:
schema:
$ref: '#/components/schemas/ConceptoListResponse'
post:
tags: [Conceptos]
summary: Crear concepto
operationId: createConcepto
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateConceptoRequest'
responses:
'201':
description: Concepto creado
content:
application/json:
schema:
$ref: '#/components/schemas/Concepto'
/conceptos/tree:
get:
tags: [Conceptos]
summary: Obtener arbol de conceptos
operationId: getConceptoTree
security:
- bearerAuth: []
parameters:
- name: rootId
in: query
schema:
type: string
format: uuid
description: ID del concepto raiz (opcional)
responses:
'200':
description: Arbol de conceptos
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/ConceptoTree'
/conceptos/{id}:
get:
tags: [Conceptos]
summary: Obtener concepto por ID
operationId: getConcepto
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/IdParam'
responses:
'200':
description: Concepto encontrado
content:
application/json:
schema:
$ref: '#/components/schemas/Concepto'
'404':
$ref: '#/components/responses/NotFound'
/presupuestos:
get:
tags: [Presupuestos]
summary: Listar presupuestos
operationId: listPresupuestos
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/PageParam'
- $ref: '#/components/parameters/LimitParam'
- name: fraccionamientoId
in: query
schema:
type: string
format: uuid
responses:
'200':
description: Lista de presupuestos
content:
application/json:
schema:
$ref: '#/components/schemas/PresupuestoListResponse'
post:
tags: [Presupuestos]
summary: Crear presupuesto
operationId: createPresupuesto
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreatePresupuestoRequest'
responses:
'201':
description: Presupuesto creado
content:
application/json:
schema:
$ref: '#/components/schemas/Presupuesto'
/presupuestos/{id}:
get:
tags: [Presupuestos]
summary: Obtener presupuesto con partidas
operationId: getPresupuesto
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/IdParam'
responses:
'200':
description: Presupuesto con partidas
content:
application/json:
schema:
$ref: '#/components/schemas/PresupuestoDetalle'
/presupuestos/{id}/partidas:
post:
tags: [Presupuestos]
summary: Agregar partida al presupuesto
operationId: addPartida
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/IdParam'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/AddPartidaRequest'
responses:
'201':
description: Partida agregada
content:
application/json:
schema:
$ref: '#/components/schemas/PresupuestoPartida'
/presupuestos/{id}/approve:
post:
tags: [Presupuestos]
summary: Aprobar presupuesto
operationId: approvePresupuesto
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/IdParam'
responses:
'200':
description: Presupuesto aprobado
content:
application/json:
schema:
$ref: '#/components/schemas/Presupuesto'
/avances:
get:
tags: [Avances]
summary: Listar avances
operationId: listAvances
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/PageParam'
- $ref: '#/components/parameters/LimitParam'
- name: loteId
in: query
schema:
type: string
format: uuid
- name: status
in: query
schema:
$ref: '#/components/schemas/AdvanceStatus'
responses:
'200':
description: Lista de avances
content:
application/json:
schema:
$ref: '#/components/schemas/AvanceListResponse'
post:
tags: [Avances]
summary: Crear avance
operationId: createAvance
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateAvanceRequest'
responses:
'201':
description: Avance creado
content:
application/json:
schema:
$ref: '#/components/schemas/AvanceObra'
/avances/{id}/fotos:
post:
tags: [Avances]
summary: Agregar foto al avance
operationId: addFotoAvance
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/IdParam'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/AddFotoRequest'
responses:
'201':
description: Foto agregada
content:
application/json:
schema:
$ref: '#/components/schemas/FotoAvance'
/avances/{id}/approve:
post:
tags: [Avances]
summary: Aprobar avance
operationId: approveAvance
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/IdParam'
responses:
'200':
description: Avance aprobado
content:
application/json:
schema:
$ref: '#/components/schemas/AvanceObra'
/estimaciones:
get:
tags: [Estimaciones]
summary: Listar estimaciones
operationId: listEstimaciones
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/PageParam'
- $ref: '#/components/parameters/LimitParam'
- name: contratoId
in: query
schema:
type: string
format: uuid
- name: status
in: query
schema:
$ref: '#/components/schemas/EstimateStatus'
responses:
'200':
description: Lista de estimaciones
content:
application/json:
schema:
$ref: '#/components/schemas/EstimacionListResponse'
post:
tags: [Estimaciones]
summary: Crear estimacion
operationId: createEstimacion
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateEstimacionRequest'
responses:
'201':
description: Estimacion creada
content:
application/json:
schema:
$ref: '#/components/schemas/Estimacion'
/estimaciones/{id}/submit:
post:
tags: [Estimaciones]
summary: Enviar estimacion para revision
operationId: submitEstimacion
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/IdParam'
responses:
'200':
description: Estimacion enviada
content:
application/json:
schema:
$ref: '#/components/schemas/Estimacion'
/estimaciones/{id}/approve:
post:
tags: [Estimaciones]
summary: Aprobar estimacion
operationId: approveEstimacion
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/IdParam'
responses:
'200':
description: Estimacion aprobada
content:
application/json:
schema:
$ref: '#/components/schemas/Estimacion'
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
parameters:
IdParam:
name: id
in: path
required: true
schema:
type: string
format: uuid
PageParam:
name: page
in: query
schema:
type: integer
minimum: 1
default: 1
LimitParam:
name: limit
in: query
schema:
type: integer
minimum: 1
maximum: 100
default: 20
responses:
BadRequest:
description: Solicitud invalida
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
Unauthorized:
description: No autorizado
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
NotFound:
description: Recurso no encontrado
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
schemas:
Error:
type: object
properties:
error:
type: string
message:
type: string
PaginationMeta:
type: object
properties:
total:
type: integer
page:
type: integer
limit:
type: integer
totalPages:
type: integer
LoginRequest:
type: object
required: [email, password]
properties:
email:
type: string
format: email
password:
type: string
minLength: 8
tenantId:
type: string
format: uuid
RegisterRequest:
type: object
required: [email, password, firstName, lastName, tenantId]
properties:
email:
type: string
format: email
password:
type: string
minLength: 8
firstName:
type: string
lastName:
type: string
tenantId:
type: string
format: uuid
RefreshTokenRequest:
type: object
required: [refreshToken]
properties:
refreshToken:
type: string
AuthResponse:
type: object
properties:
accessToken:
type: string
refreshToken:
type: string
expiresIn:
type: integer
user:
type: object
properties:
id:
type: string
format: uuid
email:
type: string
firstName:
type: string
lastName:
type: string
roles:
type: array
items:
type: string
tenant:
type: object
properties:
id:
type: string
format: uuid
name:
type: string
Concepto:
type: object
properties:
id:
type: string
format: uuid
code:
type: string
name:
type: string
description:
type: string
parentId:
type: string
format: uuid
level:
type: integer
path:
type: string
unitPrice:
type: number
isComposite:
type: boolean
createdAt:
type: string
format: date-time
ConceptoTree:
allOf:
- $ref: '#/components/schemas/Concepto'
- type: object
properties:
children:
type: array
items:
$ref: '#/components/schemas/ConceptoTree'
CreateConceptoRequest:
type: object
required: [code, name]
properties:
code:
type: string
maxLength: 50
name:
type: string
maxLength: 255
description:
type: string
parentId:
type: string
format: uuid
unitPrice:
type: number
isComposite:
type: boolean
ConceptoListResponse:
type: object
properties:
data:
type: array
items:
$ref: '#/components/schemas/Concepto'
meta:
$ref: '#/components/schemas/PaginationMeta'
Presupuesto:
type: object
properties:
id:
type: string
format: uuid
code:
type: string
name:
type: string
version:
type: integer
isActive:
type: boolean
totalAmount:
type: number
approvedAt:
type: string
format: date-time
createdAt:
type: string
format: date-time
PresupuestoPartida:
type: object
properties:
id:
type: string
format: uuid
conceptoId:
type: string
format: uuid
quantity:
type: number
unitPrice:
type: number
totalAmount:
type: number
sequence:
type: integer
PresupuestoDetalle:
allOf:
- $ref: '#/components/schemas/Presupuesto'
- type: object
properties:
partidas:
type: array
items:
$ref: '#/components/schemas/PresupuestoPartida'
CreatePresupuestoRequest:
type: object
required: [code, name]
properties:
code:
type: string
name:
type: string
description:
type: string
fraccionamientoId:
type: string
format: uuid
prototipoId:
type: string
format: uuid
AddPartidaRequest:
type: object
required: [conceptoId, quantity, unitPrice]
properties:
conceptoId:
type: string
format: uuid
quantity:
type: number
unitPrice:
type: number
sequence:
type: integer
PresupuestoListResponse:
type: object
properties:
data:
type: array
items:
$ref: '#/components/schemas/Presupuesto'
meta:
$ref: '#/components/schemas/PaginationMeta'
AdvanceStatus:
type: string
enum: [pending, captured, reviewed, approved, rejected]
AvanceObra:
type: object
properties:
id:
type: string
format: uuid
loteId:
type: string
format: uuid
conceptoId:
type: string
format: uuid
captureDate:
type: string
format: date
quantityExecuted:
type: number
percentageExecuted:
type: number
status:
$ref: '#/components/schemas/AdvanceStatus'
notes:
type: string
createdAt:
type: string
format: date-time
FotoAvance:
type: object
properties:
id:
type: string
format: uuid
fileUrl:
type: string
fileName:
type: string
description:
type: string
capturedAt:
type: string
format: date-time
CreateAvanceRequest:
type: object
required: [conceptoId, captureDate, quantityExecuted]
properties:
loteId:
type: string
format: uuid
departamentoId:
type: string
format: uuid
conceptoId:
type: string
format: uuid
captureDate:
type: string
format: date
quantityExecuted:
type: number
percentageExecuted:
type: number
notes:
type: string
AddFotoRequest:
type: object
required: [fileUrl]
properties:
fileUrl:
type: string
fileName:
type: string
description:
type: string
location:
type: object
properties:
lat:
type: number
lng:
type: number
AvanceListResponse:
type: object
properties:
data:
type: array
items:
$ref: '#/components/schemas/AvanceObra'
meta:
$ref: '#/components/schemas/PaginationMeta'
EstimateStatus:
type: string
enum: [draft, submitted, reviewed, approved, invoiced, paid, rejected, cancelled]
Estimacion:
type: object
properties:
id:
type: string
format: uuid
estimateNumber:
type: string
contratoId:
type: string
format: uuid
periodStart:
type: string
format: date
periodEnd:
type: string
format: date
sequenceNumber:
type: integer
status:
$ref: '#/components/schemas/EstimateStatus'
subtotal:
type: number
advanceAmount:
type: number
retentionAmount:
type: number
taxAmount:
type: number
totalAmount:
type: number
approvedAt:
type: string
format: date-time
createdAt:
type: string
format: date-time
CreateEstimacionRequest:
type: object
required: [contratoId, fraccionamientoId, periodStart, periodEnd]
properties:
contratoId:
type: string
format: uuid
fraccionamientoId:
type: string
format: uuid
periodStart:
type: string
format: date
periodEnd:
type: string
format: date
notes:
type: string
EstimacionListResponse:
type: object
properties:
data:
type: array
items:
$ref: '#/components/schemas/Estimacion'
meta:
$ref: '#/components/schemas/PaginationMeta'