Backend de erp-construccion - Workspace V2
Go to file
Adrian Flores Cortes 99fadef0ba [SPRINT-2] feat: Complete Quality module controllers
- Add non-conformity.controller.ts with CRUD endpoints
- Add corrective-action.controller.ts with workflow management
- Add protocolo-calidad.controller.ts for quality protocols
- Update inspection.controller.ts and exports index

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 07:05:18 -06:00
scripts Migración desde erp-construccion/backend - Estándar multi-repo v2 2026-01-16 08:11:14 -06:00
src [SPRINT-2] feat: Complete Quality module controllers 2026-02-03 07:05:18 -06:00
.env.example Migración desde erp-construccion/backend - Estándar multi-repo v2 2026-01-16 08:11:14 -06:00
.gitignore chore: Add .gitignore for clean repository 2026-01-20 07:31:35 -06:00
Dockerfile Migración desde erp-construccion/backend - Estándar multi-repo v2 2026-01-16 08:11:14 -06:00
package-lock.json feat(FASE-4A): Complete vertical modules for construction 2026-01-27 07:00:18 -06:00
package.json feat(FASE-4A): Complete vertical modules for construction 2026-01-27 07:00:18 -06:00
README.md Migración desde erp-construccion/backend - Estándar multi-repo v2 2026-01-16 08:11:14 -06:00
service.descriptor.yml Migración desde erp-construccion/backend - Estándar multi-repo v2 2026-01-16 08:11:14 -06:00
tsconfig.json Migración desde erp-construccion/backend - Estándar multi-repo v2 2026-01-16 08:11:14 -06:00

Backend - ERP Construccion

API REST para sistema de administracion de obra e INFONAVIT.

Campo Valor
Stack Node.js 20 + Express 4 + TypeScript 5 + TypeORM 0.3
Version 1.0.0
Entidades 30
Services 8
Arquitectura Multi-tenant con RLS

Quick Start

# Instalar dependencias
npm install

# Configurar variables de entorno
cp ../.env.example .env

# Desarrollo con hot-reload
npm run dev

# El servidor estara en http://localhost:3000

Estructura del Proyecto

src/
├── modules/
│   ├── auth/                    # Autenticacion JWT
│   │   ├── dto/
│   │   │   └── auth.dto.ts      # DTOs tipados
│   │   ├── middleware/
│   │   │   └── auth.middleware.ts
│   │   ├── services/
│   │   │   └── auth.service.ts
│   │   └── index.ts
│   │
│   ├── budgets/                 # MAI-003 Presupuestos
│   │   ├── entities/
│   │   │   ├── concepto.entity.ts
│   │   │   ├── presupuesto.entity.ts
│   │   │   └── presupuesto-partida.entity.ts
│   │   ├── services/
│   │   │   ├── concepto.service.ts
│   │   │   └── presupuesto.service.ts
│   │   └── index.ts
│   │
│   ├── progress/                # MAI-005 Control de Obra
│   │   ├── 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
│   │
│   ├── estimates/               # MAI-008 Estimaciones
│   │   ├── 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
│   │
│   ├── construction/            # MAI-002 Proyectos
│   │   └── entities/
│   │       ├── proyecto.entity.ts
│   │       └── fraccionamiento.entity.ts
│   │
│   ├── hr/                      # MAI-007 RRHH
│   │   └── entities/
│   │       ├── employee.entity.ts
│   │       ├── puesto.entity.ts
│   │       └── employee-fraccionamiento.entity.ts
│   │
│   ├── hse/                     # MAA-017 Seguridad HSE
│   │   └── entities/
│   │       ├── incidente.entity.ts
│   │       ├── incidente-involucrado.entity.ts
│   │       ├── incidente-accion.entity.ts
│   │       └── capacitacion.entity.ts
│   │
│   └── core/                    # Entidades base
│       └── entities/
│           ├── user.entity.ts
│           └── tenant.entity.ts
│
└── shared/
    ├── constants/               # SSOT
    │   ├── database.constants.ts
    │   ├── api.constants.ts
    │   ├── enums.constants.ts
    │   └── index.ts
    ├── services/
    │   └── base.service.ts      # CRUD multi-tenant
    └── database/
        └── typeorm.config.ts

Modulos Implementados

Auth Module

Autenticacion JWT con refresh tokens y multi-tenancy.

// Services
AuthService
  ├── login(dto)          // Login con email/password
  ├── register(dto)       // Registro de usuarios
  ├── refresh(dto)        // Renovar tokens
  ├── logout(token)       // Revocar refresh token
  └── changePassword(dto) // Cambiar password

