a218092034
Closes issue 0119. Implementation lives in the kanban_cpp sub-repo (apps/kanban_cpp/backend/). See sub-repo commit 0b93a98 for details. DoD: - [x] issues_source.go parses frontmatter via yaml.v3 - [x] flows_source.go idem (distinct status->column mapping) - [x] frontmatter_edit.go atomic PatchFrontmatterField - [x] GET /api/boards/issues/cards (smoke: 87 cards) - [x] GET /api/boards/flows/cards (smoke: 9 cards) - [x] PATCH /api/boards/issues/cards/0119 status=en-curso (mtime change verified) - [x] POST /api/boards/issues/cards/0119/launch -> 502 with suggestion - [x] Tests *_test.go: 4 + 3 + 3 + 1 cache cases, all green - [x] Cache 30s thread-safe (mutex) - [x] Taxonomy 0103 respected — only canonical statuses accepted on PATCH Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
103 lines
4.4 KiB
Markdown
103 lines
4.4 KiB
Markdown
---
|
|
id: "0119"
|
|
title: "kanban_cpp: leer dev/issues + dev/flows como cards (sync layer)"
|
|
status: pendiente
|
|
type: feature
|
|
domain:
|
|
- cpp-stack
|
|
- kanban
|
|
- dev-loop
|
|
scope: app
|
|
priority: alta
|
|
depends:
|
|
- "0112"
|
|
blocks: []
|
|
related:
|
|
- "0008"
|
|
- "0109m"
|
|
- "0114"
|
|
created: 2026-05-18
|
|
updated: 2026-05-18
|
|
tags: [kanban, issues, flows, sync, frontmatter]
|
|
flow: "0008"
|
|
---
|
|
|
|
# 0119 — kanban_cpp sync layer: issues + flows como cards
|
|
|
|
## Problema
|
|
|
|
kanban_cpp (0112) clona el backend de kanban_web con `operations.db` vacia. Pero la intencion del flow 0008 es **gestionar issues y flows directamente desde kanban_cpp**. Sin sync con `dev/issues/*.md` + `dev/flows/*.md`, el board nace vacio y el usuario tendria que recrear cards a mano.
|
|
|
|
## Decision
|
|
|
|
Anadir endpoint al backend de kanban_cpp que lee frontmatter de los `.md` y los expone como cards/columnas virtuales. Lectura directa de filesystem (no via `issues_api` 0109m — el API service aun no existe; cuando exista, swap).
|
|
|
|
### Mapping `.md` -> card
|
|
|
|
| Frontmatter | Campo card |
|
|
|---|---|
|
|
| `id` | `card.external_id` |
|
|
| `title` | `card.title` |
|
|
| `status` (`pendiente`/`en-curso`/`done`/`deferred`) | `column` (mapping) |
|
|
| `priority` (alta/media/baja) | `card.priority` |
|
|
| `type` (feature/bug/chore/app) | `card.tag` |
|
|
| `tags` | `card.tags` |
|
|
| `flow` | `card.flow_id` |
|
|
| `dod_evidence_schema` (0114) | `card.dod_items[]` |
|
|
| body `## Problema` + `## Decision` | `card.description` |
|
|
|
|
### Mapping status -> columna kanban
|
|
|
|
```
|
|
pendiente -> Backlog
|
|
en-curso -> Doing
|
|
en-revisión -> Review
|
|
done -> Done
|
|
deferred -> Deferred
|
|
```
|
|
|
|
### Tableros separados
|
|
|
|
- Board `issues`: source = `dev/issues/*.md`.
|
|
- Board `flows`: source = `dev/flows/*.md`, columnas distintas (Pending / Running / Done / Deferred). flow body trae `## Definition of Done (user-facing, 4 surfaces obligatorios)`.
|
|
|
|
### Endpoints nuevos backend kanban_cpp
|
|
|
|
- `GET /api/boards/issues/cards` — lee `dev/issues/*.md`, cachea 30s.
|
|
- `GET /api/boards/flows/cards` — lee `dev/flows/*.md`, cachea 30s.
|
|
- `PATCH /api/boards/<board>/cards/<id>` — escribe vuelta al `.md` (cambia `status` en frontmatter). Usa `edit_yaml_frontmatter_go_core` del registry (verificar existe; si no, crear via fn-constructor).
|
|
- `POST /api/boards/<board>/cards/<id>/launch` — proxy a `agent_runner_api:8486/api/runs`.
|
|
|
|
### Watcher de cambios
|
|
|
|
`fsnotify` sobre `dev/issues/` + `dev/flows/`. Cuando hay write -> invalida cache + push SSE a UI -> kanban_cpp refresca board.
|
|
|
|
## Criterios de aceptacion
|
|
|
|
- [ ] `apps/kanban_cpp/backend/issues_source.go` parsea frontmatter via funcion del registry.
|
|
- [ ] `apps/kanban_cpp/backend/flows_source.go` idem para flows.
|
|
- [ ] Endpoints arriba implementados con tests.
|
|
- [ ] `fsnotify` watcher activo; cambio en `.md` propaga a UI en < 2s.
|
|
- [ ] PATCH actualiza solo el campo `status` del frontmatter, preserva resto.
|
|
- [ ] Round-trip: PATCH `/cards/0113` status=`en-curso` -> file mtime cambia -> `dev/issues/0113-*.md` tiene `status: en-curso`.
|
|
- [ ] Click `Launch` en card invoca `agent_runner_api` con `issue_id` + DoD items extraidos del frontmatter.
|
|
- [ ] Tag taxonomy issue 0103 respetada — solo statuses canonicos.
|
|
- [ ] kanban_cpp UI muestra ambos boards (tabs `Issues` / `Flows`) con cards reales del repo al arrancar.
|
|
- [ ] e2e_check: crear `.md` dummy -> aparece en board en <5s.
|
|
|
|
## Gotchas
|
|
|
|
- Frontmatter mal formado (yaml invalid): card aparece con badge `parse-error` + tooltip detalle. NO crashea backend.
|
|
- Cambios concurrentes: humano edita `.md` con vim mientras agente lo PATCHea via API. Usar lock file `.md.lock` corto + retry.
|
|
- `fsnotify` no funciona bien en WSL para `/mnt/c/` paths. Backend corre en WSL, lee paths nativos (`/home/lucas/fn_registry/dev/...`). Verificar.
|
|
- Issue / flow grandes (>500 lineas body): NO mandar full body en `/cards` (lento). Devolver solo frontmatter + primeras 5 lineas. Body completo via `/cards/<id>` on demand.
|
|
- Cards sin `status` (frontmatter incompleto): default `pendiente`.
|
|
- Reordenamiento manual: drag-and-drop en UI cambia status (cruzar columna) PERO no orden vertical persistente — no hay campo `order` en frontmatter. Decision: orden por `updated` desc dentro de cada columna.
|
|
|
|
## Out of scope
|
|
|
|
- Sync bidireccional con `issues_api` (0109m) — cuando exista, swap filesystem por API call.
|
|
- Conflict resolution manual (3-way merge UI).
|
|
- Edicion inline del body markdown desde la card (solo PATCH de `status` + `priority` por ahora).
|
|
- Bulk operations (mover N cards a la vez).
|