Propósito: preservar el contexto completo de la sesión de trabajo sobre OLManager antes de formatear el equipo. Guardá este archivo en la nube / USB ANTES de formatear.
Fecha de la sesión: 2026-06-13 Repo: https://github.com/NicoRuedaA/OLManager — rama
0.3.6Commit base:22f3da59(fix(draft): resolve team logos using logo_url instead of slugified name)
Los cambios de código de esta sesión NO están committeados ni pusheados. Si formateás, el working tree se pierde. Tenés dos opciones antes de formatear:
- Recomendado: commitear y pushear los cambios (ver sección "Changelog reproducible").
- Mínimo: guardar este
.md— incluye los diffs exactos para reaplicarlos sobre un clon fresco de0.3.6.
Después de formatear, el flujo de recuperación es:
- Reinstalar herramientas (ver "Reconstrucción del entorno").
git clone --branch 0.3.6 https://github.com/NicoRuedaA/OLManager.git- Reaplicar los cambios del "Changelog reproducible" (si no los pusheaste).
Open League Manager — juego de simulación de gestión de esports de League of Legends (estilo Football Manager), open source, en estado pre-alpha. Fork migrado a medias desde OpenFootManager (de ahí buena parte de la deuda técnica).
- Frontend: React 19 + TypeScript ~6.0 + Vite 8 + Tailwind 4 + Zustand + i18next (8 idiomas)
- react-router 7 + Zod. Tipos TS generados desde Rust con
ts-rs.
- react-router 7 + Zod. Tipos TS generados desde Rust con
- Backend: Rust 1.80+ con Tauri v2.10, arquitectura hexagonal / DDD. Crate único
olm_core(dominio, motor de simulación, repositorios). Persistencia SQLite por partida (rusqlite, 59 migraciones). - Tests: Vitest + RTL + jsdom (frontend, 128 archivos), Rust (19 suites integración + 50 inline).
Playwright configurado pero
e2e/no existe.
React (WebView) → Zustand stores → services/ → ApiClient (adapter)
→ Tauri IPC invoke() → src-tauri/src/commands/ (handlers delgados)
→ src-tauri/src/application/ (orquestación) → olm_core (dominio/motor/DB) → SQLite
sim_live.rs= 6.383 líneas — el motor de simulación es un monolito. Otros grandes:transfers.rs(3.064),ChampionDraft.tsx(3.345),squad.rs(2.084).- 483
.unwrap()enolm_core+ 67 en comandos → pánicos en runtime potenciales. - Migración football→LoL incompleta (~53 remanentes:
home_goals,GoalsScored, etc.). src/ui-v2/_legacy/NO es legacy — contiene rutas ACTIVAS (MainMenu,MatchSimulation,ChampionDraft). Confunde sobre qué código es el bueno.- CI con frenos desactivados —
clippy/fmtconcontinue-on-error: true. csp: nullentauri.conf.json— CSP deshabilitada.- Menores: semilla fija
seed_from_u64(42)en IA de contratos, dos versiones derand, migraciones con números duplicados (v028 x2, V44/V55 repetidas).
Decisión del usuario: el web es un "intento fallido que se hará de 0 en el futuro".
Decisión arquitectónica clave: se borró la implementación web PERO se conservó la costura
del Adapter (getApiClient() + interfaz ApiClient + tauri.adapter.ts), porque esa
abstracción sostiene los tests (inyectan adapters mockeados vía setApiClient) y es el punto
limpio donde enchufar el web nuevo en el futuro. NO se colapsó a Tauri directo (habría roto tests
y destruido una abstracción útil).
Archivos borrados:
src/api/adapters/http.adapter.tsdocs/nginx.conf.github/workflows/deploy.yml(deploy web a Hetzner/Docker/Supabase; estaba roto — faltabanDockerfile.backendyDockerfile.frontend, que nunca existieron en el repo)- Dependencia
@supabase/supabase-jsremovida depackage.json(declarada pero jamás importada)
Hallazgos: el crate src-tauri/crates/server que mencionaba ARCHITECTURE.md no existía
(workspace solo tiene crates/olm_core). Era un crate fantasma documentado.
deploy.yml borrado (tipo anon, pública por diseño, pero apuntaba a un proyecto Supabase real:
https://zqvppsruobmmpssrgzbj.supabase.co). Si ese proyecto sigue vivo, conviene darlo de baja
desde el panel de Supabase.
Verificado con git stash: los 4 errores eran pre-existentes en 0.3.6, NO los introdujo
la eliminación del web. La rama de release no pasaba el type-check de fábrica (porque el CI corre
con continue-on-error). Tras los fixes, npm run build:types → exit 0.
Dos familias de error:
nullvsundefined(avatares):<img src>aceptastring | undefined, nonull, yassetUrl()devuelvestring | null. NO se tocó el util compartido (lo usanteamLogos.tsyplayerPhotos.tsdevolviendonulla propósito) — se coercionó en el borde con?? "".TFunction: la proptdeCoherenceSummarytenía un tipo hecho a mano demasiado estrecho. Se cambió porTFunctionde i18next → un fix en la definición resolvió los 2 call sites.
Hay 6 continue-on-error: true en .github/workflows/pr.yml (líneas 63, 70, 76, 96, 107, 165):
cargo fmt --check, cargo clippy (x2), cargo check -p openleaguemanager --lib, npm audit,
cargo audit.
Decisión: NO flipearlos a ciegas. Principio: un freno solo se activa cuando el check está en verde. Evidencia de que varios están en ROJO:
cargo clippy --workspace --all-targetsno compila entero (el--all-targetsarrastra targets de test que fallan).- El comentario de la línea 74 ("tests blocked by
lol_sim_v2.rs") está viejo/miente: ese archivo ya no existe en el repo (solo aparece en docs archivadas). El bloqueo real actual es otro.
El baseline del frontend YA tiene dientes: npm test y npm run build:types (pr.yml líneas
126-130) NO tienen continue-on-error y están en verde. Para simplificar archivos TS, la red ya está.
El equipo no tenía Rust. Instalado vía scoop (estaba disponible; no había winget/choco/admin):
- Rust
rustc/cargo1.96.0,rustfmt1.9.0,clippy0.1.96 - Toolchain por defecto:
stable-x86_64-pc-windows-gnu(GNU, no MSVC) - MinGW GCC 16.1.0 como linker/compilador C (para
rusqlitebundled, etc.) - WebView2 ya estaba instalado (v149)
Por qué GNU y no MSVC: MSVC Build Tools no era instalable acá (sin winget/admin, descarga de
varios GB). El toolchain GNU cubre al 100% verificar los gates (fmt/clippy/check/test).
MSVC solo hace falta para tauri build/tauri dev de producción (Tauri en Windows apunta a
MSVC oficialmente). Cuando llegues a empaquetar, instalá Visual Studio Build Tools (admin + GBs)
con los componentes "MSVC v143 x64/x86 build tools" + "Windows SDK".
Objetivo del usuario: invertir en simplificar el código — sintaxis más clara, "1 objetivo = 1 archivo", reducir tamaños.
Secuencia correcta (NO empezar por partir archivos):
- Baseline verde y confiable PRIMERO (no se refactoriza un monolito de 6.000 líneas sin red):
- ✅ Frontend:
tscen verde + gates ya enforced. - ⏸️ Rust: falta lograr que el workspace compile limpio bajo
--all-targets, corrercargo fmt, decidir política de clippy (-D warnings), y RECIÉN AHÍ activar los frenos del CI uno por uno.
- ✅ Frontend:
- Simplificar UN archivo grande como plantilla replicable:
- Blindar primero con tests de caracterización (sobre todo el simulador, que es lógica pura testeable).
- Extraer por costuras (strangler-fig), nunca big-bang.
- Métrica real: "una sola razón para cambiar por archivo", NO bajar líneas por bajar.
(
sim_live.rsya tiene submódulos — la ganancia está en clarificar límites.)
Política sugerida para los frenos de Rust (cuando el workspace compile):
- Compilar limpio bajo
--all-targets(y borrar el comentario viejo delol_sim_v2.rsen pr.yml:74). cargo fmt→ commit → flipear pr.yml:63.- Agregar
-- -D warningsa clippy, limpiar warnings → flipear pr.yml:70 y :165. - Dejar
npm auditycargo audit(pr.yml:96, :107) NON-blocking a propósito — un CVE nuevo upstream no debería bloquear un PR ajeno; son señal advisory, no gate de calidad.
Correr la batería de verificación de gates de Rust (primera compilación del workspace = varios minutos, baja+compila cientos de crates incl. SQLite vía gcc):
# 1. Asegurar el PATH del toolchain en la sesión (scoop no lo propaga a shells nuevas siempre)
$env:Path = "C:\Users\vboxuser\scoop\persist\rustup\.cargo\bin;C:\Users\vboxuser\scoop\apps\mingw\current\bin;$env:Path"
# 2. Correr los gates desde src-tauri/
cd C:\Users\vboxuser\Desktop\OLM\OLManager\src-tauri
cargo fmt --check # ¿formato OK?
cargo check -p olm_core # ¿compila el core?
cargo test -p olm_core # ¿pasan los tests del core?
cargo clippy --workspace --all-targets # ¿clippy verde? (ojo: --all-targets puede no compilar)Con eso se sabe el estado real de cada gate y cuáles se pueden activar.
Windows. Asumiendo formato limpio:
# --- scoop (gestor de paquetes a nivel usuario, sin admin) ---
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
Invoke-RestMethod -Uri https://get.scoop.sh | Invoke-Expression
# --- Node.js (frontend) ---
scoop install nodejs-lts # o la versión 20/22 que prefieras
# --- Rust toolchain GNU + MinGW (verificación de gates, sin MSVC) ---
scoop install rustup mingw
rustup toolchain install stable-x86_64-pc-windows-gnu
rustup default stable-x86_64-pc-windows-gnu
rustup component add rustfmt clippy
# --- (opcional, solo para tauri build/dev de producción) ---
# Visual Studio Build Tools con "Desktop development with C++" (MSVC v143 + Windows SDK).
# Descarga: https://visualstudio.microsoft.com/visual-cpp-build-tools/ (admin, varios GB)
# WebView2 Runtime: normalmente ya viene en Win 10/11; si no:
# https://developer.microsoft.com/microsoft-edge/webview2/
# --- proyecto ---
git clone --branch 0.3.6 https://github.com/NicoRuedaA/OLManager.git
cd OLManager
npm install
npm run build:types # debe dar verde SI reaplicaste los fixes de la Tarea BReaplicar sobre un clon fresco de
0.3.6si los cambios no se pushearon.
rm src/api/adapters/http.adapter.ts
rm docs/nginx.conf
rm .github/workflows/deploy.yml
Quitar el script dev:web y build:web:
"dev": "vite",
- "dev:web": "vite --mode web",
"build": "vite build",
- "build:web": "vite build --mode web",
"build:types": "tsc -p tsconfig.release.json",Quitar la dependencia supabase:
"@fontsource/oswald": "^5.2.8",
- "@supabase/supabase-js": "^2.106.2",
"@tauri-apps/api": "^2.11.0",Reemplazar el branch no-Tauri (que cargaba httpAdapter) por un error claro:
if (isTauri()) {
// In Tauri, imports are synchronous because Vite resolves @tauri-apps
const { tauriAdapter } = await import("./adapters/tauri.adapter")
_client = tauriAdapter
} else {
- const { httpAdapter } = await import("./adapters/http.adapter")
- _client = httpAdapter
+ // Web mode was removed in 0.3.6 and will be rebuilt from scratch. The
+ // adapter seam is intentionally kept so a future web adapter can plug in
+ // here without touching call sites or the test harness.
+ throw new Error(
+ "[ApiClient] Web mode is not supported. OLManager currently runs only under Tauri (desktop).",
+ )
}- Quitar
isWeby el alias web:
-export default defineConfig(async ({ mode }) => {
- const isWeb = mode === "web";
-
+export default defineConfig(async () => {
return {
define: { __APP_VERSION__: JSON.stringify(pkg.version) },
plugins: [react(), tailwindcss()],
resolve: {
alias: {
"@": path.resolve(__dirname, "./src"),
- ...(isWeb ? {} : {}),
},
},- Puerto fijo Tauri:
server: {
- port: isWeb ? 5173 : 1420,
- strictPort: !isWeb,
+ port: 1420,
+ strictPort: true,
host: host || false,- Quitar el bloque
proxy(elwatch.ignoredqueda igual):
},
- proxy: isWeb
- ? { "/api": { target: "http://localhost:3001", changeOrigin: true } }
- : undefined,
},Quitar la variable muerta isWebSession (ocultaba "Salir" en web; sin web siempre se muestra):
const { t, i18n } = useTranslation();
- const isWebSession = false;
const [menuState, setMenuState] = useState<- if (!isWebSession) {
- items.push({ icon: <Power />, tone: "danger" as const, label: t("menu.exitGame"), onClick: () => { void handleExitApp(); } });
- }
+ items.push({ icon: <Power />, tone: "danger" as const, label: t("menu.exitGame"), onClick: () => { void handleExitApp(); } });
return items;
- }, [t, menuState, isWebSession, navigate, handleOpenLoadMenu, handleExitApp]);
+ }, [t, menuState, navigate, handleOpenLoadMenu, handleExitApp]);- Quitar la línea
System_Ext(srv, "server", "Web HTTP API (optional)"). - Quitar la línea
Rel(frontend, srv, "HTTP /api/* (web mode)"). - "workspace ... with two crates:
olm_coreandserver." → "with a single crate:olm_core." - Quitar el bullet
**commands.rs** — Command dispatch for web/server mode. - Quitar la sección entera
###server`` y su párrafo.
src/ui-v2/_legacy/components/manager/ManagerTab.tsx (~línea 160):
- src={mgr.avatar_path ? assetUrl(mgr.avatar_path) : ""}
+ src={assetUrl(mgr.avatar_path) ?? ""}src/ui-v2/dashboard/tabs/ManagerTabV2.tsx (~línea 130):
- src={assetUrl(mgr.avatar_path ?? DEFAULT_MANAGER_ICON_PATH)}
+ src={assetUrl(mgr.avatar_path ?? DEFAULT_MANAGER_ICON_PATH) ?? ""}src/ui-v2/_legacy/components/tactics/TacticsTab.tsx:
import type { JSX } from "react";
+import type { TFunction } from "i18next";
import { useEffect, useMemo, useState } from "react"; gameState: GameStateData;
- t: (key: string, fallback?: string) => string;
+ t: TFunction;
}) {Deleted: .github/workflows/deploy.yml
Deleted: docs/nginx.conf
Deleted: src/api/adapters/http.adapter.ts
Modified: docs/ARCHITECTURE.md
Modified: package.json
Modified: package-lock.json (regenerado por npm install; sin supabase)
Modified: src/api/client.ts
Modified: src/ui-v2/_legacy/pages/MainMenu.tsx
Modified: src/ui-v2/_legacy/components/manager/ManagerTab.tsx
Modified: src/ui-v2/dashboard/tabs/ManagerTabV2.tsx
Modified: src/ui-v2/_legacy/components/tactics/TacticsTab.tsx
Modified: vite.config.ts
npm run build:types → exit 0 (verde).
Gates de Rust → sin verificar todavía (siguiente paso).