From d28186a567116374a87ab2617fe16119c832294e Mon Sep 17 00:00:00 2001 From: enlineawork Date: Wed, 9 Sep 2026 14:44:06 -0300 Subject: [PATCH 01/12] =?UTF-8?q?docs(code):=20documentar=20jerarqu=C3=ADa?= =?UTF-8?q?=20can=C3=B3nica=20de=20Inventario?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api-v3/src/asset-master/dto/create-inventory-structure.dto.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/api-v3/src/asset-master/dto/create-inventory-structure.dto.ts b/api-v3/src/asset-master/dto/create-inventory-structure.dto.ts index 3263939..b604d3c 100644 --- a/api-v3/src/asset-master/dto/create-inventory-structure.dto.ts +++ b/api-v3/src/asset-master/dto/create-inventory-structure.dto.ts @@ -9,6 +9,8 @@ import { MinLength, } from 'class-validator'; +// Invariante de dominio: Empresa es un maestro independiente. La jerarquía física +// se expresa sólo como Departamento → Área → Yacimiento → Instalación → Subinstalación. export const INVENTORY_STRUCTURE_KINDS = [ 'EMPRESA', 'DEPARTAMENTO', From a4fad611d446d554a616b8f7e99f3bd4ca6fa881 Mon Sep 17 00:00:00 2001 From: enlineawork Date: Wed, 9 Sep 2026 14:44:26 -0300 Subject: [PATCH 02/12] docs(code): fijar invariante multi-Acta --- api-v3/src/database/entities/inspection-act.entity.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/api-v3/src/database/entities/inspection-act.entity.ts b/api-v3/src/database/entities/inspection-act.entity.ts index 9f0b0f0..27f2846 100644 --- a/api-v3/src/database/entities/inspection-act.entity.ts +++ b/api-v3/src/database/entities/inspection-act.entity.ts @@ -30,6 +30,8 @@ export enum InspectionDeadlineBasis { GEDO_DATE = 'GEDO_DATE', } +// Una Inspección puede acumular múltiples Actas. El índice parcial de DRAFT es +// deliberado: permite el historial multi-Acta y bloquea dos borradores simultáneos. @Entity({ name: 'inspection_acts' }) @Index('uq_inspection_acts_one_draft_per_visit', ['visitId'], { unique: true, where: "status = 'DRAFT'" }) @Index('uq_inspection_acts_year_number', ['actYear', 'actNumber'], { unique: true }) From 0959e854876334a628e9eb329db40884863f49fe Mon Sep 17 00:00:00 2001 From: enlineawork Date: Wed, 9 Sep 2026 14:44:57 -0300 Subject: [PATCH 03/12] =?UTF-8?q?fix:=20alinear=20terminolog=C3=ADa=20del?= =?UTF-8?q?=20contexto=20de=20inspecci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../inspection-visits/inspection-visit-lifecycle.service.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/api-v3/src/inspection-visits/inspection-visit-lifecycle.service.ts b/api-v3/src/inspection-visits/inspection-visit-lifecycle.service.ts index d1d7418..3f2f377 100644 --- a/api-v3/src/inspection-visits/inspection-visit-lifecycle.service.ts +++ b/api-v3/src/inspection-visits/inspection-visit-lifecycle.service.ts @@ -295,11 +295,13 @@ export class InspectionVisitLifecycleService { } } + // El contexto operativo de una Inspección es Área + Operadora vigente. El + // Yacimiento pertenece al alcance físico y nunca reemplaza al Área raíz. private async validatePlanningContext(manager: EntityManager, visit: InspectionVisit): Promise { if (!visit.operationalAreaId || !visit.operatorCompanyId || !visit.leadInspectorUserId || !visit.plannedStartAt) { throw new ConflictException({ code: 'INSPECTION_PLANNING_INCOMPLETE', - message: 'Definí Área/Yacimiento, Operadora, Inspector responsable y fecha de inicio antes de planificar', + message: 'Definí Área, Operadora, Inspector responsable y fecha de inicio antes de planificar', }); } if (!visit.checklistGeneratedAt || visit.checklistGeneration < 1) { @@ -320,7 +322,7 @@ export class InspectionVisitLifecycleService { if (!relation) { throw new ConflictException({ code: 'INSPECTION_OPERATOR_RELATION_INVALID', - message: 'La Operadora seleccionada no tiene una relación operativa vigente con el Área/Yacimiento', + message: 'La Operadora seleccionada no tiene una relación operativa vigente con el Área', }); } const [inspector] = await manager.query(` From 5a9c4ed5ef6387e27eec66e462fe8648d77bc005 Mon Sep 17 00:00:00 2001 From: enlineawork Date: Wed, 9 Sep 2026 14:47:19 -0300 Subject: [PATCH 04/12] test: fijar invariantes transversales F6.1 --- .../test/unit/f6-1-project-invariants.test.ts | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 api-v3/test/unit/f6-1-project-invariants.test.ts diff --git a/api-v3/test/unit/f6-1-project-invariants.test.ts b/api-v3/test/unit/f6-1-project-invariants.test.ts new file mode 100644 index 0000000..d824b85 --- /dev/null +++ b/api-v3/test/unit/f6-1-project-invariants.test.ts @@ -0,0 +1,71 @@ +import assert from 'node:assert/strict'; +import { readFileSync } from 'node:fs'; +import { resolve } from 'node:path'; +import test from 'node:test'; + +function source(path: string): string { + return readFileSync(resolve(process.cwd(), path), 'utf8'); +} + +test('F6.1 conserva una jerarquía territorial única y Empresa fuera del árbol físico', () => { + const structure = source('src/asset-master/inventory-structure.service.ts'); + const dto = source('src/asset-master/dto/create-inventory-structure.dto.ts'); + + assert.match(dto, /'EMPRESA',[\s\S]*'DEPARTAMENTO',[\s\S]*'AREA',[\s\S]*'YACIMIENTO',[\s\S]*'INSTALACION',[\s\S]*'SUBINSTALACION'/); + assert.match(structure, /EMPRESA:\s*null/); + assert.match(structure, /DEPARTAMENTO:\s*null/); + assert.match(structure, /AREA:\s*'departamento'/); + assert.match(structure, /YACIMIENTO:\s*'area'/); + assert.match(structure, /INSTALACION:\s*'yacimiento'/); + assert.match(structure, /SUBINSTALACION:\s*'instalacion'/); + assert.match(structure, /Departamento → Área → Yacimiento → Instalación → Subinstalación/); +}); + +test('F6.1 usa Área + Operadora como contexto de planificación y no mezcla Yacimiento con Área', () => { + const lifecycle = source('src/inspection-visits/inspection-visit-lifecycle.service.ts'); + const visits = source('src/inspection-visits/inspection-visits.service.ts'); + + assert.match(lifecycle, /El contexto operativo de una Inspección es Área \+ Operadora vigente/); + assert.doesNotMatch(lifecycle, /Área\/Yacimiento/); + assert.match(visits, /FROM area_company_relations/); + assert.match(visits, /relation\.relation_role = 'OPERATOR'/); +}); + +test('F6.1 mantiene múltiples Actas por Inspección pero un solo borrador simultáneo', () => { + const act = source('src/database/entities/inspection-act.entity.ts'); + const lifecycle = source('src/inspection-visits/inspection-visit-lifecycle.service.ts'); + + assert.match(act, /uq_inspection_acts_one_draft_per_visit/); + assert.match(act, /where: "status = 'DRAFT'"/); + assert.match(act, /Una Inspección puede acumular múltiples Actas/); + assert.match(lifecycle, /Todas las Actas deben estar SELLADAS antes de cerrar la Inspección/); +}); + +test('F6.1 permite Hallazgos directos sólo en Yacimiento, Instalación y Subinstalación y conserva OTROS', () => { + const field = source('src/inspection-visits/field-findings.service.ts'); + const resolver = source('src/inspection-findings/f3-finding-catalog-resolver.service.ts'); + + assert.match(field, /\['yacimiento', 'instalacion', 'subinstalacion'\]\.includes\(assetTypeCode\)/); + assert.match(field, /assetTypeCode !== 'yacimiento' && !row\.inventoryFamilyId/); + assert.match(field, /canAddAnother: true/); + assert.match(resolver, /code: 'OTHER'/); + assert.match(resolver, /label: 'OTROS'/); +}); + +test('F6.1 abre Inspecciones desde Android usando el lifecycle canónico', () => { + const controller = source('src/inspection-visits/inspection-visits.controller.ts'); + + assert.match(controller, /@Post\('mobile\/open'\)/); + assert.match(controller, /leadInspectorUserId: principal\.userId/); + assert.match(controller, /this\.lifecycle\.plan\(created\.id/); + assert.match(controller, /this\.lifecycle\.start\(created\.id/); +}); + +test('F6.1 separa oficialización GEDO de la activación del vencimiento no urgente', () => { + const report = source('src/inspection-reports/inspection-report-workflow.service.ts'); + const act = source('src/database/entities/inspection-act.entity.ts'); + + assert.match(report, /GEDO oficializa el INF, pero no equivale por sí solo a la notificación/); + assert.match(report, /deadlineActivation: 'PENDING_NOTIFICATION_EVENT'/); + assert.match(act, /NOTIFICATION_DATE = 'GEDO_DATE'/); +}); From ae7326f20a49fdc3cefa4d387babfb70bf269146 Mon Sep 17 00:00:00 2001 From: enlineawork Date: Wed, 9 Sep 2026 14:47:52 -0300 Subject: [PATCH 05/12] =?UTF-8?q?docs:=20consolidar=20modelo=20can=C3=B3ni?= =?UTF-8?q?co=20de=20Inventarios=20F6.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/F6_INVENTORY_MODEL.md | 132 ++++++++++++++++++++++++++++++++++++- 1 file changed, 131 insertions(+), 1 deletion(-) diff --git a/docs/F6_INVENTORY_MODEL.md b/docs/F6_INVENTORY_MODEL.md index 78933cc..3ef8a1f 100644 --- a/docs/F6_INVENTORY_MODEL.md +++ b/docs/F6_INVENTORY_MODEL.md @@ -1 +1,131 @@ -# F6 · Modelo definitivo de Inventarios +# F6.1 · Modelo canónico de Inventarios + +Este documento es la referencia funcional y técnica del modelo de Inventarios de DH Inspección V2. Ante una contradicción con documentación histórica, prevalecen este documento, las migraciones vigentes y los contratos automatizados de F6.1. + +## 1. Jerarquía física + +La estructura territorial y física es única: + +**Departamento → Área → Yacimiento → Instalación → Subinstalación** + +Reglas: + +- `Departamento` es raíz. +- `Área` requiere un Departamento padre. +- `Yacimiento` requiere un Área padre. +- `Instalación` requiere un Yacimiento padre. +- `Subinstalación` requiere una Instalación padre. +- La base de datos rechaza combinaciones de padre/hijo que no respeten esta secuencia. +- El campo `parent_id` expresa exclusivamente esta pertenencia física. + +## 2. Empresa no pertenece al árbol físico + +`Empresa` es un maestro independiente. No es padre de Departamento, Área, Yacimiento, Instalación ni Subinstalación. + +La Operadora vigente de un Área se expresa mediante `area_company_relations`, con `relation_role = 'OPERATOR'` y vigencia temporal. Esta relación es la fuente de verdad para saber qué Empresa opera un Área en una fecha determinada. + +`assets.operator_company_id` puede existir como fotografía de compatibilidad del contexto actual, pero no debe utilizarse para reconstruir la historia ni para reparentar Inventario. + +**Cambiar de Operadora nunca mueve la jerarquía física.** Se finaliza la relación temporal anterior y se crea la nueva relación Empresa ⇄ Área. + +## 3. Contexto transversal de Área + +Los elementos bajo un Área conservan `operational_area_id` como contexto transversal para consultas, planificación y trazabilidad. El Yacimiento forma parte del alcance físico, pero no sustituye al Área como contexto operativo de una Inspección. + +Por lo tanto, la planificación de una Inspección trabaja con: + +**Área + Operadora vigente + Inspector responsable + fecha/hora de inicio**. + +## 4. Clasificación técnica + +Los niveles territoriales no usan clasificación técnica: + +- Departamento: sin familia técnica. +- Área: sin familia técnica. +- Yacimiento: sin familia técnica. + +Los niveles físicos sí la requieren: + +- Instalación: una familia de nivel `INSTALLATION`. +- Subinstalación: una familia de nivel `SUBINSTALLATION` compatible con la familia de la Instalación padre. + +La compatibilidad se almacena en `inventory_family_parent_rules` y se valida también en PostgreSQL. Una misma familia de Subinstalación puede ser compatible con varias familias de Instalación. + +Los campos técnicos específicos de cada familia se definen en `inventory_family_attribute_definitions` y sus valores por Inventario en `asset_inventory_attribute_values`. + +## 5. Hallazgos + +Un Hallazgo puede asignarse directamente a: + +- Yacimiento. +- Instalación. +- Subinstalación. + +No se asignan Hallazgos directos a Departamento ni Área. + +`OTROS / Agregar otro` debe estar siempre disponible. Permite describir un Hallazgo que no exista todavía en el catálogo aplicable y dejarlo registrado para revisión posterior. + +Para Yacimiento, la aplicabilidad del catálogo puede resolverse por tipo de Inventario y por excepciones del objeto concreto. Yacimiento no necesita una familia técnica para recibir Hallazgos. + +Instalación y Subinstalación deben estar clasificadas antes de recibir un Hallazgo. + +## 6. Inventario nacido en campo + +La APK puede incorporar Inventario encontrado durante una Inspección. Un registro creado en campo conserva su trazabilidad de origen y, antes de permitir Hallazgos sobre él, debe tener como mínimo: + +- GPS capturado para la creación. +- al menos una fotografía de campo. +- clasificación técnica cuando se trate de Instalación o Subinstalación. + +La excepción transitoria que permite crear un registro `FIELD_SURVEY + DRAFT` sin familia existe únicamente para completar la transacción de alta; no habilita Hallazgos sin clasificación. + +## 7. Carga manual recomendada + +El orden seguro para construir una estructura desde cero es: + +1. Crear las Empresas necesarias como maestros independientes. +2. Crear Departamento. +3. Crear Área dentro del Departamento. +4. Registrar la Operadora vigente del Área, si ya se conoce. +5. Crear Yacimiento dentro del Área. +6. Crear Instalación dentro del Yacimiento y seleccionar su familia técnica. +7. Crear Subinstalación dentro de la Instalación y seleccionar una familia compatible. + +La importación de archivos no debe definir la arquitectura del modelo. Los datos externos se adaptan a este contrato; el contrato no se deforma para adaptarse a cada planilla. + +## 8. Historia y consulta temporal + +DH conserva dos conceptos separados: + +- historia física/contextual del Inventario; +- historia temporal de la relación Área ⇄ Empresa. + +Los cambios relevantes generan versiones y eventos de auditoría. Las consultas históricas deben utilizar la vigencia correspondiente a la fecha consultada, no sólo la fotografía actual de las columnas de `assets`. + +## 9. Barreras de integridad + +La consistencia no depende sólo de la interfaz. Se protege en varias capas: + +- DTO y servicios de API validan niveles y padres. +- PostgreSQL valida la jerarquía canónica. +- PostgreSQL valida nivel y compatibilidad de familias técnicas. +- la planificación valida una relación Operadora ⇄ Área vigente. +- los Hallazgos validan nivel permitido, clasificación técnica y pertenencia a la Inspección/Acta. +- CI ejecuta la cadena completa de migraciones sobre PostGIS limpio y los contratos transversales. + +## 10. Corte limpio F5.1 + +`F51CleanManualInventory1790087400000` fue un corte intencional de inicio limpio. Eliminó datos operativos/importados de desarrollo y dejó los maestros técnicos necesarios para reconstruir manualmente una estructura confiable. + +Es una migración deliberadamente no reversible mediante `migration:revert`. Su recuperación depende del backup PRE del despliegue. No debe copiarse este patrón para migraciones normales sin una decisión explícita y una estrategia de restauración probada. + +## 11. Regla para cambios futuros + +Cualquier modificación del modelo debe mantener simultáneamente: + +1. la jerarquía física canónica; +2. Empresa fuera del árbol; +3. relación temporal Área ⇄ Empresa como fuente de verdad operativa; +4. compatibilidad técnica de familias; +5. trazabilidad histórica; +6. protección en base de datos y tests, no sólo en la UI. From 60c6d97f1ad90ac0f2fe59a11e5530c84fb33516 Mon Sep 17 00:00:00 2001 From: enlineawork Date: Wed, 9 Sep 2026 14:48:20 -0300 Subject: [PATCH 06/12] =?UTF-8?q?docs:=20evitar=20duplicaci=C3=B3n=20del?= =?UTF-8?q?=20modelo=20F6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/F6_INVENTORY_MODEL_FINAL.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/docs/F6_INVENTORY_MODEL_FINAL.md b/docs/F6_INVENTORY_MODEL_FINAL.md index 8a8c769..423b5bb 100644 --- a/docs/F6_INVENTORY_MODEL_FINAL.md +++ b/docs/F6_INVENTORY_MODEL_FINAL.md @@ -1,7 +1,5 @@ -# F6 · Modelo definitivo de Inventarios +# F6 · Modelo de Inventarios -La jerarquía física canónica es fija: +Este archivo se conserva por compatibilidad con referencias históricas. -Departamento → Área → Yacimiento → Instalación → Subinstalación - -Empresa es un maestro independiente y se relaciona temporalmente con Área. +La documentación canónica y mantenida está en [`F6_INVENTORY_MODEL.md`](./F6_INVENTORY_MODEL.md). From 90443b3961f55a57187ea956b51d61b8b74c7375 Mon Sep 17 00:00:00 2001 From: enlineawork Date: Wed, 9 Sep 2026 14:48:30 -0300 Subject: [PATCH 07/12] =?UTF-8?q?docs:=20evitar=20duplicaci=C3=B3n=20del?= =?UTF-8?q?=20modelo=20F6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/F6_INVENTORY_MODEL_FULL.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/docs/F6_INVENTORY_MODEL_FULL.md b/docs/F6_INVENTORY_MODEL_FULL.md index 8a8c769..423b5bb 100644 --- a/docs/F6_INVENTORY_MODEL_FULL.md +++ b/docs/F6_INVENTORY_MODEL_FULL.md @@ -1,7 +1,5 @@ -# F6 · Modelo definitivo de Inventarios +# F6 · Modelo de Inventarios -La jerarquía física canónica es fija: +Este archivo se conserva por compatibilidad con referencias históricas. -Departamento → Área → Yacimiento → Instalación → Subinstalación - -Empresa es un maestro independiente y se relaciona temporalmente con Área. +La documentación canónica y mantenida está en [`F6_INVENTORY_MODEL.md`](./F6_INVENTORY_MODEL.md). From 294abc4cf37b07d77016038609539e519ae84fbe Mon Sep 17 00:00:00 2001 From: enlineawork Date: Wed, 9 Sep 2026 14:49:21 -0300 Subject: [PATCH 08/12] docs: crear manual del programador --- docs/MANUAL_PROGRAMADOR.md | 370 +++++++++++++++++++++++++++++++++++++ 1 file changed, 370 insertions(+) create mode 100644 docs/MANUAL_PROGRAMADOR.md diff --git a/docs/MANUAL_PROGRAMADOR.md b/docs/MANUAL_PROGRAMADOR.md new file mode 100644 index 0000000..bb697a4 --- /dev/null +++ b/docs/MANUAL_PROGRAMADOR.md @@ -0,0 +1,370 @@ +# Manual del Programador · DH Inspección V2 + +**Baseline documental:** F6.1 +**API:** 0.29.0-1 +**WEB:** 0.23.0-1 +**Android:** 0.15.0 + +Este manual describe la arquitectura, las reglas que no deben romperse y el procedimiento seguro para modificar DH Inspección V2. No reemplaza los tests ni las restricciones de base de datos: los tres forman juntos el contrato del sistema. + +--- + +## 1. Estructura del repositorio + +- `api-v3/`: API NestJS + TypeORM + PostgreSQL/PostGIS. +- `web-v2/`: aplicación WEB React/Vite. +- `android-app/`: aplicación Android Kotlin/Compose. +- `scripts/`: despliegue, preflight y utilidades operativas. +- `docs/`: documentación funcional y técnica viva. +- `.github/workflows/`: CI de API/WEB/Docker y build/test de Android. + +El backend expone `/api/v3`. Los cambios de dominio deben resolverse primero en API/base de datos; WEB y Android consumen ese contrato y no deben inventar reglas paralelas. + +--- + +## 2. Invariantes de dominio + +### 2.1 Inventario físico + +La jerarquía canónica es: + +**Departamento → Área → Yacimiento → Instalación → Subinstalación** + +`parent_id` expresa exclusivamente esa jerarquía. No agregue Empresa dentro de este árbol. + +### 2.2 Empresa y Operadora + +`Empresa` es un maestro independiente. + +La relación operativa vigente se modela en `area_company_relations`: + +- Área ↔ Empresa. +- `relation_role = 'OPERATOR'` para la Operadora. +- `valid_from` / `valid_until` para vigencia. + +Esta tabla es la fuente temporal de verdad. `assets.operator_company_id` es una fotografía de compatibilidad; nunca debe usarse como sustituto del historial. + +Cambiar Operadora no mueve Yacimientos, Instalaciones ni Subinstalaciones. + +### 2.3 Clasificación técnica + +- Departamento: sin familia. +- Área: sin familia. +- Yacimiento: sin familia. +- Instalación: requiere familia `INSTALLATION`. +- Subinstalación: requiere familia `SUBINSTALLATION` compatible con la Instalación padre. + +La compatibilidad está protegida por PostgreSQL, no sólo por la UI. + +### 2.4 Hallazgos + +Un Hallazgo directo sólo puede asignarse a: + +- Yacimiento. +- Instalación. +- Subinstalación. + +Departamento y Área no reciben Hallazgos directos. + +`OTROS / Agregar otro` debe permanecer disponible siempre. En Yacimiento no se exige familia técnica. En Instalación/Subinstalación sí. + +Si un elemento fue creado en campo, antes de admitir un Hallazgo debe tener GPS de creación y al menos una fotografía; Instalación/Subinstalación además deben quedar clasificadas. + +### 2.5 Inspecciones + +Lifecycle operativo: + +`DRAFT → PLANNED → IN_PROGRESS → CLOSED` + +La planificación requiere: + +- Área. +- Operadora vigente del Área. +- Inspector responsable habilitado. +- fecha/hora prevista de inicio. +- checklist generado. + +La APK puede abrir una Inspección, pero no posee un lifecycle alternativo: el endpoint móvil crea la visita y utiliza los mismos servicios `plan()` y `start()` que el resto del sistema. + +### 2.6 Actas + +Una Inspección puede tener **múltiples Actas**. + +Reglas críticas: + +- sólo puede existir un `DRAFT` simultáneo por Inspección; +- un Acta en `DRAFT` es editable; +- al finalizar se bloquea y queda inmutable; +- el sellado conserva integridad y firmas; +- no existe reapertura normal de un Acta bloqueada a borrador; +- para cerrar la Inspección todas las Actas no canceladas deben estar `SEALED`; +- el Informe pertenece al Acta, no a la Inspección completa. + +La unicidad del borrador está protegida por el índice parcial `uq_inspection_acts_one_draft_per_visit`. + +### 2.7 Informe, GEDO y vencimientos + +Flujo conceptual: + +**Acta → INF → oficialización GEDO/IF** + +GEDO oficializa el Informe, pero **no equivale por sí solo a la notificación administrativa que inicia el plazo No urgente**. + +Existe una compatibilidad histórica importante: el valor físico `GEDO_DATE` se conserva en el enum/base, mientras el significado funcional vigente es `NOTIFICATION_DATE`. No cambie el valor persistido en una refactorización sin una migración explícita y pruebas de compatibilidad. + +--- + +## 3. Modelo de Inventarios + +La referencia completa es [`F6_INVENTORY_MODEL.md`](./F6_INVENTORY_MODEL.md). + +Puntos técnicos centrales: + +- `assets.parent_id`: pertenencia física. +- `assets.operational_area_id`: contexto transversal de Área. +- `area_company_relations`: historia de Operadora. +- `inventory_families`: clasificaciones técnicas. +- `inventory_family_parent_rules`: compatibilidad Subinstalación ↔ Instalación. +- `inventory_family_attribute_definitions`: campos técnicos por familia. +- `asset_inventory_attribute_values`: valores técnicos por objeto. +- `asset_context_history` y versiones: trazabilidad contextual/histórica. + +No se debe rediseñar el esquema para coincidir con una planilla importada. Los archivos externos se normalizan al modelo canónico. + +--- + +## 4. Migraciones + +### Regla principal + +**Nunca modifique una migración ya aplicada.** + +Si cambia esquema, constraints, seeds o reglas persistentes: + +1. cree una migración nueva; +2. haga `up()` determinista; +3. agregue verificación al final cuando la regla sea crítica; +4. implemente `down()` cuando la operación sea razonablemente reversible; +5. agregue/actualice tests de contrato; +6. pruebe la cadena completa sobre PostGIS limpio. + +### F5.1 es una excepción histórica + +`F51CleanManualInventory1790087400000` fue un corte destructivo intencional para reiniciar los datos de dominio. Su `down()` no intenta reconstruir información eliminada: el rollback depende del backup PRE. + +No repita este patrón para una migración normal sin una decisión explícita, backup validado y procedimiento de restauración. + +### Guards importantes de base de datos + +PostgreSQL protege, entre otras cosas: + +- jerarquía Departamento → Área → Yacimiento → Instalación → Subinstalación; +- familia correcta según el nivel físico; +- compatibilidad de familia de Subinstalación con su Instalación padre; +- un solo Acta `DRAFT` por Inspección. + +Las validaciones de API mejoran la experiencia, pero no reemplazan estos guards. + +--- + +## 5. API + +### Principios + +- Reutilice servicios canónicos; no duplique lifecycle en controllers móviles. +- Las mutaciones relevantes deben producir auditoría. +- Los errores de dominio deben tener `code` estable y mensaje legible. +- Los estados históricos/inmutables no deben reabrirse por conveniencia de UI. +- Para relaciones temporales, valide la vigencia en la fecha correspondiente, no sólo `valid_until IS NULL` cuando el caso exige reconstrucción histórica. + +### Áreas a revisar antes de tocar un flujo + +- Inventario: `src/asset-master/`. +- Inspecciones: `src/inspection-visits/`. +- Actas: `src/inspection-acts/`, `src/inspection-closing/`, `src/act-administration/`. +- Hallazgos: `src/inspection-findings/` y gate móvil en `src/inspection-visits/field-findings.service.ts`. +- Informes/GEDO: `src/inspection-reports/`. +- Verificaciones: `src/inspection-verifications/`. +- Entidades/migraciones: `src/database/`. + +--- + +## 6. WEB + +La WEB es el frente principal de administración, planificación y seguimiento. Las rutas protegidas se declaran en `web-v2/src/app/App.tsx` y usan permisos para controlar acceso. + +Módulos principales: + +- Dashboard. +- Mapa. +- Inventarios y dossier. +- Revisión de Inventario nacido en campo. +- Inspecciones y preparación de campo. +- Actas. +- Hallazgos y planificación de verificaciones. +- Seguimiento de Actas. +- Informes. +- Historial y consulta temporal. +- Administración de usuarios, roles, auditoría, tipos y catálogo. + +No esconda una regla sólo en la WEB: toda restricción de integridad debe existir también en API/DB. + +--- + +## 7. Android + +La APK está orientada a ejecución en campo. + +Reglas que deben mantenerse: + +- sólo un usuario con capacidad de ejecución puede iniciar/operar una Inspección; +- `Abrir inspección` selecciona Área y Operadora vigente; +- la nueva visita queda autoasignada al inspector actual; +- se genera checklist antes de iniciar; +- el backend recorre DRAFT → PLANNED → IN_PROGRESS con el lifecycle canónico; +- Inventario nuevo en campo captura evidencia mínima antes de Hallazgos; +- Hallazgos respetan los mismos niveles y catálogo que la API. + +Al cambiar contratos móviles, actualice tanto Kotlin como los tests de contrato montados por el preflight de API. + +--- + +## 8. Permisos y seguridad + +El sistema utiliza permisos finos; las pantallas no deben asumir permisos por nombre visual del rol. La fuente efectiva es la matriz rol-permiso de base de datos. + +Buenas prácticas: + +- proteja controllers con permisos explícitos; +- no confíe en que una ruta esté oculta en la WEB; +- preserve la política especial del inspector móvil; +- mantenga auditadas las mutaciones administrativas; +- no exponga secretos ni credenciales en repositorio, logs o documentación. + +--- + +## 9. Tests y CI + +La barrera principal está en `.github/workflows/ci.yml`. + +### API + +Ejecuta: + +```bash +npm ci +npm run typecheck +npm test +npm run build +``` + +### WEB + +Ejecuta: + +```bash +npm ci +npm run typecheck +bash ../scripts/check-f3-1-web-contract.sh +npm run build +``` + +### Docker / contratos + +Valida: + +- sintaxis de scripts shell; +- paridad del preflight de deploy; +- `docker compose config`; +- cadena de migraciones sobre PostGIS limpio; +- estado limpio F5.1 y preservación de maestros técnicos; +- segunda ejecución sin migraciones pendientes; +- preflight API aislado equivalente al VPS; +- build de imágenes productivas. + +### Android + +El workflow específico de Android debe completar: + +- `assembleDebug`; +- unit tests; +- publicación del artefacto APK. + +### Contrato transversal F6.1 + +`api-v3/test/unit/f6-1-project-invariants.test.ts` fija las reglas que más fácilmente podrían degradarse por refactors: jerarquía, contexto Área+Operadora, multi-Acta, Hallazgos, apertura móvil y separación GEDO/vencimiento. + +--- + +## 10. Versionado + +Cuando una entrega cambia versión, revise como mínimo: + +- `api-v3/package.json`; +- `api-v3/src/version.ts`; +- `web-v2/package.json`; +- `android-app/app/build.gradle.kts` si cambia APK; +- tests que fijen metadata de versión; +- metadata raíz de `package-lock.json` regenerándola con npm cuando corresponda. + +Los lockfiles son archivos generados: no los edite manualmente en forma parcial. Use npm para reconciliarlos. + +--- + +## 11. Flujo Git y despliegue + +Secuencia recomendada: + +1. crear rama desde `main` estable; +2. implementar código + migración + tests + documentación; +3. abrir PR; +4. exigir API + WEB + Docker/migraciones + Android verdes cuando aplique; +5. mergear a `main`; +6. exigir nuevamente CI verde sobre el SHA de `main`; +7. recién entonces promover el SHA exacto a `deploy`; +8. esperar el watcher/deploy; +9. comprobar SHA objetivo, health, versiones y backup generado. + +Nunca despliegue un SHA distinto al que pasó la barrera. Nunca use `deploy` para “probar” una rama incompleta. + +Si una migración es de una sola vía, el rollback operativo es el backup PRE validado, no un `migration:revert` improvisado. + +--- + +## 12. Checklist antes de aprobar un cambio + +- ¿Respeta la jerarquía canónica? +- ¿Empresa sigue fuera del árbol físico? +- ¿Una modificación de Operadora conserva historia temporal? +- ¿La regla importante está protegida también en API/DB? +- ¿Hallazgos siguen limitados a Yacimiento/Instalación/Subinstalación? +- ¿OTROS sigue disponible? +- ¿Una Inspección puede tener varias Actas y sólo un DRAFT simultáneo? +- ¿Actas finalizadas siguen inmutables? +- ¿Informe sigue perteneciendo al Acta? +- ¿GEDO sigue separado del inicio automático del plazo No urgente? +- ¿WEB y Android consumen el mismo contrato? +- ¿Se agregó un test para la nueva regla o regresión? +- ¿CI completa está verde? +- ¿Documentación viva quedó actualizada? + +--- + +## 13. Terminología canónica + +Use consistentemente: + +- **Inventario**, no “Activo” en la interfaz de usuario cuando se refiere al módulo funcional. +- **Departamento**. +- **Área**. +- **Yacimiento**. +- **Instalación**. +- **Subinstalación**. +- **Empresa / Operadora** como maestro/rol operativo, no como padre físico. +- **Inspección** para la visita operativa. +- **Acta** para el documento de campo; una Inspección puede contener varias. +- **Hallazgo** para la observación fiscalizable asociada a Inventario. +- **Informe / INF** por Acta. +- **GEDO / IF** para la oficialización documental, separada de la notificación administrativa cuando corresponda. + +Si una etiqueta histórica contradice estos términos, corrija la etiqueta; no cambie el modelo para conservar una denominación obsoleta. From 3a149691e22c78cfd5f445e3372f34701a9feab4 Mon Sep 17 00:00:00 2001 From: enlineawork Date: Wed, 9 Sep 2026 14:50:08 -0300 Subject: [PATCH 09/12] docs: crear manual de usuario --- docs/MANUAL_USUARIO.md | 353 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 353 insertions(+) create mode 100644 docs/MANUAL_USUARIO.md diff --git a/docs/MANUAL_USUARIO.md b/docs/MANUAL_USUARIO.md new file mode 100644 index 0000000..69434c4 --- /dev/null +++ b/docs/MANUAL_USUARIO.md @@ -0,0 +1,353 @@ +# Manual de Usuario · DH Inspección V2 + +**Versión funcional de referencia:** F6.1 + +Este manual explica el uso cotidiano del sistema. Las opciones visibles dependen de los permisos asignados a cada usuario, por lo que un Inspector, Supervisor, Director o Administrador puede ver acciones distintas. + +--- + +## 1. Conceptos principales + +DH Inspección V2 organiza el trabajo alrededor de cuatro elementos: + +1. **Inventario:** dónde se inspecciona. +2. **Inspección:** la visita de trabajo. +3. **Acta:** documento generado durante la Inspección; una Inspección puede tener varias Actas. +4. **Hallazgo:** observación asociada a un elemento concreto del Inventario. + +Además, cada Acta puede continuar con su **Informe (INF)**, oficialización documental y seguimiento posterior. + +--- + +## 2. Ingreso al sistema + +1. Abra la WEB de DH Inspección V2. +2. Ingrese usuario y contraseña. +3. El menú mostrará solamente los módulos habilitados por sus permisos. + +Si una opción no aparece o el sistema informa que no tiene autorización, consulte al Administrador antes de intentar resolverlo creando datos alternativos. + +--- + +## 3. Cómo se organiza el Inventario + +La estructura física correcta es siempre: + +**Departamento → Área → Yacimiento → Instalación → Subinstalación** + +La **Empresa** no forma parte de esa cadena. Se administra por separado y se vincula al Área cuando actúa como Operadora. + +Ejemplo: + +- Departamento: Malargüe + - Área: Área A + - Yacimiento: Yacimiento Norte + - Instalación: Planta de Tratamiento + - Subinstalación: Separador 01 + +Una Empresa puede cambiar con el tiempo sin modificar esta estructura física. + +--- + +## 4. Carga manual de Inventario + +Para construir una estructura confiable desde cero, use este orden: + +1. Cree las **Empresas** necesarias. +2. Cree el **Departamento**. +3. Cree el **Área** dentro del Departamento. +4. Registre la **Operadora vigente** del Área si corresponde. +5. Cree el **Yacimiento** dentro del Área. +6. Cree la **Instalación** dentro del Yacimiento. +7. Seleccione la clasificación técnica de la Instalación. +8. Cree la **Subinstalación** dentro de la Instalación. +9. Seleccione una clasificación técnica compatible para la Subinstalación. + +El sistema no permite saltear niveles. Por ejemplo, una Instalación no puede depender directamente de un Área. + +### Empresa y Operadora + +Cuando una Empresa opera un Área, registre la relación operativa correspondiente. Si cambia la Operadora: + +1. finalice la relación vigente anterior; +2. registre la nueva Operadora; +3. no mueva Yacimientos, Instalaciones ni Subinstalaciones. + +El historial queda conservado para consultas temporales. + +--- + +## 5. Consultar Inventario + +Desde **Inventarios** puede navegar la estructura territorial y abrir el dossier de cada registro. + +Utilice el breadcrumb para volver hacia niveles superiores. El dossier concentra, según la información disponible: + +- datos actuales; +- ubicación y clasificación; +- fotografías; +- historial de cambios; +- Hallazgos; +- verificaciones; +- Actas e Informes relacionados. + +Cuando necesite saber cómo estaba un elemento en una fecha anterior, use la **Consulta temporal** en lugar de interpretar sólo sus datos actuales. + +--- + +## 6. Crear una Inspección desde la WEB + +En **Inspecciones → Nueva Inspección**: + +1. seleccione el **Área**; +2. seleccione una **Operadora vigente** para esa Área; +3. seleccione el **Inspector responsable**; +4. indique la fecha y hora prevista de inicio; +5. confirme la creación. + +Al crearse la Inspección, el sistema genera su checklist de antecedentes. Antes de planificar, la información obligatoria debe estar completa. + +Una Inspección planificada se inicia operativamente desde la APK por un Inspector habilitado y asignado. + +--- + +## 7. Abrir una Inspección directamente desde la APK + +La APK también permite comenzar una Inspección que no haya sido preparada previamente en la WEB. + +Desde la pantalla principal: + +1. pulse **Abrir inspección**; +2. elija el **Área**; +3. elija la **Operadora vigente**; +4. pulse **Abrir inspección ahora**. + +El sistema: + +- crea la Inspección; +- la asigna al Inspector que inició sesión; +- genera su checklist; +- la planifica; +- la deja **En curso**. + +No elija una Empresa por aproximación: la APK muestra la relación operativa válida del Área. + +--- + +## 8. Trabajar con Inventario durante una Inspección + +Dentro de una Inspección en curso puede seleccionar Inventario existente del Área y agregarlo al trabajo de campo/Acta correspondiente. + +Los niveles relevantes para Hallazgos son: + +- Yacimiento; +- Instalación; +- Subinstalación. + +### Inventario encontrado en campo + +Si encuentra una Instalación o Subinstalación que todavía no existe, la APK puede darla de alta dentro de la jerarquía correspondiente. + +Antes de poder registrar Hallazgos sobre un elemento nuevo de campo, debe quedar como mínimo con: + +- GPS de creación; +- al menos una fotografía; +- clasificación técnica si es Instalación o Subinstalación. + +Esto evita que un Hallazgo quede asociado a un objeto sin identificación suficiente. + +--- + +## 9. Actas: una Inspección puede tener varias + +Una misma Inspección puede generar **varias Actas**. + +La regla práctica es: + +- puede haber varias Actas históricas dentro de la Inspección; +- sólo puede existir **un Acta en borrador al mismo tiempo**. + +Mientras un Acta está en borrador puede completar su contenido y agregar Hallazgos. Una vez finalizada/bloqueada deja de ser editable como un borrador normal. + +Para continuar con una nueva Acta dentro de la misma Inspección, finalice correctamente la actual antes de abrir la siguiente. + +--- + +## 10. Registrar Hallazgos + +Los Hallazgos se asignan directamente a: + +- **Yacimiento**; +- **Instalación**; +- **Subinstalación**. + +No se crean Hallazgos directos sobre Departamento ni Área. + +### Hallazgo de catálogo + +Si el sistema muestra un Hallazgo aplicable al elemento seleccionado: + +1. elija el Hallazgo del catálogo; +2. complete la descripción y datos requeridos; +3. guarde. + +### OTROS / Agregar otro + +La opción **OTROS** debe estar siempre disponible. + +Úsela cuando el Hallazgo observado no exista en la lista disponible. Describa claramente qué se encontró para que luego pueda revisarse y normalizarse en oficina. + +Después de guardar un Hallazgo puede utilizar **Agregar otro** para continuar cargando Hallazgos sobre el mismo Inventario. + +### En Yacimiento + +Un Yacimiento puede recibir Hallazgos aunque no tenga clasificación técnica. Cuando exista catálogo configurado para ese tipo, el sistema puede ofrecerlo; en todos los casos conserva la opción OTROS. + +--- + +## 11. Finalizar y sellar un Acta + +Antes de finalizar un Acta revise especialmente: + +- Inventario incluido; +- Hallazgos; +- observaciones; +- firmas y datos requeridos por el flujo. + +Al finalizar, el sistema bloquea el contenido y genera controles de integridad. Esto significa que **el Acta deja de ser editable como borrador**. + +No finalice un Acta para “probar” cómo queda. Primero revise todo su contenido. + +Cuando el flujo de firmas y sellado termina, el Acta queda `SELLADA` y preparada para continuar con su documentación posterior. + +--- + +## 12. Cerrar una Inspección + +Para cerrar una Inspección en curso deben cumplirse las condiciones operativas, entre ellas: + +- existir al menos un Acta; +- todas las Actas no canceladas deben estar selladas; +- si la Inspección contiene verificaciones, sus resultados deben estar registrados. + +Si el sistema impide el cierre, revise el mensaje mostrado: normalmente identifica el Acta o la verificación pendiente. + +--- + +## 13. Informes por Acta + +El Informe se genera y administra **por Acta**. + +Por eso, si una Inspección tuvo tres Actas, el seguimiento documental no debe tratarla como si existiera un único Informe global. + +Desde **Informes** puede consultar el estado del INF y continuar el flujo habilitado para su rol. + +--- + +## 14. GEDO / IF y plazo No urgente + +Registrar el identificador y PDF oficial de GEDO/IF **oficializa el Informe**, pero por sí solo no significa que haya comenzado automáticamente el plazo administrativo de una Acta No urgente. + +El vencimiento debe activarse a partir del evento administrativo de notificación que corresponda al procedimiento vigente. + +Si ve un Informe oficializado sin fecha de vencimiento activa, no lo corrija cargando una fecha ficticia de GEDO como notificación. + +--- + +## 15. Seguimiento de Hallazgos + +Después del trabajo de campo, un Hallazgo mantiene su historia. El seguimiento puede incluir: + +- respuesta de la Empresa; +- documentos y evidencias; +- fecha de control; +- planificación de una verificación; +- resultado de verificación; +- nueva fecha si continúa pendiente; +- cierre administrativo. + +No reescriba el Hallazgo original para reflejar novedades posteriores. Use los eventos de seguimiento para conservar la trazabilidad. + +--- + +## 16. Verificaciones + +Cuando un Hallazgo requiere control posterior: + +1. defina la fecha de verificación cuando corresponda; +2. planifique la visita de verificación; +3. ejecute la verificación; +4. registre el resultado y evidencia; +5. si no está resuelto, reprograme según el flujo; +6. si está resuelto y la visita quedó cerrada, continúe con el cierre administrativo del Hallazgo. + +El historial de verificaciones no debe borrarse para reemplazarlo por el último resultado. + +--- + +## 17. Historial y Consulta temporal + +Use **Historial** para revisar cambios y eventos registrados. + +Use **Consulta temporal** cuando la pregunta sea, por ejemplo: + +- “¿qué Empresa operaba esta Área en esa fecha?”; +- “¿dónde estaba ubicado este elemento?”; +- “¿qué estado tenía el Inventario en ese momento?”. + +La vista actual y la vista histórica cumplen funciones distintas. + +--- + +## 18. Revisión de Inventario nacido en campo + +Los registros creados por Inspectores en la APK pueden requerir revisión posterior en oficina. + +Al revisar: + +- confirme nombre/código; +- confirme la ubicación jerárquica; +- verifique clasificación técnica; +- revise GPS/fotografías; +- normalice información pendiente sin perder el origen de campo. + +No cree un duplicado sólo porque el nombre no coincide exactamente; primero confirme si se trata del mismo objeto. + +--- + +## 19. Mensajes frecuentes + +### “La Operadora seleccionada no tiene una relación operativa vigente con el Área” + +Revise la relación Empresa ⇄ Área y su vigencia. No cambie la jerarquía física para resolverlo. + +### “La Instalación/Subinstalación debe tener una clasificación técnica” + +Complete la familia técnica del elemento antes de registrar el Hallazgo. + +### “El Inventario creado en campo debe tener GPS y al menos una foto” + +Complete la captura de campo requerida y vuelva a intentar. + +### “Todas las Actas deben estar SELLADAS antes de cerrar la Inspección” + +Abra la Inspección y revise cuáles Actas todavía están en borrador, bloqueadas o pendientes de sellado. + +### “La inspección no tiene un Acta borrador abierta” + +Cree/abra un Acta borrador para esa Inspección antes de cargar nuevos Hallazgos. + +--- + +## 20. Buenas prácticas + +- Cargue la estructura de Inventario en orden jerárquico. +- No use Empresa como padre físico. +- No duplique Inventario ante la primera diferencia de nombre. +- Use OTROS cuando el Hallazgo no exista en catálogo. +- Revise un Acta antes de finalizarla: luego queda inmutable. +- Use seguimiento y verificaciones para agregar historia; no reescriba hechos anteriores. +- Use Consulta temporal para preguntas históricas. +- Respete los mensajes de integridad del sistema en lugar de forzar datos ficticios. + +Ante una duda funcional que pueda modificar jerarquía, Actas, Hallazgos o vencimientos, consulte antes de cargar datos masivamente. From 51ace362d7ef22eee3a9838f26da0e6d7186d312 Mon Sep 17 00:00:00 2001 From: enlineawork Date: Wed, 9 Sep 2026 14:52:03 -0300 Subject: [PATCH 10/12] =?UTF-8?q?docs:=20registrar=20auditor=C3=ADa=20de?= =?UTF-8?q?=20consistencia=20F6.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/AUDITORIA_CONSISTENCIA_F6_1.md | 91 +++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 docs/AUDITORIA_CONSISTENCIA_F6_1.md diff --git a/docs/AUDITORIA_CONSISTENCIA_F6_1.md b/docs/AUDITORIA_CONSISTENCIA_F6_1.md new file mode 100644 index 0000000..cc9a0ae --- /dev/null +++ b/docs/AUDITORIA_CONSISTENCIA_F6_1.md @@ -0,0 +1,91 @@ +# Auditoría de consistencia · F6.1 + +**Baseline revisado:** `25a63cd3d4b2c561803cc5105cce100983c8eeff` +**Alcance:** API, modelo de datos, Inventarios, Inspecciones, Actas, Hallazgos, Informes/GEDO, WEB, Android, permisos, versionado documental y CI. + +## Resultado + +El modelo funcional consolidado de F6.1 es coherente. No se detectó una contradicción estructural que requiera rediseñar tablas o migrar datos antes de continuar. + +La auditoría sí encontró deuda de terminología/documentación y una inconsistencia de metadata generada. Las correcciones funcionales/documentales se integran en esta rama; la metadata de lockfiles se documenta como observación no funcional y debe regenerarse con npm en un corte controlado, no editarse parcialmente a mano. + +## Contratos verificados + +### Inventario + +- Jerarquía física única: Departamento → Área → Yacimiento → Instalación → Subinstalación. +- Empresa es un maestro independiente. +- Operadora vigente se resuelve por relación temporal Área ⇄ Empresa. +- Cambiar Operadora no reparenta Inventario. +- Departamento, Área y Yacimiento no llevan familia técnica. +- Instalación y Subinstalación requieren familia técnica. +- Subinstalación debe ser compatible con la familia de la Instalación padre. +- PostgreSQL protege jerarquía y compatibilidad, además de las validaciones de API. + +### Inspecciones + +- Lifecycle canónico DRAFT → PLANNED → IN_PROGRESS → CLOSED. +- Planificación requiere Área, Operadora vigente, Inspector responsable, fecha/hora y checklist. +- La APK abre una Inspección reutilizando el mismo create/plan/start; no existe un lifecycle móvil paralelo. +- No hay referencias activas a `plannedEndAt` / `planned_end_at` en el código actual. + +### Actas + +- Una Inspección puede contener múltiples Actas. +- El constraint histórico de una sola Acta por visita fue eliminado por F1.1. +- Existe un índice parcial que permite sólo un Acta DRAFT simultánea por Inspección. +- El cierre de la Inspección exige que todas las Actas no canceladas estén SELLADAS. +- El Acta finalizada/bloqueada es inmutable. + +### Hallazgos + +- Destinos directos: Yacimiento, Instalación y Subinstalación. +- Departamento y Área no son destinos directos. +- OTROS / Agregar otro permanece disponible. +- Yacimiento no requiere familia técnica. +- Instalación/Subinstalación sí requieren clasificación. +- Inventario nacido en campo necesita GPS + foto antes de admitir Hallazgos. + +### Informes / GEDO + +- El Informe pertenece al Acta. +- La oficialización GEDO/IF es inmutable. +- Oficializar en GEDO no activa por sí solo el vencimiento No urgente. +- El valor persistido histórico `GEDO_DATE` se conserva como ABI de base; en código existe el alias semántico `NOTIFICATION_DATE` para evitar interpretar GEDO como notificación automática. + +## Correcciones integradas en la auditoría + +1. Se corrigió la terminología residual `Área/Yacimiento` en el lifecycle de Inspecciones. El contexto operativo queda definido inequívocamente como **Área + Operadora vigente**. +2. Se documentó en código la separación entre Empresa y la jerarquía física del Inventario. +3. Se documentó en la entidad Acta el contrato multi-Acta + único DRAFT simultáneo. +4. Se agregó un test transversal F6.1 que protege jerarquía, contexto operativo, multi-Acta, Hallazgos, apertura móvil y separación GEDO/vencimiento. +5. Se consolidó `docs/F6_INVENTORY_MODEL.md` como única referencia viva y los duplicados históricos apuntan a ella. +6. Se crearon `MANUAL_PROGRAMADOR.md` y `MANUAL_USUARIO.md`. + +## Compatibilidades históricas que NO deben “limpiarse” sin migración + +- Migraciones antiguas conservan nombres y reglas que fueron válidas en fases anteriores. No se modifican; migraciones posteriores son las que expresan la evolución. +- `InspectionDeadlineBasis.GEDO_DATE` comparte valor persistido con `NOTIFICATION_DATE` por compatibilidad de esquema. +- `assets.operator_company_id` puede conservar una fotografía de compatibilidad incluso cuando la relación temporal ya finalizó. La fuente de verdad vigente/histórica sigue siendo `area_company_relations`. +- F5.1 es una migración destructiva de inicio limpio y no tiene `down()` reconstructivo; su rollback es el backup PRE. + +## Observación no funcional: metadata de package-lock + +Los `package.json` actuales declaran las versiones de producto vigentes, pero la metadata `name/version` de la raíz de ambos `package-lock.json` todavía conserva `0.20.0-2` de un corte anterior. + +Esto no cambia el grafo de dependencias ni el runtime y `npm ci` continúa siendo la barrera de instalación. Se deja explícitamente registrado para no ocultarlo. + +**Tratamiento correcto:** regenerar cada lockfile con npm (`npm install --package-lock-only`) cuando se haga el próximo corte controlado de metadata/dependencias y verificar el diff completo. No editar manualmente sólo las primeras líneas del lockfile. + +## Criterio de aceptación de esta auditoría + +Antes de mergear esta rama deben pasar nuevamente: + +- API typecheck + tests + build. +- WEB typecheck + contrato + build. +- migraciones sobre PostGIS limpio. +- preflight aislado equivalente al VPS. +- build de imágenes productivas. +- Android assemble + unit tests cuando el workflow se dispare por el PR. + +La rama de documentación/consistencia no debe promoverse a `deploy` durante esta revisión. El despliegue queda deliberadamente pausado. From ba38dc7dda7bab72979f25dde9f885633e855951 Mon Sep 17 00:00:00 2001 From: enlineawork Date: Wed, 9 Sep 2026 14:52:26 -0300 Subject: [PATCH 11/12] docs: enlazar manuales y contrato F6.1 --- README.md | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 3197f46..abca65f 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,28 @@ Repositorio del sistema DH Inspección V2. -## Estructura +## Componentes -- `api-v3/`: API v3. -- `web-v2/`: aplicación web. -- `scripts/`: utilidades operativas y de despliegue. -- `docs/`: documentación técnica. +- `api-v3/`: API NestJS/TypeORM y contratos de dominio. +- `web-v2/`: aplicación WEB React/Vite. +- `android-app/`: aplicación Android para trabajo de campo. +- `scripts/`: utilidades operativas, preflight y despliegue. +- `docs/`: documentación funcional y técnica. + +## Documentación vigente + +- [Manual del Programador](docs/MANUAL_PROGRAMADOR.md) +- [Manual de Usuario](docs/MANUAL_USUARIO.md) +- [Modelo canónico de Inventarios F6.1](docs/F6_INVENTORY_MODEL.md) +- [Auditoría de consistencia F6.1](docs/AUDITORIA_CONSISTENCIA_F6_1.md) + +## Contratos que no deben romperse + +- Inventario físico: **Departamento → Área → Yacimiento → Instalación → Subinstalación**. +- Empresa es un maestro independiente; la Operadora se relaciona temporalmente con Área. +- Una Inspección puede tener múltiples Actas, pero sólo un Acta `DRAFT` simultánea. +- Hallazgos directos: Yacimiento, Instalación y Subinstalación, siempre con `OTROS` disponible. +- La APK puede abrir una Inspección reutilizando el lifecycle canónico del backend. +- GEDO/IF oficializa el Informe, pero no activa por sí solo el vencimiento No urgente. + +Las reglas detalladas y el procedimiento de cambio seguro están en los manuales enlazados arriba. From 433220ee3ad3cff1ba3051058cc50bbf3e716b7c Mon Sep 17 00:00:00 2001 From: enlineawork Date: Wed, 9 Sep 2026 14:52:57 -0300 Subject: [PATCH 12/12] =?UTF-8?q?docs(code):=20documentar=20apertura=20m?= =?UTF-8?q?=C3=B3vil=20can=C3=B3nica?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api-v3/src/inspection-visits/inspection-visits.controller.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/api-v3/src/inspection-visits/inspection-visits.controller.ts b/api-v3/src/inspection-visits/inspection-visits.controller.ts index c93e054..f0ea808 100644 --- a/api-v3/src/inspection-visits/inspection-visits.controller.ts +++ b/api-v3/src/inspection-visits/inspection-visits.controller.ts @@ -84,6 +84,8 @@ export class InspectionVisitsController { @Req() request: RequestWithContext, ) { assertMobileInspector(principal); + // Android no tiene un lifecycle paralelo: crea la visita y delega las + // transiciones DRAFT → PLANNED → IN_PROGRESS a los servicios canónicos. const created = await this.visits.create({ operationalAreaId: dto.operationalAreaId, operatorCompanyId: dto.operatorCompanyId,