Skip to content

Feature/air quality status page#337

Merged
vbuch merged 13 commits intomainfrom
feature/air-quality-status-page
Apr 3, 2026
Merged

Feature/air quality status page#337
vbuch merged 13 commits intomainfrom
feature/air-quality-status-page

Conversation

@vbuch
Copy link
Copy Markdown
Owner

@vbuch vbuch commented Apr 3, 2026

  • Rename variable shadowing colorscellStyle in AirQualityMap.tsx
  • Add error state handling for both useQuery calls in page.tsx
  • Switch assignToCell() from grid.find() to for...of loop in route.ts
  • Cache Storage instance at module scope in route.ts
  • Use Number.isFinite() instead of !Number.isNaN() in shared/src/air-quality/aqi.ts
  • Add tests for shared/src/air-quality/aqi.ts (27 tests)
  • Add documentation for the /air-quality monitoring page and update config table in docs/features/air-quality-monitoring.md
  • Fix maxAqiCategory to be null (not "good") when there are no cells/no data
  • Fix fitBounds to only run on first draw, not on every periodic refetch
  • Clarify per-instance cache caveat in docs
  • Fix assignToCell to use exclusive north/east edge comparisons (except outermost boundary) — maxNorth/maxEast computed once per grid, not per reading
  • Rename GCS_READINGS_BUCKETGCS_GENERIC_BUCKET in route.ts, .env.example, and test comments
  • Parse r.timestamp once per reading using Date.parse() in a single unified loop
  • Add export const runtime = "nodejs" after imports to prevent accidental Edge deployment
  • Add hermetic vi.stubEnv / vi.unstubAllEnvs() to route tests
  • Fix misleading .env.example comment about GCS authentication
  • Return 503 in production when GCS_GENERIC_BUCKET is not configured (local filesystem fallback restricted to non-production); add test coverage for this case

Copilot AI review requested due to automatic review settings April 3, 2026 05:43
@vercel
Copy link
Copy Markdown

vercel bot commented Apr 3, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
oboapp-api Ready Ready Preview, Comment Apr 3, 2026 7:39pm
oborishte-map Ready Ready Preview, Comment Apr 3, 2026 7:39pm

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a dedicated /air-quality monitoring page (with map + stats) and a backing API endpoint so the team can inspect sensor.community crawler data and notification/message counts without waiting for notifications to trigger.

Changes:

  • Added /air-quality UI with Leaflet grid-cell visualization, summary stats, and recent messages from sensor-community.
  • Added /api/air-quality/status route that reads the latest 24h readings from GCS/local FS, computes per-cell EAQI (NowCast), and returns DB counts.
  • Centralized EAQI/NowCast math in @oboapp/shared and updated ingest to re-export it; added a MongoDB index for notificationMatches.messageSnapshot.source.

Reviewed changes

Copilot reviewed 11 out of 12 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
web/package.json Adds @google-cloud/storage dependency for server-side GCS reads.
web/components/AirQualityMap.tsx New client component rendering EAQI grid cells on a Leaflet map.
web/app/api/air-quality/status/route.ts New API route: loads readings (GCS/local), computes per-cell EAQI, returns freshness + DB counts.
web/app/air-quality/page.tsx New monitoring page UI (stats, map, legend, recent alerts, message detail).
web/app/air-quality/layout.tsx Imports Leaflet CSS at route-segment layout scope.
web/.env.example Documents GCS_READINGS_BUCKET and LOCAL_READINGS_PATH for the monitoring page.
shared/src/index.ts Exposes the shared EAQI module via package index export.
shared/src/air-quality/aqi.ts New shared EAQI/NowCast implementation (PM2.5/PM10 bands + labels/categories).
ingest/lib/air-quality/constants.ts Re-exports NOWCAST_MIN_WEIGHT from @oboapp/shared.
ingest/lib/air-quality/aqi.ts Replaces local EAQI implementation with re-exports from @oboapp/shared.
db/src/indexes.ts Adds MongoDB index for notificationMatches.messageSnapshot.source used by the new status API.
pnpm-lock.yaml Lockfile updates for added dependency and resulting resolution changes.
Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

@vbuch
Copy link
Copy Markdown
Owner Author

vbuch commented Apr 3, 2026

@copilot address comments in this PR

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 3, 2026

@copilot address comments in this PR

