Commit Graph

14 Commits

Author SHA1 Message Date
serversdown fdd0426884 fix(reports): code-review findings — XSS, SMTP, blocking, unit link, email guard
- #1 XSS: escape user-controlled values (location name, baseline values, recent-
  report fields, SMTP status message) in the modals via the existing _mergeEsc
  helper — they were concatenated raw into innerHTML (stored XSS via location name).
- #2 SMTP: an unrecognized REPORT_SMTP_SECURITY no longer silently downgrades to a
  plaintext connection while still calling login() — it falls back to starttls and
  warns; warn on intentional security=none + auth.
- #3 scheduler: run the (blocking smtplib + Excel) nightly report in a worker thread
  (asyncio.to_thread + its own DB session) so it can't stall the loop that drives
  time-sensitive device cycles. New _run_one_report helper.
- #4 cycle ingest: set unit_id on the ingested data session (ingest_nrl_zip leaves
  it None) before dropping the empty placeholder, preserving the unit<->session link;
  repoint old_session_id at the real row.
- #7 robustness: wrap send_report_email in the orchestrator and run_nightly_report in
  /view + /run so a render/SMTP error returns a clean error instead of a raw 500
  after artifacts are written.

Verified: SMTP paths (typo->starttls, none, starttls, ssl), off-thread tick stamps
last_run_date + writes the file, /view 200, escaping wired, app imports.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-12 02:37:28 +00:00
serversdown ccb70698ba feat(reports): Excel renderer + attachment + archive download
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>
2026-06-11 22:49:32 +00:00
serversdown 1d49b54bd1 feat(reports): baseline-source editor in the settings modal
Gear → Settings now has a "Baseline source" toggle:
- Captured nights → the date-range fields (existing).
- Fixed values → a per-NRL grid (metrics × Evening/Nighttime) to type spec
  limits or prior-report averages, with a "Copy first NRL → all" helper.

Loads from GET /reports/baseline, saves mode via PUT /config and the per-NRL
values via PUT /reports/baseline. Verified the template renders + gates to sound.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-11 20:29:20 +00:00
serversdown 7fb4ba0343 feat(reports): wire run-now, archive, test-email, last-run status into the UI
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>
2026-06-11 17:19:30 +00:00
serversdown b2c54caebd feat(reports): per-project report config + automatic morning run
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>
2026-06-11 17:08:58 +00:00
serversdown 08d3d53702 feat(reports): add "Night Report" button to sound project header
Sound projects only: a Night Report button next to "Generate Combined Report"
opens a small modal (pick night + optional baseline range) that opens the
rendered report (/reports/nightly/view) in a new tab. Defaults the night to
last night; baseline is optional.

Verified the header partial renders and the button is gated to sound_monitoring
(hidden on vibration-only projects); modal + JS wired.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-11 00:59:50 +00:00
serversdown 295f9637b3 fix(merge-project): dropdown unclickable + modal too short to show it
Two bugs in the project-merge modal:

1. Dropdown options had the same JSON.stringify quote-collision in
   their inline onclick that broke the location Remove button and the
   metadata-backfill typeahead earlier this week:

     onclick="onMergePickTarget('${id}', ${JSON.stringify(m.name)})"

   For 'I-80 Area 1' that renders as onclick="...(\"I-80 Area 1\")" —
   the inner double quotes terminate the onclick attribute early,
   and the browser never binds the click handler.  Operator clicked
   items in the dropdown and nothing happened.

   Fixed via data-target-id / data-target-name attributes and a
   _mergePickFromButton(btn) trampoline.

2. Modal body had `flex-1 overflow-y-auto` with no min-height, so the
   container shrunk tight around the input.  When the typeahead
   dropdown appeared below the input it got clipped by the body's
   overflow and the operator had to scroll inside the modal to see
   the options.

   Fixed by adding min-height: 480px to the modal container + min-h-
   [320px] on the body so there's always room for the dropdown + the
   preview pane that appears below after a target is picked.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-15 04:54:33 +00:00
