You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
taskbot/docs/2025-11-01-plan-refactor-te...

40 KiB

Plan de Refactor Técnico — 2025-11-01

Este documento describe un plan de refactor seguro, incremental y medible para estabilizar tipado, reducir duplicación, mejorar estructura y preparar la base para evolución a largo plazo. Se prioriza no añadir dependencias externas y mantener el comportamiento actual cubierto por tests.

Objetivos

  • Reducir duplicación (fechas/horas, validaciones, helpers de tests, cripto).
  • Endurecer tipado y contratos en TypeScript (mientras mantenemos compatibilidad).
  • Clarificar capas (utils compartidos, servicios, API web, UI SvelteKit, tests).
  • Estabilizar convenciones (UTC, formato SQLite, alias/imports, nombres).
  • Mantener comportamiento: cambios sin funcionalidad nueva, validados por tests.

Hallazgos clave (del diagnóstico inicial)

  • Archivos grandes:

    • apps/web/src/lib/ui/data/TaskItem.svelte ~911 LOC (punto caliente claro).
    • Varias páginas Svelte de 250335 LOC (AppShell, /app, /app/groups, etc.).
  • Duplicación evidente:

    • Formateo SQL-UTC con toISOString().replace('T',' ').replace('Z','') aparece 35+ veces en app y tests.
    • normalizeTime duplicado en API y page.server.
    • ymdUTC y addMonthsUTC definidas 3 veces en rutas ICS y también en tests.
    • sha256Hex reimplementado en múltiples tests pese a existir en src/utils/crypto.ts.
    • SimulatedResponseQueue replicado en varios tests.
  • Tipado/infra:

    • tsc falla en apps/web por $lib y ./$types (faltan tipos generados SvelteKit) y por DOM (navigator/document) y Bun types (HeadersInit/fetch).
    • apps/web/vite.config.ts incompatibilidad de tipos (UserConfig).
    • Errores “unknown” por resultados de SQLite (faltan tipos/casts).
    • Inconsistencias null vs undefined (p. ej., groupColor, whatsapp utils).
  • Cobertura mejorable:

    • webhook-manager (~32%), maintenance (~17%), contacts (~26%), onboarding (~30%), response-queue (~50%).
  • Organización:

    • Inyección de DB mediante propiedades estáticas dispersas; funcional pero frágil. Falta un “locator” central.

Fase 1 — Diagnóstico asistido (Completada)

Comandos ejecutados con éxito el 2025-11-01; a continuación se conservan para referencia y repetibilidad:

git ls-files '*.ts' '*.tsx' '*.svelte' | xargs wc -l | sort -nr | head -n 30
git grep -n "toISOString().replace('T', ' ').replace('Z', '')"
git grep -n "normalizeTime(" && git grep -n "ymdUTC(" && git grep -n "addMonthsUTC(" && git grep -n "isValidYmd("
git grep -n "sha256Hex(" && git grep -n "SimulatedResponseQueue"
bunx tsc --noEmit --pretty false
bun test --coverage

Resultados esperados después del refactor: disminución drástica de duplicados, tsc limpio por paquete, y cobertura estable o al alza.

Progreso

  • 2025-11-01:
    • Documento creado y versionado (commit a104b69).
    • Diagnóstico ejecutado (wc -l, git grep, tsc, coverage) y hallazgos consolidados en este documento.
    • Pendiente iniciar Lote 0 (Infra de typecheck): a la espera de revisar tsconfig raíz, apps/web/tsconfig y apps/web/vite.config.
  • 2025-11-02:
    • Lote 1 completado: util canónica de fechas/UTC creada (src/utils/datetime.ts) y wrapper web (apps/web/src/lib/server/datetime.ts); migración de rutas ICS y reemplazos en producción (hooks, login, complete/uncomplete, calendar tokens, dev-seed, response-queue, maintenance, group-sync, migrator).
    • Commits relevantes: f4f7d95, 882f5c9, c1f12ff, df27161, a0f35b8.
    • Tests verdes. Cobertura actual: 85.91% funciones / 82.12% líneas.
  • 2025-11-07:
    • Lote 0 completado: scripts typecheck:core y typecheck:web configurados y verificados. Se utiliza tsconfig.core.json para aislar el typecheck del core con reglas laxas, mientras que la web usa su propia configuración de SvelteKit. Los shims en src/types/shims.d.ts resuelven conflictos de tipos entre Bun y el DOM.
    • Verificación exitosa: bun run typecheck:core y bun run typecheck:web se ejecutan sin errores.
  • 2025-11-09:
    • Lote 2 completado: centralización de helpers de tests (sha256Hex, toIsoSql), unificación de SimulatedResponseQueue y helpers ICS (ymdUTC, addDays) en tests.
    • Commits relevantes: 77e318e, 1ad36ee, y este commit.
  • 2025-11-10:
    • Lote 3 completado: endurecimiento de tipos (noImplicitAny, exactOptionalPropertyTypes, strictNullChecks), centralización de normalizeTime y tipado ligero de SQLite en servicios; inclusión de servicios en typecheck; limpieza de as any en puntos clave.
    • Verificación: typecheck core/web limpios y tests verdes.
    • Lote 4 completado: ICS central y rutas homogéneas; rate limiting por token; títulos “Wtask.org Tareas Personal/Grupo/Agregado” y PRODID “-/Wtask.org//ICS 1.0//ES”; eventos de día completo; ETag/304 y Cache-Control; actualización de last_used_at solo en 200.
    • Commit relevante: 234053c.
    • Lote 5 completado: división de TaskItem en subcomponentes (SVGs a iconos, TaskDueBadge, TaskAssignees, TaskCompleteButton, TaskActions, TaskText, TaskMeta); sin cambios funcionales; tests verdes y typecheck web limpio.
    • Lote 5.5-a completado: ResponseQueue extraído (EvolutionClient, limpieza modular, parseo de metadata); sin cambios funcionales; commits: 1b7420e, 2032712.
    • Lote 5.5-c completado: TaskService extraído (display_code, reacción al completar, mapeadores); sin cambios funcionales; LOC actual en src/tasks/service.ts ≈ 621; commits: e3ec820, a72184f.
    • Lote 5.5-b completado: GroupSyncService modularizado (api.ts, repo.ts, cache.ts, reconcile.ts) y desacople de Onboarding A3 (publishGroupCoveragePrompt); umbral aplicado; tests y typecheck limpios; commits: 1b0d2ec, 0ce3ecb, 2f24806.
    • Lote 5.5-d completado: WebhookServer modularizado (/metrics, /health y bootstrap a src/http; handleMessageUpsert extraído a src/http/webhook-handler.ts); sin cambios funcionales; tests verdes; commits: 46bec52, 7189756, e430fc1.
    • Lote 6.0-6.2 completados: DB Locator mínimo, conexión en bootstrap con setDb y ruta única de DB (centralización y reexport en web); sin cambios funcionales; tests y typecheck limpios; commits: 9222242, 6196dba, 2669d42.
    • Lote 6.3 completado: adopción piloto con fallback en ResponseQueue y TaskService; añadido smoke test de fallback (tests/unit/locator.fallback.test.ts); tests y typecheck limpios; commit relevante: 77ad9d7.
    • Lote 6.4 completado: adopción progresiva de servicios al locator (fallback parámetro → .dbInstance → getDb()) en CommandService, RemindersService, MaintenanceService, AdminService y fachada de GroupSync; tests y typecheck limpios; commits: cd83455, f786ba8.
    • Lote 6.5 completado: limpieza de .dbInstance, añadido resetDb/clearDb en locator, migración de tests al locator; nota: ~8 tests frágiles en paralelo; en CI ejecutar la suite en un solo worker.
    • Estado: Lote 6 completado.

