Skip to content

Denuo-Web/CrowdPMPlatform

Repository files navigation

CrowdPM Platform

Ask DeepWiki

CrowdPM is a TypeScript/Firebase platform for crowd-sourced PM2.5 measurements. It pairs sensor nodes with Firebase users, accepts DPoP-bound ingest batches, stores raw payloads for audit, processes measurements into Firestore, and renders public or owned batches on a React/WebGL map.

The project has two supported environments:

  • local development: Vite plus the Firebase Emulator Suite using the local project ID crowdpm-local.
  • deployed: Firebase Hosting, Cloud Functions, Firestore, Storage, and Auth in the configured Firebase project.

Architecture

Area Path Responsibility
Frontend frontend/ React 19 + Vite app, Google Maps/deck.gl map, activation UI, dashboards, moderation UI.
Functions functions/ Firebase HTTPS Functions, Fastify REST API, pairing, DPoP validation, ingest processing, admin routes.
Shared types shared-types/ Workspace package consumed by the frontend and functions for API/data contracts.
Scripts scripts/ Local device emulator, deployed-device helpers, and workspace packaging utilities.
Firebase config firebase.json, firestore.rules, storage.rules Emulator ports, Hosting rewrites, deploy targets, and security rules.

Project History

CrowdPM Platform originated as an Oregon State University EECS Capstone project proposed by Jaron Rosenau / Denuo Web LLC. The project is now maintained and operated by Denuo Web LLC.

The repository includes contributions from multiple project contributors. See AUTHORS.md and the Git commit history for attribution.

Quick Start

Use Node 24 before running project commands:

source ~/.nvm/nvm.sh && nvm use 24
corepack enable
corepack prepare pnpm@10.18.1 --activate
pnpm install

Create local environment files:

cp frontend/.env.example frontend/.env.local
cp functions/.env.example functions/.env.local

Edit frontend/.env.local with a Google Maps JavaScript API key, vector map ID, Firebase web app config, and the local API base:

VITE_API_BASE=http://127.0.0.1:5001/crowdpm-local/us-central1/crowdpmApi
VITE_FIREBASE_AUTH_EMULATOR_HOST=127.0.0.1:9099

Edit functions/.env.local with a real Ed25519 PKCS8 private key for DEVICE_TOKEN_PRIVATE_KEY. The local emulator also supports generated ephemeral keys, but a stable key is required when testing device registration and repeat ingest.

Start the full local stack:

pnpm dev

Local URLs:

  • Frontend: http://localhost:5173
  • API health: http://127.0.0.1:5001/crowdpm-local/us-central1/crowdpmApi/health
  • Firebase Emulator UI: http://localhost:4000

Common Commands

pnpm dev                                  # frontend, functions emulator, TS watch
pnpm lint                                 # workspace ESLint
pnpm --filter crowdpm-functions test      # functions Vitest suite
pnpm build                                # build all workspaces
pnpm --filter crowdpm-frontend build      # frontend only
pnpm --filter crowdpm-functions build     # functions only

Device emulator examples:

pnpm device:pair -- --key .device-key.json --interval 3
pnpm device:pair -- --mode ingest --key .device-key.json
pnpm device:simulate:osu -- --count 20 --minutes 36

API And Data Flow

Primary Fastify routes are exported through the crowdpmApi HTTPS Function. The ingest gateway is a separate HTTPS Function because it preserves raw payloads before processing.

  • Pairing: POST /device/start, /device/token, /device/register, /device/access-token
  • Activation UI support: GET /v1/device-activation, POST /v1/device-activation/authorize
  • User APIs: /v1/devices, /v1/measurements, /v1/batches, /v1/user/settings
  • Public data: /v1/public/batches
  • Admin and moderation: /v1/admin/*
  • Ingest gateway: POST /ingestGateway

Raw ingest batches are stored in Cloud Storage at ingest/{deviceId}/{batchId}.json. Processed measurements are stored in Firestore under devices/{deviceId}/measures/{hourBucket}/rows/{doc}, with batch metadata under devices/{deviceId}/batches/{batchId}.

Documentation

  • docs/README.md - documentation index and conventions
  • docs/development.md - local setup and daily workflow
  • docs/deployment.md - deployed Firebase release process
  • docs/hardware-builder.md - hardware pairing and ingest contract
  • docs/openapi-swagger-ui.md - local Swagger UI for functions/src/openapi.yaml
  • frontend/README.md, functions/README.md, shared-types/README.md, scripts/README.md - package-specific notes

Deployment

Use docs/deployment.md for the deployed environment. Always deploy with an explicit Firebase project ID and never deploy the local fake project:

FIREBASE_PROJECT_ID=crowdpmplatform
pnpm lint
pnpm build
firebase deploy --only hosting,functions --project "$FIREBASE_PROJECT_ID"

Deploy Firestore indexes and Firestore or Storage rules only when those files changed and have been reviewed.

License

CrowdPM Platform is licensed under GNU AGPLv3-or-later unless otherwise stated.

Copyright © 2025–2026 Denuo Web LLC and contributors.

The hosted service, hardware node sales, support, fulfillment, and related commercial services are operated by Denuo Web LLC.

Commercial licensing may be available from Denuo Web LLC for portions of the project owned by, assigned to, or otherwise licensed to Denuo Web LLC for that purpose. Contributor-owned portions remain subject to their applicable license terms unless separate written permission has been obtained.

See LICENSE.md, NOTICE.md, AUTHORS.md, CONTRIBUTING.md, and CLA.md.

About

CrowdPM is a TypeScript/Firebase platform for crowd-sourced PM2.5 measurements. It pairs sensor nodes with Firebase users, accepts DPoP-bound ingest batches, stores raw payloads for audit, processes measurements into Firestore, and renders public or owned batches on a React/WebGL map.

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Contributors