agmission/client/docs/ADVANCED_REPORTS_IMPLEMENTATION_PLAN.md

9.6 KiB
Raw Permalink Blame History

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).
  • ApplicationDetail is 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.

  1. Line segmentation — group ApplicationDetail points by llnum; sprayStat == 3 marks line start, spray-on = sprayStat ∈ {1, 3} (pattern: getSprayOnSegments, controllers/job.js:604).
  2. Zone assignment — point-in-polygon (turf) of each line's points against job.sprayAreas; majority wins for straddling lines (FR-5.2).
  3. 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 loop workers/job_worker.js:1486).
  4. 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).
  5. Mission totals — sums/weighted averages of zone values (must equal page-1 figures exactly, NFR-3.3); ferry time/distance = flight spray.
  6. Planned areas — turf area from polygon geometry (sprayAreas[].properties.area absent in live data); coverage capped at 100.0% display.
  7. Weather — reuse jobUtil.getDataWeatherInfo(fileIds) (helpers/job_util.js:325); manual job.weatherInfo override.

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)

  1. POST /preAdvancedReport in routes/job.js, same auth middleware as preAppReport (NFR-4.1). Returns { rid, path, c } (FR-1.1).
  2. Controller flow (mirrors preAppReport_post): load job with populated refs → persist Report Settings incl. Report Contents selections (job.rptOp pattern, FR-7.5) → stream ApplicationDetail by the job's fileIds with field projection (NFR-1.2) → run D1 engine → render maps via D3 → write rptDS.json → select template.
  3. 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).
  4. Template selection: app_advanced_<applicatorId>.mrt else app_advanced.mrt; applicator id sanitized to hex ObjectId (NFR-4.2).
  5. 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).
  6. 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)

  1. Extend web_util to open one Chromium instance and capture multiple pages/states per report (NFR-1.3).
  2. 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).
  3. Zone detail variant: per-zone fitBounds, boundary + spray lines + dashed ferry lines, neighbouring zones faded into the background; unsprayed zones render boundary + ferry only.
  4. 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.
  5. 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).
  6. 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)

  1. 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).
  2. 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 .mrt JSON; GlobalizationStrings for en-US / pt-PT / es-ES with non-empty Items targeting existing components; unique component names; every band's DataSourceName / MasterComponent / DataRelationName resolves against the Dictionary; DataBands nested inside DataBands are StiPanel-wrapped; every {table.column} expression references a declared Dictionary column.
  3. Section suppression via empty datasets; dash placeholder rows come from the datasource, not template logic.
  4. Committed .mrt is the source of truth (NFR-6.1). Footer Created <date> + page/totalPages; header band per page type.

7. D5 — Frontend (client repo)

  1. 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.
  2. Advanced Report as a report option alongside the legacy report; on Preview call preAdvancedReport and hand {rid, path} to the existing viewer unchanged.

8. D6 — Testing & verification

  1. D1 unit tests over fixtures (all FR-8 degradation rows covered, NFR-3.4).
  2. Cross-page consistency test: mission totals ≡ zone roll-ups (NFR-3.3).
  3. Offline Stimulsoft harness (file:// + stimulsoft.reports.pack.js) loading the real .mrt + generated rptDS.json — reproduces viewer load/localize/render without the app (NFR-6.2); Trial watermark acceptable in tests.
  4. 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.
  5. 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

  1. Verify production aggregate coverage (avgXtError, avgSpraySpeed, totalFlightLength) on recent Applications; re-run scripts/migrate_applications.js only if gaps found (NFR-8.1).
  2. Deploy app_advanced*.mrt to the environment's REPORT_DIR (may be outside this repo — NFR-6.4).
  3. 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).