Estado actual (2025-11-10)

  • Fase 1 — Diagnóstico asistido: Completada.
  • Fase 2 — Plan de refactor por lotes: En curso.
    • Lote 0 — Infra de typecheck: Completado.
    • Lote 1 — Utilidades de fecha/hora y validaciones: Completado.
    • Lote 2 — Helpers de test y cripto: Completado.
    • Lote 3 — Tipos y endurecimiento suave: Completado.
    • Lote 4 — ICS central y rutas homogéneas: Completado.
    • Lote 5 — Svelte: dividir componentes grandes: Completado.
    • Lote 5.5 — Refactor de servicios grandes (god classes): Completado.
    • Lote 6 — DB Locator / DI ligera: Completado (PRs 6.06.5).
    • Lote 7 — Cobertura en módulos flojos: Pendiente.

Fase 2 — Plan de refactor por lotes (PRs pequeñas y seguras)

Cada lote incluye objetivo, cambios, métricas y comprobaciones. Mantener tests verdes en cada paso.

Lote 0 — Infra de typecheck (preparación) - Completado

  • Objetivo:
    • Separar el chequeo de tipos por paquete (core vs web) para aislar errores de SvelteKit/Bun/DOM.
  • Cambios:
    • Scripts: typecheck:core (tsc -p tsconfig.core.json), typecheck:web (apps/web: svelte-kit sync + tsc).
    • En raíz, excluir apps/web del typecheck general si hace falta hasta que esté sincronizado.
    • Ajustar lib/types: en core, definir tipos mínimos para HeadersInit/fetch si no se quiere añadir bun-types; en web, asegurar DOM y tipos SvelteKit (via svelte-kit sync).
    • Revisar apps/web/vite.config.ts para que encaje con tipos UserConfig.
  • Métricas:
    • bunx tsc --noEmit limpio por paquete.
    • Desaparecen errores $lib y ./$types tras svelte-kit sync.
  • Comprobaciones:
    • cd apps/web && bunx svelte-kit sync && bunx tsc --noEmit.

Lote 1 — Utilidades de fecha/hora y validaciones - Completado

  • Objetivo:
    • Centralizar y unificar: SQL-UTC, validadores YMD y HH:mm, utilidades ICS (ymdUTC, addMonthsUTC).
  • Cambios:
    • Crear helpers canónicos (por ejemplo, toIsoSqlUTC, isValidYmd, normalizeTime, ymdUTC, addMonthsUTC) en un módulo compartido (core o shared) y exportarlos también para web si aplica.
    • Reemplazar todas las ocurrencias del patrón toISOString().replace(...).
    • Unificar las 3 rutas ICS para usar las mismas utilidades.
  • Métricas:
    • git grep "toISOString().replace('T', ' ').replace('Z', '')" → 1 referencia (en el helper) o 0 si se encapsula internamente.
    • git grep "ymdUTC(" y "addMonthsUTC(" solo en helpers + imports.
  • Comprobaciones:
    • Tests ICS y API siguen verdes.

