mirror of
https://github.com/Pandipipas/scoreko-dev.git
synced 2026-06-06 03:32:06 +00:00
feat: add architectural documentation for refactor process, including audit, rules, migration plan, session handoff, and target architecture
This commit is contained in:
@@ -0,0 +1,60 @@
|
|||||||
|
# Scoreko-dev: Auditoría de Arquitectura
|
||||||
|
|
||||||
|
Este documento consolida el análisis de la arquitectura actual y el diagnóstico de los problemas encontrados, sirviendo como punto de partida para el refactor.
|
||||||
|
|
||||||
|
## Análisis de la Estructura Actual
|
||||||
|
|
||||||
|
El proyecto está estructurado utilizando `pnpm workspaces` (`nodecg`, `shared` y el directorio raíz). El código fuente principal reside en `src/`, y se compila a `extension/`, `dashboard/` y `graphics/`.
|
||||||
|
|
||||||
|
### Distribución de Carpetas
|
||||||
|
|
||||||
|
| Carpeta | Descripción |
|
||||||
|
| :--- | :--- |
|
||||||
|
| `src/dashboard/scoreko-dev/` | Contiene la UI del dashboard construida con Vue 3, Quasar y Pinia. |
|
||||||
|
| `src/graphics/` | Contiene los overlays (scoreboard, commentary, scoreboard-2xko) en Vue 3. |
|
||||||
|
| `src/extension/` | Backend NodeCG. Contiene la integración con start.gg, Challonge y la gestión de packs. |
|
||||||
|
| `src/shared/` | Lógica o utilidades compartidas (por ejemplo, lista de países). |
|
||||||
|
| `src/browser_shared/` | Replicantes expuestos a las apps Vue. |
|
||||||
|
|
||||||
|
### Flujo de Datos y Estado (Stores y Replicants)
|
||||||
|
|
||||||
|
- **Dashboard (Pinia + Replicants)**: Se usan stores de Pinia (`scoreboard.ts`, `players.ts`, `commentary.ts`) para manejar el estado en el dashboard. Existe un mecanismo de sincronización `store-sync.ts` que ata los ref de Vue (stores) a los Replicants de NodeCG, con un fallback en `localStorage`.
|
||||||
|
- **Graphics**: Los componentes gráficos (ej. `src/graphics/scoreboard/main.vue`) importan directamente los replicants de `browser_shared/replicants.ts` y usan `watch` para reaccionar a cambios. No parecen usar Pinia, sino estado reactivo local (`ref`, `computed`).
|
||||||
|
|
||||||
|
### Componentes Monolíticos
|
||||||
|
|
||||||
|
Existen componentes excesivamente grandes que mezclan responsabilidades:
|
||||||
|
|
||||||
|
- **`src/dashboard/scoreko-dev/views/Players.vue`** (>680 líneas): Mezcla presentación, diálogos de UI, validaciones de formulario, llamadas a composables de integración (`useIntegration`), transformación de datos, renderizado manual de iconos SVG hardcodeados y lógica de exportación/importación JSON.
|
||||||
|
- **`src/graphics/scoreboard/main.vue`** (>690 líneas): Mezcla la UI del marcador, cálculos de dimensiones de fuentes (`fitText`), timeouts manuales para animaciones, carga asíncrona de SVG de banderas usando importación dinámica de Vite, bindings a NodeCG y redirecciones de URL basadas en configuraciones gráficas.
|
||||||
|
|
||||||
|
### Acoplamientos y Efectos Secundarios
|
||||||
|
|
||||||
|
- En el dashboard, la lógica de integración de torneos (start.gg/Challonge) está fuertemente acoplada a la vista de jugadores mediante composables y callbacks, con SVGs directamente embebidos en el template.
|
||||||
|
- En el backend (`src/extension/startgg.ts`), hay mezcla de servidor OAuth HTTP puro, lógica de peticiones GraphQL con strings literales gigantes, parsing de errores y endpoints de NodeCG (`nodecg.listenFor`), todo en el mismo archivo (>440 líneas).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Diagnóstico
|
||||||
|
|
||||||
|
### Problemas Críticos
|
||||||
|
|
||||||
|
1. **Lógica de negocio acoplada a la UI**: Componentes como `Players.vue` y `main.vue` del scoreboard saben demasiado. Tienen lógica de red, cálculos de DOM, manejo de timeouts y manipulación de datos en crudo en lugar de delegar a stores o servicios.
|
||||||
|
2. **"Vibe Coding" y AI Slop**: Hay parches evidentes como la inclusión manual de SVGs inmensos inline en los templates, y utilidades infladas (cálculos rudimentarios de `fitText` en los overlays en lugar de usar CSS moderno o directivas reutilizables).
|
||||||
|
3. **Estado implícito y dependencias circulares potenciales**: El sistema de `store-sync.ts` que sincroniza Pinia <-> LocalStorage <-> NodeCG Replicants es frágil, creando condiciones de carrera sobre cuál es la "fuente de la verdad".
|
||||||
|
4. **Falta de abstracción en el Backend NodeCG**: Los archivos de `extension/` son scripts procesales en lugar de arquitecturas separadas.
|
||||||
|
|
||||||
|
### Impacto a Medio y Largo Plazo
|
||||||
|
|
||||||
|
- **Mantenibilidad Reducida**: Agregar nuevas integraciones (ej. smash.gg, Toornament) requerirá copiar/pegar más bloques monolíticos y añadir más SVGs hardcodeados.
|
||||||
|
- **Riesgo de Regresiones**: Modificar animaciones del scoreboard puede romper el cálculo del tamaño de fuente o la lógica de banderas, debido al acoplamiento.
|
||||||
|
- **Developer Experience (DX) Pobre**: La curva de aprendizaje es alta. Entender cómo fluye un cambio de score desde el dashboard hasta el overlay se vuelve muy complejo.
|
||||||
|
|
||||||
|
### Estrategia de Resolución
|
||||||
|
|
||||||
|
- **Reorganización**: Mantener la estructura base (`src/dashboard`, `src/graphics`, `src/extension`), pero crear subcarpetas por dominio/feature en el backend y separación estricta en el frontend.
|
||||||
|
- **Refactor**: Simplificar stores (eliminar puentes complejos a NodeCG), extracción de composables puros en el dashboard, separación de UI *Dumb* vs UI *Smart*.
|
||||||
|
- **Reescritura controlada**:
|
||||||
|
- `Players.vue`: Dividir drásticamente.
|
||||||
|
- `main.vue` (scoreboard): Extraer lógica de flags, animaciones y `fitText`.
|
||||||
|
- `startgg.ts` / `challonge.ts`: Adoptar un patrón Service/Repository.
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
# Reglas Arquitectónicas de Implementación
|
||||||
|
|
||||||
|
> [!IMPORTANT]
|
||||||
|
> Estas reglas son estrictas y obligatorias. Se deben aplicar sin excepción durante toda la fase de refactorización y en el futuro desarrollo.
|
||||||
|
|
||||||
|
1. **NO `any`, NO IGNORES**
|
||||||
|
- Prohibido el uso de `any`, `@ts-ignore` o casteos forzados ciegos (`as unknown as Tipo`). Todo debe tener tipado fuerte en TypeScript.
|
||||||
|
|
||||||
|
2. **CERO LÓGICA DE NEGOCIO EN COMPONENTES**
|
||||||
|
- Los componentes de Vue (`.vue`) no deben tener llamadas `fetch`, lógica compleja de parseo, o cálculos pesados.
|
||||||
|
- Su sección `<script>` debe limitarse exclusivamente a invocar *composables* o *stores*, y exponer datos al `template`.
|
||||||
|
|
||||||
|
3. **COMPONENTES PEQUEÑOS Y "DUMB"**
|
||||||
|
- Si el template de un componente supera las 100 líneas, es un síntoma de que debe subdividirse.
|
||||||
|
- Fomentar la creación de componentes presentacionales ("dumb components") que reciben datos únicamente mediante `props` y se comunican hacia arriba mediante `emits`.
|
||||||
|
|
||||||
|
4. **FUNCIONES PURAS (PURE FUNCTIONS) PRIMERO**
|
||||||
|
- Cualquier transformación de datos (ej. extraer *gamertags*, limpiar strings, dar formato a números) debe residir en una función pura y testeable, fuera del ecosistema Vue y de NodeCG.
|
||||||
|
|
||||||
|
5. **SIN WRAPPERS INÚTILES**
|
||||||
|
- Evitar crear *composables* simplemente por envolver una o dos líneas de código si no aportan verdadera semántica o abstracción de dominio.
|
||||||
|
|
||||||
|
6. **USO DE PATRONES ESTÁNDAR VUE 3**
|
||||||
|
- Utilizar exclusivamente convenciones estándar de Vue 3: Composition API pura, `<script setup>` y el ecosistema reactivo estándar de Pinia.
|
||||||
|
- Nada de patrones híbridos ni inventados.
|
||||||
|
|
||||||
|
7. **BORRAR SOBRE CONSERVAR (Limpieza de AI Slop)**
|
||||||
|
- Si se detecta código redundante o inútil (ej. código "AI slop" o enormes SVGs hardcodeados en HTML para iconos simples), la prioridad es eliminarlo.
|
||||||
|
- Sustituir por alternativas limpias y mantenibles (como usar iconos vectoriales de Quasar u hojas de estilo puras).
|
||||||
|
|
||||||
|
8. **EFECTOS SECUNDARIOS (SIDE EFFECTS) CONTROLADOS**
|
||||||
|
- El uso de `watch` debe ser el mínimo indispensable.
|
||||||
|
- Siempre que se deba reaccionar a un cambio, preferir flujos de datos unidireccionales (ej. variables calculadas mediante `computed`) en lugar de mutar un estado local desde un watcher reactivo.
|
||||||
|
|
||||||
|
9. **REESCRITURA SÍ, PARCHEO NO**
|
||||||
|
- Las zonas marcadas para reescritura en el plan (ej. `Players.vue` y `graphics/main.vue`) deben ser rehechas lógicamente.
|
||||||
|
- El objetivo es mantener el output visual o funcional intacto pero desechando la estructura legacy interna. No se aceptan "parches temporales" en estas áreas clave.
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
# Plan de Migración
|
||||||
|
|
||||||
|
> [!WARNING]
|
||||||
|
> Este plan está diseñado para evitar regresiones y mantener un estado "compilable" en todo momento. Se debe ejecutar estrictamente de backend a frontend, y de lógica pura a UI.
|
||||||
|
|
||||||
|
## Paso 1: Estabilización del Shared y Tipos
|
||||||
|
- **Acciones**:
|
||||||
|
- Mover utilidades genéricas (como la lista de `countries`, funciones de manipulación de strings) a `src/shared/utils/`.
|
||||||
|
- Refinar y consolidar los tipos en `src/shared/types/` para que representen el dominio real.
|
||||||
|
- Eliminar tipos parciales o duplicados dispersos en el código.
|
||||||
|
- **Riesgo**: Bajo. Gran parte es movimiento y ajuste de imports.
|
||||||
|
|
||||||
|
## Paso 2: Refactor del Backend (Extension)
|
||||||
|
- **Acciones**:
|
||||||
|
- **Reescritura controlada de integraciones**: Dividir `startgg.ts` en:
|
||||||
|
- `services/startgg.ts` (lógica de negocio y transformaciones).
|
||||||
|
- `api/startgg.ts` (GraphQL / HTTP requests).
|
||||||
|
- `oauth/startgg.ts` (flujo OAuth).
|
||||||
|
- `nodecg-bindings/startgg.ts` (vinculación exclusiva de `nodecg.listenFor`).
|
||||||
|
- Repetir la misma división para `challonge.ts`.
|
||||||
|
- Mover cualquier otra utilidad de backend a `extension/utils/`.
|
||||||
|
- **Riesgo**: Moderado. Requiere trasladar código con cuidado para no romper las firmas de los métodos.
|
||||||
|
|
||||||
|
## Paso 3: Refactor del Estado del Dashboard (Stores)
|
||||||
|
- **Acciones**:
|
||||||
|
- Limpiar `store-sync.ts`. Reducir la complejidad y sobre-ingeniería generada por el uso del `localStorage`.
|
||||||
|
- Asegurar que Pinia dependa directa y limpiamente de los Replicantes como fuente de datos real.
|
||||||
|
- Garantizar que los stores exporten acciones limpias, evitando que el estado interno se mute manualmente desde los componentes de la vista.
|
||||||
|
- **Riesgo**: Medio. Afecta el flujo de reactividad base de la UI.
|
||||||
|
|
||||||
|
## Paso 4: Modularización de los Componentes Grandes (Dashboard)
|
||||||
|
- **Acciones**:
|
||||||
|
- **Reescritura/División controlada de `Players.vue`**:
|
||||||
|
- Extraer modales a componentes independientes (ej. `ImportDialog.vue`, `PlayerEditDialog.vue`).
|
||||||
|
- Extraer los selectores de integración a componentes puros (`StartGGPanel.vue`, `ChallongePanel.vue`).
|
||||||
|
- Reemplazar los SVGs "hardcodeados" en el template por un componente dedicado o usar la librería de iconos de Quasar.
|
||||||
|
- Extraer partes de vistas monolíticas (`PlayerSidePanel.vue`) en sub-componentes especializados.
|
||||||
|
- **Riesgo**: Medio. Afecta directamente a la UI. Es crítico asegurar que los eventos (`emits`) se propagen y conecten correctamente.
|
||||||
|
|
||||||
|
## Paso 5: Refactor de los Gráficos (Scoreboard)
|
||||||
|
- **Acciones**:
|
||||||
|
- **Reescritura controlada de `main.vue`**:
|
||||||
|
- Extraer la lógica de ajuste de fuente a un archivo dedicado, ya sea como directiva o función: `graphics/shared/utils/fitText.ts` (o `v-fit-text`).
|
||||||
|
- Extraer la lógica de resolución de banderas (flags) y su caché a un composable dedicado: `useFlag(countryCode)`.
|
||||||
|
- Extraer el control de animaciones y timeouts a `useScoreAnimation(scoreRef)`.
|
||||||
|
- Dividir el DOM en componentes claros: `<BackgroundPanel>`, `<PlayerInfo side="left">`, `<ScoreDisplay>`, orquestados desde `App.vue` (o `main.vue` simplificado).
|
||||||
|
- **Riesgo**: Alto. Las animaciones y cálculos visuales de DOM son delicados. El objetivo visual final debe ser idéntico, y el comportamiento ante cambios de Replicants debe mantenerse exacto.
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
# Session Handoff: Refactor NodeCG Scoreboard
|
||||||
|
|
||||||
|
Este documento sirve como registro de estado y transferencia de contexto para cualquier agente o desarrollador en futuras sesiones de trabajo.
|
||||||
|
|
||||||
|
## Estado Actual
|
||||||
|
- **Fase de Análisis y Diagnóstico:** Completada.
|
||||||
|
- **Fase de Definición de Arquitectura y Reglas:** Completada.
|
||||||
|
- **Documentación:** Generada y almacenada en `docs/refactor/`.
|
||||||
|
|
||||||
|
## Fuente de la Verdad (Source of Truth)
|
||||||
|
Para cualquier duda, decisión arquitectónica, o estructuración de código durante el refactor, consulta **EXCLUSIVAMENTE** el documento:
|
||||||
|
- [TARGET_ARCHITECTURE.md](./TARGET_ARCHITECTURE.md)
|
||||||
|
|
||||||
|
Además, asegúrate de seguir las directrices dictadas en:
|
||||||
|
- [ARCHITECTURE_RULES.md](./ARCHITECTURE_RULES.md)
|
||||||
|
|
||||||
|
## Próximos Pasos (Next Actions)
|
||||||
|
La próxima sesión debe comenzar con la ejecución del `MIGRATION_PLAN.md`, ejecutando los pasos de forma estrictamente secuencial:
|
||||||
|
|
||||||
|
1. **Revisar [MIGRATION_PLAN.md](./MIGRATION_PLAN.md) -> Paso 1.**
|
||||||
|
2. Comenzar la creación/movimiento de utilidades compartidas hacia `src/shared/`.
|
||||||
|
3. Proceder únicamente al Paso 2 cuando el Paso 1 compile perfectamente y no existan errores de tipado.
|
||||||
|
|
||||||
|
No te desvíes de la secuencia. Evita realizar cambios no relacionados o abordar los gráficos antes de tener estabilizado el backend (`extension/`) y el core compartido.
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
# Arquitectura Objetivo (Target Architecture)
|
||||||
|
|
||||||
|
> [!IMPORTANT]
|
||||||
|
> Este documento sirve como la única fuente de la verdad para el diseño del sistema durante y después del refactor.
|
||||||
|
|
||||||
|
## Estructura de Capas
|
||||||
|
|
||||||
|
La aplicación se dividirá estrictamente en las siguientes capas lógicas:
|
||||||
|
|
||||||
|
1. **Capa NodeCG (Bindings)**: Archivos cuya *única* responsabilidad es declarar `nodecg.listenFor` (backend) o importar `nodecg.Replicant` (frontend).
|
||||||
|
2. **Capa de Estado (Stores)**: Pinia será la única fuente de la verdad para la UI. Los stores se hidratarán de los replicants sin lógicas cruzadas complejas de `localStorage`.
|
||||||
|
3. **Capa de Lógica Pura (Services/Domain)**: Funciones en TypeScript puro sin dependencias de Vue ni de NodeCG que transforman, formatean o calculan datos.
|
||||||
|
4. **Capa de UI (Dumb Components)**: Componentes Vue puramente presentacionales que solo reciben `props` y emiten `events`.
|
||||||
|
5. **Capa de Orquestación (Smart Components / Composables)**: Vistas y composables que conectan los Stores y/o NodeCG con los Dumb Components.
|
||||||
|
|
||||||
|
## Estructura de Carpetas Propuesta
|
||||||
|
|
||||||
|
```text
|
||||||
|
src/
|
||||||
|
├── browser_shared/
|
||||||
|
│ ├── replicants.ts # Declaraciones puras
|
||||||
|
│ └── useReplicant.ts # (NUEVO) Composable unificado para hidratar Vue desde NodeCG
|
||||||
|
├── shared/
|
||||||
|
│ ├── types/ # Tipos estrictos compartidos
|
||||||
|
│ └── utils/ # Helpers de dominio puros (ej. formateo)
|
||||||
|
├── extension/ # Backend NodeCG
|
||||||
|
│ ├── index.ts # Entry point
|
||||||
|
│ ├── nodecg-bindings/ # Registro exclusivo de nodecg.listenFor()
|
||||||
|
│ ├── services/ # Lógica de negocio pura (StartGGService, ChallongeService)
|
||||||
|
│ ├── api/ # Llamadas HTTP/GraphQL
|
||||||
|
│ └── oauth/ # Manejo de flujos de autenticación OAuth aislados
|
||||||
|
├── dashboard/
|
||||||
|
│ └── scoreko-dev/
|
||||||
|
│ ├── components/ # UI (Small, dumb components)
|
||||||
|
│ ├── composables/ # Lógica orquestada y reutilizable
|
||||||
|
│ ├── features/ # (NUEVO) Dominio agrupado (ej. /players, /integrations)
|
||||||
|
│ ├── stores/ # Pinia stores (Fuente de la verdad UI)
|
||||||
|
│ └── views/ # Smart components (Orquestadores)
|
||||||
|
└── graphics/
|
||||||
|
├── shared/ # (NUEVO) Componentes y composables compartidos entre gráficos
|
||||||
|
│ ├── directives/ # ej. v-fit-text
|
||||||
|
│ └── composables/ # ej. useScoreAnimation, useFlags
|
||||||
|
├── scoreboard/
|
||||||
|
│ ├── components/ # Componentes segregados (PlayerName.vue, Score.vue, BackgroundPanel.vue)
|
||||||
|
│ └── App.vue # Orquestador principal del scoreboard
|
||||||
|
└── scoreboard-2xko/
|
||||||
|
```
|
||||||
|
|
||||||
|
## Reglas Arquitectónicas de Diseño
|
||||||
|
|
||||||
|
- **Domain Driven**: El backend y el dashboard se organizarán por dominio o feature (`players`, `scoreboard`, `integrations`) donde sea posible.
|
||||||
|
- **Aislamiento de NodeCG**: En el backend, toda lógica debe vivir en clases o funciones de servicio que reciben datos y devuelven promesas. La integración con la API de NodeCG solo llama a esos servicios; no se debe inyectar NodeCG en los servicios si no es estrictamente necesario.
|
||||||
|
- **Tipado Estricto**: Todo el output de GraphQL/HTTP debe validarse/parsearse a un tipo de dominio lo antes posible en la capa de API.
|
||||||
Reference in New Issue
Block a user