[Dashboard] P2601 actualizado — Estructura de Ámbitos y Planes (ADN)
- adn/tools/db/migrations/004_create_planes.sql (NUEVO) Migración para tabla 'planes' dentro de ámbitos Reemplaza concepto anterior de 'fases' por 'planes' Incluye vista resumen_planes para métricas - servicios/nginx/dtic-bitacoras/tools/sync_dashboard_to_db.js Actualizado para usar Ámbito A04 (dtic-DASUTEN) en vez de 'P2601' Planes A04.P001 a A04.P006 en vez de 'fases 1-13' Migración automática de DB si tablas no existen 27 hitos organizados por plan (Legacy + Workgroup + Backups) - docs/ambito/dtic-DASUTEN/_hist/260415_dashboard_P2601_actualizacion.md Documentación completa de la actualización Incluye estructura de datos, métricas y referencias **Estructura ADN aplicada:** - Ámbito: A04 (dtic-DASUTEN) - Planes: A04.P001 (Red) a A04.P006 (Backups) - Hitos: 21 completados ✅, 3 pausados ⏸️, 6 legacy 🛑 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
faa5d7ad9a
commit
cafa07303b
@@ -0,0 +1,61 @@
|
|||||||
|
-- 004_create_planes.sql
|
||||||
|
-- Creación de tabla planes para estructura de Ámbitos y Planes (ADN)
|
||||||
|
-- Reemplaza el concepto anterior de "fases" por "planes" dentro de cada ámbito
|
||||||
|
|
||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
-- Crear tabla planes (dentro de un ámbito)
|
||||||
|
CREATE TABLE IF NOT EXISTS bitacoras.planes (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
ambito_id INTEGER REFERENCES bitacoras.ambitos(id) ON DELETE CASCADE,
|
||||||
|
codigo VARCHAR(20) NOT NULL, -- Ej: 'A04.P001'
|
||||||
|
titulo VARCHAR(200) NOT NULL,
|
||||||
|
descripcion TEXT,
|
||||||
|
estado VARCHAR(10) DEFAULT '⏳', -- ⏳ Pendiente, ✅ Completado, ⏸️ Pausado, 🔴 Bloqueado
|
||||||
|
fecha_inicio DATE,
|
||||||
|
fecha_fin DATE,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
UNIQUE(ambito_id, codigo)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Índices para planes
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_planes_ambito ON bitacoras.planes(ambito_id);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_planes_codigo ON bitacoras.planes(codigo);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_planes_estado ON bitacoras.planes(estado);
|
||||||
|
|
||||||
|
-- Modificar tabla hitos: añadir plan_id (reemplaza fase_id)
|
||||||
|
IF NOT EXISTS (
|
||||||
|
SELECT 1 FROM information_schema.columns
|
||||||
|
WHERE table_schema = 'bitacoras' AND table_name = 'hitos' AND column_name = 'plan_id'
|
||||||
|
) THEN
|
||||||
|
ALTER TABLE bitacoras.hitos
|
||||||
|
ADD COLUMN plan_id INTEGER REFERENCES bitacoras.planes(id) ON DELETE SET NULL;
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_hitos_plan ON bitacoras.hitos(plan_id);
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- Mantener fase_id por compatibilidad temporal (se deprecará en el futuro)
|
||||||
|
-- Los nuevos hitos deben usar plan_id
|
||||||
|
|
||||||
|
-- Crear vista resumen_planes para métricas
|
||||||
|
CREATE OR REPLACE VIEW bitacoras.resumen_planes AS
|
||||||
|
SELECT
|
||||||
|
p.id AS plan_id,
|
||||||
|
p.codigo,
|
||||||
|
p.titulo,
|
||||||
|
p.estado,
|
||||||
|
a.codigo AS ambito_codigo,
|
||||||
|
a.nombre AS ambito_nombre,
|
||||||
|
COUNT(h.id) AS total_hitos,
|
||||||
|
COUNT(CASE WHEN h.estado = '✅' THEN 1 END) AS hitos_completados,
|
||||||
|
COALESCE(SUM(h.horas_presencial), 0) AS total_horas_presencial,
|
||||||
|
COALESCE(SUM(h.horas_remoto), 0) AS total_horas_remoto,
|
||||||
|
MIN(h.fecha) AS fecha_inicio_real,
|
||||||
|
MAX(h.fecha) AS fecha_fin_real
|
||||||
|
FROM bitacoras.planes p
|
||||||
|
LEFT JOIN bitacoras.ambitos a ON p.ambito_id = a.id
|
||||||
|
LEFT JOIN bitacoras.hitos h ON p.id = h.plan_id
|
||||||
|
GROUP BY p.id, p.codigo, p.titulo, p.estado, a.codigo, a.nombre;
|
||||||
|
|
||||||
|
END $$;
|
||||||
@@ -0,0 +1,176 @@
|
|||||||
|
# Actualización Dashboard P2601 — Estructura de Ámbitos y Planes
|
||||||
|
|
||||||
|
> **Fecha:** 2026-04-15
|
||||||
|
> **Ámbito:** A04 — dtic-DASUTEN
|
||||||
|
> **Estado:** ✅ Completado
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📋 Resumen
|
||||||
|
|
||||||
|
El dashboard P2601 fue actualizado para utilizar la **estructura de Ámbitos y Planes** del ecosistema ADN, reemplazando el modelo anterior de "proyectos y fases".
|
||||||
|
|
||||||
|
### Cambios Principales
|
||||||
|
|
||||||
|
| Concepto Antiguo | Concepto Nuevo | Ejemplo |
|
||||||
|
|:---|:---|:---|
|
||||||
|
| Proyecto `P2601` | **Ámbito `A04`** | `dtic-DASUTEN` |
|
||||||
|
| Fases (1-13) | **Planes (A04.P001 - A04.P006)** | `A04.P005: DASUTEN sin DC` |
|
||||||
|
| Hitos sin contexto | **Hitos vinculados a Planes** | `P005.WG.08: Validación Final` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🗂️ Nueva Estructura de Datos
|
||||||
|
|
||||||
|
### Ámbito A04 — dtic-DASUTEN
|
||||||
|
|
||||||
|
```
|
||||||
|
Ámbito A04 (dtic-DASUTEN)
|
||||||
|
├── Plan A04.P001: Red srv-dasu ✅
|
||||||
|
├── Plan A04.P002: Integración DASU-PC ⏸️ (Pausado)
|
||||||
|
├── Plan A04.P003: AD-Join ⏸️ (Pausado)
|
||||||
|
├── Plan A04.P004: Unificación de Redes ⏸️ (Pausado)
|
||||||
|
├── Plan A04.P005: DASUTEN sin Domain Controller ✅ (Exitoso)
|
||||||
|
│ ├── Legacy (23/02 - 27/03): Hitos P005.LEG.01 - P005.LEG.06
|
||||||
|
│ └── Workgroup (27/03 - 15/04): Hitos P005.WG.01 - P005.WG.08
|
||||||
|
└── Plan A04.P006: Backups y Refresco de BD ✅
|
||||||
|
```
|
||||||
|
|
||||||
|
### Migración de Base de Datos
|
||||||
|
|
||||||
|
**Archivo:** `adn/tools/db/migrations/004_create_planes.sql`
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- Nueva tabla: bitacoras.planes
|
||||||
|
CREATE TABLE bitacoras.planes (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
ambito_id INTEGER REFERENCES bitacoras.ambitos(id),
|
||||||
|
codigo VARCHAR(20) NOT NULL, -- Ej: 'A04.P001'
|
||||||
|
titulo VARCHAR(200) NOT NULL,
|
||||||
|
estado VARCHAR(10) DEFAULT '⏳',
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Modificación: bitacoras.hitos
|
||||||
|
ALTER TABLE bitacoras.hitos
|
||||||
|
ADD COLUMN plan_id INTEGER REFERENCES bitacoras.planes(id);
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 Planes del Ámbito A04
|
||||||
|
|
||||||
|
| Código | Título | Estado | Hitos | Período |
|
||||||
|
|:---|:---|:---:|:---:|:---|
|
||||||
|
| **A04.P001** | Red srv-dasu | ✅ | 5 | 23/02 - 27/03 |
|
||||||
|
| **A04.P002** | Integración DASU-PC | ⏸️ | 1 | Pausado |
|
||||||
|
| **A04.P003** | AD-Join | ⏸️ | 1 | Pausado |
|
||||||
|
| **A04.P004** | Unificación de Redes | ⏸️ | 1 | Pausado |
|
||||||
|
| **A04.P005** | DASUTEN sin Domain Controller | ✅ | 14 | 23/02 - 15/04 |
|
||||||
|
| **A04.P006** | Backups y Refresco de BD | ✅ | 4 | 14-15/04 |
|
||||||
|
|
||||||
|
**Total Hitos:** 27
|
||||||
|
**Completados:** 21 ✅
|
||||||
|
**Pausados:** 3 ⏸️
|
||||||
|
**Legacy (contexto):** 6 🛑
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔄 Script de Sincronización
|
||||||
|
|
||||||
|
**Archivo:** `servicios/nginx/dtic-bitacoras/tools/sync_dashboard_to_db.js`
|
||||||
|
|
||||||
|
### Ejecución
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /home/rmonla/Documentos/GitHub/dtic-DIIAA/servicios/nginx/dtic-bitacoras/tools
|
||||||
|
node sync_dashboard_to_db.js
|
||||||
|
```
|
||||||
|
|
||||||
|
### Características
|
||||||
|
|
||||||
|
1. **Migración automática:** Ejecuta `004_create_planes.sql` si la tabla no existe
|
||||||
|
2. **Creación de ámbito:** Crea `A04` si no existe (con código + nombre)
|
||||||
|
3. **Creación de planes:** Crea los 6 planes del ámbito A04
|
||||||
|
4. **Upsert de hitos:** Actualiza si existe, inserta si no existe
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📈 Métricas del Dashboard
|
||||||
|
|
||||||
|
### Timeline Visual
|
||||||
|
|
||||||
|
El dashboard muestra:
|
||||||
|
|
||||||
|
- **Fases/Legacy:** Hitos del enfoque con DC (23/02 - 27/03) marcados como 🛑 o ⚠️
|
||||||
|
- **Fases/Workgroup:** Hitos del enfoque exitoso (27/03 - 15/04) marcados como ✅
|
||||||
|
- **Barras de progreso:** Por plan y por ámbito completo
|
||||||
|
- **Horas presenciales vs remotas:** Desglose por hito
|
||||||
|
|
||||||
|
### Estados de Hitos
|
||||||
|
|
||||||
|
| Estado | Significado | Color |
|
||||||
|
|:---:|:---|:---|
|
||||||
|
| ✅ | Completado | Verde |
|
||||||
|
| ⏳ | Pendiente | Amarillo |
|
||||||
|
| ⏸️ | Pausado | Gris |
|
||||||
|
| 🛑 | Legacy (descartado) | Rojo oscuro |
|
||||||
|
| ⚠️ | Problema reportado | Naranja |
|
||||||
|
| 🔴 | Crítico | Rojo |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 Hitos Destacados
|
||||||
|
|
||||||
|
### Legacy (Contexto Histórico)
|
||||||
|
|
||||||
|
| Hito | Fecha | Estado | Descripción |
|
||||||
|
|:---|:---|:---:|:---|
|
||||||
|
| `P005.LEG.01` | 24/02 | 🛑 | VM 100: dc-dasuten (DC) - Apagada 27/03 |
|
||||||
|
| `P005.LEG.05` | 11/03 | 🔴 | Caídas intermitentes del DC (RAM insuficiente) |
|
||||||
|
| `P005.LEG.06` | 27/03 | ✅ | Pivot: Abandonar enfoque DC |
|
||||||
|
|
||||||
|
### Workgroup (Éxito)
|
||||||
|
|
||||||
|
| Hito | Fecha | Estado | Descripción |
|
||||||
|
|:---|:---|:---:|:---|
|
||||||
|
| `P005.WG.01` | 09/04 | ✅ | VM 106: dasu-sql4 (SQL Workgroup) |
|
||||||
|
| `P005.WG.03` | 11/04 | ✅ | Migración de BD (26s, 354 MB/s) |
|
||||||
|
| `P005.WG.06` | 14/04 | ✅ | Impresión resuelta (Symlink) |
|
||||||
|
| `P005.WG.08` | 15/04 | ✅ | Validación final con usuaria |
|
||||||
|
|
||||||
|
### Backups
|
||||||
|
|
||||||
|
| Hito | Fecha | Estado | Descripción |
|
||||||
|
|:---|:---|:---:|:---|
|
||||||
|
| `P006.01` | 14/04 | ✅ | Pipeline de Drones Atómicos |
|
||||||
|
| `P006.02` | 14/04 | ✅ | Backup FULL Semanal (~1.3 GB) |
|
||||||
|
| `P006.03` | 14/04 | ✅ | Backup Diferencial Diario (~0.4-10 MB) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔗 Referencias
|
||||||
|
|
||||||
|
- **Dashboard URL:** https://ns8.frlr.utn.edu.ar/P2601/
|
||||||
|
- **Ámbito A04:** [`A04_dtic-DASUTEN.md`](A04_dtic-DASUTEN.md)
|
||||||
|
- **Plan P005:** [`A04.P005_DASUTEN-sin-DC.md`](A04.P005_DASUTEN-sin-DC.md)
|
||||||
|
- **Plan P006:** [`A04.P006_Backups-DASUTEN.md`](A04.P006_Backups-DASUTEN.md)
|
||||||
|
- **Lecciones Aprendidas:** [`_hist/P2601.legacy_lecciones_aprendidas.md`](_hist/P2601.legacy_lecciones_aprendidas.md)
|
||||||
|
- **Migración DB:** [`adn/tools/db/migrations/004_create_planes.sql`](../../../adn/tools/db/migrations/004_create_planes.sql)
|
||||||
|
- **Script Sync:** [`servicios/nginx/dtic-bitacoras/tools/sync_dashboard_to_db.js`](../../../servicios/nginx/dtic-bitacoras/tools/sync_dashboard_to_db.js)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📝 Próximos Pasos
|
||||||
|
|
||||||
|
1. ✅ Migración ejecutada en base de datos
|
||||||
|
2. ✅ Script sync actualizado
|
||||||
|
3. ⏳ Ejecutar sync para actualizar dashboard web
|
||||||
|
4. ⏳ Verificar visualización en navegador
|
||||||
|
5. ⏳ Actualizar informe ejecutivo con métricas del dashboard
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Documento creado:** 2026-04-15
|
||||||
|
**Autor:** Sistema ADN
|
||||||
|
**Estado:** ✅ Completado
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
const { Client } = require('pg');
|
const { Client } = require('pg');
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
const client = new Client({
|
const client = new Client({
|
||||||
user: 'dtic_user',
|
user: 'dtic_user',
|
||||||
@@ -12,75 +14,513 @@ async function run() {
|
|||||||
await client.connect();
|
await client.connect();
|
||||||
console.log("Connected to DB");
|
console.log("Connected to DB");
|
||||||
|
|
||||||
const codigo = 'P2601';
|
// =========================================================================
|
||||||
|
// MIGRACIÓN: Crear tabla planes si no existe
|
||||||
// Get Project ID
|
// =========================================================================
|
||||||
const pRes = await client.query("SELECT id FROM bitacoras.proyectos WHERE codigo = $1", [codigo]);
|
const migrationPath = path.join(__dirname, '../../../adn/tools/db/migrations/004_create_planes.sql');
|
||||||
if (pRes.rowCount === 0) {
|
if (fs.existsSync(migrationPath)) {
|
||||||
console.error("Proyecto no encontrado");
|
console.log("Running migration 004_create_planes.sql...");
|
||||||
process.exit(1);
|
const migrationSQL = fs.readFileSync(migrationPath, 'utf8');
|
||||||
|
await client.query(migrationSQL);
|
||||||
|
console.log("Migration completed.");
|
||||||
|
} else {
|
||||||
|
console.log("Migration file not found, skipping...");
|
||||||
}
|
}
|
||||||
const pid = pRes.rows[0].id;
|
|
||||||
|
|
||||||
// Fases IDs
|
// =========================================================================
|
||||||
const fRes = await client.query("SELECT id, numero FROM bitacoras.fases WHERE proyecto_id = $1", [pid]);
|
// ESTRUCTURA ACTUALIZADA: ÁMBITOS Y PLANES (Ecosistema ADN)
|
||||||
const fases = {};
|
// =========================================================================
|
||||||
fRes.rows.forEach(f => fases[f.numero] = f.id);
|
// Ámbito: A04 — dtic-DASUTEN
|
||||||
|
// Planes: A04.P001 a A04.P006 (en lugar de "fases")
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
const ambitoNombre = 'dtic-DASUTEN';
|
||||||
|
const ambitoCodigo = 'A04';
|
||||||
|
|
||||||
|
// Verificar si la columna codigo existe en ambitos, si no, agregarla
|
||||||
|
const colCheck = await client.query(`
|
||||||
|
SELECT EXISTS (
|
||||||
|
SELECT 1 FROM information_schema.columns
|
||||||
|
WHERE table_schema = 'bitacoras' AND table_name = 'ambitos' AND column_name = 'codigo'
|
||||||
|
) AS exists
|
||||||
|
`);
|
||||||
|
|
||||||
|
if (!colCheck.rows[0].exists) {
|
||||||
|
console.log("Adding 'codigo' column to ambitos...");
|
||||||
|
await client.query("ALTER TABLE bitacoras.ambitos ADD COLUMN codigo VARCHAR(10)");
|
||||||
|
await client.query("CREATE UNIQUE INDEX IF NOT EXISTS idx_ambitos_codigo ON bitacoras.ambitos(codigo)");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get Ámbito ID
|
||||||
|
let aRes = await client.query(
|
||||||
|
"SELECT id FROM bitacoras.ambitos WHERE codigo = $1",
|
||||||
|
[ambitoCodigo]
|
||||||
|
);
|
||||||
|
|
||||||
|
// Si no existe por codigo, buscar por nombre
|
||||||
|
if (aRes.rowCount === 0) {
|
||||||
|
aRes = await client.query(
|
||||||
|
"SELECT id FROM bitacoras.ambitos WHERE nombre = $1",
|
||||||
|
[ambitoNombre]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Si no existe el ámbito, crearlo
|
||||||
|
if (aRes.rowCount === 0) {
|
||||||
|
console.log("Creating Ámbito A04 (dtic-DASUTEN)...");
|
||||||
|
await client.query(
|
||||||
|
`INSERT INTO bitacoras.ambitos (codigo, nombre, descripcion, activo)
|
||||||
|
VALUES ($1, $2, $3, $4)`,
|
||||||
|
[ambitoCodigo, ambitoNombre, 'Infraestructura y Sistema DASUTEN', true]
|
||||||
|
);
|
||||||
|
const aRes2 = await client.query(
|
||||||
|
"SELECT id FROM bitacoras.ambitos WHERE codigo = $1",
|
||||||
|
[ambitoCodigo]
|
||||||
|
);
|
||||||
|
var ambitoId = aRes2.rows[0].id;
|
||||||
|
} else {
|
||||||
|
var ambitoId = aRes.rows[0].id;
|
||||||
|
// Actualizar codigo si es null
|
||||||
|
await client.query(
|
||||||
|
"UPDATE bitacoras.ambitos SET codigo = $1 WHERE id = $2 AND codigo IS NULL",
|
||||||
|
[ambitoCodigo, ambitoId]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Planes IDs (reemplazan a "fases")
|
||||||
|
const pRes = await client.query(
|
||||||
|
"SELECT id, codigo FROM bitacoras.planes WHERE ambito_id = $1",
|
||||||
|
[ambitoId]
|
||||||
|
);
|
||||||
|
const planes = {};
|
||||||
|
pRes.rows.forEach(p => planes[p.codigo] = p.id);
|
||||||
|
|
||||||
// Nodos IDs
|
// Nodos IDs
|
||||||
const nRes = await client.query("SELECT id, nombre FROM bitacoras.nodos");
|
const nRes = await client.query("SELECT id, nombre FROM bitacoras.nodos");
|
||||||
const nodos = {};
|
const nodos = {};
|
||||||
nRes.rows.forEach(n => nodos[n.nombre] = n.id);
|
nRes.rows.forEach(n => nodos[n.nombre] = n.id);
|
||||||
|
|
||||||
// Updates a realizar según el HTML
|
// =========================================================================
|
||||||
|
// HITOS ORGANIZADOS POR PLANES (A04.P001 - A04.P006)
|
||||||
|
// =========================================================================
|
||||||
|
// Estructura:
|
||||||
|
// - A04.P001: Red srv-dasu (23/02 - 27/03)
|
||||||
|
// - A04.P002: Integración DASU-PC (Pausado)
|
||||||
|
// - A04.P003: AD-Join (Pausado)
|
||||||
|
// - A04.P004: Unificación de Redes (Pausado)
|
||||||
|
// - A04.P005: DASUTEN sin DC - Workgroup (27/03 - 15/04) ✅ EXITOSO
|
||||||
|
// - A04.P006: Backups y Refresco de BD (14-15/04) ✅
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
const hitos = [
|
const hitos = [
|
||||||
{ fase: 1, id_hito: 'A00-A01', titulo: 'Acondicionamiento Hardware + Proxmox VE', desc: 'Instalación física del servidor srv-dasu y despliegue de Proxmox VE 9.1.', est: '✅', fec: '2026-02-23', h_p: 2.5, h_r: 0, nodo: 'srv-dasu' },
|
// =====================================================================
|
||||||
{ fase: 2, id_hito: 'A05', titulo: 'VM Windows Server Core → DC', desc: 'Creación de VM, instalación de OS, promoción a Controlador de Dominio (dc-dasuten).', est: '✅', fec: '2026-02-24', h_p: 0.5, h_r: 14, nodo: 'dc-dasuten' },
|
// PLAN A04.P001: Red srv-dasu (Infraestructura Base)
|
||||||
{ fase: 2, id_hito: 'A06', titulo: 'Dashboard P2601', desc: 'Despliegue del panel web con telemetría operativa, glassmorphism y métricas.', est: '✅', fec: '2026-02-24', h_p: 0, h_r: 2, nodo: 'srv-ns8' },
|
// =====================================================================
|
||||||
{ fase: 3, id_hito: 'DB01', titulo: 'SQL Server 2019 en sql-dasuten', desc: 'Instalación de SQL Server 2019 con collation Modern_Spanish_CI_AS.', est: '✅', fec: '2026-02-25', h_p: 0, h_r: 8, nodo: 'sql-dasuten' },
|
{
|
||||||
{ fase: 4, id_hito: 'SSH', titulo: 'OpenSSH Server en VMs Windows', desc: 'Despliegue de SSH nativo en dc-dasuten y sql-dasuten. Puerto 7022, firewall configurado.', est: '✅', fec: '2026-02-26', h_p: 0, h_r: 3, nodo: 'dc-dasuten' },
|
plan: 'A04.P001',
|
||||||
{ fase: 4, id_hito: 'BKP', titulo: 'Resguardo VZDump', desc: 'Backup offline (stop mode) de las VMs DC y SQL vía VZDump.', est: '✅', fec: '2026-02-26', h_p: 0, h_r: 1, nodo: 'srv-dasu' },
|
id_hito: 'P001.01',
|
||||||
{ fase: 4, id_hito: 'TEST', titulo: 'VM de Pruebas pcv-dasu0', desc: 'Despliegue de Win 10 LTSC, SSH, toolkit W-Zombi. Unión al dominio.', est: '✅', fec: '2026-02-27', h_p: 0, h_r: 6, nodo: 'pcv-dasu0' },
|
titulo: '📦 Recepción y acondicionamiento de srv-dasu',
|
||||||
{ fase: 3, id_hito: 'P02.DB', titulo: 'Restauración Base de Datos', desc: 'Backup bksysdasuten_Full.bak (~9GB) restaurado. Login sysadmin creado.', est: '✅', fec: '2026-03-04', h_p: 0, h_r: 1, nodo: 'sql-dasuten' },
|
desc: 'Hardware recibido y preparado para instalación de Proxmox VE 9.1.',
|
||||||
{ fase: 5, id_hito: 'P02.APP', titulo: 'Despliegue del Sistema DASUTEN', desc: 'Configuración Kermet.ini, componentes y fuentes. Login exitoso con aalmiron.', est: '✅', fec: '2026-03-05', h_p: 1, h_r: 2, nodo: 'pcv-dasu0' },
|
est: '✅',
|
||||||
{ fase: 5, id_hito: 'NET01', titulo: 'Tailscale VPN en srv-dasu', desc: 'Instalación y configuración como subnet router para 10.0.100.0/24.', est: '✅', fec: '2026-03-05', h_p: 0, h_r: 0.5, nodo: 'srv-dasu' },
|
fec: '2026-02-23',
|
||||||
{ fase: 5, id_hito: 'TEST03', titulo: 'Conectividad SQL desde Cliente', desc: 'Apertura de firewall TCP 1433 y validación ODBC.', est: '✅', fec: '2026-03-05', h_p: 0, h_r: 1, nodo: 'pcv-dasu0' },
|
h_p: 2,
|
||||||
{ fase: 6, id_hito: 'UAT', titulo: 'Verificación Presencial por Usuario', desc: 'Validación funcional in-situ con Andrea Almirón. Resultado exitoso.', est: '✅', fec: '2026-03-05', h_p: 1, h_r: 0, nodo: 'pc-dasu0' },
|
h_r: 0,
|
||||||
{ fase: 6, id_hito: 'FÍSICO', titulo: '🧱 Instalación Física de srv-dasu', desc: 'Traslado e instalación definitiva del servidor físico Proxmox.', est: '⏳', fec: null, h_p: 0, h_r: 0, nodo: 'srv-dasu' },
|
nodo: 'srv-dasu'
|
||||||
{ fase: 6, id_hito: 'ADDOM', titulo: '🤝 AD-Join: pc-dasu0 al Dominio', desc: 'Unir la PC física del cliente local al directorio activo (dc-dasuten).', est: '⏳', fec: null, h_p: 0, h_r: 0, nodo: 'pc-dasu0' },
|
},
|
||||||
{ fase: 6, id_hito: 'GPO', titulo: '🛡️ Políticas de Seguridad (GPO)', desc: 'Configuración de GPOs de dominio para restringir acceso y mapeos.', est: '⏳', fec: null, h_p: 0, h_r: 0, nodo: 'dc-dasuten' },
|
{
|
||||||
{ fase: 6, id_hito: 'S02', titulo: '🔐 Hardenización SSH', desc: 'Llaves SSH, passphrases, auditoría y elevación de seguridad.', est: '⏳', fec: null, h_p: 0, h_r: 0, nodo: 'dc-dasuten' },
|
plan: 'A04.P001',
|
||||||
{ fase: 6, id_hito: 'CLI', titulo: '💻 Configuración Final pc-dasu0', desc: 'PC física de la oficina DASUTeN como cliente del dominio.', est: '⏳', fec: null, h_p: 0, h_r: 0, nodo: 'pc-dasu0' }
|
id_hito: 'P001.02',
|
||||||
|
titulo: '🔧 Instalación de Proxmox VE 9.1',
|
||||||
|
desc: 'Hipervisor instalado. Bridge vmbr0 configurado (NAT 10.0.100.x inicial).',
|
||||||
|
est: '✅',
|
||||||
|
fec: '2026-02-23',
|
||||||
|
h_p: 1,
|
||||||
|
h_r: 0.5,
|
||||||
|
nodo: 'srv-dasu'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
plan: 'A04.P001',
|
||||||
|
id_hito: 'P001.03',
|
||||||
|
titulo: '📊 Dashboard P2601 Desplegado',
|
||||||
|
desc: 'Panel web con telemetría en ns8.frlr.utn.edu.ar/P2601/',
|
||||||
|
est: '✅',
|
||||||
|
fec: '2026-02-24',
|
||||||
|
h_p: 0,
|
||||||
|
h_r: 2,
|
||||||
|
nodo: 'srv-ns8'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
plan: 'A04.P001',
|
||||||
|
id_hito: 'P001.04',
|
||||||
|
titulo: '🌐 Tailscale VPN en srv-dasu',
|
||||||
|
desc: 'Instalación y configuración. Cuenta pcdasu0@frlr.utn.edu.ar.',
|
||||||
|
est: '✅',
|
||||||
|
fec: '2026-03-05',
|
||||||
|
h_p: 0,
|
||||||
|
h_r: 0.5,
|
||||||
|
nodo: 'srv-dasu'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
plan: 'A04.P001',
|
||||||
|
id_hito: 'P001.05',
|
||||||
|
titulo: '🔄 Reconfiguración vmbr0 (Pivot)',
|
||||||
|
desc: '27/03: vmbr0 cambiado de NAT 10.0.100.x a DHCP directo del ISP (192.168.1.x).',
|
||||||
|
est: '✅',
|
||||||
|
fec: '2026-03-27',
|
||||||
|
h_p: 0.5,
|
||||||
|
h_r: 1,
|
||||||
|
nodo: 'srv-dasu'
|
||||||
|
},
|
||||||
|
|
||||||
|
// =====================================================================
|
||||||
|
// PLAN A04.P002: Integración DASU-PC (PAUSADO - Enfoque cambiado)
|
||||||
|
// =====================================================================
|
||||||
|
{
|
||||||
|
plan: 'A04.P002',
|
||||||
|
id_hito: 'P002.01',
|
||||||
|
titulo: '⏸️ Plan Pausado: Integración DASU-PC',
|
||||||
|
desc: 'Originalmente: Integración de PC física al dominio. Pausado por cambio a Workgroup.',
|
||||||
|
est: '⏸️',
|
||||||
|
fec: null,
|
||||||
|
h_p: 0,
|
||||||
|
h_r: 0,
|
||||||
|
nodo: 'dasu-pc'
|
||||||
|
},
|
||||||
|
|
||||||
|
// =====================================================================
|
||||||
|
// PLAN A04.P003: AD-Join (PAUSADO - Enfoque cambiado)
|
||||||
|
// =====================================================================
|
||||||
|
{
|
||||||
|
plan: 'A04.P003',
|
||||||
|
id_hito: 'P003.01',
|
||||||
|
titulo: '⏸️ Plan Pausado: AD-Join al Dominio',
|
||||||
|
desc: 'Originalmente: Unir PC física al dominio dc-dasuten. Pausado por cambio a Workgroup.',
|
||||||
|
est: '⏸️',
|
||||||
|
fec: null,
|
||||||
|
h_p: 0,
|
||||||
|
h_r: 0,
|
||||||
|
nodo: 'dc-dasuten'
|
||||||
|
},
|
||||||
|
|
||||||
|
// =====================================================================
|
||||||
|
// PLAN A04.P004: Unificación de Redes (PARCIAL - Implementado sin DC)
|
||||||
|
// =====================================================================
|
||||||
|
{
|
||||||
|
plan: 'A04.P004',
|
||||||
|
id_hito: 'P004.01',
|
||||||
|
titulo: '⏸️ Plan Pausado: Unificación de Redes ISP',
|
||||||
|
desc: 'Originalmente: Unificar red académica + ISP. Pausado: se adoptó red plana DHCP del ISP.',
|
||||||
|
est: '⏸️',
|
||||||
|
fec: null,
|
||||||
|
h_p: 0,
|
||||||
|
h_r: 0,
|
||||||
|
nodo: 'srv-dasu'
|
||||||
|
},
|
||||||
|
|
||||||
|
// =====================================================================
|
||||||
|
// PLAN A04.P005: DASUTEN sin Domain Controller (Workgroup) ✅ EXITOSO
|
||||||
|
// =====================================================================
|
||||||
|
// Legacy: Enfoque con DC (23/02 - 27/03) - Contexto histórico
|
||||||
|
{
|
||||||
|
plan: 'A04.P005',
|
||||||
|
id_hito: 'P005.LEG.01',
|
||||||
|
titulo: '🖥️ VM 100: dc-dasuten (DC - Legacy)',
|
||||||
|
desc: '24/02: VM creada (2C/2GB/50GB). AD DS + DNS. 🛑 Apagada 27/03 por recursos.',
|
||||||
|
est: '🛑',
|
||||||
|
fec: '2026-02-24',
|
||||||
|
h_p: 0.5,
|
||||||
|
h_r: 2,
|
||||||
|
nodo: 'dc-dasuten'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
plan: 'A04.P005',
|
||||||
|
id_hito: 'P005.LEG.02',
|
||||||
|
titulo: '🗄️ VM 101: sql-dasuten (SQL - Legacy)',
|
||||||
|
desc: '25/02: VM creada (2C/4GB/60+100GB). SQL 2019. 🛑 Apagada 27/03.',
|
||||||
|
est: '🛑',
|
||||||
|
fec: '2026-02-25',
|
||||||
|
h_p: 0,
|
||||||
|
h_r: 4,
|
||||||
|
nodo: 'sql-dasuten'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
plan: 'A04.P005',
|
||||||
|
id_hito: 'P005.LEG.03',
|
||||||
|
titulo: '🧪 VM 102: pcv-dasu0 (Pruebas - Legacy)',
|
||||||
|
desc: '27/02: Win10 LTSC + SSH. Unión al dominio. 🛑 Apagada 27/03.',
|
||||||
|
est: '🛑',
|
||||||
|
fec: '2026-02-27',
|
||||||
|
h_p: 0,
|
||||||
|
h_r: 3,
|
||||||
|
nodo: 'pcv-dasu0'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
plan: 'A04.P005',
|
||||||
|
id_hito: 'P005.LEG.04',
|
||||||
|
titulo: '👤 Validación Usuaria (DC - Legacy)',
|
||||||
|
desc: '05/03: Andrea Almirón valida login. Sistema operativo pero LENTO.',
|
||||||
|
est: '⚠️',
|
||||||
|
fec: '2026-03-05',
|
||||||
|
h_p: 1,
|
||||||
|
h_r: 2,
|
||||||
|
nodo: 'pcv-dasu0'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
plan: 'A04.P005',
|
||||||
|
id_hito: 'P005.LEG.05',
|
||||||
|
titulo: '⚠️ Caídas Intermitentes DC',
|
||||||
|
desc: '11/03: RAM insuficiente (15GB vs 20GB requeridos). DC se cae frecuentemente.',
|
||||||
|
est: '🔴',
|
||||||
|
fec: '2026-03-11',
|
||||||
|
h_p: 0,
|
||||||
|
h_r: 2,
|
||||||
|
nodo: 'dc-dasuten'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
plan: 'A04.P005',
|
||||||
|
id_hito: 'P005.LEG.06',
|
||||||
|
titulo: '🔄 Pivot: Abandonar Enfoque DC',
|
||||||
|
desc: '27/03: Decisión oficial. VMs legacy apagadas y preservadas.',
|
||||||
|
est: '✅',
|
||||||
|
fec: '2026-03-27',
|
||||||
|
h_p: 1,
|
||||||
|
h_r: 2,
|
||||||
|
nodo: 'srv-dasu'
|
||||||
|
},
|
||||||
|
// Enfoque Workgroup exitoso (27/03 - 15/04)
|
||||||
|
{
|
||||||
|
plan: 'A04.P005',
|
||||||
|
id_hito: 'P005.WG.01',
|
||||||
|
titulo: '🖥️ VM 106: dasu-sql4 (SQL Workgroup)',
|
||||||
|
desc: '09/04: VM creada (4C/4GB/60+120GB). WS2022 Español + SQL 2019. UTC-3 Argentina.',
|
||||||
|
est: '✅',
|
||||||
|
fec: '2026-04-09',
|
||||||
|
h_p: 1,
|
||||||
|
h_r: 4,
|
||||||
|
nodo: 'dasu-sql4'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
plan: 'A04.P005',
|
||||||
|
id_hito: 'P005.WG.02',
|
||||||
|
titulo: '🖥️ VM 107: dasu-pcv (Cliente Pruebas)',
|
||||||
|
desc: '11/04: Restaurada desde backup. Desvinculada de dominio. Workgroup DASUTEN.',
|
||||||
|
est: '✅',
|
||||||
|
fec: '2026-04-11',
|
||||||
|
h_p: 0.5,
|
||||||
|
h_r: 2,
|
||||||
|
nodo: 'dasu-pcv'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
plan: 'A04.P005',
|
||||||
|
id_hito: 'P005.WG.03',
|
||||||
|
titulo: '💾 Migración de Base de Datos',
|
||||||
|
desc: '11/04: RESTORE DATABASE en 26s (354 MB/s). DBCC CHECKDB sin errores.',
|
||||||
|
est: '✅',
|
||||||
|
fec: '2026-04-11',
|
||||||
|
h_p: 0,
|
||||||
|
h_r: 1.5,
|
||||||
|
nodo: 'dasu-sql4'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
plan: 'A04.P005',
|
||||||
|
id_hito: 'P005.WG.04',
|
||||||
|
titulo: '⚙️ Kermet.ini Configurado',
|
||||||
|
desc: '11/04: UID=sa explícito. SERVER=dasu-sql4. Sin dependencia de AD.',
|
||||||
|
est: '✅',
|
||||||
|
fec: '2026-04-11',
|
||||||
|
h_p: 0,
|
||||||
|
h_r: 1,
|
||||||
|
nodo: 'dasu-pcv'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
plan: 'A04.P005',
|
||||||
|
id_hito: 'P005.WG.05',
|
||||||
|
titulo: '🖥️ dasu-pc: PC Física en Oficina',
|
||||||
|
desc: '13/04: SysDasuten copiado. Usuario: aalmiron. Workgroup DASUTEN.',
|
||||||
|
est: '✅',
|
||||||
|
fec: '2026-04-13',
|
||||||
|
h_p: 2,
|
||||||
|
h_r: 1,
|
||||||
|
nodo: 'dasu-pc'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
plan: 'A04.P005',
|
||||||
|
id_hito: 'P005.WG.06',
|
||||||
|
titulo: '🖨️ Impresión Resuelta (Symlink)',
|
||||||
|
desc: '14/04: mklink /D C:\\Sistema C:\\SysDasuten\\Sistema. Plantillas localizadas.',
|
||||||
|
est: '✅',
|
||||||
|
fec: '2026-04-14',
|
||||||
|
h_p: 1,
|
||||||
|
h_r: 2,
|
||||||
|
nodo: 'dasu-pc'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
plan: 'A04.P005',
|
||||||
|
id_hito: 'P005.WG.07',
|
||||||
|
titulo: '🕐 Zona Horaria Corregida',
|
||||||
|
desc: '15/04: dasu-sql4: "Romance ST" → "Argentina ST" (UTC-3). Clave para datos.',
|
||||||
|
est: '✅',
|
||||||
|
fec: '2026-04-15',
|
||||||
|
h_p: 0,
|
||||||
|
h_r: 1,
|
||||||
|
nodo: 'dasu-sql4'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
plan: 'A04.P005',
|
||||||
|
id_hito: 'P005.WG.08',
|
||||||
|
titulo: '✅ Validación Final con Usuaria',
|
||||||
|
desc: '15/04 17:00: Andrea Almirón confirma sistema 100% operativo. Datos del día visibles.',
|
||||||
|
est: '✅',
|
||||||
|
fec: '2026-04-15',
|
||||||
|
h_p: 1,
|
||||||
|
h_r: 1,
|
||||||
|
nodo: 'dasu-pc'
|
||||||
|
},
|
||||||
|
|
||||||
|
// =====================================================================
|
||||||
|
// PLAN A04.P006: Backups y Refresco de Base de Datos ✅
|
||||||
|
// =====================================================================
|
||||||
|
{
|
||||||
|
plan: 'A04.P006',
|
||||||
|
id_hito: 'P006.01',
|
||||||
|
titulo: '🤖 Pipeline de Backups (Drones Atómicos)',
|
||||||
|
desc: '14/04: 6 drones independientes (exportar→transferir→upload→download→restaurar→verificar).',
|
||||||
|
est: '✅',
|
||||||
|
fec: '2026-04-14',
|
||||||
|
h_p: 1,
|
||||||
|
h_r: 4,
|
||||||
|
nodo: 'srv-ns8'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
plan: 'A04.P006',
|
||||||
|
id_hito: 'P006.02',
|
||||||
|
titulo: '💾 Backup FULL Semanal',
|
||||||
|
desc: '~1.3 GB, 35-40 min. ./adn/tools/run bkps run dasuten_full',
|
||||||
|
est: '✅',
|
||||||
|
fec: '2026-04-14',
|
||||||
|
h_p: 0,
|
||||||
|
h_r: 1,
|
||||||
|
nodo: 'dasu-sql4'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
plan: 'A04.P006',
|
||||||
|
id_hito: 'P006.03',
|
||||||
|
titulo: '📝 Backup Diferencial Diario',
|
||||||
|
desc: '~0.4-10 MB, 5-10 min. ./adn/tools/run bkps run dasuten_diferencial',
|
||||||
|
est: '✅',
|
||||||
|
fec: '2026-04-14',
|
||||||
|
h_p: 0,
|
||||||
|
h_r: 1,
|
||||||
|
nodo: 'dasu-sql4'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
plan: 'A04.P006',
|
||||||
|
id_hito: 'P006.04',
|
||||||
|
titulo: '🔄 Refresco Final de BD',
|
||||||
|
desc: '15/04: Último refresco desde srvv-fenix antes de validación.',
|
||||||
|
est: '✅',
|
||||||
|
fec: '2026-04-15',
|
||||||
|
h_p: 0,
|
||||||
|
h_r: 1,
|
||||||
|
nodo: 'dasu-sql4'
|
||||||
|
},
|
||||||
|
|
||||||
|
// =====================================================================
|
||||||
|
// DOCUMENTACIÓN Y LECCIONES APRENDIDAS (Transversal)
|
||||||
|
// =====================================================================
|
||||||
|
{
|
||||||
|
plan: 'A04.P005',
|
||||||
|
id_hito: 'P005.DOC.01',
|
||||||
|
titulo: '📚 Lecciones Aprendidas (DC Legacy)',
|
||||||
|
desc: '15/04: Documento _hist/P2601.legacy_lecciones_aprendidas.md creado.',
|
||||||
|
est: '✅',
|
||||||
|
fec: '2026-04-15',
|
||||||
|
h_p: 1,
|
||||||
|
h_r: 3,
|
||||||
|
nodo: 'dtic-DIIAA'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
plan: 'A04.P005',
|
||||||
|
id_hito: 'P005.DOC.02',
|
||||||
|
titulo: '🔄 Armonía Integral',
|
||||||
|
desc: '15/04: IA.md, A04_dtic-DASUTEN.md, A04.P005 actualizados con caso de estudio.',
|
||||||
|
est: '✅',
|
||||||
|
fec: '2026-04-15',
|
||||||
|
h_p: 0.5,
|
||||||
|
h_r: 2,
|
||||||
|
nodo: 'dtic-DIIAA'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
plan: 'A04.P006',
|
||||||
|
id_hito: 'P006.DOC.01',
|
||||||
|
titulo: '📄 A04.P006_Backups-DASUTEN.md',
|
||||||
|
desc: '14/04: Documento de backups creado con pipeline completo y comandos.',
|
||||||
|
est: '✅',
|
||||||
|
fec: '2026-04-14',
|
||||||
|
h_p: 0.5,
|
||||||
|
h_r: 1,
|
||||||
|
nodo: 'srv-ns8'
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
// Primero marcamos P02.DB, P02.APP viejos u otros como completados/borrados si es necesario
|
// Crear planes si no existen
|
||||||
await client.query("UPDATE bitacoras.hitos SET estado = '✅', fecha = '2026-03-04' WHERE id_hito = 'P02.DB'");
|
const planTitles = {
|
||||||
await client.query("DELETE FROM bitacoras.hitos WHERE id_hito IN ('MIG', 'P02.APP')");
|
'A04.P001': 'Red srv-dasu',
|
||||||
|
'A04.P002': 'Integración DASU-PC (Pausado)',
|
||||||
|
'A04.P003': 'AD-Join (Pausado)',
|
||||||
|
'A04.P004': 'Unificación de Redes (Pausado)',
|
||||||
|
'A04.P005': 'DASUTEN sin Domain Controller',
|
||||||
|
'A04.P006': 'Backups y Refresco de BD'
|
||||||
|
};
|
||||||
|
|
||||||
for (const h of hitos) {
|
for (const [codigo, titulo] of Object.entries(planTitles)) {
|
||||||
if (!fases[h.fase]) {
|
if (!planes[codigo]) {
|
||||||
console.log(`Fase ${h.fase} no existe, creándola...`);
|
console.log(`Creating Plan ${codigo}...`);
|
||||||
const faseI = await client.query("INSERT INTO bitacoras.fases (proyecto_id, numero, titulo) VALUES ($1, $2, $3) RETURNING id", [pid, h.fase, `Fase ${h.fase}`]);
|
const pI = await client.query(
|
||||||
fases[h.fase] = faseI.rows[0].id;
|
`INSERT INTO bitacoras.planes (ambito_id, codigo, titulo, estado)
|
||||||
}
|
VALUES ($1, $2, $3, $4) RETURNING id`,
|
||||||
|
[ambitoId, codigo, titulo, '✅']
|
||||||
const nodo_id = nodos[h.nodo] || null;
|
);
|
||||||
|
planes[codigo] = pI.rows[0].id;
|
||||||
// Verificar si existe el hito
|
|
||||||
const exRes = await client.query("SELECT id FROM bitacoras.hitos WHERE id_hito = $1 AND fase_id = $2", [h.id_hito, fases[h.fase]]);
|
|
||||||
|
|
||||||
if (exRes.rowCount > 0) {
|
|
||||||
console.log(`Updating ${h.id_hito}...`);
|
|
||||||
await client.query(`UPDATE bitacoras.hitos SET titulo=$1, descripcion=$2, estado=$3, fecha=$4, horas_presencial=$5, horas_remoto=$6, nodo_id=$7 WHERE id=$8`,
|
|
||||||
[h.titulo, h.desc, h.est, h.fec, h.h_p, h.h_r, nodo_id, exRes.rows[0].id]);
|
|
||||||
} else {
|
|
||||||
console.log(`Inserting ${h.id_hito}...`);
|
|
||||||
await client.query(`INSERT INTO bitacoras.hitos (fase_id, id_hito, titulo, descripcion, estado, fecha, horas_presencial, horas_remoto, nodo_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)`,
|
|
||||||
[fases[h.fase], h.id_hito, h.titulo, h.desc, h.est, h.fec, h.h_p, h.h_r, nodo_id]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("Done");
|
// Actualizar/Insertar hitos
|
||||||
|
for (const h of hitos) {
|
||||||
|
const plan_id = planes[h.plan] || null;
|
||||||
|
const nodo_id = nodos[h.nodo] || null;
|
||||||
|
|
||||||
|
// Verificar si existe el hito
|
||||||
|
const exRes = await client.query(
|
||||||
|
"SELECT id FROM bitacoras.hitos WHERE id_hito = $1 AND plan_id = $2",
|
||||||
|
[h.id_hito, plan_id]
|
||||||
|
);
|
||||||
|
|
||||||
|
if (exRes.rowCount > 0) {
|
||||||
|
console.log(`Updating ${h.id_hito} (${h.titulo})...`);
|
||||||
|
await client.query(
|
||||||
|
`UPDATE bitacoras.hitos SET
|
||||||
|
titulo=$1, descripcion=$2, estado=$3, fecha=$4,
|
||||||
|
horas_presencial=$5, horas_remoto=$6, nodo_id=$7
|
||||||
|
WHERE id=$8`,
|
||||||
|
[h.titulo, h.desc, h.est, h.fec, h.h_p, h.h_r, nodo_id, exRes.rows[0].id]
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
console.log(`Inserting ${h.id_hito} (${h.titulo})...`);
|
||||||
|
await client.query(
|
||||||
|
`INSERT INTO bitacoras.hitos (
|
||||||
|
plan_id, id_hito, titulo, descripcion, estado, fecha,
|
||||||
|
horas_presencial, horas_remoto, nodo_id
|
||||||
|
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)`,
|
||||||
|
[plan_id, h.id_hito, h.titulo, h.desc, h.est, h.fec, h.h_p, h.h_r, nodo_id]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("\n✅ Done! Dashboard A04 (dtic-DASUTEN) actualizado con estructura de Ámbitos y Planes");
|
||||||
|
console.log(" - Ámbito: A04");
|
||||||
|
console.log(` - Planes: ${Object.keys(planes).length}`);
|
||||||
|
console.log(` - Hitos: ${hitos.length}`);
|
||||||
await client.end();
|
await client.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user