Lote 2 — Helpers de test y cripto - Completado

  • Objetivo:
    • Eliminar duplicación en tests.
  • Cambios:
    • Reemplazar implementaciones locales de sha256Hex por import desde src/utils/crypto.
    • Centralizar SimulatedResponseQueue en tests/helpers/queue.ts y reusarlo.
    • Unificar helpers de fechas en tests (toIsoSql, ymdUTC, addDays) en tests/helpers/dates.ts.
  • Métricas:
    • git grep -n "async function sha256Hex" en tests → 0.
    • git grep -n "SimulatedResponseQueue" → 1 implementación única.
  • Comprobaciones:
    • bun test --coverage estable o mejor.

Lote 3 — Tipos y endurecimiento suave - Completado

  • Objetivo:
    • Bajar ruido de TS con cambios mínimos, sin funcionalidad nueva.
  • Cambios:
    • Resolver undefined vs null en utils como groupColor/whatsapp.
    • Corregir HeadersInit/fetch en servicios (group-sync, webhook-manager, contacts) para encajar con tipos.
    • Añadir refinamientos y cheques donde TS marca “posiblemente undefined”.
    • Tipar resultados de SQLite .get()/.all() en tests y servicios.
  • Métricas:
    • bunx tsc --noEmit limpio en core.
  • Comprobaciones:
    • Tests verdes.

Lote 4 — ICS central y rutas homogéneas - Completado

  • Objetivo:
    • Consolidar construcción de ICS (escape, folding, etag) en un módulo central.
  • Cambios:
    • Mover ymdUTC/addMonthsUTC al módulo apps/web/src/lib/server/ics.ts y usarlos desde aggregate/group/personal.
    • Mantener helpers de escape/folding/etag en el mismo módulo.
  • Métricas:
    • git grep -n "function ymdUTC" y "function addMonthsUTC" solo en ics.ts.
  • Comprobaciones:
    • Tests ICS (tests/web/ics.*) verdes.

Lote 5 — Svelte: dividir componentes grandes

  • Objetivo:
    • Reducir complejidad de UI; mejorar mantenibilidad.
  • Cambios:
    • Dividir TaskItem.svelte (~911 LOC) en subcomponentes: Header/Status, Assignees, DueBadge, Actions, Metadata, etc.
    • Revisar AppShell y /app/+page para separar lógica de datos y presentación (stores y load).
  • Métricas:
    • TaskItem.svelte < 300 LOC.
  • Comprobaciones:
    • Pruebas E2E web verdes.

