Skip to content

Panel web, asistente de primer arranque y binarios descargables - #6

Merged
aprendomx merged 4 commits into
mainfrom
feat/fase-4-api-http
Sep 3, 2026
Merged

Panel web, asistente de primer arranque y binarios descargables#6
aprendomx merged 4 commits into
mainfrom
feat/fase-4-api-http

Conversation

@aprendomx

Copy link
Copy Markdown
Owner

Cierra el tramo que va desde la API hasta algo que otra persona puede descargar y usar.
CI verde en los tres jobs sobre el commit final.

Qué trae

  • Panel web (Vue 3 + Quasar sobre Vite), servido desde dentro del binario por
    go:embed. La lista de canales es una rejilla de tarjetas que se adapta al ancho.
  • Asistente de primer arranque. Desde la propia máquina no pide nada; desde fuera
    exige un código que el binario imprime al arrancar. Es el riesgo por el que en la fase 4
    se descartó el setup por interfaz, resuelto sin volver a abrirlo.
  • Créditos y licencias en el panel, leídas de los paquetes: go-rtmp resultó ser
    Boost Software License y coder/websocket ISC.
  • Manual de instalación en el README y manual de usuario aparte, con lo que solo
    se aprende usando esto contra plataformas reales.
  • Release automática para cinco plataformas al empujar una etiqueta v*.

Verificación

Las cinco combinaciones de compilación cruzada probadas de verdad. El flujo del asistente
probado de punta a punta contra una instalación nueva. El ciclo en caliente —alta, apagado,
encendido y cambio de clave— verificado con ffprobe sobre el vídeo que llega al destino,
no por contadores.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Q3gNCRtNfVtrqyTptn6Ssj

jadrians and others added 4 commits September 3, 2026 14:48
En un monitor ancho, una tarjeta por fila dejaba medio panel vacío y obligaba a
hacer scroll para ver tres canales. Con auto-fill y un mínimo de 320 px sale una
columna en el móvil y las que quepan en el escritorio, sin puntos de ruptura a
mano.

La tarjeta se reorganiza para funcionar como pieza autocontenida: identidad y
estado arriba, que es lo que se lee de un vistazo, y el detalle técnico al pie en
gris, que importa solo cuando algo falla. El asa de arrastre entra dentro de la
tarjeta.

Tres arreglos que salieron de mirarlo funcionando:

- Al recargar la página, el WebSocket no se conectaba: solo lo hacía entrar(), y
  con la cookie válida se entra por cargar(). El panel se quedaba con la foto del
  GET inicial y no volvía a actualizarse.
- La lista de arrastre era un computed cuyo getter devolvía un array nuevo en
  cada evaluación; con v-model sobre vuedraggable eso se realimenta. Ahora es un
  ref sincronizado por watch, que además ignora el estado que empuja el
  WebSocket mientras se arrastra, para que la lista no salte bajo el dedo.
- El fallback del panel devolvía el index para CUALQUIER ruta, incluido
  /favicon.ico: HTML donde el navegador espera otra cosa. Ahora una ruta con
  extensión que no existe da 404, y solo las rutas sin extensión caen al index.

La tarjeta de ingesta también acota su ancho: el botón de copiar estaba al otro
extremo de la pantalla en un monitor grande.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q3gNCRtNfVtrqyTptn6Ssj
Cubre los dos casos que el usuario planteó, pero sin preguntar: el servidor ya
sabe desde dónde se abre el panel.

Desde la propia máquina (127.0.0.1) el asistente no pide nada: quien está en el
teclado ya controla el equipo, y exigirle un código sería fricción sin ganancia.
Es el caso del PC de escritorio, que será la mayoría.

Desde fuera —un VPS con el puerto abierto, o el móvil en la red de casa— pide un
código de un solo uso que el binario imprime al arrancar sin configurar. Sin él,
el primero que cargue la página se queda con el servicio: es exactamente el
riesgo por el que en la fase 4 se descartó el setup por interfaz y se eligió
-setpassword.

Preguntar "¿estás en un PC?" habría sido peor: es una pregunta que la gente
responde mal y que un atacante responde que sí.

El endpoint deja de existir en cuanto hay contraseña, ni siquiera desde la propia
máquina, y va con el mismo limitador que el login porque doce caracteres se
prueban a fuerza bruta. El código se compara en tiempo constante y su error no
distingue "casi" de "nada".

El asistente avisa, como se pidió, cuando el panel es accesible desde la red:
esa contraseña es lo único que separa a cualquiera de las claves de
retransmisión.

Probado de punta a punta contra una instalación nueva: código impreso, setup sin
código desde local, el estado cambia, y el login funciona con la contraseña
elegida.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q3gNCRtNfVtrqyTptn6Ssj
El test prohibía la palabra "contraseña" en la salida de arranque, y el aviso del
primer arranque dice legítimamente "elige tu contraseña". Confundía nombrar un
concepto con filtrar un secreto: lo que hay que vigilar son las claves, que ya se
comprueban aparte.

A cambio se añade lo que sí importa: que el aviso y su código aparezcan solo
mientras no haya contraseña. Seguir imprimiéndolo en cada reinicio de un servicio
ya configurado lo dejaría en el journal para siempre sin ninguna razón.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q3gNCRtNfVtrqyTptn6Ssj
…or plataforma

Créditos y licencias en el panel, con enlace al proyecto. Las licencias están
leídas de los propios paquetes, no supuestas: go-rtmp resultó ser Boost Software
License y no MIT, y coder/websocket es ISC. Cada dependencia del motor dice
además para qué está ahí, que es lo que un lector querría saber.

Manual de instalación en el README, escrito para alguien que descarga un binario
y no ha compilado nada en su vida: incluye la cuarentena de macOS, el aviso de
SmartScreen en Windows, y una unidad de systemd que deja la clave maestra fuera
del archivo de la unidad, porque lo que se escribe ahí lo lee cualquiera con
`systemctl cat`.

Manual de usuario aparte, con lo que solo se aprende usando esto contra
plataformas reales: el intervalo de fotogramas clave que YouTube exige y que OBS
no pone en modo Simple, el techo de 6 Mbps de Twitch, el límite de emisiones
activas de Facebook —y qué hacer cuando se agota—, y que TikTok da un servidor
distinto en cada emisión.

Release automática al empujar una etiqueta: cinco plataformas, con checksums. La
compilación cruzada solo es posible porque no hay cgo; con el SQLite de C haría
falta un toolchain por plataforma y esta matriz no existiría. El workflow
comprueba que el panel viaja DENTRO de cada binario, porque uno sin panel arranca
igual y el fallo no se vería hasta abrir la página.

Las cinco combinaciones verificadas compilando de verdad, no por suposición.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q3gNCRtNfVtrqyTptn6Ssj
@aprendomx
aprendomx merged commit 8982253 into main Sep 3, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants