Files
fn_registry/dev/issues/0092-kanban-done-archive.md
T
egutierrez be8a61e724 docs(issues): kanban 0089-0093 reportes diarios + perf + archive
Archivos de issue para el trabajo de kanban de las ultimas iteraciones:

- 0089: tiempo maximo por columna con borde rojo (incluye followup popover
  con seleccion de unidad min/h/d/sem/mes).
- 0090: seleccion aleatoria por columna con animacion de ruleta. Ya con
  fix de no mostrar en columnas Done.
- 0092: archivo automatico para cards en columnas Done con +30 dias.
- 0093: reporte diario al pulsar el numero del dia en el calendario.

Los issues 0088 y 0091 ya estaban registrados.
2026-05-14 17:57:44 +02:00

66 lines
3.0 KiB
Markdown

---
id: "0092"
title: "kanban: archivo automatico para cards en columnas Done con +30 dias"
status: open
created_at: 2026-05-14
priority: medium
app: kanban
---
## Problema
Las columnas Done acumulan decenas de cards completadas que ya no participan en el trabajo activo. Lastran el board, gastan render (incluso con el split memoizado por perf) y obligan a scroll horizontal hasta el infinito sin aportar valor diario.
## Solucion
Archive `archived_at` por card (independiente de papelera `deleted_at`). Card archivada sale del board pero sigue en BD. Cajon "Hecho (archivo)" en el sidebar bajo Papelera con boton para sacar una card de vuelta a su columna Done.
### Migration
`apps/kanban/backend/migrations/012_card_archived.sql`:
```sql
ALTER TABLE cards ADD COLUMN archived_at TEXT;
```
`NULL` = card activa. ISO timestamp = card archivada.
### Backend
- `Card.ArchivedAt *string` json `archived_at`.
- `ListCardsWithTime` filtra `archived_at IS NULL`.
- `ArchiveCard(id)`, `UnarchiveCard(id)`, `ListArchivedCards()`.
- `AutoArchiveDoneOlderThan(d)`: UPDATE cards SET archived_at=now WHERE archived_at IS NULL AND deleted_at IS NULL AND column_id IN (SELECT id FROM columns WHERE is_done=1) AND id IN (SELECT card_id FROM card_column_history WHERE exited_at IS NULL AND entered_at < cutoff).
- `maybeAutoArchive(db)` con throttle `archiveSweepEvery = 30m` y `archiveAfter = 30d`. Disparado lazy desde `handleGetBoard`.
- Rutas:
- `GET /api/archive`
- `POST /api/cards/{id}/archive`
- `POST /api/cards/{id}/unarchive`
### Frontend
- Tipo `Card.archived_at: string | null`.
- `api.listArchive()` / `api.archiveCard(id)` / `api.unarchiveCard(id)`.
- `App` state `archive`, `archiveOpen`, `reloadArchive`, `handleArchiveCard`, `handleUnarchiveCard`. `reloadArchive` se llama tras login + tras archivar/desarchivar.
- UI: cajon "Hecho (archivo)" bajo "Papelera" en el sidebar. Toggle similar (`Badge` con conteo, `IconChevronRight/Down`). Solo boton "Restaurar" (`IconArrowBackUp`). No hay "purgar permanentemente" desde el archivo — solo borrado via card normal en su columna.
- `KanbanCard`: nuevo `Menu.Item` "Archivar" (`IconArchive` teal) condicionado a `isDone && onArchive` antes del divisor + Borrar.
### Tests
- Playwright `e2e/archive.spec.ts`: archivar manual via menu de card en columna done, asserta desaparece del board, abre cajon "Hecho", des-archiva, asserta vuelve al board.
- Auto-archive 30d sin test e2e (timing real no es practico). Cubierto por audit manual del flag `archiveAfter` y la query SQL.
## Criterios de aceptacion
- [ ] Cards con +30 dias en columna Done se auto-archivan tras la primera lectura del board (max 30m).
- [ ] Cajon "Hecho (archivo)" visible bajo Papelera. Muestra conteo.
- [ ] Boton "Restaurar" devuelve la card a su columna sin reset de historial.
- [ ] Menu de card en columna Done muestra "Archivar" para archivado manual.
- [ ] Cards archivadas NO aparecen en `/api/board`.
- [ ] E2E `archive.spec.ts` pasa.
## Rama / commits
- Rama: `issue/0092-kanban-done-archive`
- Merge `--no-ff` a master.