diff --git a/dev/issues/0128-kanban-files-attachments.md b/dev/issues/0128-kanban-files-attachments.md new file mode 100644 index 00000000..b2654640 --- /dev/null +++ b/dev/issues/0128-kanban-files-attachments.md @@ -0,0 +1,91 @@ +--- +id: "0128" +title: "kanban: adjuntar archivos (drag&drop desc/chat + tab Archivos)" +status: in_progress +type: feature +domain: + - apps-tools + - frontend +scope: app +priority: media +depends: [] +blocks: [] +related: [] +created: 2026-05-27 +updated: 2026-05-27 +tags: [kanban, files, upload, sqlite, mantine] +--- + +# 0128 — kanban: adjuntos de archivos en cards + +Hoy el tab "Archivos" del `CardEditPanel` esta disabled ("Proximamente"). Se habilita con tres vias de upload y vista agregada estilo `CardLinksPanel`. + +## Alcance + +- Adjuntar archivos a una card desde: + 1. Drag&drop en el editor de descripcion → inserta markdown ref. + 2. Drag&drop / boton paperclip en el chat → mensaje con ref. + 3. Boton "Subir" en el tab Archivos (sin embed). +- Render inline en chat y descripcion: + - Imagenes (png/jpg/webp/gif): thumb clickable. + - PDFs, excel, csv, txt, resto: chip con icono + nombre + size. +- Tab "Archivos" agrega: + - Uploads directos sobre la card. + - Refs detectadas en `description`. + - Refs detectadas en mensajes del chat. +- MIME soportado: cualquiera. Limite 10 MB por archivo. Sin quota agregada. +- Borrado: cualquier usuario del board borra. Soft delete (`deleted_at`). Cron purge fuera de scope. + +## Backend + +- Migracion `backend/migrations/014_card_files.sql` (aditiva, idempotente): + - `card_files(id TEXT PK, card_id TEXT FK, uploader_id TEXT, filename TEXT, mime TEXT, size INTEGER, stored_path TEXT, source TEXT, created_at TEXT, deleted_at TEXT NULL)` + - `source IN ('upload','description','chat')` — informativo, no condiciona logica. + - Index `(card_id, deleted_at)`. +- Endpoints nuevos en `backend/files.go`: + - `POST /api/cards/{id}/files` multipart, max 10MB, devuelve metadata. + - `GET /api/cards/{id}/files` lista activa (deleted_at IS NULL). + - `GET /api/files/{id}` sirve binario con Content-Type + Content-Disposition. + - `DELETE /api/files/{id}` soft delete. +- Storage en disco: `apps/kanban/uploads//__`. +- `apps/kanban/uploads/` gitignored en el sub-repo. + +## Frontend + +- `CardFilesPanel.tsx` (replica de `CardLinksPanel`): + - Carga `/api/cards/{id}/files` al montar. + - Detecta refs en `description` + mensajes (regex sobre `/api/files/`). + - Render grid: imagenes en `` Mantine como thumb 120px, resto como chip con `IconFile*` segun MIME. + - Boton borrar por archivo (confirm modal). + - Boton "Subir" → input file → POST. +- `CardChatPanel`: dropzone + boton paperclip. Tras upload, inyecta mensaje con `![](url)` (imagen) o `[name](url)` (resto). +- `CardForm` (editor desc): `` Mantine envolviendo el textarea. Tras upload, insertar ref en posicion del cursor. +- Render inline en chat: parser markdown ya existente (revisar) o componente simple. Imagenes via ``. Resto chip. + +## Tests + +- `e2e/files_smoke.sh` (bash): + - Login. + - Crear card. + - POST imagen 1KB → asserts 200 + JSON con id. + - GET lista archivos → asserts 1 elemento. + - GET binario → asserts content-type image/png. + - DELETE → asserts 204. + - GET lista → asserts 0 elementos. + +## Versionado + +- Bump `apps/kanban/app.md` 0.4.0 → 0.5.0. +- Anadir entrada en `## Capability growth log`: + `v0.5.0 (2026-05-27) — adjuntos de archivos por card (issue 0128): drag&drop en desc/chat, tab Archivos agregado, soft delete, 10MB max`. + +## DoD + +- [ ] Migracion aplicada, schema verificable con `sqlite3 operations.db ".schema card_files"`. +- [ ] 4 endpoints responden segun spec (testeados con curl). +- [ ] Tab Archivos lista uploads + refs. +- [ ] Drag&drop funciona en desc y en chat. +- [ ] Render inline de imagenes en chat y desc. +- [ ] Soft delete oculta el archivo de la lista y los embeds rompen (esperado). +- [ ] e2e smoke pasa. +- [ ] PR draft a `dataforge/kanban`.