All review comments addressed in c3caa38:

  • Variable shadowing — renamed const colorsconst cellStyle in AirQualityMap.tsx
  • Error states — added isError from both useQuery calls in page.tsx; each failing section now renders an explicit error message instead of silently showing empty/dash states
  • assignToCell performance — switched from grid.find() to a for...of loop
  • Storage singleton — cached at module scope so repeated requests reuse the same client
  • Number.isFinite — replaced !Number.isNaN in nowCastWeightedAverage to also filter out Infinity
  • Tests — added shared/src/air-quality/aqi.test.ts with 27 tests covering bands, NowCast weighting, label/category boundaries, and Infinity/NaN filtering
  • Docs — updated docs/features/air-quality-monitoring.md with a Monitoring Page section and updated the configuration table

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 13 out of 14 changed files in this pull request and generated 3 comments.

Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 13 out of 14 changed files in this pull request and generated 5 comments.

Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

vbuch added a commit that referenced this pull request Apr 3, 2026
…ndling, route tests, NEXT_PUBLIC_LOCALITY docs

- Replace Math.min/max spread over validTimestamps with a single loop to
  avoid hitting the JS argument limit on large 24h datasets
- Treat calculateNowCastAqi returning 0 as "no data" (aqi/aqiLabel/aqiCategory → null);
  sort null-aqi cells last; derive maxAqi via .find() instead of cells[0]
- Update AirQualityCell/AqiCell interfaces to allow null aqi/aqiLabel/aqiCategory;
  fix AirQualityMap tooltip and CATEGORY_COLORS lookup for null aqiCategory
- Add /api/air-quality/status route tests (10 tests: locality validation, no-data
  path, with-data shape, null-aqi propagation, staleness, db stats)
- Document NEXT_PUBLIC_LOCALITY in the air-quality-monitoring config table

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@vercel vercel bot temporarily deployed to Preview – oboapp-api April 3, 2026 07:54 Inactive
@vercel vercel bot temporarily deployed to Preview – oboapp-api April 3, 2026 08:06 Inactive
@vbuch vbuch requested a review from Copilot April 3, 2026 08:07
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 13 out of 13 changed files in this pull request and generated 1 comment.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 13 out of 13 changed files in this pull request and generated no new comments.

vbuch and others added 13 commits April 3, 2026 22:37
- Add /air-quality page with map, AQI overview, and notification stats
- Add /api/air-quality/status route serving current AQI, GCS data window, and notification counts
- Move AQI helpers from ingest into shared/src/air-quality/aqi.ts and re-export from ingest
- Add AirQualityMap component using Mapbox
- Add DB index for air quality station queries
- Update web/package.json and pnpm-lock.yaml for new dependencies
- Document required env vars in web/.env.example
…ndling, route tests, NEXT_PUBLIC_LOCALITY docs

- Replace Math.min/max spread over validTimestamps with a single loop to
  avoid hitting the JS argument limit on large 24h datasets
- Treat calculateNowCastAqi returning 0 as "no data" (aqi/aqiLabel/aqiCategory → null);
  sort null-aqi cells last; derive maxAqi via .find() instead of cells[0]
- Update AirQualityCell/AqiCell interfaces to allow null aqi/aqiLabel/aqiCategory;
  fix AirQualityMap tooltip and CATEGORY_COLORS lookup for null aqiCategory
- Add /api/air-quality/status route tests (10 tests: locality validation, no-data
  path, with-data shape, null-aqi propagation, staleness, db stats)
- Document NEXT_PUBLIC_LOCALITY in the air-quality-monitoring config table

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
GCS_READINGS_BUCKET is set in CI, causing the route to attempt a real
GCS connection instead of falling back to the local filesystem. Mock
the Storage class (using a class literal so new Storage() works) and
supply test data via both paths so tests pass regardless of whether
GCS_READINGS_BUCKET is set.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The previous test placed both readings at the same lat/lng, so they
landed in one cell — the second mockReturnValueOnce(0) was never
consumed and the sort assertion was skipped behind a conditional.

Now uses (42.61, 23.21) → r0c0 and (42.75, 23.45) → r4c5 so two
cells are created, calculateNowCastAqi is called once per cell, and
the ordering assertion runs unconditionally.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…T to GCS_GENERIC_BUCKET

Agent-Logs-Url: https://github.com/vbuch/oboapp/sessions/68cc96d3-9bdc-492e-9b94-74f230f0b5ac

Co-authored-by: vbuch <5102057+vbuch@users.noreply.github.com>
@vbuch vbuch force-pushed the feature/air-quality-status-page branch from 80fb993 to 0c129a3 Compare April 3, 2026 19:37
@vbuch vbuch merged commit 2fbdc63 into main Apr 3, 2026
7 checks passed
@vbuch vbuch deleted the feature/air-quality-status-page branch April 3, 2026 19:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Create a page for previewing the data available from the sensor.community crawler

3 participants