feat(kanban): bocadillo agente + PDF descargable en reporte diario (issue 0094)

Anade tres capas sobre el reporte diario del issue 0093:

1) Bocadillo del agente: cuadro azul encima de "Tareas hechas" con un
   resumen en lenguaje natural (max 4 frases) generado por claude -p
   sobre el JSON del reporte. Botones Regenerar e icono Settings.

2) Settings del prompt: modal con textarea editable para el template
   del agente (key=daily_report_prompt). Compartido por todos los
   usuarios. Boton Restablecer por defecto.

3) PDF descargable: boton que abre ventana nueva con HTML imprimible
   (estilo A4, KPIs filtrados, tabla con enlaces absolutos por card).
   Permite compartir el listado de tareas hechas con los solicitantes.

Backend:
- Migration 013 anade tablas daily_summaries y settings; seed del
  prompt por defecto en castellano.
- daily_summary.go con GetSetting/SetSetting, GetDailySummary/Upsert,
  runClaudePrompt (envuelve claude -p) y GenerateDailySummary que
  orquesta DailyReportFor + plantilla + claude + persist.
- Nuevos endpoints:
  * GET  /api/reports/daily/summary
  * POST /api/reports/daily/summary
  * GET  /api/settings/{key}
  * PUT  /api/settings/{key}

Frontend:
- api.ts: getDailySummary, generateDailySummary, getSetting, setSetting.
- DailyReport.tsx: estado de summary, settingsOpen, promptDraft,
  filterRequester, filterAssignee, filteredDoneCards, exportPDF.
- Bocadillo con IconSparkles + IconRefresh + IconSettings.
- Modal de prompt con Guardar/Cancelar/Reset.
- Filtros Select por solicitante y asignado encima de la tabla.
- exportPDF abre window.open con HTML self-contained que incluye
  enlaces ${origin}/?card=${id} y window.print() automatico.

E2E nuevo (daily-summary-pdf.spec.ts): CRUD del setting, GET summary
shape, presencia del boton PDF/Settings/Regenerar en el modal. No
invoca claude real (binario externo, no disponible en CI).

Suite completa 11/11 pasa.
This commit is contained in:
2026-05-14 18:08:09 +02:00
parent fc7e6a34a7
commit 9c5e76e03f
9 changed files with 1887 additions and 1196 deletions
+31
View File
@@ -203,6 +203,37 @@ export function dailyReport(date: string, tz?: string): Promise<DailyReport> {
return fetchJSON(`/reports/daily?${params.toString()}`);
}
export interface DailySummary {
date: string;
summary: string;
prompt?: string;
model?: string;
generated_at?: string;
generated_by?: string | null;
exists: boolean;
}
export function getDailySummary(date: string): Promise<DailySummary> {
return fetchJSON(`/reports/daily/summary?date=${encodeURIComponent(date)}`);
}
export function generateDailySummary(date: string, tz?: string): Promise<DailySummary> {
const params = new URLSearchParams({ date });
if (tz) params.set("tz", tz);
return fetchJSON(`/reports/daily/summary?${params.toString()}`, { method: "POST" });
}
export function getSetting(key: string): Promise<{ key: string; value: string }> {
return fetchJSON(`/settings/${encodeURIComponent(key)}`);
}
export function setSetting(key: string, value: string): Promise<void> {
return fetchJSON(`/settings/${encodeURIComponent(key)}`, {
method: "PUT",
body: JSON.stringify({ value }),
});
}
export function moveCard(id: string, column_id: string, ordered_ids: string[]): Promise<void> {
return fetchJSON(`/cards/${id}/move`, {
method: "POST",