Lote 5.5 — Refactor de servicios grandes (god classes)

  • Objetivo general:

    • Reducir acoplamiento y responsabilidades múltiples en servicios grandes para mejorar testabilidad, DX y preparar Lote 6 (locator/DI) sin cambios funcionales.
    • Mantener APIs públicas y rutas de import estables, delegando a nuevos módulos internos.
  • Alcance y orden de PRs:

    1. PR 5.5-a — ResponseQueue (673 LOC)

      • Motivos: mezcla de repositorio (SQLite), backoff, envío HTTP (texto/reacciones), idempotencia, limpieza/retención, métricas y lógica de onboarding.
      • Cambios clave:
        • Extraer cliente Evolution (HTTP):
          • Nuevo módulo: src/clients/evolution.ts con buildHeaders(), sendText(payload), sendReaction(payload) y manejo de errores/logging.
        • Tipar metadata y parsers:
          • Tipo QueueMetadata = { kind: 'onboarding' | 'reaction'; ... }, helpers parseQueueMetadata(), isReactionJob().
        • Aislar limpieza/retención:
          • Nuevo módulo: src/services/queue/cleanup.ts con runCleanupOnce(), startCleanupScheduler(), stopCleanupScheduler().
        • ResponseQueue queda como orquestador (claim → enviar → marcar), delegando a EvolutionClient y Cleanup.
      • Archivos a consultar:
        • src/services/response-queue.ts (origen), src/utils/datetime.ts, src/services/metrics.ts, src/services/identity.ts, src/utils/whatsapp.ts, src/db/migrations/index.ts (esquema response_queue), tests tests/unit/services/response-queue.test.ts.
      • Métricas de aceptación:
        • src/services/response-queue.ts < 350 LOC.
        • No variación en defaults (MAX_ATTEMPTS, REACTIONS_MAX_ATTEMPTS, backoff).
        • Idempotencia de reacciones (24h) intacta.
      • Comprobaciones y comandos:
        bunx tsc -p tsconfig.core.json --noEmit --pretty false
        bun test --coverage
        git grep -n "sendReaction\\|sendText" src
        
    2. PR 5.5-c — TaskService (Completado; ~621 LOC)

      • Motivos: mezcla de creación (códigos display), queries de listado/contadores, reglas de negocio (claim/unassign), y reacción al completar.
      • Cambios clave:
        • Extraer generación de display_code:
          • Nuevo: src/tasks/display-code.ts con pickNextDisplayCode(db).
        • Extraer reacción al completar:
          • Nuevo: src/tasks/complete-reaction.ts con enqueueCompletionReactionIfEligible(db, taskId).
        • Extraer mapeos a DTO:
          • Nuevo: src/tasks/mappers.ts con mapRowToTask(), mapRowsToListItem().
        • TaskService.createTask/completeTask/list* delegan en estos helpers.
      • Archivos a consultar:
        • src/tasks/service.ts (origen), src/services/allowed-groups.ts, src/services/response-queue.ts (reacción), src/utils/whatsapp.ts, src/db/migrations/index.ts, tests tests/unit/tasks/*.test.ts, tests/unit/services/command.*.test.ts.
      • Métricas de aceptación:
        • src/tasks/service.ts < 500 LOC.
        • TTL y gating de reacciones sin cambios de comportamiento.
      • Comprobaciones y comandos:
        bunx tsc -p tsconfig.core.json --noEmit --pretty false
        bun test --coverage
        git grep -n "display_code" src
        
    3. PR 5.5-b — GroupSyncService (1310 LOC) — Completado

      • Motivos: agrupa API (Evolution), parseos, upsert/caché, scheduling, reconciliación de miembros, allowed-groups y publicación de onboarding.
      • Cambios clave:
        • Extraer acceso Evolution API:
          • Nuevo: src/services/group-sync/api.ts con fetchGroups(), fetchMembers(groupId) y parseos robustos.
        • Extraer repositorio/caché:
          • Nuevo: src/services/group-sync/repo.ts con upsertGroups(), ensureGroupExists(), getActiveCount(), cacheActiveGroups(), listActiveMemberIds(), getters/setters onboarding_prompted_at.
          • Nuevo: src/services/group-sync/cache.ts para la Map<string,string> y helpers.
        • Extraer reconciliación:
          • Nuevo: src/services/group-sync/reconcile.ts con reconcileGroupMembers(db, groupId, snapshot, nowIso?).
        • Mover publicación de mensajes de cobertura de alias a OnboardingService:
          • Añadir método en src/services/onboarding.ts: publishGroupCoveragePrompt(db, groupId, ratio, options).
        • GroupSyncService queda como fachada (APIs públicas y schedulers), delegando internamente.
      • Archivos a consultar:
        • src/services/group-sync.ts (origen), src/services/allowed-groups.ts, src/services/identity.ts, src/services/metrics.ts, src/utils/datetime.ts, src/db/migrations/index.ts, tests tests/unit/services/group-sync.*.test.ts.
      • Métricas de aceptación:
        • src/services/group-sync.ts ≈ 600700 LOC (fase 1), sin cambios funcionales.
        • Caché y métricas sin variaciones de semántica.
      • Comprobaciones y comandos:
        bunx tsc -p tsconfig.core.json --noEmit --pretty false
        bun test --coverage
        git grep -n "fetchAllGroups\\|participants" src/services/group-sync*
        
    4. PR 5.5-d — WebhookServer (665 LOC)

      • Motivos: src/server.ts mezcla handlers HTTP (/metrics, /health), bootstrap y manejo del webhook (message upsert).
      • Cambios clave:
        • Controladores HTTP dedicados:
          • Nuevo: src/http/metrics.ts (render y headers).
          • Nuevo: src/http/health.ts (cálculo payload; usa GroupSyncService.getSecondsUntilNextGroupSync()).
          • Nuevo: src/http/webhook-handler.ts con handleMessageUpsert(data).
          • Nuevo: src/http/bootstrap.ts con startServices() (webhook-manager, schedulers, queues, maintenance).
        • src/server.ts queda como wire-up (validateEnv → migrate → Bun.serve) y reexporta fachada WebhookServer para no romper tests.
      • Archivos a consultar:
        • src/server.ts (origen), src/services/webhook-manager.ts, src/services/response-queue.ts, src/services/maintenance.ts, src/services/reminders.ts, src/services/group-sync.ts, src/services/admin.ts, src/services/allowed-groups.ts, src/services/contacts.ts, src/services/command.ts.
      • Métricas de aceptación:
        • src/server.ts < 350 LOC.
        • Rutas/contratos HTTP y logs sin cambios de comportamiento.
      • Comprobaciones y comandos:
        bunx tsc -p tsconfig.core.json --noEmit --pretty false
        bun test --coverage
        git grep -n "handleRequest(\\|handleMessageUpsert" src
        
  • Métricas de aceptación (global Lote 5.5):

    • Tests verdes y sin cambios funcionales observables.
    • Reducción de LOC por fichero objetivo:
      • response-queue.ts < 350, tasks/service.ts < 500, group-sync.ts ≈ 600700, server.ts < 350.
    • bunx tsc --noEmit limpio en core.
    • Cobertura igual o superior en piezas extraídas (api/reconcile/cleanup/complete-reaction).
  • Riesgos y mitigación:

    • Dividir módulos puede introducir imports cíclicos:
      • Mitigación: módulos nuevos sin importar servicios de alto nivel; inyectar db como parámetro; reexportar desde fachada.
    • Cambios en logging o tiempos:
      • Mitigación: mantener mensajes/claves existentes; conservar defaults; validar en tests de integración.

Lote 6 — DB Locator / DI ligera

  • Objetivo:

    • Simplificar inyección de DB en runtime y tests.
  • Cambios:

    • Crear un “dbLocator” (getDb/setDb/withDb) central y migrar servicios a usarlo progresivamente, manteniendo compatibilidad con propiedades estáticas mientras dura la transición.
    • Unificar resolveDbAbsolutePath entre core y web (una sola fuente, con reexport en web para no romper imports).
  • Métricas:

    • Sin cambios de comportamiento; tests de servicios verdes.
  • PRs propuestos y archivos a tocar:

    PR 6.0 — Locator mínimo (infraestructura, sin usos en servicios) — Completado

    • Nuevos archivos:
      • src/db/locator.ts — export { setDb, getDb, withDb }.
      • tests/unit/db/locator.test.ts — pruebas básicas del locator.
    • Cambios en docs:
      • Este documento (apartado de Lote 6).

    PR 6.1 — Conexión en bootstrap (setDb al arrancar) — Completado

    • Archivos a modificar:
      • src/http/bootstrap.ts — importar setDb desde src/db/locator y llamarlo en el arranque (cuando se abra la DB).
      • src/server.ts — si es quien abre la DB, llamar setDb(db) justo después de crearla (o delegar en bootstrap).
    • Servicios: sin cambios (compatibilidad total con dbInstance estático).

    PR 6.2 — Ruta única de DB (centralizar resolveDbAbsolutePath) — Completado

    • Nuevos archivos:
      • src/env/db-path.ts — export function resolveDbAbsolutePath(filename = 'tasks.db'): string.
    • Archivos a modificar:
      • apps/web/src/lib/server/env.ts — reexportar desde src/env/db-path.ts para mantener compatibilidad (sin cambios de API pública).
      • src/server.ts o src/http/bootstrap.ts — actualizar imports a src/env/db-path.
    • Comprobaciones esperadas:
      • bunx tsc -p tsconfig.core.json --noEmit
      • bun test --coverage

    PR 6.3 — Adopción piloto con fallback (2 servicios) — Completado

    • Archivos a modificar:
      • src/services/response-queue.ts — usar (ResponseQueue as any).dbInstance ?? getDb().
      • src/tasks/service.ts — usar (TaskService as any).dbInstance ?? getDb().
    • Tests a ajustar (si aplica):
      • tests/unit/services/response-queue.test.ts — asegurar setDb(memdb) en beforeAll cuando no se inyecte dbInstance.
      • tests/unit/tasks/*.test.ts — idem.
    • Comprobaciones esperadas:
      • bunx tsc -p tsconfig.core.json --noEmit
      • bun test --coverage

    PR 6.4 — Adopción progresiva (resto de servicios principales) — Completado

    • Archivos a modificar (por tandas pequeñas):
      • src/services/group-sync/*.ts (api.ts, repo.ts, cache.ts, reconcile.ts) — fallback a getDb().
      • src/services/command.ts, src/services/reminders.ts, src/services/maintenance.ts, src/services/admin.ts, src/services/contacts.ts, src/services/webhook-manager.ts — fallback a getDb().
    • Tests a ajustar según servicio:
      • tests/unit/services/**/*.test.ts — añadir setDb(memdb) donde no se use dbInstance explícita.
    • Comprobaciones esperadas:
      • bunx tsc -p tsconfig.core.json --noEmit
      • bun test --coverage

    PR 6.5 — Limpieza final — Completado

    • Hecho:
      • Eliminadas propiedades estáticas dbInstance de servicios migrados a locator.
      • Añadidos resetDb/clearDb en src/db/locator.ts para tests.
      • Migrados tests a setDb(...) y resetDb()/clearDb(); se observa flakiness en ejecución paralela en ~8 tests. Recomendación: ejecutar la suite en un solo worker en CI.