// Middleware
AuthMiddleware
  ├── authenticate        // Validar JWT (requerido)
  ├── optionalAuthenticate // Validar JWT (opcional)
  ├── authorize(...roles) // Autorizar por roles
  ├── requireAdmin        // Solo admin/super_admin
  └── requireSupervisor   // Solo supervisores+

Budgets Module (MAI-003)

Catalogo de conceptos y presupuestos de obra.

// Entities
Concepto           // Catalogo jerarquico (arbol)
Presupuesto        // Presupuestos versionados
PresupuestoPartida // Lineas con calculo automatico

// Services
ConceptoService
  ├── createConcepto(ctx, dto)     // Crear con nivel/path automatico
  ├── findRootConceptos(ctx)       // Conceptos raiz
  ├── findChildren(ctx, parentId)  // Hijos de un concepto
  ├── getConceptoTree(ctx, rootId) // Arbol completo
  └── search(ctx, term)            // Busqueda por codigo/nombre

PresupuestoService
  ├── createPresupuesto(ctx, dto)
  ├── findByFraccionamiento(ctx, id)
  ├── findWithPartidas(ctx, id)
  ├── addPartida(ctx, id, dto)
  ├── updatePartida(ctx, id, dto)
  ├── removePartida(ctx, id)
  ├── recalculateTotal(ctx, id)
  ├── createNewVersion(ctx, id)    // Versionamiento
  └── approve(ctx, id)

Progress Module (MAI-005)

Control de avances fisicos y bitacora de obra.

// Entities
AvanceObra         // Avances con workflow
FotoAvance         // Evidencias fotograficas con GPS
BitacoraObra       // Bitacora diaria
ProgramaObra       // Programa maestro
ProgramaActividad  // Actividades WBS

// Services
AvanceObraService
  ├── createAvance(ctx, dto)
  ├── findByLote(ctx, loteId)
  ├── findByDepartamento(ctx, deptoId)
  ├── findWithFilters(ctx, filters)
  ├── findWithFotos(ctx, id)
  ├── addFoto(ctx, id, dto)
  ├── review(ctx, id)              // Workflow: revisar
  ├── approve(ctx, id)             // Workflow: aprobar
  ├── reject(ctx, id, reason)      // Workflow: rechazar
  └── getAccumulatedProgress(ctx)  // Acumulado por concepto

BitacoraObraService
  ├── createEntry(ctx, dto)        // Numero automatico
  ├── findByFraccionamiento(ctx, id)
  ├── findWithFilters(ctx, id, filters)
  ├── findByDate(ctx, id, date)
  ├── findLatest(ctx, id)
  └── getStats(ctx, id)            // Estadisticas

Estimates Module (MAI-008)

Estimaciones periodicas con workflow de aprobacion.

// Entities
Estimacion           // Estimaciones con workflow
EstimacionConcepto   // Lineas con acumulados
Generador            // Numeros generadores
Anticipo             // Anticipos
Amortizacion         // Amortizaciones
Retencion            // Retenciones
FondoGarantia        // Fondo de garantia
EstimacionWorkflow   // Historial de estados

// Services
EstimacionService
  ├── createEstimacion(ctx, dto)   // Numero automatico
  ├── findByContrato(ctx, contratoId)
  ├── findWithFilters(ctx, filters)
  ├── findWithDetails(ctx, id)     // Con relaciones
  ├── addConcepto(ctx, id, dto)
  ├── addGenerador(ctx, conceptoId, dto)
  ├── recalculateTotals(ctx, id)   // Llama funcion PG
  ├── submit(ctx, id)              // Workflow
  ├── review(ctx, id)              // Workflow
  ├── approve(ctx, id)             // Workflow
  ├── reject(ctx, id, reason)      // Workflow
  └── getContractSummary(ctx, id)  // Resumen financiero

Base Service

Servicio base con CRUD multi-tenant.

// Uso
class MiService extends BaseService<MiEntity> {
  constructor(repository: Repository<MiEntity>) {
    super(repository);
  }
}

// Metodos disponibles
BaseService<T>
  ├── findAll(ctx, options?)       // Paginado
  ├── findById(ctx, id)
  ├── findOne(ctx, where)
  ├── find(ctx, options)
  ├── create(ctx, data)
  ├── update(ctx, id, data)
  ├── softDelete(ctx, id)
  ├── hardDelete(ctx, id)
  ├── count(ctx, where?)
  └── exists(ctx, where)

// ServiceContext
interface ServiceContext {
  tenantId: string;
  userId: string;
}

SSOT Constants

Sistema de constantes centralizadas.

// database.constants.ts
import { DB_SCHEMAS, DB_TABLES, TABLE_REFS } from '@shared/constants';

DB_SCHEMAS.CONSTRUCTION  // 'construction'
DB_TABLES.construction.CONCEPTOS  // 'conceptos'
TABLE_REFS.FRACCIONAMIENTOS  // 'construction.fraccionamientos'

// api.constants.ts
import { API_ROUTES } from '@shared/constants';

API_ROUTES.PRESUPUESTOS.BASE  // '/api/v1/presupuestos'
API_ROUTES.ESTIMACIONES.BY_ID(id)  // '/api/v1/estimaciones/:id'

// enums.constants.ts
import { ROLES, PROJECT_STATUS } from '@shared/constants';

ROLES.ADMIN  // 'admin'
PROJECT_STATUS.IN_PROGRESS  // 'in_progress'

Scripts NPM

# Desarrollo
npm run dev              # Hot-reload con ts-node-dev
npm run build            # Compilar TypeScript
npm run start            # Produccion (dist/)

# Calidad
npm run lint             # ESLint
npm run lint:fix         # ESLint con autofix
npm run test             # Jest
npm run test:watch       # Jest watch mode
npm run test:coverage    # Jest con cobertura

# Base de datos
npm run migration:generate  # Generar migracion
npm run migration:run       # Ejecutar migraciones
npm run migration:revert    # Revertir ultima

# SSOT
npm run validate:constants  # Validar no hardcoding
npm run sync:enums          # Sincronizar a frontend
npm run precommit           # lint + validate

Convenciones

Nomenclatura

Tipo Convencion Ejemplo
Archivos kebab-case.tipo.ts concepto.entity.ts
Clases PascalCase + sufijo ConceptoService
Variables camelCase totalAmount
Constantes UPPER_SNAKE_CASE DB_SCHEMAS
Metodos camelCase + verbo findByContrato

Entity Pattern

@Entity({ schema: 'construction', name: 'conceptos' })
@Index(['tenantId', 'code'], { unique: true })
export class Concepto {
  @PrimaryGeneratedColumn('uuid')
  id: string;

  @Column({ name: 'tenant_id', type: 'uuid' })
  tenantId: string;

  // ... columnas con name: 'snake_case'

  // Soft delete
  @Column({ name: 'deleted_at', type: 'timestamptz', nullable: true })
  deletedAt: Date | null;

  // Relations
  @ManyToOne(() => Tenant)
  @JoinColumn({ name: 'tenant_id' })
  tenant: Tenant;
}

Service Pattern

export class MiService extends BaseService<MiEntity> {
  constructor(
    repository: Repository<MiEntity>,
    private readonly otroRepo: Repository<OtroEntity>
  ) {
    super(repository);
  }

  async miMetodo(ctx: ServiceContext, data: MiDto): Promise<MiEntity> {
    // ctx tiene tenantId y userId
    return this.create(ctx, data);
  }
}

Seguridad

  • Helmet para HTTP security headers
  • CORS configurado por dominio
  • Rate limiting por IP
  • JWT con refresh tokens
  • Bcrypt (12 rounds) para passwords
  • class-validator para inputs
  • RLS para aislamiento de tenants

Testing

# Ejecutar tests
npm test

# Con cobertura
npm run test:coverage

# Watch mode
npm run test:watch
// Ejemplo de test
describe('ConceptoService', () => {
  let service: ConceptoService;
  let mockRepo: jest.Mocked<Repository<Concepto>>;

  beforeEach(() => {
    mockRepo = createMockRepository();
    service = new ConceptoService(mockRepo);
  });

  it('should create concepto with level', async () => {
    const ctx = { tenantId: 'uuid', userId: 'uuid' };
    const dto = { code: '001', name: 'Test' };

    mockRepo.save.mockResolvedValue({ ...dto, level: 0 });

    const result = await service.createConcepto(ctx, dto);
    expect(result.level).toBe(0);
  });
});

Debugging

VS Code

{
  "type": "node",
  "request": "launch",
  "name": "Debug Backend",
  "runtimeArgs": ["-r", "ts-node/register"],
  "args": ["${workspaceFolder}/src/server.ts"],
  "env": { "NODE_ENV": "development" }
}

Logs

// Configurar en .env
LOG_LEVEL=debug
LOG_FORMAT=dev

Ultima actualizacion: 2025-12-12