9.6 KiB
Advanced Reports — Implementation Plan (Phase 1)
Version: 1.0
Date: July 9, 2026
Status: Draft — derived from the approved planning set
Related Documents: ADVANCED_REPORTS_FEASIBILITY.md, ADVANCED_REPORTS_FUNCTIONAL.md, ADVANCED_REPORTS_NON_FUNCTIONAL.md, ADVANCED_REPORTS_API.md, ADVANCED_REPORTS_PROPOSAL.md
1. Approach
Build the Advanced Application Report on the existing report pipeline: the server computes analytics, renders map images, and writes a datasource; the client Stimulsoft viewer renders and exports. One analytics engine feeds every page (FR-5.4); content options are applied by shaping the datasource, not by swapping templates.
Guiding principles:
- Pure-function analytics core — testable without HTTP, Mongo, or Puppeteer (NFR-6.3).
- Legacy untouched — no shared-code change may alter
preAppReport/loadsheet behaviour (NFR-5.1). ApplicationDetailis read once per report (single pass, streaming cursor, projected fields only — NFR-1.2/1.4).- One Chromium instance per report for all captures (NFR-1.3).
2. Deliverables map
| # | Deliverable | New/Changed files |
|---|---|---|
| D1 | Analytics engine | helpers/report_util.js (new) |
| D2 | Endpoint + datasource builder | controllers/advanced_report.js (new), routes/job.js (route), model/job.js (report-contents options persistence) |
| D3 | Map page variants + multi-capture | public/sprayMap.html (variants), helpers/web_util.js (browser reuse) |
| D4 | Template + validation | reports/app_advanced.mrt (authored in the Stimulsoft designer), scripts/validate_advanced_report_template.js (new) |
| D5 | Frontend wiring | client repo: Report Settings "Report Contents" panel, advanced-report option, viewer call |
| D6 | Tests + offline harness | tests/ fixtures + unit/integration tests, offline Stimulsoft harness |
| D7 | Rollout | backfill verification, template deploy to REPORT_DIR, release notes |
Sequencing: D1 → D2 → (D3 ∥ D4) → D5 → D6 → D7. D3 and D4 are independent once D2 fixes the datasource shape. D6 grows alongside every deliverable (D1 unit tests land with D1).
3. D1 — Analytics engine (helpers/report_util.js)
Pure functions over point arrays; no I/O.
- Line segmentation — group
ApplicationDetailpoints byllnum;sprayStat == 3marks line start, spray-on =sprayStat ∈ {1, 3}(pattern:getSprayOnSegments,controllers/job.js:604). - Zone assignment — point-in-polygon (turf) of each line's points against
job.sprayAreas; majority wins for straddling lines (FR-5.2). - Per-line stats — start time, spray time, length (
geoUtil.distance()— km), avg speed, area = length × swath, app rate, avg |xTrack|, turn time (gap to next line; pattern: turn-time loopworkers/job_worker.js:1486). - Zone roll-ups — sprayed area, coverage %, volume, flight/spray time, avg turn time, avg height, avg XT, avg flow rate (mean
lminApp— completely new calculation, degrade when flat 0). - Mission totals — sums/weighted averages of zone values (must equal page-1 figures exactly, NFR-3.3); ferry time/distance = flight − spray.
- Planned areas — turf area from polygon geometry (
sprayAreas[].properties.areaabsent in live data); coverage capped at 100.0% display. - Weather — reuse
jobUtil.getDataWeatherInfo(fileIds)(helpers/job_util.js:325); manualjob.weatherInfooverride.
Unit-test fixtures (with D1): typical multi-zone job, no-flow-controller job (lminApp = 0), SatLoc-style job (no xTrack/turn data), unsprayed zone, single-zone job, boundary-straddling line.
4. D2 — Endpoint + datasource (controllers/advanced_report.js)
POST /preAdvancedReportinroutes/job.js, same auth middleware aspreAppReport(NFR-4.1). Returns{ rid, path, c }(FR-1.1).- Controller flow (mirrors
preAppReport_post): load job with populated refs → persist Report Settings incl. Report Contents selections (job.rptOppattern, FR-7.5) → streamApplicationDetailby the job'sfileIds with field projection (NFR-1.2) → run D1 engine → render maps via D3 → writerptDS.json→ select template. - Datasource shape (all display values pre-localized strings, FR-1.3):
mission— header/info block, KPI tiles, statistics, generation date.zones[]— per-zone info + stats + map image refs; empty-state zones carry–placeholder values (FR-4.6); filtered per Report Contents options.lines[]nested per zone — flight-line table rows; single–placeholder row for unsprayed zones; omitted when Flight Line Statistics is off.products[],weather(suppressed when unavailable),coverageCards[](all zones, always).
- Template selection:
app_advanced_<applicatorId>.mrtelseapp_advanced.mrt; applicator id sanitized to hex ObjectId (NFR-4.2). - Structure the generation function so a worker can call it without the HTTP layer (NFR-2.3); a simple in-process counter limits it to max 2 concurrent generations (NFR-2.2).
- Per-phase pino logging: query, data aggregation, each capture, datasource write (NFR-7.1).
5. D3 — Maps (public/sprayMap.html variants + helpers/web_util.js)
- Extend
web_utilto open one Chromium instance and capture multiple pages/states per report (NFR-1.3). - Mission map variant: fitBounds over all zones; numbered markers + zone/field names + acreage labels; spray/ferry layers; legend/scale/north arrow. Mode switch (FR-2.3.3): compute zone pixel footprint at fitted zoom — below threshold (~25 px) render locator badges (
divIcon, zone numbers) instead of polygons (FR-2.3.2). - Zone detail variant: per-zone fitBounds, boundary + spray lines + dashed ferry lines, neighbouring zones faded into the background; unsprayed zones render boundary + ferry only.
- Background toggle: when Hide Map Background is selected (FR-7.4), all variants skip the satellite tile layer and render on the plain dark-green background used in the mockups (a fixed CSS background on the map container) — no tile downloads during capture.
- Thumbnails: crop from the single all-zones capture when single-viewport; per-zone captures when dispersed; skipped entirely above 12 zones (FR-3.5) or when zone pages are excluded (Report Contents).
- Zone capture failure → placeholder image + log, report continues; mission map failure → request fails (NFR-3.1).
6. D4 — Template (reports/app_advanced.mrt, authored in the Stimulsoft designer)
- Three page designs authored manually in the embedded Stimulsoft designer: Mission Overview, Mission Coverage (grid ≤12 zones / compact table >12), Zone Detail (master band per zone, flight-line table as StiPanel-wrapped child band).
- Validation script
scripts/validate_advanced_report_template.js(NFR-5.2/6.1), run after every designer save and before deploy. Checks: no empty{}collections in the.mrtJSON;GlobalizationStringsfor en-US / pt-PT / es-ES with non-empty Items targeting existing components; unique component names; every band'sDataSourceName/MasterComponent/DataRelationNameresolves against the Dictionary; DataBands nested inside DataBands are StiPanel-wrapped; every{table.column}expression references a declared Dictionary column. - Section suppression via empty datasets; dash placeholder rows come from the datasource, not template logic.
- Committed
.mrtis the source of truth (NFR-6.1). FooterCreated <date>+page/totalPages; header band per page type.
7. D5 — Frontend (client repo)
- Report Settings dialog: add right-side Report Contents panel — Include All Zone Detail (default on), nested Sprayed Zones Only (default off), Include Flight Line Statistics (default on), Hide Map Background (default off), info tooltips (FR-7.4); restore last selections per job.
- Advanced Report as a report option alongside the legacy report; on Preview call
preAdvancedReportand hand{rid, path}to the existing viewer unchanged.
8. D6 — Testing & verification
- D1 unit tests over fixtures (all FR-8 degradation rows covered, NFR-3.4).
- Cross-page consistency test: mission totals ≡ zone roll-ups (NFR-3.3).
- Offline Stimulsoft harness (file:// +
stimulsoft.reports.pack.js) loading the real.mrt+ generatedrptDS.json— reproduces viewer load/localize/render without the app (NFR-6.2); Trial watermark acceptable in tests. - Integration run against a live-like multi-zone job; visual check of all three page types, both map modes, >12-zone compact layout, both unit systems, all three cultures.
- Performance measurement against NFR-1.1 (~35 s per 10 zones; ~15 s typical 3-zone job) with per-phase timings from NFR-7.1 logs.
9. D7 — Rollout
- Verify production aggregate coverage (
avgXtError,avgSpraySpeed,totalFlightLength) on recent Applications; re-runscripts/migrate_applications.jsonly if gaps found (NFR-8.1). - Deploy
app_advanced*.mrtto the environment'sREPORT_DIR(may be outside this repo — NFR-6.4). - Release notes: flow-rate fields require a flow controller; SatLoc-sourced applications omit XT/turn statistics (NFR-8.2).
10. Open items
- F-OQ-1 Page orientation (portrait-only vs landscape variant) — blocks D4 template freeze; portrait assumed until the PO decides.
- F-OQ-2 Compact coverage layout threshold (more than 12 vs 12-and-above; threshold value) — affects D3 thumbnail logic and the D4 coverage page; "more than 12" assumed until the PO decides.
- Regeneration reuse/caching for repeat downloads of unchanged reports — not in Phase 1 scope; candidate optimization if NFR-1.1 budgets prove tight in practice (D2's worker-ready structure keeps the door open).