Files
Carlos Sandoval 55eff5df89 feat: agregar auto update
spec: separar responsabilidades
feat: agregra pipeline de construccion en gitea
2026-09-02 20:01:35 +00:00

4.2 KiB

Design: split-main-into-files

Context

El proyecto outline-mcp vive íntegramente en main.go (425 líneas, paquete main), según la decisión D2 del change create-outline-mcp-server, que explícitamente anticipaba la extracción a múltiples archivos como refactor futuro. El archivo mezcla tres dominios independientes (cliente HTTP de Outline, handlers de tools MCP, auto-update vía Gitea). No hay tests aún; la verificación actual es go build, golangci-lint run y prueba manual por stdio.

Goals / Non-Goals

Goals:

  • Repartir main.go en archivos por responsabilidad dentro del mismo paquete main, sin ningún cambio de comportamiento.
  • Dejar el código preparado para añadir tests y nuevas tools sin fricción.
  • Cumplir la promesa de D2: extracción sin impacto en specs de comportamiento ni en el pipeline de release.

Non-Goals:

  • Introducir paquetes internal/ (descartado: no hay necesidad de ocultar API entre dominios con el alcance actual).
  • Añadir tests (cambio posterior; solo se deja el terreno listo).
  • Renombrar o refactorizar funciones, tipos o lógica.
  • Modificar go.mod, dependencias, pipeline de release o contrato de nombres de assets.

Decisions

D1: Múltiples archivos en paquete main (opción B) frente a internal/ (opción C)

  • Elección: dividir en archivos del mismo paquete main. Estructura resultante:
    • main.go — función main(), variables de build (Version, GiteaURL, RepoOwner, RepoName) y registro de tools.
    • client.go — tipo OutlineClient, newOutlineClient, método post.
    • tools.go — los cuatro handlers de tools MCP.
    • updater.go — giteaRelease, parseVersion, versionNewer, doUpdate.
  • Alternativa (internal/outline, internal/tools, internal/selfupdate): descartada porque obliga a decidir superficie exportada acoplando los handlers al SDK (mcp.CallToolResult en firmas) y no aporta ocultación real con el alcance actual. Queda como refactor futuro si el número de tools crece de forma significativa.
  • Alternativa (mantener un solo archivo): descartada; el argumento de bootstrap de D2 ya se cumplió y la mezcla de dominios penaliza la legibilidad y los futuros diffs.

D2 (revisión): se actualiza la decisión del change create-outline-mcp-server

La D2 original ("todo el código en main.go") queda sustituida por esta organización multi-archivo en paquete único. El carácter de monolito deliberado (un único binario, un único paquete) se mantiene; lo que cambia es la distribución física en archivos.

D3: Movimiento mecánico de código, sin reescritura

Las funciones y tipos se trasladan íntegras (mismos nombres, firmas, comentarios y directivas //nolint). Solo se ajustan los bloques import de cada archivo nuevo. Esto minimiza el riesgo del refactor y hace el diff auditable como puro movimiento.

D4: Las variables de build permanecen en main.go

Version, GiteaURL, RepoOwner y RepoName se inyectan con -ldflags -X main.Version=... y el paquete sigue siendo main, por lo que no hay razón para moverlas. Permanecen junto al entrypoint, que es su punto natural de referencia.

Risks / Trade-offs

  • [División incorrecta de imports causa fallo de compilación] → Verificación inmediata con go build ./... en el contenedor tras cada movimiento; es un error de compilación, no un error silencioso.
  • [golangci-lint señala imports sin usar o duplicados] → Ejecutar golangci-lint run en el contenedor como parte de la verificación.
  • [Confusión temporal por familiaridad con el archivo único] → El diff es puro movimiento de código; los nombres de archivo (client.go, tools.go, updater.go) se corresponden directamente con los dominios.
  • [Regresión funcional no detectada por compilación] → Prueba manual por stdio del servidor MCP (handshake + tools/list) tras el refactor, igual que en el change original.

Migration Plan

  1. Crear los tres archivos nuevos moviendo bloques completos desde main.go.
  2. Reducir main.go a entrypoint + variables de build + registro de tools.
  3. Compilar, lintear y probar por stdio en el contenedor DevPod.
  4. Rollback trivial: git revert del commit único del refactor.

Open Questions

(ninguna)