workspace-v1/projects/erp-construccion/docs/02-definicion-modulos/MAI-009-calidad-postventa/especificaciones/ET-QUA-002-no-conformidades.md
rckrdmrd 66161b1566 feat: Workspace-v1 complete migration with NEXUS v3.4
Sistema NEXUS v3.4 migrado con:

Estructura principal:
- core/orchestration: Sistema SIMCO + CAPVED (27 directivas, 28 perfiles)
- core/catalog: Catalogo de funcionalidades reutilizables
- shared/knowledge-base: Base de conocimiento compartida
- devtools/scripts: Herramientas de desarrollo
- control-plane/registries: Control de servicios y CI/CD
- orchestration/: Configuracion de orquestacion de agentes

Proyectos incluidos (11):
- gamilit (submodule -> GitHub)
- trading-platform (OrbiquanTIA)
- erp-suite con 5 verticales:
  - erp-core, construccion, vidrio-templado
  - mecanicas-diesel, retail, clinicas
- betting-analytics
- inmobiliaria-analytics
- platform_marketing_content
- pos-micro, erp-basico

Configuracion:
- .gitignore completo para Node.js/Python/Docker
- gamilit como submodule (git@github.com:rckrdmrd/gamilit-workspace.git)
- Sistema de puertos estandarizado (3005-3199)

Generated with NEXUS v3.4 Migration System
EPIC-010: Configuracion Git y Repositorios
2026-01-04 03:37:42 -06:00

1.9 KiB

ET-QUA-002: Sistema de No Conformidades

ID: ET-QUA-002 | Módulo: MAI-009

Schema

CREATE TYPE quality.nc_severity AS ENUM ('minor', 'major', 'critical');
CREATE TYPE quality.nc_status AS ENUM ('open', 'in_progress', 'corrected', 'verified', 'closed');

CREATE TABLE quality.non_conformities (
  id UUID PRIMARY KEY,
  numero VARCHAR(50) UNIQUE, -- NC-2025-001
  inspection_id UUID,
  housing_id UUID,
  severity quality.nc_severity,
  category VARCHAR(50),
  description TEXT,
  photo_url TEXT,
  detected_by UUID,
  detected_at TIMESTAMPTZ DEFAULT NOW(),
  status quality.nc_status DEFAULT 'open',
  assigned_to UUID,
  sla_deadline TIMESTAMPTZ,
  corrective_action TEXT,
  preventive_action TEXT,
  corrected_at TIMESTAMPTZ,
  verification_photo TEXT,
  verified_by UUID,
  closed_at TIMESTAMPTZ
);

Backend Service

@Injectable()
export class NonConformityService {
  async create(dto: CreateNCDto): Promise<NonConformity> {
    const slaDeadline = this.calculateSLADeadline(dto.severity);
    const numero = await this.getNextNumber();
    
    const nc = this.ncRepo.create({ ...dto, numero, slaDeadline, status: 'open' });
    await this.ncRepo.save(nc);
    
    // Asignar automáticamente según categoría
    await this.autoAssign(nc);
    
    // Alerta si es crítica
    if (dto.severity === 'critical') {
      await this.alertCriticalNC(nc);
    }
    
    return nc;
  }

  private calculateSLADeadline(severity: NCSeverity): Date {
    const hours = { minor: 168, major: 72, critical: 24 };
    return new Date(Date.now() + hours[severity] * 60 * 60 * 1000);
  }

  @Cron('0 */1 * * *') // Cada hora
  async checkOverdueSL(): Promise<void> {
    const overdue = await this.ncRepo.find({
      where: { status: In(['open', 'in_progress']), slaDeadline: LessThan(new Date()) }
    });
    
    for (const nc of overdue) {
      await this.escalateNC(nc);
    }
  }
}

Generado: 2025-11-20