serversdown b1c2a1d778 feat(projects): "Merge into…" button to consolidate duplicate projects
Operator-facing tool for cleaning up duplicate projects.  Common after
the metadata-backfill parser auto-creates near-duplicates from operator
name variations ("SR81" vs "SR 81", "Swank-Karns Crossing" vs
"Swank-Karns Crossings", "Trumbull-Bryman Mont.Dam" vs
"Trumbull-Brayman-Mont Dam", etc.).

Workflow: visit the duplicate project's detail page, click "Merge into…"
in the header, search for the canonical target project from a typeahead,
review the preview (what assignments / locations / sessions will move,
any conflicts), confirm.  Source is soft-deleted; everything else
re-points to the target.  Smart consolidation: same-named locations in
both projects merge into one (source's assignments move to target's
existing location with the same name; source's empty location is then
deleted).  Different-named locations move as-is.

Backend:
- backend/services/project_merge.py (new): preview() and execute()
  functions.  Transaction-safe.  Per-assignment UnitHistory audit row
  with change_type='assignment_merged' so the deployment timeline shows
  the merge.  Source modules disabled; missing modules added to target.
  Handles edge cases: same project_id rejected, deleted projects rejected,
  orphan project-direct assignments (no location) re-pointed defensively.

- backend/routers/projects.py: new endpoints
    GET  /api/projects/{source_id}/merge_preview?target_id=...
    POST /api/projects/{source_id}/merge_into?target_id=...

Frontend (templates/partials/projects/project_header.html):
- "Merge into…" button in Project Actions area.
- Modal with typeahead (reuses /api/admin/metadata_backfill/projects_search)
  scoped to existing projects only (no create-new option).  Filters out
  the source project from candidates so operator can't accidentally pick
  it as target.
- Preview pane shows totals + per-location plan (consolidate vs move) +
  warnings (mismatched client names, location consolidation note).
- Red "Merge (permanent)" confirm button only enables after a target is
  picked and preview loads.
- On success, browser redirects to target project page.

Smoke verified: "Swank-Karns Crossing" (1 assignment) merged into
"Swank-Karns Crossings"; target now has 2 locations + 2 assignments,
source has 0 dangling rows, 1 project_merge audit entry written.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-12 20:18:42 +00:00
serversdown 73a6ff4d20 feat: Refactor project creation and management to support modular project types
- Updated project creation modal to allow selection of optional modules (Sound and Vibration Monitoring).
- Modified project dashboard and header to display active modules and provide options to add/remove them.
- Enhanced project detail view to dynamically adjust UI based on enabled modules.
- Implemented a new migration script to create a `project_modules` table and seed it based on existing project types.
- Adjusted form submissions to handle module selections and ensure proper API interactions for module management.
2026-03-30 21:44:15 +00:00
serversdown bc02dc9564 feat: Enhance project and reservation management
- Updated reservation list to display estimated units and improved count display.
- Added "Upcoming" status to project dashboard and header with corresponding styles.
- Implemented a dropdown for quick status updates in project header.
- Modified project list compact view to reflect new status labels.
- Updated project overview to include a tab for upcoming projects.
- Added migration script to introduce estimated_units column in job_reservations table.
2026-03-19 22:52:35 +00:00
serversdown 015ce0a254 feat: add data collection mode to projects with UI updates and migration script 2026-03-05 21:50:41 +00:00
serversdown ef8c046f31 feat: add slm model schemas, please run migration on prod db
Feat: add complete combined sound report creation tool (wizard), add new slm schema for each model

feat: update project header link for combined report wizard

feat: add migration script to backfill device_model in monitoring_sessions

feat: implement combined report preview template with spreadsheet functionality

feat: create combined report wizard template for report generation.
2026-03-05 20:43:22 +00:00
claude a9c9b1fd48 feat: SLM project report generator added. WIP 2026-01-20 08:46:06 +00:00
claude c8a030a3ba fixed project view title appearing as JSON string 2026-01-18 07:48:10 +00:00