# Documentacion de Modulos Backend Este documento detalla la implementacion de cada modulo del backend. --- ## Indice 1. [Auth Module](#auth-module) 2. [Budgets Module (MAI-003)](#budgets-module-mai-003) 3. [Progress Module (MAI-005)](#progress-module-mai-005) 4. [Estimates Module (MAI-008)](#estimates-module-mai-008) 5. [Construction Module (MAI-002)](#construction-module-mai-002) 6. [HR Module (MAI-007)](#hr-module-mai-007) 7. [HSE Module (MAA-017)](#hse-module-maa-017) 8. [Core Module](#core-module) --- ## Auth Module **Ubicacion:** `backend/src/modules/auth/` ### Descripcion Modulo de autenticacion JWT con refresh tokens y soporte multi-tenant. ### Estructura ``` auth/ ├── dto/ │ └── auth.dto.ts # DTOs de autenticacion ├── services/ │ └── auth.service.ts # Logica de autenticacion ├── middleware/ │ └── auth.middleware.ts # Middleware JWT └── index.ts # Exports ``` ### DTOs ```typescript // LoginDto { email: string; // Email del usuario password: string; // Password } // RegisterDto { email: string; password: string; firstName: string; lastName: string; tenantId: string; // Tenant al que pertenece } // RefreshTokenDto { refreshToken: string; } // AuthResponse { user: UserDto; accessToken: string; refreshToken: string; expiresIn: number; } ``` ### AuthService | Metodo | Descripcion | Parametros | Retorna | |--------|-------------|------------|---------| | `login` | Autentica usuario | `LoginDto` | `AuthResponse` | | `register` | Registra nuevo usuario | `RegisterDto` | `AuthResponse` | | `refresh` | Renueva tokens | `RefreshTokenDto` | `AuthResponse` | | `logout` | Revoca refresh token | `token: string` | `boolean` | | `changePassword` | Cambia password | `ChangePasswordDto` | `boolean` | | `validateToken` | Valida JWT | `token: string` | `JwtPayload` | ### AuthMiddleware | Metodo | Descripcion | |--------|-------------| | `authenticate` | Valida JWT (requerido) | | `optionalAuthenticate` | Valida JWT (opcional) | | `authorize(...roles)` | Autoriza por roles | | `requireAdmin` | Solo admin/super_admin | | `requireSupervisor` | Solo supervisores+ | | `setRLSContext` | Configura tenant en sesion PostgreSQL | ### Ejemplo de Uso ```typescript // Login const auth = await authService.login({ email: 'user@example.com', password: 'securePassword123' }); // Usar token en requests headers: { 'Authorization': `Bearer ${auth.accessToken}` } // Refresh cuando expire const newAuth = await authService.refresh({ refreshToken: auth.refreshToken }); ``` --- ## Budgets Module (MAI-003) **Ubicacion:** `backend/src/modules/budgets/` ### Descripcion Gestion de catalogos de conceptos y presupuestos de obra. ### Estructura ``` budgets/ ├── entities/ │ ├── concepto.entity.ts │ ├── presupuesto.entity.ts │ └── presupuesto-partida.entity.ts ├── services/ │ ├── concepto.service.ts │ └── presupuesto.service.ts └── index.ts ``` ### Entidades #### Concepto Catalogo jerarquico de conceptos de obra. | Campo | Tipo | Descripcion | |-------|------|-------------| | `id` | UUID | Primary key | | `tenantId` | UUID | Discriminador multi-tenant | | `code` | string | Codigo unico (ej: "01.02.003") | | `name` | string | Nombre del concepto | | `description` | string | Descripcion detallada | | `unit` | string | Unidad de medida (M2, ML, PZA) | | `unitPrice` | decimal | Precio unitario | | `parentId` | UUID | Concepto padre (null=raiz) | | `level` | number | Nivel jerarquico (0=raiz) | | `path` | string | Ruta completa (ej: "01/02/003") | | `isActive` | boolean | Activo para uso | **Relaciones:** - `parent` → Concepto (auto-referencial) - `children` → Concepto[] (hijos) #### Presupuesto Presupuesto versionado de obra. | Campo | Tipo | Descripcion | |-------|------|-------------| | `id` | UUID | Primary key | | `tenantId` | UUID | Discriminador | | `fraccionamientoId` | UUID | Proyecto asociado | | `code` | string | Codigo del presupuesto | | `name` | string | Nombre descriptivo | | `version` | number | Version (1, 2, 3...) | | `status` | enum | draft/submitted/approved | | `totalAmount` | decimal | Total calculado | | `approvedAt` | timestamp | Fecha de aprobacion | | `approvedById` | UUID | Usuario que aprobo | **Relaciones:** - `fraccionamiento` → Fraccionamiento - `partidas` → PresupuestoPartida[] #### PresupuestoPartida Lineas de presupuesto. | Campo | Tipo | Descripcion | |-------|------|-------------| | `id` | UUID | Primary key | | `presupuestoId` | UUID | Presupuesto padre | | `conceptoId` | UUID | Concepto referenciado | | `quantity` | decimal | Cantidad | | `unitPrice` | decimal | Precio unitario | | `totalAmount` | decimal | **GENERADO**: quantity * unitPrice | ### ConceptoService | Metodo | Descripcion | |--------|-------------| | `createConcepto(ctx, dto)` | Crea concepto, calcula nivel/path | | `findRootConceptos(ctx)` | Conceptos raiz (nivel 0) | | `findChildren(ctx, parentId)` | Hijos de un concepto | | `getConceptoTree(ctx, rootId?)` | Arbol completo/parcial | | `search(ctx, term)` | Busqueda por codigo/nombre | ### PresupuestoService | Metodo | Descripcion | |--------|-------------| | `createPresupuesto(ctx, dto)` | Crea presupuesto | | `findByFraccionamiento(ctx, id)` | Por proyecto | | `findWithPartidas(ctx, id)` | Con lineas cargadas | | `addPartida(ctx, presupuestoId, dto)` | Agregar linea | | `updatePartida(ctx, partidaId, dto)` | Modificar linea | | `removePartida(ctx, partidaId)` | Eliminar linea | | `recalculateTotal(ctx, presupuestoId)` | Recalcular total | | `createNewVersion(ctx, presupuestoId)` | Crear version nueva | | `approve(ctx, presupuestoId)` | Aprobar presupuesto | --- ## Progress Module (MAI-005) **Ubicacion:** `backend/src/modules/progress/` ### Descripcion Control de avances fisicos, bitacora y programacion de obra. ### Estructura ``` progress/ ├── entities/ │ ├── avance-obra.entity.ts │ ├── foto-avance.entity.ts │ ├── bitacora-obra.entity.ts │ ├── programa-obra.entity.ts │ └── programa-actividad.entity.ts ├── services/ │ ├── avance-obra.service.ts │ └── bitacora-obra.service.ts └── index.ts ``` ### Entidades #### AvanceObra Registro de avance fisico con workflow. | Campo | Tipo | Descripcion | |-------|------|-------------| | `id` | UUID | Primary key | | `tenantId` | UUID | Discriminador | | `loteId` | UUID | Lote donde se registro | | `departamentoId` | UUID | Departamento (opcional) | | `conceptoId` | UUID | Concepto de catalogo | | `quantity` | decimal | Cantidad ejecutada | | `progressDate` | date | Fecha de avance | | `status` | enum | captured/reviewed/approved/rejected | | `capturedById` | UUID | Usuario que capturo | | `reviewedAt` | timestamp | Fecha de revision | | `approvedAt` | timestamp | Fecha de aprobacion | | `rejectionReason` | string | Motivo de rechazo | | `notes` | string | Notas adicionales | #### FotoAvance Evidencia fotografica con geolocalización. | Campo | Tipo | Descripcion | |-------|------|-------------| | `id` | UUID | Primary key | | `avanceObraId` | UUID | Avance asociado | | `fileName` | string | Nombre del archivo | | `filePath` | string | Ruta en storage | | `fileSize` | number | Tamano en bytes | | `mimeType` | string | Tipo MIME | | `latitude` | decimal | Latitud GPS | | `longitude` | decimal | Longitud GPS | | `takenAt` | timestamp | Fecha de captura | | `description` | string | Descripcion | #### BitacoraObra Bitacora diaria de obra. | Campo | Tipo | Descripcion | |-------|------|-------------| | `id` | UUID | Primary key | | `tenantId` | UUID | Discriminador | | `fraccionamientoId` | UUID | Proyecto | | `entryNumber` | number | Numero secuencial | | `entryDate` | date | Fecha de entrada | | `weather` | string | Clima del dia | | `temperature` | decimal | Temperatura | | `workersCount` | number | Personal en obra | | `activities` | text | Actividades realizadas | | `incidents` | text | Incidentes | | `observations` | text | Observaciones | | `createdById` | UUID | Usuario que creo | ### AvanceObraService | Metodo | Descripcion | |--------|-------------| | `createAvance(ctx, dto)` | Crear avance en status captured | | `findByLote(ctx, loteId)` | Avances de un lote | | `findByDepartamento(ctx, deptoId)` | Avances de departamento | | `findWithFilters(ctx, filters)` | Busqueda con filtros | | `findWithFotos(ctx, id)` | Avance con fotos | | `addFoto(ctx, avanceId, dto)` | Agregar foto | | `review(ctx, id)` | Workflow: revisar | | `approve(ctx, id)` | Workflow: aprobar | | `reject(ctx, id, reason)` | Workflow: rechazar | | `getAccumulatedProgress(ctx)` | Acumulado por concepto | ### BitacoraObraService | Metodo | Descripcion | |--------|-------------| | `createEntry(ctx, dto)` | Crear entrada (numero automatico) | | `findByFraccionamiento(ctx, id)` | Entradas de proyecto | | `findWithFilters(ctx, id, filters)` | Con filtros | | `findByDate(ctx, id, date)` | Por fecha especifica | | `findLatest(ctx, id)` | Ultima entrada | | `getStats(ctx, id)` | Estadisticas | --- ## Estimates Module (MAI-008) **Ubicacion:** `backend/src/modules/estimates/` ### Descripcion Estimaciones periodicas con workflow de aprobacion completo. ### Estructura ``` estimates/ ├── entities/ │ ├── estimacion.entity.ts │ ├── estimacion-concepto.entity.ts │ ├── generador.entity.ts │ ├── anticipo.entity.ts │ ├── amortizacion.entity.ts │ ├── retencion.entity.ts │ ├── fondo-garantia.entity.ts │ └── estimacion-workflow.entity.ts ├── services/ │ └── estimacion.service.ts └── index.ts ``` ### Entidades #### Estimacion Estimacion periodica principal. | Campo | Tipo | Descripcion | |-------|------|-------------| | `id` | UUID | Primary key | | `tenantId` | UUID | Discriminador | | `contratoId` | UUID | Contrato asociado | | `number` | number | Numero secuencial | | `periodStart` | date | Inicio del periodo | | `periodEnd` | date | Fin del periodo | | `status` | enum | draft/submitted/reviewed/approved/rejected | | `subtotal` | decimal | Suma de conceptos | | `iva` | decimal | IVA calculado | | `retentions` | decimal | Retenciones | | `amortization` | decimal | Amortizacion de anticipo | | `totalAmount` | decimal | Total neto | | `submittedAt` | timestamp | Fecha de envio | | `reviewedAt` | timestamp | Fecha de revision | | `approvedAt` | timestamp | Fecha de aprobacion | | `rejectionReason` | string | Motivo de rechazo | #### EstimacionConcepto Lineas de estimacion con acumulados. | Campo | Tipo | Descripcion | |-------|------|-------------| | `id` | UUID | Primary key | | `estimacionId` | UUID | Estimacion padre | | `conceptoId` | UUID | Concepto de catalogo | | `contractQuantity` | decimal | Cantidad contratada | | `previousQuantity` | decimal | Cantidad acumulada anterior | | `currentQuantity` | decimal | Cantidad este periodo | | `accumulatedQuantity` | decimal | **GENERADO**: previous + current | | `pendingQuantity` | decimal | **GENERADO**: contract - accumulated | | `unitPrice` | decimal | Precio unitario | | `currentAmount` | decimal | **GENERADO**: current * price | | `accumulatedAmount` | decimal | **GENERADO**: accumulated * price | #### Generador Numeros generadores (desglose de cantidades). | Campo | Tipo | Descripcion | |-------|------|-------------| | `id` | UUID | Primary key | | `estimacionConceptoId` | UUID | Linea de estimacion | | `description` | string | Descripcion del calculo | | `length` | decimal | Largo | | `width` | decimal | Ancho | | `height` | decimal | Alto | | `quantity` | decimal | Cantidad/Piezas | | `partial` | decimal | **GENERADO**: formula | | `formula` | string | Formula aplicada | #### Anticipo Anticipos de contrato. | Campo | Tipo | Descripcion | |-------|------|-------------| | `id` | UUID | Primary key | | `contratoId` | UUID | Contrato | | `type` | enum | obra/materiales | | `percentage` | decimal | Porcentaje del contrato | | `amount` | decimal | Monto del anticipo | | `grantedDate` | date | Fecha de otorgamiento | | `amortizedAmount` | decimal | Monto ya amortizado | | `pendingAmount` | decimal | **GENERADO** | | `status` | enum | pending/partial/completed | #### FondoGarantia Fondo de garantia acumulado. | Campo | Tipo | Descripcion | |-------|------|-------------| | `id` | UUID | Primary key | | `contratoId` | UUID | Contrato | | `percentage` | decimal | Porcentaje retenido | | `accumulatedAmount` | decimal | Monto acumulado | | `releasedAmount` | decimal | Monto liberado | | `pendingAmount` | decimal | **GENERADO** | ### EstimacionService | Metodo | Descripcion | |--------|-------------| | `createEstimacion(ctx, dto)` | Crear con numero automatico | | `findByContrato(ctx, contratoId)` | Estimaciones de contrato | | `findWithFilters(ctx, filters)` | Busqueda con filtros | | `findWithDetails(ctx, id)` | Con todas las relaciones | | `addConcepto(ctx, estimacionId, dto)` | Agregar linea | | `addGenerador(ctx, conceptoId, dto)` | Agregar generador | | `recalculateTotals(ctx, id)` | Recalcular totales | | `submit(ctx, id)` | Workflow: enviar | | `review(ctx, id)` | Workflow: revisar | | `approve(ctx, id)` | Workflow: aprobar | | `reject(ctx, id, reason)` | Workflow: rechazar | | `getContractSummary(ctx, contratoId)` | Resumen financiero | --- ## Construction Module (MAI-002) **Ubicacion:** `backend/src/modules/construction/` ### Descripcion Gestion de proyectos y estructura organizacional. ### Entidades #### Proyecto | Campo | Tipo | Descripcion | |-------|------|-------------| | `id` | UUID | Primary key | | `tenantId` | UUID | Discriminador | | `code` | string | Codigo del proyecto | | `name` | string | Nombre | | `description` | text | Descripcion | | `status` | enum | planning/in_progress/completed/cancelled | | `startDate` | date | Fecha inicio | | `endDate` | date | Fecha fin | | `budget` | decimal | Presupuesto total | | `location` | geography | Ubicacion GPS | | `address` | string | Direccion | | `city` | string | Ciudad | | `state` | string | Estado | #### Fraccionamiento | Campo | Tipo | Descripcion | |-------|------|-------------| | `id` | UUID | Primary key | | `tenantId` | UUID | Discriminador | | `proyectoId` | UUID | Proyecto padre | | `code` | string | Codigo | | `name` | string | Nombre | | `totalLots` | number | Total de lotes | | `builtLots` | number | Lotes construidos | | `soldLots` | number | Lotes vendidos | --- ## HR Module (MAI-007) **Ubicacion:** `backend/src/modules/hr/` ### Descripcion Gestion de recursos humanos y asignaciones. ### Entidades #### Employee | Campo | Tipo | Descripcion | |-------|------|-------------| | `id` | UUID | Primary key | | `tenantId` | UUID | Discriminador | | `employeeNumber` | string | Numero de empleado | | `firstName` | string | Nombre | | `lastName` | string | Apellidos | | `email` | string | Email | | `phone` | string | Telefono | | `hireDate` | date | Fecha de contratacion | | `puestoId` | UUID | Puesto | | `status` | enum | active/inactive/terminated | | `dailyRate` | decimal | Salario diario | | `imssNumber` | string | Numero IMSS | | `curp` | string | CURP | | `rfc` | string | RFC | #### Puesto | Campo | Tipo | Descripcion | |-------|------|-------------| | `id` | UUID | Primary key | | `tenantId` | UUID | Discriminador | | `code` | string | Codigo | | `name` | string | Nombre del puesto | | `department` | string | Departamento | | `level` | number | Nivel jerarquico | | `baseSalary` | decimal | Salario base | #### EmployeeFraccionamiento Asignacion de empleados a proyectos. | Campo | Tipo | Descripcion | |-------|------|-------------| | `id` | UUID | Primary key | | `employeeId` | UUID | Empleado | | `fraccionamientoId` | UUID | Proyecto | | `role` | string | Rol en el proyecto | | `startDate` | date | Fecha inicio | | `endDate` | date | Fecha fin (null=activo) | --- ## HSE Module (MAA-017) **Ubicacion:** `backend/src/modules/hse/` ### Descripcion Seguridad, salud y medio ambiente. ### Entidades #### Incidente | Campo | Tipo | Descripcion | |-------|------|-------------| | `id` | UUID | Primary key | | `tenantId` | UUID | Discriminador | | `fraccionamientoId` | UUID | Proyecto | | `incidentNumber` | string | Numero de reporte | | `incidentDate` | timestamp | Fecha y hora | | `type` | enum | accident/near_miss/incident | | `severity` | enum | low/medium/high/critical | | `description` | text | Descripcion | | `location` | string | Ubicacion | | `immediateActions` | text | Acciones inmediatas | | `rootCause` | text | Causa raiz | | `status` | enum | reported/investigating/closed | | `reportedById` | UUID | Quien reporto | #### IncidenteInvolucrado | Campo | Tipo | Descripcion | |-------|------|-------------| | `id` | UUID | Primary key | | `incidenteId` | UUID | Incidente | | `employeeId` | UUID | Empleado (opcional) | | `name` | string | Nombre (si no es empleado) | | `role` | enum | victim/witness/reporter | | `injuryType` | string | Tipo de lesion | | `treatmentRequired` | boolean | Requirio tratamiento | #### IncidenteAccion Acciones correctivas. | Campo | Tipo | Descripcion | |-------|------|-------------| | `id` | UUID | Primary key | | `incidenteId` | UUID | Incidente | | `description` | text | Descripcion de la accion | | `responsibleId` | UUID | Responsable | | `dueDate` | date | Fecha limite | | `completedAt` | timestamp | Fecha de cierre | | `status` | enum | pending/in_progress/completed | #### Capacitacion | Campo | Tipo | Descripcion | |-------|------|-------------| | `id` | UUID | Primary key | | `tenantId` | UUID | Discriminador | | `name` | string | Nombre del curso | | `type` | enum | induction/specific/recertification | | `duration` | number | Duracion en horas | | `validityMonths` | number | Vigencia en meses | | `instructor` | string | Instructor | | `scheduledDate` | date | Fecha programada | | `status` | enum | scheduled/completed/cancelled | --- ## Core Module **Ubicacion:** `backend/src/modules/core/` ### Descripcion Entidades base del sistema (usuarios, tenants). ### Entidades #### User | Campo | Tipo | Descripcion | |-------|------|-------------| | `id` | UUID | Primary key | | `email` | string | Email unico | | `passwordHash` | string | Password hasheado | | `firstName` | string | Nombre | | `lastName` | string | Apellidos | | `role` | enum | Rol del sistema | | `isActive` | boolean | Usuario activo | | `lastLoginAt` | timestamp | Ultimo acceso | | `emailVerifiedAt` | timestamp | Email verificado | #### Tenant | Campo | Tipo | Descripcion | |-------|------|-------------| | `id` | UUID | Primary key | | `code` | string | Codigo unico | | `name` | string | Nombre de la empresa | | `subdomain` | string | Subdominio | | `plan` | enum | basic/professional/enterprise | | `isActive` | boolean | Tenant activo | | `settings` | jsonb | Configuraciones | | `createdAt` | timestamp | Fecha de creacion | --- ## Shared: BaseService **Ubicacion:** `backend/src/shared/services/base.service.ts` ### Descripcion Servicio base abstracto que proporciona operaciones CRUD multi-tenant. ### Interface ServiceContext ```typescript interface ServiceContext { tenantId: string; userId: string; } ``` ### Interface PaginatedResult ```typescript interface PaginatedResult { data: T[]; total: number; page: number; limit: number; totalPages: number; } ``` ### Metodos | Metodo | Descripcion | Retorna | |--------|-------------|---------| | `findAll(ctx, options?)` | Listado paginado | `PaginatedResult` | | `findById(ctx, id)` | Por ID | `T \| null` | | `findOne(ctx, where)` | Por condicion | `T \| null` | | `find(ctx, options)` | Por opciones | `T[]` | | `create(ctx, data)` | Crear registro | `T` | | `update(ctx, id, data)` | Actualizar | `T \| null` | | `softDelete(ctx, id)` | Borrado logico | `boolean` | | `hardDelete(ctx, id)` | Borrado fisico | `boolean` | | `count(ctx, where?)` | Contar registros | `number` | | `exists(ctx, where)` | Verificar existencia | `boolean` | ### Ejemplo de Uso ```typescript class MiService extends BaseService { constructor(repository: Repository) { super(repository); } // Metodos personalizados async findActive(ctx: ServiceContext): Promise { return this.find(ctx, { where: { isActive: true }, order: { createdAt: 'DESC' }, }); } } // Uso const ctx = { tenantId: 'uuid', userId: 'uuid' }; const items = await miService.findAll(ctx, { page: 1, limit: 10 }); const item = await miService.findById(ctx, 'item-uuid'); const created = await miService.create(ctx, { name: 'Nuevo' }); ``` --- **Ultima actualizacion:** 2025-12-12