# FTP Report Pipeline — session brief

**Branch:** `feat/ftp-report-pipeline` (off `dev`), worktree `/home/serversdown/terra-view-reports`.
**Scope:** Terra-View only. Do NOT touch SLMM — the SLMM alert/monitor work is live in a
parallel session on `slmm` branch `feat/drd-fix`. Pull device data through the **existing**
SLMM FTP proxy endpoints; add no SLMM code (for v1).

See memory note `client_sound_monitoring_job_2026-07` for the client requirements + timeline.

## Goal
Automated **daily morning report** for the John Myler 3-location sound job: each AM, last
night's noise levels vs the **baseline week**, per location. Data pulled from the meters via
FTP (the meter records 24/7 to SD regardless of TCP wedges). Alerts are a *separate* workstream
(SLMM, real-time DOD) — not in scope here.

## The big realization (why this is small)
The hard parts already exist:
- **SLMM (use as-is, via the `/api/slmm/...` proxy):**
  - `GET  /api/slmm/{unit}/ftp/files?path=/NL-43` → list files/folders
  - `POST /api/slmm/{unit}/ftp/download-folder` → returns the `Auto_####` folder as a **ZIP**
- **Terra-View ingest (reuse):** `backend/routers/project_locations.py:1743` `upload_nrl_data`
  already accepts a **ZIP**, extracts, keeps `.rnh` + `_Leq_ .rnd` (drops `_Lp_`/junk via
  `_is_wanted`), runs `_parse_rnh` (line 1687) → creates `MonitoringSession` + `DataFile`.
- **Report generator (reuse, source-agnostic):** `backend/routers/projects.py`. The `.rnd`
  file reads funnel through 3 helpers — `_peek_rnd_headers` (~135), `_is_leq_file` (~147),
  `_read_rnd_file_rows` (~256). `.rnd` files live on disk under `data/{file_path}` (DataFile
  holds the path, not a BLOB). The stats/Excel/formatting logic doesn't care where bytes come from.

## Build (Terra-View)
1. **Refactor** `upload_nrl_data`'s core into a callable `ingest_nrl_zip(location_id, zip_bytes, db)`
   so it can be invoked programmatically (not only via HTTP UploadFile).
2. **Scheduled pull job** (reuse the existing scheduler): per project location/unit →
   `GET /ftp/files` to find new `Auto_####` folders → `POST /ftp/download-folder` (zip) →
   `ingest_nrl_zip(...)`. **Dedup** so repeated pulls don't duplicate sessions/files
   (track ingested folder names per location).
3. **Baseline aggregation:** aggregate the baseline-week `_Leq_` intervals per location →
   reference values (nighttime Leq, L90 floor, typical Lmax).
4. **Nightly report + email:** compute last night's metrics per location, compare to baseline
   (deltas), render (reuse the Excel/report machinery), email each morning.

## Data-location decision (light version, agreed)
Keep `MonitoringSession`/`DataFile` **metadata in TV** for now; reuse the existing on-disk file
store. Optional refinement (later): have SLMM keep the pulled files and TV read them through a
SLMM file-serve endpoint (avoids the copy-into-TV step). Don't do that refinement under the
deadline unless trivial — the report logic is identical either way.

## Open questions to resolve early
1. **What's actually in a `_Leq_ .rnd`** — Leq only, or Leq + Lmax + Ln per 15-min interval?
   Decides whether the night-vs-baseline report can show L90/Lmax or just Leq. Inspect a real file.
2. **Session rollover / dedup** — does a 2-week run write one growing `Auto_####` folder or new
   folders? Drives the "what's new" logic.
3. **`download-folder` over a multi-day run** — confirm it zips cleanly (size/time).

## Client params (confirm with Dave before locking)
Threshold/metric + their "night" window; report recipients + format (email body vs PDF/Excel).

## Timeline
Setup ~7/1–7/2 (baseline week), shutdown week through ~7/17. Reports needed by ~7/8 (before
shutdown). Today is ~3 weeks out — reliability > features.
