F3.1 hotfix · aislar preflight API del WEB (#19)

Separa el contrato visual F3.1 del test API y agrega a CI el mismo preflight Docker aislado que ejecuta el VPS antes de producción.
This commit is contained in:
2026-09-07 15:53:27 -03:00
committed by GitHub
3 changed files with 49 additions and 12 deletions
+12
View File
@@ -47,6 +47,8 @@ jobs:
cache-dependency-path: web-v2/package-lock.json cache-dependency-path: web-v2/package-lock.json
- run: npm ci - run: npm ci
- run: npm run typecheck - run: npm run typecheck
- name: F3.1 WEB contract
run: bash ../scripts/check-f3-1-web-contract.sh
- run: npm run build - run: npm run build
contract: contract:
@@ -62,5 +64,15 @@ jobs:
done < <(find scripts -type f -name '*.sh' -print0) done < <(find scripts -type f -name '*.sh' -print0)
- name: Validate Compose - name: Validate Compose
run: docker compose --env-file .env.example config >/dev/null run: docker compose --env-file .env.example config >/dev/null
- name: VPS-equivalent isolated API preflight
run: |
set -Eeuo pipefail
image="dhv2-api:ci-vps-preflight-${GITHUB_SHA::12}"
docker build --target builder -t "$image" api-v3
docker run --rm \
-v "$PWD/api-v3/test:/app/test:ro" \
-v "$PWD/api-v3/tsconfig.test.json:/app/tsconfig.test.json:ro" \
"$image" npm test
docker image rm "$image" >/dev/null 2>&1 || true
- name: Build production images - name: Build production images
run: docker compose --env-file .env.example build api migrate web run: docker compose --env-file .env.example build api migrate web
@@ -52,15 +52,3 @@ test('F3.1 fuerza Área → Yacimiento → Instalación → Subinstalación en s
assert.match(service, /SUBINSTALACION: 'instalacion'/); assert.match(service, /SUBINSTALACION: 'instalacion'/);
assert.match(service, /INVENTORY_SUBINSTALLATION_FAMILY_PARENT_INVALID/); assert.match(service, /INVENTORY_SUBINSTALLATION_FAMILY_PARENT_INVALID/);
}); });
test('F3.1 retira Relevamientos del dashboard y usa alta guiada de cuatro niveles', () => {
const layout = readFileSync('../web-v2/src/layout/AppLayout.tsx', 'utf8');
const app = readFileSync('../web-v2/src/app/App.tsx', 'utf8');
const page = readFileSync('../web-v2/src/pages/InventoryCreatePage.tsx', 'utf8');
assert.doesNotMatch(layout, /label: 'Relevamientos'/);
assert.match(app, /path="\/relevamiento\/\*" element={<Navigate to="\/inventarios" replace \/>}/);
assert.match(app, /path="\/inventarios\/nuevo" element={<InventoryCreatePage \/>}/);
for (const kind of ['AREA', 'YACIMIENTO', 'INSTALACION', 'SUBINSTALACION']) assert.match(page, new RegExp(`kind: '${kind}'`));
assert.doesNotMatch(page, /kind: 'EQUIPO'/);
assert.match(page, /getInventoryFamilyFindings/);
});
+37
View File
@@ -0,0 +1,37 @@
#!/usr/bin/env bash
set -Eeuo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
LAYOUT="$ROOT/web-v2/src/layout/AppLayout.tsx"
APP="$ROOT/web-v2/src/app/App.tsx"
PAGE="$ROOT/web-v2/src/pages/InventoryCreatePage.tsx"
for file in "$LAYOUT" "$APP" "$PAGE"; do
test -f "$file" || {
echo "F3.1 WEB contract: falta $file"
exit 1
}
done
if grep -Fq "label: 'Relevamientos'" "$LAYOUT"; then
echo "F3.1 WEB contract: Relevamientos no debe volver al menú principal"
exit 1
fi
grep -Fq 'path="/relevamiento/*"' "$APP"
grep -Fq 'Navigate to="/inventarios" replace' "$APP"
grep -Fq 'path="/inventarios/nuevo"' "$APP"
grep -Fq 'InventoryCreatePage' "$APP"
for kind in AREA YACIMIENTO INSTALACION SUBINSTALACION; do
grep -Fq "kind: '$kind'" "$PAGE"
done
if grep -Fq "kind: 'EQUIPO'" "$PAGE"; then
echo "F3.1 WEB contract: el alta guiada no debe restaurar EQUIPO como quinto nivel estructural"
exit 1
fi
grep -Fq 'getInventoryFamilyFindings' "$PAGE"
echo 'F3.1 WEB contract: OK'