[P2606] WebServer NGINX: plan actualizado, ficha nodo, HTTPS operativo

- P2606: Plan v1.1 EN EJECUCIÓN. Fases 1-3 completadas.
- Ficha nodo srvv-nginx-rm.md. P2606 en adn/07_proyectos.md.
- Incluye cambios acumulados de sesiones anteriores.
This commit is contained in:
Ricardo Monla
2026-03-28 12:18:42 -03:00
parent 97d9b777b4
commit 160da47f96
78 changed files with 6461 additions and 624 deletions
+134 -32
View File
@@ -10,18 +10,22 @@ module ADN
modo: nil,
es_ia: false,
nodo: nil,
tema: nil
tema: nil,
plantilla: nil,
fecha: nil,
ambito: nil,
doc_path: nil
}
parser = OptionParser.new do |opt|
opt.banner = "Uso: adn db evento:crear [OPCIONES]"
opt.on("--inicio HH:MM", "Hora de inicio (requerido)") do |i|
opt.on("--inicio HH:MM[:SS]", "Hora de inicio (requerido)") do |i|
opts[:inicio] = i
end
opt.on("--descripcion TEXTO", "Descripción de la actividad (requerido)") do |d|
opts[:descripcion] = d
end
opt.on("--fin HH:MM", "Hora de fin (opcional)") do |f|
opt.on("--fin HH:MM[:SS]", "Hora de fin (opcional)") do |f|
opts[:fin] = f
end
opt.on("--estado ESTADO", "Estado (⏳, ✅, ❌, ⚠️, ⏸️)") do |e|
@@ -33,9 +37,21 @@ module ADN
opt.on("--nodo NOMBRE", "Nombre del nodo (servidor/VM)") do |n|
opts[:nodo] = n
end
opt.on("--fecha YYYY-MM-DD", "Fecha de la bitácora (default: hoy)") do |f|
opts[:fecha] = f
end
opt.on("--ambito NOMBRE_O_ID", "Ámbito del evento") do |a|
opts[:ambito] = a
end
opt.on("--doc RUTA", "Ruta al plan .md (ej: P2601_Dasuten/P2601.09_DASUTEN-sin-DC.md)") do |d|
opts[:doc_path] = d
end
opt.on("--ia", "Marcar como generado por IA") do
opts[:es_ia] = true
end
opt.on("--plantilla TIPO", "Usar plantilla (implementacion, investigacion, resolucion, documentacion, test, debug, planificacion)") do |p|
opts[:plantilla] = p
end
opt.on("-h", "--help", "Mostrar ayuda") do
puts opt
exit
@@ -51,12 +67,32 @@ module ADN
end
# Validaciones básicas
unless opts[:inicio] && opts[:descripcion]
puts "#{Color::RED}✗ Error: --inicio y --descripcion son requeridos#{Color::RESET}"
unless opts[:descripcion]
puts "#{Color::RED}✗ Error: --descripcion es requerido#{Color::RESET}"
puts parser
exit 1
end
# Si no se especifica --inicio, usar hora actual
opts[:inicio] ||= Time.now.strftime('%H:%M:%S')
puts "#{Color::DIM} Hora de inicio: #{opts[:inicio]}#{Color::RESET}"
# Si se specify plantilla, mostrar y prependear al texto
if opts[:plantilla]
require_relative '../../templates/plantillas_eventos'
if ADN::PlantillasEventos.existe?(opts[:plantilla])
plantilla = ADN::PlantillasEventos.obtener(opts[:plantilla])
puts "#{Color::CYAN}📋 Plantilla: #{opts[:plantilla]}#{Color::RESET}"
puts plantilla
puts ""
puts "#{Color::YELLOW}💡 Completa la plantilla y usa --descripcion con el resultado#{Color::RESET}"
else
puts "#{Color::RED}✗ Tipo de plantilla desconocido: #{opts[:plantilla]}#{Color::RESET}"
puts "#{Color::YELLOW}Disponibles: #{ADN::PlantillasEventos.lista_tipos.join(', ')}#{Color::RESET}"
exit 1
end
end
# Obtener modo desde jornada actual si no se especifica
modo_resuelto = opts[:modo]
if modo_resuelto.nil?
@@ -79,24 +115,44 @@ module ADN
end
end
# Buscar bitácora para hoy (o crearla)
fecha_hoy = Date.today.to_s
bitacora = db.find_bitacora_by_fecha(fecha_hoy)
# Resolver ámbito si se especificó
ambito_id = nil
if opts[:ambito]
ambito = db.get_ambito(opts[:ambito])
if ambito
ambito_id = ambito['id']
puts " #{Color::DIM}Ámbito encontrado: #{opts[:ambito]} (ID: #{ambito_id})#{Color::RESET}"
else
puts "#{Color::YELLOW}⚠ Ámbito '#{opts[:ambito]}' no encontrado#{Color::RESET}"
end
end
# Determinar fecha: --fecha o hoy
fecha_target = opts[:fecha] ? opts[:fecha] : Date.today.to_s
if opts[:fecha]
begin
Date.parse(opts[:fecha])
puts " #{Color::DIM} Fecha especificada: #{fecha_target}#{Color::RESET}"
rescue Date::Error
puts "#{Color::RED}✗ Formato de fecha inválido: #{opts[:fecha]}. Usar YYYY-MM-DD#{Color::RESET}"
exit 1
end
end
bitacora = db.find_bitacora_by_fecha(fecha_target)
if bitacora.nil?
puts " #{Color::DIM}Creando bitácora para hoy...#{Color::RESET}"
bitacora = db.create_bitacora(fecha: fecha_hoy)
puts " #{Color::DIM}Creando bitácora para #{fecha_target}...#{Color::RESET}"
bitacora = db.create_bitacora(fecha: fecha_target)
end
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}"
if bitacora && bitacora['modo']
modo_resuelto = bitacora['modo']
puts " #{Color::DIM} Modo resuelto desde jornada: #{modo_resuelto == 'P' ? 'Presencial' : (modo_resuelto == 'R' ? 'Remoto' : 'Servicio')}#{Color::RESET}"
else
modo_resuelto = 'P' # default
puts " #{Color::DIM} Sin jornada activa, usando default: Presencial#{Color::RESET}"
@@ -128,7 +184,20 @@ module ADN
tema_id: nil # Por ahora sin tema
)
# Asignar doc_path si se especificó
if opts[:doc_path] && entrada
db.update_entrada(entrada['id'], { doc_path: opts[:doc_path] })
puts " #{Color::DIM} Doc vinculado: #{opts[:doc_path]}#{Color::RESET}"
end
# Asignar ámbito si se especificó
if ambito_id && entrada
db.update_entrada(entrada['id'], { ambito_id: ambito_id })
puts " #{Color::DIM} Ámbito asignado (ID: #{ambito_id})#{Color::RESET}"
end
puts "#{Color::GREEN}✅ Entrada creada exitosamente#{Color::RESET}"
puts " #{Color::BOLD}Fecha:#{Color::RESET} #{fecha_target}"
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']}"
@@ -141,7 +210,7 @@ module ADN
def comando_evento_actualizar(args)
if args.length < 1 || args[0].start_with?('-')
puts "#{Color::YELLOW}Uso: adn db evento:actualizar <ID> [OPCIONES]#{Color::RESET}"
puts "Opciones soportadas: --fin \"HH:MM\", --inicio \"HH:MM\", --estado \"\", --descripcion \"Texto\", --nodo \"Nombre\""
puts "Opciones soportadas: --fin \"HH:MM[:SS]\", --inicio \"HH:MM[:SS]\", --estado \"\", --descripcion \"Texto\", --nodo \"Nombre\""
return
end
@@ -150,12 +219,14 @@ module ADN
parser = OptionParser.new do |opt|
opt.banner = "Opciones:"
opt.on("--inicio HH:MM", "Nueva hora de inicio") { |i| opts[:inicio] = i }
opt.on("--fin HH:MM", "Nueva hora de fin") { |f| opts[:fin] = f }
opt.on("--inicio HH:MM[:SS]", "Nueva hora de inicio") { |i| opts[:inicio] = i }
opt.on("--fin HH:MM[:SS]", "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("--ambito NOMBRE_O_ID", "Nuevo ámbito") { |a| opts[:ambito_raw] = a }
opt.on("--doc RUTA", "Ruta al plan .md vinculado") { |d| opts[:doc_path] = d }
opt.on("-h", "--help", "Mostrar ayuda") do
puts opt
exit
@@ -199,6 +270,20 @@ module ADN
opts.delete(:nodo_raw)
end
if opts.key?(:ambito_raw)
if opts[:ambito_raw].nil? || opts[:ambito_raw].empty?
opts[:ambito_id] = nil
else
ambito = db.get_ambito(opts[:ambito_raw])
if ambito
opts[:ambito_id] = ambito['id']
else
puts "#{Color::YELLOW}⚠ Ámbito '#{opts[:ambito_raw]}' no encontrado#{Color::RESET}"
end
end
opts.delete(:ambito_raw)
end
begin
res = db.update_entrada(id_evento, opts)
if res
@@ -232,6 +317,9 @@ module ADN
opt.on("--nodo NOMBRE", "Filtrar por nombre de nodo") do |n|
opts[:nodo] = n
end
opt.on("--ambito NOMBRE_O_ID", "Filtrar por ámbito") do |a|
opts[:ambito] = a
end
opt.on("--estado ESTADO", "Filtrar por estado (⏳, ✅, ❌, ⚠️, ⏸️)") do |e|
opts[:estado] = e
end
@@ -276,7 +364,20 @@ module ADN
end
end
# Obtener ID de ámbito si se especificó nombre
ambito_id = nil
if opts[:ambito]
ambito = db.get_ambito(opts[:ambito])
if ambito
ambito_id = ambito['id']
puts " #{Color::DIM}Filtrando por ámbito: #{opts[:ambito]} (ID: #{ambito_id})#{Color::RESET}"
else
puts "#{Color::YELLOW}⚠ Ámbito '#{opts[:ambito]}' no encontrado#{Color::RESET}"
end
end
entradas = db.list_entradas(
ambito_id: ambito_id,
nodo_id: nodo_id,
estado: opts[:estado],
buscar: opts[:buscar],
@@ -296,9 +397,9 @@ module ADN
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)'
inicio = e['inicio'] ? e['inicio'][0..7] : '--:--:--'
fin = e['fin'] ? e['fin'][0..7] : '--:--:--'
nodo = "#{e['ambito_nombre'] || '-'} / #{e['nodo_nombre'] || '-'}"
estado = e['estado']
desc = e['descripcion']
@@ -306,22 +407,23 @@ module ADN
puts " #{desc}"
end
else
# Formato tabla compacta (original)
# Formato tabla compacta (original ajustado)
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 "#{Color::BOLD}#{"ID".ljust(5)} #{"Inicio".ljust(9)} #{"Fin".ljust(9)} #{"Ámbito/Nodo".ljust(25)} #{"Est".ljust(3)} #{"Descripción".ljust(35)}#{Color::RESET}"
puts "#{"" * 5} #{"" * 9} #{"" * 9} #{"" * 25} #{"" * 3} #{"" * 35}"
entradas.each do |e|
id = e['id'].to_s
inicio = e['inicio'][0..7] # HH:MM:SS -> HH:MM
inicio = e['inicio'] ? e['inicio'][0..7] : '--:--'
fin = e['fin'] ? e['fin'][0..7] : '--:--'
nodo = e['nodo_nombre'] || '(sin nodo)'
nodo = nodo[0..13] + '...' if nodo.length > 15
nodo = "#{e['ambito_nombre'] || '-'} / #{e['nodo_nombre'] || '-'}"
nodo = nodo[0..23] + '...' if nodo.length > 25
estado = e['estado']
desc = e['descripcion']
desc = desc[0..37] + '...' if desc.length > 40
desc = e['descripcion'] || ''
desc = desc.split("\n").first || '' # Tomar solo la primera línea
desc = desc[0..32] + '...' if desc.length > 35
puts "#{id.ljust(5)} #{inicio.ljust(8)} #{fin.ljust(8)} #{nodo.ljust(15)} #{estado.ljust(3)} #{desc.ljust(40)}"
puts "#{id.ljust(5)} #{inicio.ljust(9)} #{fin.ljust(9)} #{nodo.ljust(25)} #{estado.ljust(3)} #{desc.ljust(35)}"
end
end
@@ -397,13 +499,13 @@ module ADN
entradas.each do |e|
id = e['id'].to_s
inicio = e['inicio'][0..4] # HH:MM:SS -> HH:MM
inicio = e['inicio'] ? e['inicio'][0..7] : '--:--:--' # HH:MM:SS
nodo = (e['nodo_nombre'] || '(sin nodo)')[0..14]
desc = e['descripcion']
desc = desc[0..47] + '...' if desc.length > 50
estado_icon = e['estado']
puts " #{estado_icon} #{Color::YELLOW}ID #{id.ljust(5)}#{Color::RESET} #{inicio.ljust(5)} #{nodo.ljust(15)} #{desc}"
puts " #{estado_icon} #{Color::YELLOW}ID #{id.ljust(5)}#{Color::RESET} #{inicio.ljust(11)} #{nodo.ljust(15)} #{desc}"
end
end