feat: add architectural documentation for refactor; include audit, migration plan, rules, target architecture, and session handoff

This commit is contained in:
2026-05-23 20:48:31 +02:00
parent 8c270feb5b
commit 225b2b36a2
5 changed files with 665 additions and 0 deletions
+108
View File
@@ -0,0 +1,108 @@
# Architecture Audit
Este documento resume el estado arquitectónico actual de Scoreko y debe usarse como referencia para el refactor. No redefine la arquitectura objetivo; documenta el diagnóstico existente y los riesgos detectados.
## Estado Actual
La repo es un bundle NodeCG con Vite, Vue 3, Quasar, Pinia y `vite-plugin-nodecg`.
| Área | Ruta | Responsabilidad actual |
| --- | --- | --- |
| Extension | `src/extension` | Lógica server NodeCG, OAuth, brackets y pack manager. |
| Dashboard | `src/dashboard/scoreko-dev` | App Quasar/Pinia para control. |
| Graphics | `src/graphics` | Overlays broadcast: `scoreboard`, `scoreboard-2xko`, `commentary`. |
| Browser shared | `src/browser_shared/replicants.ts` | Acceso browser a replicants. |
| Shared | `src/shared` | Tipos, utilidades, países, packs y personajes. |
| Schemas | `schemas` | Schemas de replicants principales. |
| Build outputs | `dashboard`, `graphics`, `extension`, `shared/dist` | Outputs ignorados por git. |
## Replicants
### Declarados por Schema
- `scoreboard`
- `players`
- `commentary`
- `graphicsSettings`
- `exampleReplicant`
### Declarados Solo en Código
- `installedPacks`
- `packRegistry`
- `downloadStates`
- `availableUpdates`
### Problema Principal
El contrato realtime está dividido entre schemas y código runtime. Parte vive en `schemas`, y parte en `pack-manager` o `usePackRegistry`. Esto dificulta validar cambios, regenerar tipos y entender qué estado público existe realmente.
## Flujo de Datos
1. El dashboard escribe en Pinia stores.
2. Los stores sincronizan con replicants mediante `store-sync.ts`.
3. Los overlays leen replicants directamente desde `browser_shared/replicants.ts`.
4. La extensión escucha mensajes NodeCG como `startgg:*`, `challonge:*` y `downloadPack`.
5. La extensión actualiza replicants o disco.
6. `graphicsSettings.scoreboardSkin` redirige entre overlays `scoreboard` y `scoreboard-2xko`.
## Zonas Grandes o de Riesgo
| Archivo | Riesgo |
| --- | --- |
| `src/dashboard/scoreko-dev/views/Players.vue` | Vista demasiado grande: tabla, CRUD, import/export, integraciones y dialogs. |
| `src/dashboard/scoreko-dev/components/PlayerSidePanel.vue` | UI duplicada para left/right. |
| `src/dashboard/scoreko-dev/views/Settings.vue` | Mezcla idioma, shortcuts, OAuth y tokens. |
| `src/dashboard/scoreko-dev/composables/useIntegration.ts` | Mezcla estado UI, localStorage, polling OAuth, importación y cleanup. |
| `src/extension/pack-manager.ts` | Mezcla config, tipos, FS, HTTP static, downloads, updates, replicants y handlers. |
| `src/graphics/scoreboard/main.vue` | Lógica, layout, animaciones, flags y CSS mezclados. |
| `src/graphics/scoreboard-2xko/main.vue` | Mismo riesgo que `scoreboard/main.vue`. |
## Hallazgos Técnicos
- No se detectaron ciclos de imports en los archivos TS/Vue revisados.
- Sí hay accesos frágiles al entorno NodeCG:
- `nodecg` global en composables.
- `NodeCG.Replicant` declarado manualmente.
- Imports a `package.json` desde UI.
- Tipos generados desalineados.
- Acceso directo a replicants fuera de stores o servicios.
## Problemas Reales
- La frontera NodeCG está rota: `browser_shared/replicants.ts`, stores, `Graphics.vue`, overlays y `usePackRegistry` acceden a NodeCG de formas distintas.
- Los contratos realtime no están centralizados.
- `pack-manager.ts` necesita reescritura controlada, no parcheo incremental.
- `usePackRegistry.ts` y `fighting-characters.ts` necesitan reescritura controlada.
- `startgg.ts` y `challonge.ts` duplican estructura: OAuth mode, proxy exchange, session polling API y parsing básico.
- `Players.vue` y `Settings.vue` son feature modules completos metidos en vistas.
- Los overlays son de alto riesgo visual y deben tocarse con mucho cuidado.
- Hay dead code claro: `exampleReplicant`, `example.ts`, `ExampleType` y schema de ejemplo.
- `src/types/schemas/configschema.d.ts` está stale: contiene `exampleProperty`, pero `configschema.json` ya no lo define.
- `lint` falla por `_id` en `Players.vue` y `_config` en `startgg.ts` y `challonge.ts`.
- El resto de lint son warnings de formato Vue.
## Impacto a Medio y Largo Plazo
- Añadir providers o skins duplicará lógica.
- Contributors externos no sabrán dónde tocar: store, composable, replicant o extensión.
- Refactors visuales pueden romper overlays porque no hay separación entre view model y presentación.
- El sistema de packs es el mayor riesgo por acoplar descarga, estado realtime, manifests, FS y UI.
## Zonas a Preservar
- La idea de `syncStateWithReplicant`.
- Stores `scoreboard`, `players` y `commentary` como base razonable.
- `oauth-server.ts` como pieza reusable.
- `countries.ts`, que está bien encapsulado.
- Schemas JSON como fuente de tipos.
- UI Quasar existente, preservando comportamiento visual mientras se divide.
## Baseline de Checks
| Check | Estado |
| --- | --- |
| `vue-tsc` | Pasa. |
| `tsc` | Pasa. |
| `lint` | Falla con 3 errores reales y 243 warnings de formato. |
+97
View File
@@ -0,0 +1,97 @@
# Architecture Rules
Estas reglas son obligatorias para cualquier refactor posterior. Están pensadas para mantener boundaries claros, reducir acoplamiento y preservar comportamiento durante la migración.
## TypeScript
- No usar `any`.
- Usar `unknown` solo en boundaries.
- Normalizar `unknown` inmediatamente al entrar al dominio.
- No duplicar tipos entre extension y browser.
- Todo replicant nuevo debe tener schema y tipo generado.
- Regenerar tipos siempre desde schemas.
## Boundaries NodeCG
- No acceder directamente a replicants fuera de `nodecg/browser` o `nodecg/extension`.
- No usar `nodecg.sendMessage` directo en componentes o composables de feature.
- No usar `nodecg.Replicant` directo fuera de la capa `nodecg`.
- No depender de `nodecg` global salvo dentro del boundary correspondiente.
- Centralizar nombres de replicants en `replicantNames`.
- Centralizar nombres de messages en una capa de messages.
## Shared y Dominio
- `shared/domain` solo puede contener funciones puras, tipos, normalizadores y mapping.
- `shared/domain` no puede importar Vue.
- `shared/domain` no puede importar NodeCG.
- `shared/domain` no puede acceder al DOM.
- Preferir funciones puras para normalización, parsing, derivación y mapping.
- Validar o normalizar datos externos al cruzar boundaries.
## Dashboard
- Los stores mantienen estado de aplicación y sync con replicants.
- Los stores no deben contener UI compleja.
- Las vistas no deben implementar features completos.
- Los componentes deben ser pequeños y orientados a UI.
- Los composables de feature no deben hablar directamente con NodeCG.
- Toda lógica de negocio debe vivir en dominio, services o stores según corresponda.
## Extension
- `extension/modules` debe contener handlers pequeños registrados desde bootstrap explícito.
- No mezclar FS, HTTP, replicants, downloads y parsing en el mismo módulo.
- Todo handler NodeCG debe declarar claramente qué message escucha y qué replicants toca.
- Todo acceso a `nodecg.listenFor`, `nodecg.Replicant`, `nodecg.mount` y logging debe pasar por `nodecg/extension`.
## Packs
- Pack registry, manifests, downloads y estado instalado deben compartir tipos comunes.
- Todo replicant de packs debe tener schema.
- Mantener nombres y defaults actuales durante la migración.
- Validar manifests en el boundary antes de exponerlos al dominio o UI.
- No mantener estado mutable de módulo opaco para packs instalados.
- No usar `ref` de Vue dentro de shared.
## Integraciones
- Providers como Start.gg y Challonge deben compartir patrón de OAuth, session polling y parsing.
- Cada provider debe tener cliente propio y normalizadores propios.
- El flujo OAuth debe apoyarse en `oauth-server.ts` cuando aplique.
- Todo timer o polling debe tener cleanup.
- Todo listener debe tener cleanup.
## Graphics y Overlays
- Los overlays se refactorizan al final.
- Primero preservar píxel y comportamiento; después limpiar internals.
- No cambiar CSS, SVG, posiciones o markup sensible sin baseline visual.
- Extraer view models antes de deduplicar layout.
- Helpers compartidos de flags, score animation y text fitting deben vivir en `graphics/shared`.
## Side Effects
- No side effects en imports salvo bootstrap explícito.
- No estado mutable de módulo salvo singleton justificado y documentado.
- Todo timer/listener debe registrar cleanup.
- No wrappers vacíos.
- No inventar un patrón si una función simple basta.
## Naming
| Elemento | Regla | Ejemplo |
| --- | --- | --- |
| Replicants | `camelCase`, constantes en `replicantNames` | `graphicsSettings` |
| Messages | Namespaced por dominio | `packs:download` |
| Stores | `use<Feature>Store` | `useScoreboardStore` |
| Services | `create<Domain>Service` o `create<Provider>Client` | `createPackService` |
| View models | `use<Overlay>ViewModel` | `useScoreboardOverlayViewModel` |
## Compatibilidad
- Mantener comportamiento público durante la migración.
- Mantener nombres públicos hasta completar el refactor.
- No romper overlays sin baseline visual y verificación.
- Priorizar eliminar legacy muerto antes que envolverlo.
+187
View File
@@ -0,0 +1,187 @@
# Migration Plan
Este plan define el orden de migración. Debe ejecutarse de forma secuencial para reducir riesgo, preservar comportamiento y evitar reescrituras amplias sin baseline.
## Principios
- Mantener nombres públicos y comportamiento hasta completar la migración.
- Congelar comportamiento antes de mover responsabilidades.
- Eliminar legacy muerto antes de envolverlo.
- Separar boundaries antes de reescribir módulos complejos.
- Tocar overlays al final y con verificación visual.
## Secuencia
| Paso | Objetivo | Tipo |
| --- | --- | --- |
| 1 | Congelar comportamiento con screenshots de overlays, fixtures de replicants, build, typecheck y lint baseline. | Baseline |
| 2 | Quitar `example*`, regenerar schema types y eliminar `.js` redundantes en `src/shared` si no se usan. | Limpieza |
| 3 | Crear `nodecg/browser` y `nodecg/extension` sin cambiar comportamiento. | Boundary |
| 4 | Añadir schemas para replicants de packs manteniendo nombres y defaults exactos. | Contratos |
| 5 | Extraer tipos/config de packs a `shared` y ajustar `tsconfig.extension` para no duplicar. | Shared |
| 6 | Reescribir controladamente `pack-manager`. | Reescritura |
| 7 | Reescribir controladamente `usePackRegistry` y `fighting-characters`. | Reescritura |
| 8 | Dividir `useIntegration`. | Modularización |
| 9 | Dividir `Players.vue`. | Modularización |
| 10 | Dividir `Settings.vue`. | Modularización |
| 11 | Refactor suave de dashboard scoreboard para eliminar duplicación left/right. | Modularización |
| 12 | Extraer view models y helpers de overlays sin tocar CSS/markup al inicio. | Overlays |
| 13 | Añadir tests puros para normalizadores y lógica de dominio. | Tests |
| 14 | Añadir verificación visual Playwright para overlays principales. | Visual QA |
## Detalle por Fase
### 1. Congelar Comportamiento
Crear una baseline antes de refactorizar:
- Screenshots de `scoreboard`, `scoreboard-2xko` y `commentary`.
- Fixtures representativos de replicants.
- Resultado actual de build y typecheck.
- Resultado actual de lint, incluyendo los 3 errores reales conocidos.
### 2. Limpiar Dead y Stale Code
Eliminar código que no representa comportamiento productivo:
- `exampleReplicant`.
- `example.ts`.
- `ExampleType`.
- Schema de ejemplo.
- Tipos generados stale.
- `.js` redundantes en `src/shared` si se confirma que no se usan.
### 3. Crear Boundaries NodeCG
Introducir APIs sin cambiar comportamiento:
- `src/nodecg/browser/replicants.ts`
- `src/nodecg/browser/messages.ts`
- `src/nodecg/extension/replicants.ts`
- `src/nodecg/extension/messages.ts`
- `src/nodecg/extension/context.ts`
El objetivo es centralizar acceso a replicants, messages, logging y NodeCG globals.
### 4. Centralizar Contratos Realtime
Añadir schemas para:
- `installedPacks`
- `packRegistry`
- `downloadStates`
- `availableUpdates`
Los nombres y defaults deben mantenerse exactamente para no romper dashboard, extensión ni overlays.
### 5. Extraer Shared de Packs
Mover a `shared`:
- Tipos de manifest.
- Tipos de registry.
- Tipos de estado de descarga.
- Config derivada común.
- Validación ligera en boundaries.
No duplicar tipos entre extension y browser.
### 6. Reescritura Controlada de Pack Manager
Separar `pack-manager.ts` en módulos pequeños:
| Módulo | Responsabilidad |
| --- | --- |
| Registry client | Fetch y normalización del registry remoto. |
| Downloader | Descargas, progreso y errores. |
| Disk store | Lectura/escritura en disco. |
| Static mount | Exposición HTTP de assets instalados. |
| Handlers | Registro de mensajes NodeCG. |
| Replicant sync | Actualización centralizada de replicants. |
### 7. Reescritura de Pack Registry Runtime
Rehacer `usePackRegistry` y `fighting-characters` para:
- Quitar estado mutable de módulo opaco.
- Evitar `ref` en shared.
- Modelar packs instalados como estado explícito.
- Cargar manifests mediante boundaries claros.
- Eliminar comentarios que contradicen el estado real de assets.
### 8. Dividir Integraciones
Extraer `useIntegration` en piezas:
- `nodecgMessageClient`
- `oauthClient`
- `temporaryPlayers`
- `tournamentImport`
Cada pieza debe tener cleanup explícito para timers/listeners.
### 9. Dividir Players
Extraer desde `Players.vue`:
- `PlayersTable`
- `PlayerEditorDialog`
- `IntegrationImportCard`
- `ImportPlayersDialog`
La vista debe coordinar el feature, no contener la implementación completa.
### 10. Dividir Settings
Extraer desde `Settings.vue`:
- `LanguageSettings`
- `ShortcutSettings`
- `IntegrationSettings`
Mantener UI Quasar y comportamiento actual.
### 11. Refactor Suave de Scoreboard Dashboard
Eliminar duplicación left/right con subcomponentes pequeños, sin cambiar el comportamiento público ni el layout principal.
### 12. Overlays al Final
Primero extraer sin modificar presentación:
- View models.
- Helpers de flags.
- Helpers de score animation.
- Helpers de text fitting.
Después de verificar baseline visual, deduplicar internals.
### 13. Tests Puros
Añadir tests para:
- Normalizadores.
- Pack registry.
- Shortcut parsing.
- Country resolving.
- Bracket round formatting.
### 14. Verificación Visual
Añadir Playwright para overlays principales:
- `scoreboard`.
- `scoreboard-2xko`.
- `commentary`.
Debe validar screenshots o checks visuales estables antes de tocar CSS sensible.
## Clasificación de Trabajo
| Categoría | Incluye |
| --- | --- |
| Automatizable | Moves/imports, schema generation, lint autofix, snapshots. |
| Reescritura controlada | Packs y registry runtime. |
| División | `Players.vue`, `Settings.vue`, overlays. |
| Conservar | Quasar UI, Pinia, schemas, `oauth-server`, concepto de `store-sync`, layout visual de overlays. |
+70
View File
@@ -0,0 +1,70 @@
# Session Handoff
Este handoff resume el contexto que debe asumir cualquier sesión futura antes de continuar el refactor. El análisis arquitectónico ya está hecho; no debe repetirse desde cero.
## Estado de la Sesión
- No se habían modificado archivos antes de crear esta documentación.
- Se leyó la estructura del proyecto, configs, schemas, extensión, dashboard, overlays y shared.
- `vue-tsc` pasa.
- `tsc` pasa.
- `lint` falla con 3 errores reales y 243 warnings de formato.
## Documentación Creada
| Documento | Propósito |
| --- | --- |
| `docs/refactor/ARCHITECTURE_AUDIT.md` | Diagnóstico del estado actual y riesgos. |
| `docs/refactor/MIGRATION_PLAN.md` | Orden secuencial de migración. |
| `docs/refactor/ARCHITECTURE_RULES.md` | Reglas accionables para implementación posterior. |
| `docs/refactor/TARGET_ARCHITECTURE.md` | Source of truth de la arquitectura objetivo. |
| `docs/refactor/SESSION_HANDOFF.md` | Contexto operativo para futuras sesiones. |
## Source of Truth
Para futuras sesiones:
1. Usar `TARGET_ARCHITECTURE.md` como referencia principal.
2. Aplicar siempre `ARCHITECTURE_RULES.md`.
3. Ejecutar `MIGRATION_PLAN.md` en orden.
4. Consultar `ARCHITECTURE_AUDIT.md` solo para entender el diagnóstico original.
## Próximo Paso Recomendado
El siguiente paso técnico, cuando se decida continuar, es iniciar el Paso 1 del plan:
- Congelar comportamiento.
- Capturar screenshots de overlays.
- Crear fixtures de replicants.
- Registrar baseline de build, typecheck y lint.
No empezar moviendo código antes de tener esa baseline.
## Riesgos a Recordar
- El sistema de packs es el área de mayor riesgo.
- Los overlays son sensibles a cambios visuales y deben tocarse al final.
- La frontera NodeCG debe centralizarse antes de reescribir features.
- Los replicants de packs deben formalizarse con schemas antes de limpiar runtime.
- `Players.vue` y `Settings.vue` deben dividirse, no reescribirse desde cero.
## Checks Conocidos
| Check | Resultado |
| --- | --- |
| `vue-tsc` | Pasa. |
| `tsc` | Pasa. |
| `lint` | Falla con 3 errores reales. |
Errores lint reales conocidos:
- `_id` en `Players.vue`.
- `_config` en `startgg.ts`.
- `_config` en `challonge.ts`.
Los demás avisos conocidos son warnings de formato Vue.
## Instrucción para Futuras Sesiones
No reanalizar el proyecto desde cero salvo que el código haya cambiado de forma sustancial. Continuar desde estos documentos y ejecutar el plan en orden.
+203
View File
@@ -0,0 +1,203 @@
# Target Architecture
Este documento es la source of truth para la arquitectura objetivo del refactor. Las futuras sesiones deben alinearse con esta estructura y con las reglas de `ARCHITECTURE_RULES.md`.
## Objetivo
Crear una arquitectura simple y realista que:
- Centralice la frontera NodeCG.
- Centralice contratos realtime.
- Separe dominio puro de UI y runtime.
- Permita añadir providers, packs y skins sin duplicación.
- Preserve el comportamiento visual de overlays durante la migración.
## Estructura Objetivo
```text
src/
shared/
schemas/
types/
domain/
scoreboard/
players/
commentary/
packs/
integrations/
utils/
nodecg/
browser/
replicants.ts
messages.ts
extension/
context.ts
replicants.ts
messages.ts
extension/
modules/
packs/
integrations/
startgg/
challonge/
oauth/
dashboard/
app/
features/
scoreboard/
players/
graphics/
settings/
integrations/
packs/
stores/
ui/
graphics/
shared/
composables/
view-models/
assets/
scoreboard/
scoreboard-2xko/
commentary/
```
## Boundaries
| Boundary | Puede hacer | No puede hacer |
| --- | --- | --- |
| `shared/domain` | Tipos, funciones puras, normalizadores, mapping. | Importar Vue, NodeCG o DOM. |
| `nodecg/browser` | Acceso browser a replicants y messages. | Contener lógica de negocio o UI. |
| `nodecg/extension` | Acceso server a `nodecg.Replicant`, `listenFor`, `mount` y logging. | Implementar lógica específica de features. |
| `dashboard/stores` | Estado de aplicación y sync con replicants. | Contener UI compleja. |
| `dashboard/features` | Componentes y composables por feature. | Acceder directamente a NodeCG. |
| `graphics/shared` | View models, helpers visuales compartidos, assets compartidos. | Cambiar contratos realtime. |
| `extension/modules` | Handlers y servicios pequeños registrados desde bootstrap. | Mezclar responsabilidades sin separación. |
## Flujo Realtime Objetivo
```text
schemas
-> generated types
-> nodecg/browser + nodecg/extension
-> dashboard stores / extension modules / graphics view models
```
Reglas del flujo:
- Todo replicant persistente o realtime tiene schema.
- Los tipos se generan desde schemas.
- Dashboard y graphics no crean replicants directamente.
- Extension modules no exponen replicants sin pasar por `nodecg/extension`.
## Replicants
### Fuente de Verdad
Los schemas son la fuente de verdad para todos los replicants.
### Replicants a Mantener
- `scoreboard`
- `players`
- `commentary`
- `graphicsSettings`
### Replicants de Packs a Formalizar
- `installedPacks`
- `packRegistry`
- `downloadStates`
- `availableUpdates`
### Replicants a Eliminar
- `exampleReplicant`
## Messages
Los messages deben estar namespaced por dominio.
| Dominio | Ejemplos |
| --- | --- |
| Packs | `packs:fetchRegistry`, `packs:download` |
| Start.gg | `integrations:startgg:createOAuthSession` |
| Challonge | `integrations:challonge:createOAuthSession` |
Los componentes y composables de feature no deben llamar `nodecg.sendMessage` directamente. Deben usar clientes o services definidos en el boundary browser.
## Shared Domain
`shared/domain` contiene lógica reusable sin runtime:
- `scoreboard`: normalización de estado, mapping de jugadores, derivaciones de marcador.
- `players`: normalizadores, import/export, validación ligera.
- `commentary`: estado y mapping de comentaristas.
- `packs`: manifests, registry, installed packs y derivaciones.
- `integrations`: tipos normalizados, parsing básico y modelos comunes.
## Extension Modules
La extensión debe registrarse desde un bootstrap explícito y delegar en módulos:
| Módulo | Responsabilidad |
| --- | --- |
| `packs` | Registry, downloads, disk store, static mount, replicant sync y handlers. |
| `integrations/startgg` | Cliente Start.gg, OAuth session polling y parsing. |
| `integrations/challonge` | Cliente Challonge, OAuth session polling y parsing. |
| `oauth` | Reuso de `oauth-server.ts` y flujos comunes OAuth. |
## Dashboard
El dashboard se organiza por features:
- `scoreboard`
- `players`
- `graphics`
- `settings`
- `integrations`
- `packs`
Las vistas coordinan features. Los componentes implementan UI. Los stores mantienen estado y sincronización.
## Graphics
Los overlays deben leer estado mediante view models:
- `useScoreboardOverlayViewModel`
- `useCommentaryOverlayViewModel`
`graphics/shared` contiene:
- Composables visuales.
- View models.
- Helpers de flags.
- Helpers de score animation.
- Helpers de text fitting.
- Assets compartidos.
El layout visual existente se conserva hasta tener verificación visual estable.
## Naming Canónico
| Tipo | Convención | Ejemplo |
| --- | --- | --- |
| Replicant | `camelCase` | `graphicsSettings` |
| Replicant constants | `replicantNames` | `replicantNames.graphicsSettings` |
| Message | `<domain>:<action>` | `packs:download` |
| Integration message | `integrations:<provider>:<action>` | `integrations:startgg:createOAuthSession` |
| Store | `use<Feature>Store` | `usePlayersStore` |
| Service | `create<ServiceName>` | `createPackService` |
| Provider client | `create<Provider>Client` | `createStartggClient` |
| Overlay view model | `use<Overlay>OverlayViewModel` | `useScoreboardOverlayViewModel` |
## Arquitectura a Preservar
- Pinia como estado del dashboard.
- Quasar como UI principal.
- Schemas JSON como fuente de tipos.
- `syncStateWithReplicant` como concepto.
- `oauth-server.ts` como base reusable.
- `countries.ts` como utilidad encapsulada.
- Layout visual de overlays hasta completar verificación visual.