Lote 7 — Cobertura en módulos flojos

  • Objetivo:
    • Aumentar cobertura en módulos con lógica y baja cobertura (webhook-manager, maintenance, contacts, onboarding, response-queue).
  • Cambios:
    • Añadir pruebas de ramas de error y caminos menos transitados.
  • Métricas:
    • Cobertura de líneas > 80% en esos módulos.

Convenciones acordadas

  • Fechas/horas:

    • Persistir en UTC en SQLite con formato ISO-SQL “YYYY-MM-DD HH:MM:SS[.SSS]”.
    • Un solo helper para serializar/deserializar timestamps.
    • Validadores canónicos: YMD (YYYY-MM-DD), HH:mm (0023:0059).
  • Tipado:

    • TS estricto por módulos de forma incremental: strict, noImplicitAny, noUncheckedIndexedAccess, exactOptionalPropertyTypes (activación progresiva).
    • Resultados SQLite tipados (interfaces pequeñas y casts controlados).
  • Organización:

    • Helpers compartidos (fecha/validaciones/cripto) en módulo único (o shared).
    • Tests reusan helpers de tests/helpers.
  • SvelteKit:

    • svelte-kit sync antes de tsc para generar tipos.
    • Rutas ICS homogéneas con helpers de lib/server/ics.

Riesgos y mitigación

  • Fechas/UTC: posibles regresiones en límites y recordatorios.
    • Mitigación: snapshots/fixtures antes/después de serializaciones, comparar salidas ICS.
  • DI de DB: transición puede generar inconsistencias si se mezcla estático/locator.
    • Mitigación: migración gradual y adaptador de compatibilidad temporal.
  • Tipado estricto: ruido inicial.
    • Mitigación: endurecer flags por paquete/módulo en varias PRs pequeñas.

Métricas de aceptación por lote

  • Tests verdes y sin cambios funcionales.
  • Reducción de duplicados medible (git grep antes/después).
  • bunx tsc --noEmit limpio en el ámbito del lote.
  • Cobertura estable o en subida en módulos afectados.

Siguientes pasos prácticos

  1. Estabilizar typecheck (Lote 0): Completado.
  2. Unificar fechas/validaciones (Lote 1): Completado.
  3. Centralizar helpers de tests y cripto (Lote 2): Completado.
  4. Endurecer tipos en core (Lote 3): Completado.
  5. Consolidar ICS (Lote 4): Completado.
  6. Dividir TaskItem y revisar AppShell (Lote 5): Completado.
  7. DI ligera para DB (Lote 6).
  8. Aumentar cobertura en módulos flojos (Lote 7).
  9. Documentación exhaustiva (Fase D): plan y PRs D0D6.
  10. Internacionalización (Fase I): plan y PRs I0I7.

