PoTraffic is a Blazor WebAssembly + ASP.NET Core application that measures commute route volatility using Google Maps travel times (TomTom supplies traffic incidents only). It records travel-time samples on a schedule, computes route baselines, and flags congestion or reroute anomalies in real time.
| Layer | Technology |
|---|---|
| Front-end | Blazor WebAssembly (.NET 10) + Radzen Blazor |
| Back-end | ASP.NET Core Minimal API (.NET 10); feature-folder handlers called from minimal-API endpoints |
| Persistence | Azure Table Storage, Azurite locally |
| Background Jobs | Table Storage-backed scheduler |
| Auth | Microsoft OAuth in dev/prod, Testing-only auth bypasses |
| Logging | Serilog + WASM client log forwarding |
| Observability | OpenTelemetry + Azure Monitor / Application Insights; app spans (PoTraffic.API source: jobs, Google Maps / TomTom / Open-Meteo calls, Table Storage writes) export only when App Insights or OTEL_EXPORTER_OTLP_ENDPOINT is configured |
| Testing | xUnit + NSubstitute, integration tests, Playwright .NET E2E |
The API and Blazor WASM static files are hosted together on Azure App Service. CORS is intentionally not configured.
src/
PoTraffic.API/ # ASP.NET Core host, Features/ slices, Infrastructure/
PoTraffic.Client/ # Blazor WASM front-end
PoTraffic.Shared/ # DTOs shared by API and client
tests/
PoTraffic.UnitTests/
PoTraffic.IntegrationTests/
PoTraffic.E2ETests/
- .NET 10 SDK
- Docker Desktop for Azurite
- Azure CLI for local Key Vault access
dotnet restore
dotnet build
./SCRIPTS/start-dev.ps1The startup script stops a stale PoTraffic host, starts PoTraffic's own Azurite (host port 10012, so it never collides with another project's Azurite on 10002), and launches the hosted API/client. If another app already holds 5001/5000 it uses 5011/5010 (then 5021/5020) and prints the URL.
| URL | Purpose |
|---|---|
https://localhost:5001 |
Hosted API + Blazor client |
https://localhost:5001/scalar/v1 |
Scalar API reference in Development |
https://localhost:5001/health |
Health status page (JSON at /health/json) |
https://localhost:5001/diag/keyvault |
Admin-only Key Vault diagnostics API |
./SCRIPTS/run-tests.ps1Or run individual suites:
dotnet test tests/PoTraffic.UnitTests
dotnet test tests/PoTraffic.IntegrationTests
dotnet test tests/PoTraffic.E2ETestsRoutes have monitoring windows. When a window is active, the scheduler records traffic samples at configured intervals until the window closes. Samples are stored in Table Storage and used to build baseline travel-time bands per route and time slot.
On a route's Schedule tab a user can edit the schedule (swapped in one save, so a rejected edit keeps the old one), change the addresses (only a changed address is geocoded again; history is kept), and pause or resume monitoring (paused keeps the schedule and history but stops the poll chain; Stop only ends today's session). The sample commute's history is generated, so it never counts toward spend, admin usage or the fleet volatility chart. With mock providers on, address suggestions are canned and free.
Cost controls, all editable by administrators on the Admin page (System Config tab, or
PUT /api/admin/configuration/{key}):
| Config key | Default | Effect |
|---|---|---|
quota.daily.default |
10 |
Monitoring sessions per user per local day. A per-user override (PUT /api/admin/users/{userId}/daily-quota, null to clear) takes precedence. |
cost.perpoll.googlemaps |
0.005 |
USD per Distance Matrix call: each recorded poll and each Check now. |
cost.pergeocode.googlemaps |
0.005 |
USD per address geocode (two per route created). |
cost.perdirections.googlemaps |
0.005 |
USD per Directions call (a route map's road shape, fetched once per route). |
cost.perautocomplete.googlemaps |
0.00283 |
USD per Places Autocomplete request (address suggestions while typing). |
cost.monthly.cap.usd |
100 |
Monthly provider budget. Spend is this UTC month's polls plus the Check now, geocode, directions and autocomplete calls (counted in the ProviderUsage table), each at its rate. Once it reaches the cap, scheduled polls and Check now pause until the next month or until the cap is raised; route creation and suggestions keep working. 0 disables the cap. Breakdown: GET /api/admin/spending. |
Development and Production require Microsoft OAuth. Testing exposes isolated auth bypass endpoints for integration and E2E tests; these are not available when running the app normally.
- Keep features as vertical slices under
Features/<FeatureName>/. - Do not add root-level
Services/,Repositories/, orDTOs/folders. - Keep NuGet versions in
Directory.Packages.props. - Do not enable AOT or trimming.
- Remove dead code and stale docs before merge.
See AGENTS.md for the full coding-agent contract.