[RFC-ADN-01] Normalizar nomenclatura de proyectos
- Directorios: PascalCase (p2601_dasuten → P2601_Dasuten) - Planes: numeración pura (P2601_6.1.A → P2601.06.01) - Sin caracteres especiales en nombres de archivo - 07_proyectos.md: convención RFC-ADN-01 integrada, P2604/P2605 agregados - evento:listar: nueva opción --detalle para descripciones completas
This commit is contained in:
+53
-10
@@ -10,13 +10,54 @@ Un **Proyecto** es un esfuerzo coordinado que agrupa múltiples tareas, nodos y
|
||||
- Un **Nodo** (infraestructura estática, snapshot),
|
||||
- Una **Bitácora** (registro diario, efímero),
|
||||
|
||||
Un Proyecto tiene **alcance temporal definido** y **visibilidad gerárquica**: las partes jerárquicas (superiores, coordinadores) pueden consultar su avance de forma asíncrona, típicamente a través de un dashboard web.
|
||||
Un Proyecto tiene **alcance temporal definido** y **visibilidad jerárquica**: las partes jerárquicas (superiores, coordinadores) pueden consultar su avance de forma asíncrona, típicamente a través de un dashboard web.
|
||||
|
||||
## 2. Identificación
|
||||
## 2. Identificación (RFC-ADN-01)
|
||||
|
||||
- **Código**: Alfanumérico con prefijo `P` (ej: `P2601`).
|
||||
- **Ubicación**: `proyectos/<código>_<nombre>.md` (ej: `proyectos/P2601_dasuten.md`).
|
||||
- **Referencia en Bitácoras**: Los hitos que pertenecen a un proyecto deben referenciar su código en la descripción.
|
||||
### Código de Proyecto
|
||||
|
||||
```
|
||||
PYYNN_Tema
|
||||
```
|
||||
|
||||
| Elemento | Significado | Ejemplo |
|
||||
| :------- | :---------- | :------ |
|
||||
| `P` | Prefijo fijo | `P` |
|
||||
| `YY` | Año de creación (2 dígitos) | `26` |
|
||||
| `NN` | Número correlativo | `01` |
|
||||
| `Tema` | Nombre corto (PascalCase) | `Dasuten` |
|
||||
|
||||
**Ejemplo:** `P2601_Dasuten` → Proyecto 01, año 2026, tema Dasuten.
|
||||
|
||||
### Secciones y Sub-secciones
|
||||
|
||||
```
|
||||
PYYNN.SS.ss_Tema.md
|
||||
```
|
||||
|
||||
| Elemento | Significado | Ejemplo |
|
||||
| :------- | :---------- | :------ |
|
||||
| `PYYNN` | ID del proyecto | `P2601` |
|
||||
| `SS` | Sección (2 dígitos) | `06` |
|
||||
| `ss` | Subsección (2 dígitos) | `01` |
|
||||
| `Tema` | Nombre corto (guiones) | `Red-SrvDasu` |
|
||||
|
||||
**Ejemplo:** `P2601.06.01_Red-SrvDasu.md` → P2601, sección 06, sub 01, tema Red del servidor Dasu.
|
||||
|
||||
### Directorio del Proyecto
|
||||
|
||||
```
|
||||
docs/proy/PYYNN_Tema/
|
||||
├── README.md ← Manifiesto (o PYYNN_Tema.md)
|
||||
├── plan/ ← Planes de ejecución
|
||||
│ └── PYYNN.SS.ss_Tema.md
|
||||
└── _hist/ ← Archivo histórico
|
||||
```
|
||||
|
||||
**Reglas de nomenclatura:**
|
||||
- Directorios: `PascalCase` con guión bajo (`P2601_Dasuten`)
|
||||
- Archivos de plan: Numeración pura, guiones en tema (`P2601.06.01_Red-SrvDasu.md`)
|
||||
- Sin caracteres especiales (`:`, espacios) en nombres de archivo
|
||||
|
||||
## 3. Formato de Manifiesto
|
||||
|
||||
@@ -30,8 +71,8 @@ Cada proyecto debe tener un archivo manifiesto con las siguientes secciones:
|
||||
| **Nombre** | Nombre descriptivo del proyecto. |
|
||||
| **Objetivo** | Para qué existe, qué problema resuelve. |
|
||||
| **Stakeholders** | Quién consulta/supervisa el avance (cargo, relación). |
|
||||
| **Topología y Red** | Contexto espacial: subredes en uso, hypervisors anfitriones, aislamiento NAT y reglas de ruteo/VPN necesarias para acceder al entorno. |
|
||||
| **Nodos Involucrados** | Qué infraestructura participa (links a `nodos/`). Debe categorizarse en **Nodos Exclusivos** (Core) y **Nodos de Soporte/Infraestructura**. |
|
||||
| **Topología y Red** | Contexto espacial: subredes, hypervisors, aislamiento NAT y reglas de ruteo/VPN. |
|
||||
| **Nodos Involucrados** | Qué infraestructura participa (links a `nodos/`). Categorizar en **Core** y **Soporte**. |
|
||||
| **Herramientas** | Software, scripts y servicios utilizados. |
|
||||
| **Hitos Clave** | Timeline de alto nivel con estados y fechas. |
|
||||
| **Referencias** | Links a bitácoras, nodos, documentos técnicos. |
|
||||
@@ -64,6 +105,8 @@ Los proyectos son el **tejido conectivo** que une nodos y bitácoras en un prop
|
||||
|
||||
| Código | Nombre | Estado | Manifiesto |
|
||||
| :--- | :--- | :---: | :--- |
|
||||
| P2601 | Sistema DASUTEN | ⏳ | [P2601_dasuten.md](../proyectos/P2601_dasuten.md) |
|
||||
| P2602 | Backups DTIC | ⏳ | [P2602_backups.md](../proyectos/P2602_backups.md) |
|
||||
| P2603 | Sistema de Bitácoras | ⏳ | [P2603_bitacoras.md](../proyectos/P2603_bitacoras.md) |
|
||||
| P2601 | Sistema DASUTEN | ⏳ | [P2601_Dasuten](../docs/proy/P2601_Dasuten/P2601_dasuten.md) |
|
||||
| P2602 | Backups DTIC | ⏳ | [P2602_Backups](../docs/proy/P2602_Backups/P2602_backups.md) |
|
||||
| P2603 | Sistema de Bitácoras | ⏳ | [P2603_Bitacoras](../docs/proy/P2603_Bitacoras/P2603_bitacoras.md) |
|
||||
| P2604 | Mejoras ADN | ⏳ | [P2604_Mejoras-ADN](../docs/proy/P2604_Mejoras-ADN/P2604_mejoras_ADN.md) |
|
||||
| P2605 | Bitácoras Web | ⏳ | [P2605_Bitacoras-Web](../docs/proy/P2605_Bitacoras-Web/P2605_Migracion_Solo_Bitacoras_Web.md) |
|
||||
|
||||
+17
-11
@@ -47,11 +47,11 @@
|
||||
|
||||
### Flujo de Trabajo DB-First
|
||||
1. **Iniciar jornada**: `./adn/tools/run jornada iniciar [modo] [HH:MM]` (registra en DB)
|
||||
2. **Registrar actividad**: `./adn/tools/run db evento:crear [opciones]` (crea entrada en DB)
|
||||
2. **Registrar actividad**: `./adn/tools/run db evento:crear [opciones]` (estado y modo se calculan automáticamente)
|
||||
3. **Desarrollar componente Ruby**: Seguir principios "Menos es Más" (atómico, reutilizable)
|
||||
4. **Operaciones DB**: Usar `./adn/tools/run db` para todas las operaciones (listar, actualizar, eliminar)
|
||||
5. **Registrar finalización**: `./adn/tools/run db evento:actualizar <ID> --fin HH:MM --estado completado`
|
||||
6. **Verificar en Web**: Acceder a `http://localhost:5174` para visualizar bitácora actualizada
|
||||
5. **Registrar finalización**: `./adn/tools/run db evento:actualizar <ID> --fin HH:MM` (estado se calcula automáticamente)
|
||||
6. **Verificar en Web**: Acceder a `http://localhost:5174` - La bitácora se actualiza automáticamente cada 30s o al recuperar el foco
|
||||
7. **Resguardar cambios**: Commit y push con formato `[Categoría] Descripción`
|
||||
|
||||
### Subcomandos DB Disponibles
|
||||
@@ -60,9 +60,12 @@
|
||||
./adn/tools/run db salud:bd
|
||||
|
||||
# Gestión de eventos (entradas cronológicas)
|
||||
./adn/tools/run db evento:crear --nodo <nombre> --titulo "Título" --inicio HH:MM
|
||||
# Estado y modo se calculan automáticamente:
|
||||
# - Estado: si tiene --fin → ✅, si no → ⏳
|
||||
# - Modo: si no se especifica, se obtiene desde la última jornada del día
|
||||
./adn/tools/run db evento:crear --nodo <nombre> --descripcion "Texto" --inicio HH:MM [--fin HH:MM] [--modo P|R]
|
||||
./adn/tools/run db evento:listar [--desde FECHA] [--hasta FECHA] [--nodo NODO]
|
||||
./adn/tools/run db evento:actualizar <ID> [--fin HH:MM] [--estado ESTADO]
|
||||
./adn/tools/run db evento:actualizar <ID> [--fin HH:MM] # Estado se calcula automáticamente
|
||||
./adn/tools/run db evento:eliminar <ID>
|
||||
|
||||
# Gestión de bitácoras
|
||||
@@ -166,9 +169,9 @@ referencia canónica y exclusiva de las directivas que un agente IA debe seguir.
|
||||
| `db salud:bd` | Verificar conexión y estado de PostgreSQL | DB-First |
|
||||
| `db bitacora:crear` | Crear nueva bitácora diaria en DB | DB-First |
|
||||
| `db bitacora:listar` | Listar bitácoras existentes desde DB | DB-First |
|
||||
| `db evento:crear` | Crear nueva entrada cronológica (I-F-D-E) | DB-First |
|
||||
| `db evento:crear` | Crear entrada (estado y modo se calculan auto.) | DB-First |
|
||||
| `db evento:listar` | Listar entradas con filtros desde DB | DB-First |
|
||||
| `db evento:actualizar` | Actualizar una entrada existente en DB | DB-First |
|
||||
| `db evento:actualizar` | Actualizar entrada (estado auto. si --fin) | DB-First |
|
||||
| `db evento:eliminar` | Eliminar una entrada existente por ID de DB | DB-First |
|
||||
| `db nodo:crear` | Crear nuevo nodo en DB | DB-First |
|
||||
| `db nodo:listar` | Listar nodos desde DB | DB-First |
|
||||
@@ -184,14 +187,17 @@ referencia canónica y exclusiva de las directivas que un agente IA debe seguir.
|
||||
# 1. INICIO DE JORNADA (registra en DB)
|
||||
./adn/tools/run jornada iniciar presencial 08:00
|
||||
|
||||
# 2. REGISTRAR ACTIVIDAD DE DESARROLLO RUBY (DB-First)
|
||||
./adn/tools/run db evento:crear --nodo srv-ns8 --titulo "Desarrollo componente Ruby: hook pre-commit mejorado" --inicio 09:00 --descripcion "Mejora del hook pre-commit para mayor robustez y aplicación de principios ADN"
|
||||
# 2. REGISTRAR ACTIVIDAD (estado y modo se calculan automáticamente)
|
||||
./adn/tools/run db evento:crear --nodo srv-ns8 --descripcion "Mejora del hook pre-commit" --inicio 09:00
|
||||
|
||||
# 2a. Con hora de fin (estado será ✅ automáticamente)
|
||||
./adn/tools/run db evento:crear --nodo srv-ns8 --descripcion "Tarea completada" --inicio 09:00 --fin 10:00
|
||||
|
||||
# 3. LISTAR ACTIVIDADES DEL DÍA (consulta DB)
|
||||
./adn/tools/run db evento:listar --desde $(date +%Y-%m-%d)
|
||||
|
||||
# 4. ACTUALIZAR ENTRADA AL FINALIZAR (DB-First)
|
||||
./adn/tools/run db evento:actualizar <ID> --fin 12:30 --estado completado
|
||||
# 4. ACTUALIZAR ENTRADA AL FINALIZAR (estado se calcula desde --fin)
|
||||
./adn/tools/run db evento:actualizar <ID> --fin 12:30
|
||||
|
||||
# 5. CERRAR JORNADA (registra en DB)
|
||||
./adn/tools/run jornada cerrar remoto 18:00
|
||||
|
||||
+79
-24
@@ -57,6 +57,12 @@ module ADN
|
||||
exit 1
|
||||
end
|
||||
|
||||
# Obtener modo desde jornada actual si no se especifica
|
||||
modo_resuelto = opts[:modo]
|
||||
if modo_resuelto.nil?
|
||||
puts "#{Color::DIM}ℹ Modo no especificado, buscando jornada actual...#{Color::RESET}"
|
||||
end
|
||||
|
||||
puts "#{Color::CYAN}📝 Creando nueva entrada...#{Color::RESET}"
|
||||
|
||||
BitacorasDB::BitacoraDB.with_connection do |db|
|
||||
@@ -84,13 +90,38 @@ module ADN
|
||||
|
||||
bitacora_id = bitacora['id']
|
||||
|
||||
# Obtener modo desde jornada actual si no se especificó
|
||||
if modo_resuelto.nil?
|
||||
entradas = db.list_entradas(bitacora_id: bitacora_id, limit: 10)
|
||||
jornada = entradas.find { |e| e['descripcion']&.downcase&.include?('inicio de jornada') }
|
||||
if jornada && jornada['modo']
|
||||
modo_resuelto = jornada['modo']
|
||||
puts " #{Color::DIM}ℹ Modo resuelto desde jornada: #{modo_resuelto == 'P' ? 'Presencial' : 'Remoto'}#{Color::RESET}"
|
||||
else
|
||||
modo_resuelto = 'P' # default
|
||||
puts " #{Color::DIM}ℹ Sin jornada activa, usando default: Presencial#{Color::RESET}"
|
||||
end
|
||||
end
|
||||
|
||||
# Calcular estado automáticamente desde hora_fin
|
||||
estado_resuelto = opts[:estado]
|
||||
if estado_resuelto.nil?
|
||||
if opts[:fin]
|
||||
estado_resuelto = '✅'
|
||||
puts " #{Color::DIM}ℹ Estado calculado: ✅ (tiene hora de fin)#{Color::RESET}"
|
||||
else
|
||||
estado_resuelto = '⏳'
|
||||
puts " #{Color::DIM}ℹ Estado calculado: ⏳ (sin hora de fin)#{Color::RESET}"
|
||||
end
|
||||
end
|
||||
|
||||
# Crear la entrada
|
||||
entrada = db.create_entrada(
|
||||
inicio: opts[:inicio],
|
||||
descripcion: opts[:descripcion],
|
||||
fin: opts[:fin],
|
||||
estado: opts[:estado],
|
||||
modo: opts[:modo],
|
||||
estado: estado_resuelto,
|
||||
modo: modo_resuelto,
|
||||
es_ia: opts[:es_ia],
|
||||
bitacora_id: bitacora_id,
|
||||
nodo_id: nodo_id,
|
||||
@@ -98,15 +129,9 @@ module ADN
|
||||
)
|
||||
|
||||
puts "#{Color::GREEN}✅ Entrada creada exitosamente#{Color::RESET}"
|
||||
puts ""
|
||||
puts " #{Color::BOLD}ID:#{Color::RESET} #{entrada['id']}"
|
||||
puts " #{Color::BOLD}Inicio:#{Color::RESET} #{entrada['inicio']}"
|
||||
puts " #{Color::BOLD}Fin:#{Color::RESET} #{entrada['fin'] || '(sin fin)'}"
|
||||
puts " #{Color::BOLD}Descripción:#{Color::RESET} #{entrada['descripcion']}"
|
||||
puts " #{Color::BOLD}Estado:#{Color::RESET} #{entrada['estado']}"
|
||||
puts " #{Color::BOLD}Modo:#{Color::RESET} #{entrada['modo'] == 'P' ? 'Presencial' : 'Remoto'}"
|
||||
puts " #{Color::BOLD}IA:#{Color::RESET} #{entrada['es_ia'] ? 'Sí' : 'No'}"
|
||||
puts " #{Color::BOLD}Bitácora:#{Color::RESET} #{fecha_hoy} (ID: #{bitacora_id})"
|
||||
puts " 📝 #{Color::BOLD}Descripción:#{Color::RESET} #{entrada['descripcion']}"
|
||||
|
||||
mostrar_pendientes(db)
|
||||
end
|
||||
@@ -129,6 +154,7 @@ module ADN
|
||||
opt.on("--fin HH:MM", "Nueva hora de fin") { |f| opts[:fin] = f }
|
||||
opt.on("--descripcion TEXTO", "Nueva descripción") { |d| opts[:descripcion] = d }
|
||||
opt.on("--estado ESTADO", "Nuevo estado (⏳, ✅, ❌, ⚠️, ⏸️)") { |e| opts[:estado] = e }
|
||||
opt.on("--modo MODO", "Modo (P=Presencial, R=Remoto)") { |m| opts[:modo] = m }
|
||||
opt.on("--nodo NOMBRE", "Nuevo nodo") { |n| opts[:nodo_raw] = n }
|
||||
opt.on("-h", "--help", "Mostrar ayuda") do
|
||||
puts opt
|
||||
@@ -144,13 +170,21 @@ module ADN
|
||||
end
|
||||
|
||||
if opts.empty?
|
||||
puts "#{Color::YELLOW}⚠ No se especificó nada para actualizar. Use --fin, --inicio, --descripcion, --estado o --nodo#{Color::RESET}"
|
||||
puts "#{Color::YELLOW}⚠ No se especificó nada para actualizar. Use --fin, --inicio, --descripcion, --estado, --modo o --nodo#{Color::RESET}"
|
||||
return
|
||||
end
|
||||
|
||||
puts "#{Color::CYAN}🔄 Actualizando evento #{id_evento}...#{Color::RESET}"
|
||||
|
||||
BitacorasDB::BitacoraDB.with_connection do |db|
|
||||
# Calcular estado automáticamente si se proporciona --fin (sin verificar entrada actual)
|
||||
if opts.key?(:fin) && !opts.key?(:estado)
|
||||
if opts[:fin] && !opts[:fin].empty?
|
||||
opts[:estado] = '✅'
|
||||
puts " #{Color::DIM}ℹ Estado calculado automáticamente: ✅ (hora de fin agregada)#{Color::RESET}"
|
||||
end
|
||||
end
|
||||
|
||||
if opts.key?(:nodo_raw)
|
||||
if opts[:nodo_raw].nil? || opts[:nodo_raw].empty?
|
||||
opts[:nodo_id] = nil
|
||||
@@ -171,6 +205,7 @@ module ADN
|
||||
puts "#{Color::GREEN}✅ Evento #{id_evento} actualizado exitosamente.#{Color::RESET}"
|
||||
puts " #{Color::BOLD}Inicio:#{Color::RESET} #{res['inicio']}"
|
||||
puts " #{Color::BOLD}Fin:#{Color::RESET} #{res['fin'] || '(sin fin)'}"
|
||||
puts " 📝 #{Color::BOLD}Descripción:#{Color::RESET} #{res['descripcion']}"
|
||||
else
|
||||
puts "#{Color::YELLOW}⚠ No se pudo actualizar el evento. ¿Existe el ID #{id_evento}?#{Color::RESET}"
|
||||
end
|
||||
@@ -184,7 +219,7 @@ module ADN
|
||||
|
||||
# Comando: evento:listar [OPCIONES] - Listar entradas con filtros
|
||||
def comando_evento_listar(args)
|
||||
opts = { limit: 20, offset: 0, nodo: nil, estado: nil, buscar: nil, desde: nil, hasta: nil }
|
||||
opts = { limit: 20, offset: 0, nodo: nil, estado: nil, buscar: nil, desde: nil, hasta: nil, detalle: false }
|
||||
|
||||
parser = OptionParser.new do |opt|
|
||||
opt.banner = "Uso: adn db evento:listar [OPCIONES]"
|
||||
@@ -209,6 +244,9 @@ module ADN
|
||||
opt.on("--hasta FECHA", "Filtrar hasta fecha (YYYY-MM-DD)") do |h|
|
||||
opts[:hasta] = h
|
||||
end
|
||||
opt.on("--detalle", "Mostrar descripciones completas (formato vertical)") do
|
||||
opts[:detalle] = true
|
||||
end
|
||||
opt.on("-h", "--help", "Mostrar ayuda") do
|
||||
puts opt
|
||||
exit
|
||||
@@ -253,21 +291,38 @@ module ADN
|
||||
return
|
||||
end
|
||||
|
||||
puts ""
|
||||
puts "#{Color::BOLD}#{"ID".ljust(5)} #{"Inicio".ljust(8)} #{"Fin".ljust(8)} #{"Nodo".ljust(15)} #{"Estado".ljust(3)} #{"Descripción".ljust(40)}#{Color::RESET}"
|
||||
puts "#{"─" * 5} #{"─" * 8} #{"─" * 8} #{"─" * 15} #{"─" * 3} #{"─" * 40}"
|
||||
if opts[:detalle]
|
||||
# Formato vertical con descripciones completas
|
||||
entradas.each_with_index do |e, i|
|
||||
puts "#{Color::DIM}#{"─" * 60}#{Color::RESET}" if i > 0
|
||||
id = e['id'].to_s
|
||||
inicio = e['inicio'][0..7]
|
||||
fin = e['fin'] ? e['fin'][0..7] : '--:--'
|
||||
nodo = e['nodo_nombre'] || '(sin nodo)'
|
||||
estado = e['estado']
|
||||
desc = e['descripcion']
|
||||
|
||||
entradas.each do |e|
|
||||
id = e['id'].to_s
|
||||
inicio = e['inicio'][0..7] # HH:MM:SS -> HH:MM
|
||||
fin = e['fin'] ? e['fin'][0..7] : '--:--'
|
||||
nodo = e['nodo_nombre'] || '(sin nodo)'
|
||||
nodo = nodo[0..13] + '...' if nodo.length > 15
|
||||
estado = e['estado']
|
||||
desc = e['descripcion']
|
||||
desc = desc[0..37] + '...' if desc.length > 40
|
||||
puts "#{estado} #{Color::BOLD}##{id}#{Color::RESET} | #{inicio} → #{fin} | #{Color::CYAN}#{nodo}#{Color::RESET}"
|
||||
puts " #{desc}"
|
||||
end
|
||||
else
|
||||
# Formato tabla compacta (original)
|
||||
puts ""
|
||||
puts "#{Color::BOLD}#{"ID".ljust(5)} #{"Inicio".ljust(8)} #{"Fin".ljust(8)} #{"Nodo".ljust(15)} #{"Estado".ljust(3)} #{"Descripción".ljust(40)}#{Color::RESET}"
|
||||
puts "#{"─" * 5} #{"─" * 8} #{"─" * 8} #{"─" * 15} #{"─" * 3} #{"─" * 40}"
|
||||
|
||||
puts "#{id.ljust(5)} #{inicio.ljust(8)} #{fin.ljust(8)} #{nodo.ljust(15)} #{estado.ljust(3)} #{desc.ljust(40)}"
|
||||
entradas.each do |e|
|
||||
id = e['id'].to_s
|
||||
inicio = e['inicio'][0..7] # HH:MM:SS -> HH:MM
|
||||
fin = e['fin'] ? e['fin'][0..7] : '--:--'
|
||||
nodo = e['nodo_nombre'] || '(sin nodo)'
|
||||
nodo = nodo[0..13] + '...' if nodo.length > 15
|
||||
estado = e['estado']
|
||||
desc = e['descripcion']
|
||||
desc = desc[0..37] + '...' if desc.length > 40
|
||||
|
||||
puts "#{id.ljust(5)} #{inicio.ljust(8)} #{fin.ljust(8)} #{nodo.ljust(15)} #{estado.ljust(3)} #{desc.ljust(40)}"
|
||||
end
|
||||
end
|
||||
|
||||
puts ""
|
||||
|
||||
@@ -1 +1 @@
|
||||
1773604966
|
||||
1773667642
|
||||
Reference in New Issue
Block a user