issue(0128): kanban file attachments — PR draft en dataforge/kanban#1
This commit is contained in:
@@ -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/<card_id>/<file_id>__<safe_filename>`.
|
||||||
|
- `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/<id>`).
|
||||||
|
- Render grid: imagenes en `<Image>` 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 `` (imagen) o `[name](url)` (resto).
|
||||||
|
- `CardForm` (editor desc): `<Dropzone>` 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 `<Image fit="contain" maw={200}>`. 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`.
|
||||||
Reference in New Issue
Block a user