3 Commits

Author SHA1 Message Date
egutierrez fec8ebd4ec merge: origin/master into local 2026-05-27 18:48:28 +02:00
egutierrez f5f05e4624 chore: auto-commit (2 archivos)
- dev/issues/completed/0126-pipeline-launcher-migration-003.md
- dev/proposals_e2e_checks_0121/pipeline_launcher.yaml

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 18:48:14 +02:00
egutierrez 532f3d0ea8 issue(0128): kanban file attachments — PR draft en dataforge/kanban#1 2026-05-27 10:53:13 +02:00
4 changed files with 174 additions and 74 deletions
@@ -1,53 +0,0 @@
---
id: "0126"
title: "pipeline_launcher: aplicar migracion 003_logs a operations.db"
status: pendiente
type: bugfix
domain:
- apps-infra
scope: app
priority: baja
depends: []
blocks: []
related:
- "0121a"
created: 2026-05-19
updated: 2026-05-19
tags: [pipeline_launcher, migrations, db]
---
# 0126 — pipeline_launcher migracion 003_logs
Origen: detectado lateral por `fn-recopilador design-e2e apps/pipeline_launcher` en 0121a.
## Problema
`apps/pipeline_launcher/operations.db` tiene migraciones 001+002 aplicadas pero falta 003_logs (definida en `fn_operations/migrations/003_logs.sql`). La tabla `logs` no existe → cualquier feature futuro de logging in-app falla silencioso.
Investigacion necesaria: por que no aplico? Probable que pipeline_launcher use version vieja del codigo `fn_operations` o tenga su propio applier que no lee la migracion 003.
## Decision
1. Diagnosticar por que 003 no aplico (busca `applyMigrations` en codigo de pipeline_launcher o si usa la libreria `fn_operations`).
2. Aplicar 003 a la BD existente preservando datos.
3. Si pipeline_launcher tiene applier custom, hacerlo consumir las migraciones del registry padre via `embed.FS`.
## Tareas
1. Inspeccionar `apps/pipeline_launcher/{main.go, db.go, store.go}` para localizar applier.
2. Aplicar `003_logs.sql` manualmente: `sqlite3 apps/pipeline_launcher/operations.db < fn_operations/migrations/003_logs.sql`.
3. Si custom applier: refactor para consumir migraciones del padre.
4. Verificar con `PRAGMA table_info(logs);` que la tabla existe.
5. Actualizar propuesta 0121a `pipeline_launcher.yaml` removiendo check `ops_schema_complete` (ya no aplica).
## Acceptance
- [ ] `sqlite3 apps/pipeline_launcher/operations.db "PRAGMA table_info(logs);"` devuelve columnas esperadas.
- [ ] Reaplicar 003 sobre BD ya migrada NO falla (idempotente — `CREATE TABLE IF NOT EXISTS`).
- [ ] Tests de pipeline_launcher pasan (si existen).
## DoD
- **Donde**: sqlite3 introspeccion + log de la app si tiene.
- **Latencia**: invisible al usuario.
- **Onboarding**: "Si una app tiene operations.db, las migraciones del registry padre se aplican al arrancar — verificar con `PRAGMA table_info`."
@@ -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 `![](url)` (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`.
@@ -0,0 +1,78 @@
---
id: "0126"
title: "pipeline_launcher: aplicar migracion 003_logs a operations.db"
status: completado
type: bugfix
domain:
- apps-infra
scope: app
priority: baja
depends: []
blocks: []
related:
- "0121a"
created: 2026-05-19
updated: 2026-05-27
tags: [pipeline_launcher, migrations, db]
---
# 0126 — pipeline_launcher migracion 003_logs
Origen: detectado lateral por `fn-recopilador design-e2e apps/pipeline_launcher` en 0121a.
## Problema
`apps/pipeline_launcher/operations.db` tiene migraciones 001+002 aplicadas pero falta 003_logs (definida en `fn_operations/migrations/003_logs.sql`). La tabla `logs` no existe → cualquier feature futuro de logging in-app falla silencioso.
Investigacion necesaria: por que no aplico? Probable que pipeline_launcher use version vieja del codigo `fn_operations` o tenga su propio applier que no lee la migracion 003.
## Decision
1. Diagnosticar por que 003 no aplico (busca `applyMigrations` en codigo de pipeline_launcher o si usa la libreria `fn_operations`).
2. Aplicar 003 a la BD existente preservando datos.
3. Si pipeline_launcher tiene applier custom, hacerlo consumir las migraciones del registry padre via `embed.FS`.
## Tareas
1. Inspeccionar `apps/pipeline_launcher/{main.go, db.go, store.go}` para localizar applier.
2. Aplicar `003_logs.sql` manualmente: `sqlite3 apps/pipeline_launcher/operations.db < fn_operations/migrations/003_logs.sql`.
3. Si custom applier: refactor para consumir migraciones del padre.
4. Verificar con `PRAGMA table_info(logs);` que la tabla existe.
5. Actualizar propuesta 0121a `pipeline_launcher.yaml` removiendo check `ops_schema_complete` (ya no aplica).
## Acceptance
- [ ] `sqlite3 apps/pipeline_launcher/operations.db "PRAGMA table_info(logs);"` devuelve columnas esperadas.
- [ ] Reaplicar 003 sobre BD ya migrada NO falla (idempotente — `CREATE TABLE IF NOT EXISTS`).
- [ ] Tests de pipeline_launcher pasan (si existen).
## DoD
- **Donde**: sqlite3 introspeccion + log de la app si tiene.
- **Latencia**: invisible al usuario.
- **Onboarding**: "Si una app tiene operations.db, las migraciones del registry padre se aplican al arrancar — verificar con `PRAGMA table_info`."
## Resolucion (2026-05-27)
Diagnostico (desde aurgi-pc; BD afectada vive en home-wsl):
1. `apps/pipeline_launcher` importa `fn-registry/fn_operations` y abre la BD via `ops.Open()` (ver `apps/pipeline_launcher/app/model.go:44`).
2. `fn_operations.Open` (`fn_operations/db.go:35`) llama a `migrate()` que delega en `ApplyVersionedMigrations` (`fn_operations/migrate.go:17`).
3. `ApplyVersionedMigrations` (`functions/infra/sqlite_apply_versioned_migrations.go`) lee `schema_migrations`, ordena por version numerica y aplica las pendientes en transaccion. NO existe applier custom en pipeline_launcher.
Conclusion: el codigo es correcto. La BD afectada quedo en version=2 porque pipeline_launcher no se ha vuelto a abrir desde que se anadieron 003-006 al registry padre. En la proxima ejecucion en home-wsl, `ops.Open()` aplicara 003_logs, 004_e2e_tests, 005_e2e_runs, 006_task_runs automaticamente.
Verificacion del comportamiento: `TestMigrations` en `fn_operations/operations_test.go` pasa, y `fn ops` sobre BD fresca recientemente compilada incluye `logs` en `schema_migrations` (versiones 1..5 — la stale del template de `fn ops init` es separado, no bloquea pipeline_launcher porque este usa `ops.Open` directo, no el template).
Acciones tomadas:
- Removido el check `ops_schema_complete` de `dev/proposals_e2e_checks_0121/pipeline_launcher.yaml` (queda obsoleto al ser auto-resuelto por `ApplyVersionedMigrations`). `ops_audit` sigue cubriendo la integridad de schema/datos.
- Clonado `apps/pipeline_launcher` desde Gitea en aurgi-pc para la investigacion; `pc_locations` pasa de `missing` a `active` tras `fn sync` futuro.
Pendiente fuera de scope:
- `apps/pipeline_launcher/go.mod` tiene `replace fn-registry => /home/lucas/fn_registry` hardcoded — el build solo funciona en home-wsl. Issue aparte si se quiere cross-PC build.
- `fn_operations/project_template/operations.db` tiene migraciones aplicadas hasta v5, falta v6. Stale template — issue aparte.
Acceptance:
- Tabla `logs` se creara automaticamente al reabrir la app en home-wsl (verificable con `sqlite3 apps/pipeline_launcher/operations.db "PRAGMA table_info(logs);"` tras el primer lanzamiento).
- Reaplicar 003 es idempotente: tracking por version en `schema_migrations` salta versiones ya aplicadas.
- pipeline_launcher no tiene tests propios; los tests de `fn_operations` cubren la logica de migracion.
@@ -84,27 +84,11 @@ e2e_checks:
timeout_s: 10
expect_stdout_contains: "OK"
# -----------------------------------------------------------------------
# check: ops_schema_complete
# Por que: la operations.db de pipeline_launcher no tiene la tabla logs
# (migracion 003_logs NO aplicada al momento de la auditoria).
# Este check aplica fn ops init sobre una copia en /tmp para
# verificar que las 3 migraciones (001_init, 002_executions_assertions,
# 003_logs) se aplican limpiamente sin errores.
# Idempotente: crea DB nueva en /tmp cada vez.
# -----------------------------------------------------------------------
- id: ops_schema_complete
cmd: >
rm -f /tmp/pipeline_launcher_e2e_ops.db &&
cp /home/lucas/fn_registry/apps/pipeline_launcher/operations.db /tmp/pipeline_launcher_e2e_ops.db &&
FN_REGISTRY_ROOT=/home/lucas/fn_registry /home/lucas/fn_registry/fn ops init /tmp/pipeline_launcher_e2e_ops.db &&
sqlite3 /tmp/pipeline_launcher_e2e_ops.db "SELECT name FROM sqlite_master WHERE type='table' AND name='logs';" | grep -q logs && echo "logs table OK" || { echo "FAIL: logs table missing after ops init"; exit 1; }
timeout_s: 30
expect_stdout_contains: "logs table OK"
severity: warning
# NOTA: severity warning porque la migracion faltante no bloquea el uso
# normal de la TUI (no escribe logs todavia). Promover a critical cuando
# la app comience a usar la tabla logs activamente.
# NOTA: el check `ops_schema_complete` se removio (issue 0126).
# Razon: `fn_operations.Open` usa `ApplyVersionedMigrations` con tabla
# `schema_migrations` — al abrir pipeline_launcher, 003_logs y migraciones
# posteriores se aplican automaticamente sobre la BD existente. No hay
# applier custom. Verificar via ops_audit (siguiente check) basta.
# -----------------------------------------------------------------------
# check: ops_audit