Información adicional a recopilar (para Lote 0)

  • tsconfig.json (raíz)
  • apps/web/tsconfig.json
  • apps/web/vite.config.ts

Con estos 3 archivos podremos definir cambios mínimos para tener un typecheck limpio por paquetes sin introducir dependencias externas.

Fase D — Documentación (nueva)

El objetivo de esta fase es frenar la “entropía documental” actual, ofrecer una narración clara para quien llega nuevo y, a la vez, dejar una base sólida para seguir evolucionando el sistema sin añadir deuda técnica.

Principios

  • Markdown en /docs como fuente de verdad; sin dependencias nuevas; build opcional más adelante.
  • Documentación estructurada por qué quiere hacer la persona lectora (evaluar, desplegar, operar, contribuir), no por “lista de archivos existentes”.
  • README raíz orientado a adopción (pitch, casos de uso, requisitos), con enlaces claros a la documentación detallada.
  • Documentación “v2” claramente separada de planes históricos y documentos de trabajo.
  • Verificación simple en CI para comprobar “completitud” (p. ej., grep de variables de entorno usadas vs documentadas).

D0: Reset estructural y guía de estilo

Objetivo: redefinir la estructura de documentación y marcar qué es canónico vs histórico, sin perder información.

Cambios:

  • README raíz (del repo):

    • Reescribirlo con foco en:
      • Tagline y pitch corto (qué resuelve, para quién).
      • Casos de uso y “no es para ti si…”.
      • Requisitos para desplegarlo (Evolution API, hosting, etc.).
      • Vista de alto nivel de cómo funciona.
      • Enlace claro a docs/ (Quickstart, Guía de uso, Arquitectura, etc.).
  • Definir documentos canónicos en docs/ (columna vertebral “v2”):

    • docs/README.md — índice general y guía de estilo.
    • docs/overview.md — visión general y flujos clave (evaluación).
    • docs/quickstart.md — de cero a bot funcionando (dev/prod).
    • docs/config/env.md — referencia única de variables de entorno.
    • docs/usage/commands.md — uso por WhatsApp (comandos).
    • docs/usage/web.md — uso de la interfaz web.
    • docs/architecture.md — arquitectura lógica y DB locator.
    • docs/operations.md — operación, métricas, backups, health/metrics.
    • docs/contributing.md — cómo tocar el código sin romper convenciones.
  • Crear un área de documentación histórica:

    • Nuevo directorio: docs/legacy/ (o similar).
    • Mover allí:
      • Planes antiguos (plan-*.md, *-plan.md) que ya no encajen con el estado actual.
      • Documentos de trabajo y notas de diseño que han quedado superadas por este plan.
    • Añadir docs/legacy/README.md explicando que:
      • Son documentos históricos, útiles como contexto, pero no representan el estado actual ni la decisión vigente.
  • Guía de estilo mínima en docs/README.md:

    • Idioma principal: español para texto narrativo; identificadores y nombres técnicos en inglés.
    • Convenciones de nombres de archivos (kebab-case, sufijos como -guide, etc.).
    • Expectativas por documento (público objetivo y nivel técnico).

Métricas de aceptación:

  • README raíz reescrito y enlazando a la nueva estructura.
  • docs/README.md actualizado con el índice “v2” y la guía de estilo.
  • Todos los planes/documentos obsoletos movidos a docs/legacy/ y etiquetados como históricos.

D1: Referencia de variables de entorno

Objetivo: consolidar una tabla única y fiable de configuración por entorno.

Cambios:

  • Construir un inventario completo:

    • Partir del git grep process.env (ya recogido en este documento).
    • Complementar con las variables definidas en .env.example.
    • Identificar:
      • variables usadas en código pero ausentes en .env.example,
      • variables presentes en .env.example que ya no se usan.
  • Crear docs/config/env.md:

    • Tabla con columnas:
      • VARIABLE | Descripción | Tipo | Por defecto | Obligatoria | Ámbito (core/web) | Sensible (sí/no).
    • Sección explicando:
      • cómo se cargan (ficheros .env vs entorno),
      • qué variables son imprescindibles para arrancar,
      • particularidades en test (variables que los tests fuerzan o suponen).
  • Sincronizar .env.example con la tabla:

    • Mismas variables.
    • Comentarios alineados con la descripción de docs/config/env.md.
    • README raíz solo enumera un subconjunto (“configuración esencial”) y enlaza a este documento para el resto.

Métricas de aceptación:

  • docs/config/env.md cubre el 100% de las variables utilizadas en código.
  • .env.example sin variables huérfanas ni faltantes respecto al inventario.
  • Potencial check de CI: script simple que compare nombres de variables entre código, env.md y .env.example.

D2: Quickstart e instalación

Objetivo: permitir que alguien nuevo pase de “clonar el repo” a “tengo el bot funcionando” sin leer todo el resto.

Cambios:

  • Crear/actualizar docs/quickstart.md:

    • Requisitos:
      • Bun/Node versión recomendada.
      • Instancia de Evolution API.
      • Almacenamiento para SQLite.
    • Pasos:
      • Clonar repositorio e instalar dependencias.
      • Copiar .env.example y rellenar variables mínimas.
      • Arrancar en desarrollo (core + web).
      • Arrancar en producción (comandos de build + start).
    • “Happy path”:
      • ejemplo de mensaje de WhatsApp para crear una tarea,
      • cómo verla en la web (/app),
      • cómo confirmar que /health y /metrics responden.
  • Alinear README raíz con este quickstart:

    • Sección “Instalación rápida” condensando los pasos principales.
    • Enlace explícito a docs/quickstart.md para detalles.

