feat(reports): FTP night-report pipeline foundation #62
Reference in New Issue
Block a user
Delete Branch "feat/ftp-report-pipeline"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Add backend/routers/reports.py (registered in main.py): - GET /api/projects/{id}/reports/nightly/view — render the night report HTML inline (preview; no write, no email) - POST /api/projects/{id}/reports/nightly/run — build -> write report.html/report.json to disk -> dry-run email -> JSON result + view_url Same entry point the scheduled morning tick will reuse. Query params: night_date (default last night, local tz), baseline_start/end, metrics, send. Orchestrator now also returns the rendered html for inline display. Verified via FastAPI TestClient on real meter data (200 HTML with the computed numbers, files written to disk, 400/404 validation paths). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>Add SoundReportConfig (one row per project) + the scheduler tick that runs the nightly report on its own: - model SoundReportConfig (enabled, report_time, metric_keys, baseline range, recipients, last_run_date) — new table, auto-created by create_all (no migration). - GET/PUT /api/projects/{id}/reports/config with validation. - SchedulerService.run_due_reports(): each loop, for every enabled config past its report_time, run last night's report once (dedup via last_run_date), writing the file + emailing (dry-run until SMTP is set). - UI: gear button beside "Night Report" opens a settings modal (enable, time, baseline range, metrics, recipients) that GET/PUTs the config. Verified: table registers + auto-creates, config CRUD + validation, tick runs/dedups, templates render and gate to sound projects. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>Backend (reports router): - POST /reports/test-email — send a test email (body/config recipients; dry-run if SMTP unset) to verify the relay. - GET /reports/list — list generated report artifacts on disk (newest first). - GET /reports/archive/{date} — serve a saved report.html (traversal-guarded). Frontend (sound project header modals): - Night Report modal: "Run & Email" button (POST /run) + a "Recent reports" list (GET /list → opens the archived report.html in a new tab). - Settings modal: schedule + last-run status line, and a "Send test email" button. Verified: endpoints (run→list→archive, traversal blocked, test-email recipient fallback) and the template renders with all four wired + gated to sound projects. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>Baseline can now come from fixed values typed per location, not just captured data — for a spec limit ("L10 = 85") or a prior report's averages when the raw data isn't available. - SoundReportConfig.baseline_mode ("captured" | "reference"). - report_pipeline: _location_reference_baseline() reads per-location values from location_metadata; build_*_night_report honor baseline_mode (reference cells use the typed value; unset metrics compare against nothing). - reports router: GET/PUT /reports/baseline (mode on config + per-location values in location_metadata); config carries baseline_mode; manual view/run fall back to the saved config's baseline when no explicit dates are given. - orchestrator + scheduler tick thread baseline_mode through. Verified end-to-end: PUT/GET /baseline, reference deltas (L10 66.6 vs 85 -> -18.4), unset metrics compare against nothing, captured-mode regression intact. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>render_excel(report): one worksheet per location — interval table, a line chart, and a Last/Base/Δ summary per window. Metric-driven, so it tracks whatever metric set is configured. - orchestrator: render report.xlsx alongside report.html, attach it to the email (dry-run until SMTP set), expose xlsx_path. Never lets a spreadsheet error sink the report. - reports router: /list includes xlsx_url when present; new GET /archive/{date}/xlsx serves the saved spreadsheet. - UI: Recent-reports rows get an "Excel" download link. Verified: real Feb data -> valid .xlsx (sheet per NRL, interval table + chart + summary with real values), attachment path runs, both archive routes registered. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>