feat(jira): indicator per-card + import view desde Jira board 33

Backend:
- migration 018: cards.jira_last_status / sync_at / error (estado persistido del ultimo
  sync para render UI sin polling Jira).
- Dispatcher: sync.Map inflight para 'yellow' realtime + persistencia de exito/fallo
  en cards tras cada dispatch attempt.
- GET /api/cards/{id}/jira-sync: devuelve {jira_key, last_status, last_sync_at,
  last_error, inflight, issue_url} para el tooltip del indicador.
- GET /api/jira/issues: lista issues del board 33 con flag already_imported +
  mapped_column_id (reverse status_map). Filtros include_imported, limit.
- POST /api/jira/import: multi-key. Cada issue -> CreateCard + setCardJiraKey +
  seed jira_last_status. Cae en columna mapeada por status, o en fallback_column_id.
  ADF de description extraido a texto plano.

Frontend:
- JiraSyncIndicator: dot gris/amarillo/verde/rojo bajo IconDotsVertical de cada card.
  Mantine HoverCard con jira_key, status, last_sync, last_error, link 'Abrir en Jira'.
  Poll cada 10s, refresh-tick opcional.
- KanbanCard: agrupa menu + indicator en Stack vertical (indicator debajo de los 3 dots).
- ImportJiraModal: modal admin con tabla de issues. Checkbox por fila, filtro por texto,
  toggle 'mostrar ya importadas', Select de columna fallback. Tras import recarga board.
- App.tsx: nueva entrada de menu 'Importar de Jira' (admin) y ImportJiraModal mounted.

Backend tests siguen verdes (test mock cubre transitions endpoints).
Frontend pnpm build OK.
This commit is contained in:
egutierrez
2026-05-29 12:00:26 +02:00
parent 5744b82f58
commit c3cc42b350
13 changed files with 2450 additions and 1330 deletions
+5
View File
@@ -687,6 +687,11 @@ func apiRoutes(db *DB, chatWorkdir string, logger *ChatLogger, internalToken str
{Method: "DELETE", Path: "/api/modules/{id}", Handler: handleDeleteModule(db)},
{Method: "GET", Path: "/api/modules/{id}/logs", Handler: handleModuleLogs(db)},
{Method: "POST", Path: "/api/modules/{id}/test", Handler: handleTestModule(db, dispatcher)},
// Per-card Jira sync state (indicator + tooltip).
{Method: "GET", Path: "/api/cards/{id}/jira-sync", Handler: handleCardJiraSync(db, dispatcher)},
// Jira import: list issues not yet in kanban + bulk import.
{Method: "GET", Path: "/api/jira/issues", Handler: handleListJiraIssues(db)},
{Method: "POST", Path: "/api/jira/import", Handler: handleImportJiraIssues(db)},
}
}