Métricas de aceptación:

  • Una persona que no conoce el proyecto puede seguir docs/quickstart.md en una máquina limpia y terminar con:
    • webhook recibiendo eventos,
    • tareas visibles en /app,
    • métricas en /metrics.

D3: Uso (web + comandos)

Objetivo: documentar claramente la experiencia de uso, separando canales (WhatsApp vs web) y evitando duplicidad.

Cambios:

  • Reorganizar la documentación de uso actual en dos archivos:

    • docs/usage/commands.md:

      • Basado en docs/USER_GUIDE.md y docs/commands-inventory.md.
      • Contenido:
        • prefijo de comandos y principios (DM vs grupo, fechas, rate limit),
        • catálogo de comandos con alias, parámetros y ejemplos,
        • notas sobre:
          • interpretación de fechas (“hoy”, “mañana”, YYYY-MM-DD),
          • menciones reales vs tokens @número,
          • comportamiento en grupo vs DM,
        • sección de administración (/admin…).
    • docs/usage/web.md:

      • Basado en plan-diseno-web.md, plan-web-fases.md y el estado actual de la UI.
      • Contenido:
        • estructura de /app (lista de tareas, grupos, preferencias),
        • flujo típico de uso desde web (reclamar/soltar, editar, completar),
        • relación entre lo que ves en WhatsApp y lo que ves en la web,
        • vistas de calendario/ICS y cómo se consumen.
  • Dejar docs/USER_GUIDE.md como entrada que redirige:

    • Puede convertirse en un índice breve que apunte a usage/commands.md y usage/web.md, o bien moverse a docs/legacy/ cuando la nueva estructura esté madura.

Métricas de aceptación:

  • No hay duplicación significativa de contenido entre README, USER_GUIDE, usage/commands y usage/web.
  • Los ejemplos de comandos están actualizados y probados manualmente (al menos los principales).

D4: Operaciones y despliegue

Objetivo: facilitar la vida a quien opera Taskbot en producción (observabilidad, mantenimiento, CI/CD).

Cambios:

  • Crear/actualizar docs/operations.md:

    • Basado en operations.md, metrics-plan.md, CI-CD-PLAN.md y docs/grafana/.
    • Contenido:
      • Despliegue:
        • opciones típicas (proceso único vs supervisado por systemd, contenedores, etc.),
        • recomendaciones de recursos y almacenamiento,
        • interacción con Evolution API (timeouts, health checks).
      • Migraciones y base de datos:
        • cómo y cuándo se ejecutan migraciones,
        • política de WAL y PRAGMAs más importantes,
        • estrategias de backup/restore de SQLite.
      • Observabilidad:
        • uso de /health (qué comprueba, señales de fallo),
        • uso de /metrics (Prometheus/JSON, flags de configuración),
        • referencia al dashboard de Grafana (docs/grafana/taskbot-metrics.json): qué gráficos hay y qué significan.
      • Schedulers y tareas periódicas:
        • sincronización de grupos,
        • recordatorios,
        • limpieza de cola de respuestas,
        • cómo ajustar intervalos y qué implicaciones tienen.
  • Conectar con variables de entorno:

    • Enlazar a docs/config/env.md para cada opción relevante (p. ej. GROUP_SYNC_INTERVAL_MS, RQ_*, METRICS_*).

Métricas de aceptación:

  • Operador externo puede entender:
    • qué mirar en caso de problemas (health/metrics/logs),
    • cómo hacer backup/restore sin corromper la DB,
    • cómo cambiar la frecuencia de tareas periódicas con seguridad.

D5: Arquitectura y DB

Objetivo: ofrecer una visión clara de cómo está organizado el sistema internamente, especialmente tras el refactor (servicios extraídos, DB locator, ICS central).

Cambios:

  • Consolidar docs/architecture.md:

    • Integrar/actualizar contenido de architecture.md, overview.md, database.md y este propio plan.
    • Contenido:
      • Componentes principales:
        • servidor HTTP (WebhookServer y handlers /webhook, /health, /metrics),
        • servicios de dominio (TaskService, ResponseQueue, GroupSync, Reminders, Admin…),
        • cola de respuestas y cliente Evolution,
        • app web SvelteKit.
      • DB Locator:
        • motivación,
        • API básica (getDb/setDb/withDb),
        • cómo se usa en servicios y tests.
      • Flujos clave:
        • mensaje entrante → comando → creación/actualización de tarea → encolado de respuesta/reacción,
        • sincronización de grupos y membresías,
        • recordatorios.
      • Base de datos:
        • tablas principales (tasks, task_assignments, groups, group_members, response_queue, user_preferences…),
        • invariantes importantes,
        • decisiones de diseño (WAL, migraciones up-only).
  • Mantener docs/database.md como detalle de esquema:

    • Puede centrarse en:
      • descripción tabla a tabla,
      • índices relevantes,
      • ejemplos de consultas típicas,
    • enlazado desde docs/architecture.md.

Métricas de aceptación:

  • Contributors nuevos pueden entender dónde “colgar” código nuevo (por ejemplo, un nuevo servicio, una nueva tabla o un nuevo comando).
  • Este plan de refactor técnico se percibe como coherente con la arquitectura documentada (no como un documento separado y divergente).

D6: Contribución y ADRs

Objetivo: ayudar a futuras personas contribuidoras (incluido tú mismo “del futuro”) a cambiar el sistema sin romper las convenciones ni repetir debates ya resueltos.

Cambios:

  • Crear/actualizar docs/contributing.md:

    • Contenido:
      • cómo montar entorno de desarrollo (dependencias, comandos básicos),
      • cómo ejecutar:
        • typecheck core (bun run typecheck:core),
        • typecheck web (bun run typecheck:web),
        • tests y cobertura (bun test --coverage),
      • convenciones de código:
        • UTC y formato de timestamps en SQLite,
        • uso de helpers centralizados (datetime, crypto, helpers de test),
        • tipos estrictos en TS (flags activados y expectativas),
        • uso del DB locator.
      • criterios para abrir PRs:
        • tests verdes,
        • sin cambios funcionales en lotes que se declaran “refactor internos”,
        • cuándo y cómo añadir un ADR.
      • referencia rápida a how-tos existentes:
        • how-to/adding-command.md,
        • how-to/adding-migration.md,
        • how-to/adjusting-group-sync.md,
        • how-to/adding-env.md.
  • Consolidar ADRs:

    • Mantener docs/adr/*.md como registro de decisiones de arquitectura.
    • Añadir ADRs nuevos cuando:
      • se tomen decisiones de largo plazo (p. ej., i18n, políticas de rate limiting, cambios de almacenamiento).
    • Desde docs/contributing.md, explicar:
      • cuándo merece la pena un ADR,
      • cómo estructurarlo (título, contexto, decisión, consecuencias).

Métricas de aceptación:

  • Contributors pueden:
    • saber qué comandos ejecutar antes de abrir PR,
    • entender las decisiones ya tomadas (UTC, DB locator, ICS, estructura de servicios),
    • no tener que “descubrirlas” leyendo código o este plan.

Orden recomendado de ejecución para Fase D

  1. Ejecutar D0 (reset estructural):

    • nuevo README raíz orientado a adopción,
    • índice v2 en docs/README.md,
    • movimiento de documentos antiguos a docs/legacy/.
  2. Ejecutar D1 (env) y D2 (quickstart) en paralelo:

    • cerrar la historia de “cómo configuro esto” y “cómo lo echo a andar”.
  3. Completar D3 (uso commands/web) apoyándose en la guía de usuario actual, reorganizando sin perder contenido útil.

  4. Redondear con D4 (operaciones) y D5 (arquitectura/DB) usando este plan de refactor como referencia.

  5. Cerrar con D6 (contribución+ADRs), conectando:

    • decisiones técnicas ya tomadas,
    • how-tos existentes,
    • y el pipeline de typecheck/tests.

Esta Fase D se coordina con los lotes técnicos previo/posteriores:

  • depende de que el estado del core/web esté relativamente estable (Lotes 06),
  • y sirve como preparación explícita antes de acometer cambios más invasivos (i18n, nuevos comandos, cambios de esquema), reduciendo el riesgo de deuda técnica futura.

Fase I — Internacionalización (nueva)

  • Principios:

    • Sin dependencias externas: diccionarios JSON + helper t() con plantillas {var}.
    • en-US como base del código; es-ES como primera localización.
    • Locale configurable por ENV y, en web, preferencia por usuario (con fallback).
  • PR I0: Inventario y glosario

    • Auditoría de textos visibles (servicios, UI, errores “para usuario”, títulos ICS).
    • Glosario EN/ES y convenciones de keys (scope.key).
    • Aceptación: listado consolidado.
  • PR I1: Normalización de identificadores a inglés

    • Renombrar funciones/variables/módulos que sigan en español (sin tocar textos visibles).
    • Aceptación: grep de identificadores no ingleses → 0 o lista de excepciones (nombres propios).
  • PR I2: Infra i18n mínima (core)

    • Helper t(locale, key, params) y carga de diccionarios.
    • ENV APP_LOCALE y orden de resolución (env → usuario → default).
    • Aceptación: conmutación en 12 mensajes de ejemplo entre en-US/es-ES.
  • PR I3: Externalización de mensajes en servicios

    • WhatsApp/CLI/respuestas de comandos → keys + params.
    • Mantener es-ES como referencia y crear en-US equivalentes.
    • Aceptación: tests de comandos verdes en ambos locales; 0 strings hardcoded en servicios.
  • PR I4: UI web (SvelteKit)

    • Carga de diccionarios por ruta/layout, helper en frontend, marcadores para traducciones faltantes.
    • Preferencia de idioma por usuario y fallback Accept-Language.
    • Aceptación: cambiar idioma desde preferencias refleja cadenas principales.
  • PR I5: Formatos y convenciones por locale

    • Fechas/números con Intl; labels de días; ymd→dmy solo en vistas.
    • ICS: título/PRODID localizables; contenido sigue en UTC.
    • Aceptación: pruebas de formateo y snapshots actualizados.
  • PR I6: Logs y métricas

    • Política: logs en inglés estable; mensajes de usuario traducibles; métricas/labels estáticos.
    • Aceptación: política documentada y aplicada.
  • PR I7: QA i18n en CI

    • Comprobador: claves sin traducción, claves huérfanas, placeholders inválidos.
    • Smoke tests en en-US y es-ES (web y comandos básicos).
    • Aceptación: CI bloquea claves faltantes.
  • Orden recomendado:

    1. Completar Lote 7 (cobertura) para congelar comportamiento.
    2. PRs D0D6 (documentación) en paralelo donde sea posible.
    3. PRs I0I7 (i18n) en tandas pequeñas, con tests en ambos locales.