Accessibility-aware urban routing with .NET 9, PostGIS, Redis/Kafka workers, graph preprocessing, hazard scoring, and an Expo mobile client.
C#
0
96 commits
updated Aug 29, 2026
AccessCity is an accessibility-focused urban routing system. It combines a .NET 9 geospatial API, PostGIS-backed OSM ingestion, Redis/Kafka worker paths, route graph preprocessing, hazard/risk scoring, vector tile support, and an Expo React Native client.
The project is built for safe, reproducible route decisions: AI assistance is limited to text normalization, report summarization, and explanations. It does not generate routes or dynamically change routing edge costs.
AccessCity is an active pre-production system. The local and Kubernetes deployment paths are wired for API replicas, background workers, Kafka, Redis, PostGIS/PgBouncer, observability, SLO alerts, and route graph artifact profiling, but it is not an emergency service and has not yet been proven at global production scale.
Current verified baseline:
See K6 load results, route graph preprocessing, and distributed load testing for methodology and limits.

AccessCity is a modular monolith with independently scalable deployment roles:
Module boundaries are documented in Modular Architecture. Scaling guardrails are documented in SLO and Scaling.
kubectl, kustomize, and a Kubernetes cluster for distributed validationRun the API, PostGIS, Redis, Kafka, and the routing/import worker:
docker compose --profile worker up -d --build
The API is exposed through the local gateway at:
http://localhost:8080
Useful local endpoints:
GET /healthGET /health/readyhttp://localhost:8080/openapi/v1.jsonhttp://localhost:8080/scalar/v1Stop the stack:
docker compose --profile worker down
Keep only the backing services in Docker, then run the API locally:
docker compose up -d db redis kafka
cd AccessCity.API
export ASPNETCORE_ENVIRONMENT=Development
export ConnectionStrings__DefaultConnection="Host=localhost;Port=5432;Database=accesscitydb;Username=accesscity;Password=accesscity123"
export ConnectionStrings__Redis="localhost:6379"
export Messaging__UseKafka=false
export Routing__DispatchJobsToWorker=false
dotnet run
The default development launch settings expose HTTP on port 5005 unless overridden.
cd AccessCity.App
npm ci
npm run web
For simulator, device, and QR workflows:
npx expo start
The client API base URL is resolved in AccessCity.App/services/apiConfig.ts. Override it with EXPO_PUBLIC_API_URL, EXPO_PUBLIC_API_HOST, or EXPO_PUBLIC_API_PORT.
Most runtime settings use ASP.NET configuration keys and can be supplied through environment variables with __ separators.
High-value settings:
| Setting | Purpose |
|---|---|
ConnectionStrings__DefaultConnection | PostGIS primary connection string. |
READONLY_DATABASE_URL | Optional read-only Postgres/PgBouncer path for hot geospatial reads. |
ConnectionStrings__Redis | Redis L2 cache and distributed job status path. |
Messaging__UseKafka | Enables Kafka-backed job publishing and worker consumption. |
Kafka__BootstrapServers | Kafka broker list. |
Jwt__Key / Jwt__PreviousKeys | Current and previous JWT signing keys for rotation. |
Routing__AsyncFirstForCacheMiss | Returns 202 Accepted for cold route misses instead of blocking API pods. |
Routing__DispatchJobsToWorker | Sends route jobs to workers rather than computing in the API process. |
Routing__RouteGraphPackedArtifactsEnabled | Uses compact binary graph artifacts for cache/storage. |
Routing__RouteGraphMaxDistributedSnapshotBytes | Prevents oversized merged route graph bundles from being written to Redis/L2. |
Routing__RouteGraphCorridorSlicingEnabled / Routing__RouteGraphCorridorPaddingMetres | Loads a route corridor of reusable graph cells instead of the whole padded rectangle for city-scale routes. |
Routing__RouteGraphAdaptiveCorridorWideningEnabled | Retries a wider route graph corridor when the first slice lacks endpoint coverage or a connected accessible path. |
Routing__RouteGraphProfileFailOnQualityGate | Fails graph profiling when configured artifact/latency budgets are exceeded. |
Secret rotation is documented in Secret Rotation. Do not use the checked-in development JWT placeholder in production.
Backend format, build, and tests:
dotnet format CodeConquerors.sln --verify-no-changes --verbosity minimal
dotnet build CodeConquerors.sln --configuration Release
dotnet test AccessCity.Tests/AccessCity.Tests.csproj --configuration Release --no-build --verbosity normal
Frontend lint and tests:
cd AccessCity.App
npm ci
npm run lint
npm run test:ci
Dependency vulnerability checks:
dotnet list CodeConquerors.sln package --vulnerable --include-transitive
cd AccessCity.App
npm audit --audit-level=high --registry=https://registry.npmjs.org
Container and Kubernetes config checks:
docker compose config --quiet
docker compose --profile worker config --quiet
kubectl kustomize deploy/kubernetes >/tmp/accesscity-kustomize.yaml
CI gates are documented in CI/CD. Test architecture is documented in Test Architecture.
Profile a real city OSM extract through the offline graph preprocessing path:
tools/profile-city-route-graph.sh
The script downloads a Birmingham extract by default, builds source shards, packs graph artifacts, profiles warmup routes, and writes:
data/route-graph-artifacts/profile-report.json
Use fail mode in release validation:
Routing__RouteGraphProfileFailOnQualityGate=true \
Routing__RouteGraphProfileMaxRedisPayloadBytes=8388608 \
Routing__RouteGraphProfileMaxArtifactUnpackMilliseconds=150 \
tools/profile-city-route-graph.sh
The profile report is intentionally strict. A failed quality gate does not mean the app is broken; it means a city graph or route bundle exceeds the configured production budget and should be split, cached differently, or preprocessed more aggressively before rollout.
Render manifests:
kubectl kustomize deploy/kubernetes
Apply the base stack:
kubectl apply -k deploy/kubernetes
The Kubernetes manifests include:
Before production, replace example secrets, configure a managed Postgres/PostGIS or CloudNativePG path, point READONLY_DATABASE_URL at a read pooler/replica, and run the distributed k6 job in Distributed Load Testing.
The local observability stack is under deploy/observability:
SLOs include safe-path p95, API 5xx rate, route computation saturation, external dependency fallback rate, and shared cache hit ratio. See SLO and Scaling.
Jwt__PreviousKeys.AccessCity.API/ .NET 9 API, modules, workers, routing, geospatial services
AccessCity.App/ Expo React Native client
AccessCity.Tests/ xUnit integration, routing, architecture, stress, and benchmark tests
AccessCity.SoakTestRunner/ standalone soak/allocation harness
deploy/kubernetes/ Kubernetes production manifests and load/soak jobs
deploy/observability/ OpenTelemetry, Prometheus, Grafana, and alerts
docs/ architecture, operations, scaling, security, and test reports
tools/ city route graph profiling tooling
data/ local OSM extracts and generated graph artifacts
Open an issue or pull request with a clear problem statement, reproduction steps, and the validation commands you ran. For routing changes, include profile-specific route quality tests or benchmark fixtures whenever behavior changes.
See Contributing and Code of Conduct.
AccessCity is licensed under the MIT License.
Accessibility-aware urban routing with .NET 9, PostGIS, Redis/Kafka workers, graph preprocessing, hazard scoring, and an Expo mobile client.
C#
0
96 commits
updated Aug 29, 2026
AccessCity is an accessibility-focused urban routing system. It combines a .NET 9 geospatial API, PostGIS-backed OSM ingestion, Redis/Kafka worker paths, route graph preprocessing, hazard/risk scoring, vector tile support, and an Expo React Native client.
The project is built for safe, reproducible route decisions: AI assistance is limited to text normalization, report summarization, and explanations. It does not generate routes or dynamically change routing edge costs.
AccessCity is an active pre-production system. The local and Kubernetes deployment paths are wired for API replicas, background workers, Kafka, Redis, PostGIS/PgBouncer, observability, SLO alerts, and route graph artifact profiling, but it is not an emergency service and has not yet been proven at global production scale.
Current verified baseline:
See K6 load results, route graph preprocessing, and distributed load testing for methodology and limits.

AccessCity is a modular monolith with independently scalable deployment roles:
Module boundaries are documented in Modular Architecture. Scaling guardrails are documented in SLO and Scaling.
kubectl, kustomize, and a Kubernetes cluster for distributed validationRun the API, PostGIS, Redis, Kafka, and the routing/import worker:
docker compose --profile worker up -d --build
The API is exposed through the local gateway at:
http://localhost:8080
Useful local endpoints:
GET /healthGET /health/readyhttp://localhost:8080/openapi/v1.jsonhttp://localhost:8080/scalar/v1Stop the stack:
docker compose --profile worker down
Keep only the backing services in Docker, then run the API locally:
docker compose up -d db redis kafka
cd AccessCity.API
export ASPNETCORE_ENVIRONMENT=Development
export ConnectionStrings__DefaultConnection="Host=localhost;Port=5432;Database=accesscitydb;Username=accesscity;Password=accesscity123"
export ConnectionStrings__Redis="localhost:6379"
export Messaging__UseKafka=false
export Routing__DispatchJobsToWorker=false
dotnet run
The default development launch settings expose HTTP on port 5005 unless overridden.
cd AccessCity.App
npm ci
npm run web
For simulator, device, and QR workflows:
npx expo start
The client API base URL is resolved in AccessCity.App/services/apiConfig.ts. Override it with EXPO_PUBLIC_API_URL, EXPO_PUBLIC_API_HOST, or EXPO_PUBLIC_API_PORT.
Most runtime settings use ASP.NET configuration keys and can be supplied through environment variables with __ separators.
High-value settings:
| Setting | Purpose |
|---|---|
ConnectionStrings__DefaultConnection | PostGIS primary connection string. |
READONLY_DATABASE_URL | Optional read-only Postgres/PgBouncer path for hot geospatial reads. |
ConnectionStrings__Redis | Redis L2 cache and distributed job status path. |
Messaging__UseKafka | Enables Kafka-backed job publishing and worker consumption. |
Kafka__BootstrapServers | Kafka broker list. |
Jwt__Key / Jwt__PreviousKeys | Current and previous JWT signing keys for rotation. |
Routing__AsyncFirstForCacheMiss | Returns 202 Accepted for cold route misses instead of blocking API pods. |
Routing__DispatchJobsToWorker | Sends route jobs to workers rather than computing in the API process. |
Routing__RouteGraphPackedArtifactsEnabled | Uses compact binary graph artifacts for cache/storage. |
Routing__RouteGraphMaxDistributedSnapshotBytes | Prevents oversized merged route graph bundles from being written to Redis/L2. |
Routing__RouteGraphCorridorSlicingEnabled / Routing__RouteGraphCorridorPaddingMetres | Loads a route corridor of reusable graph cells instead of the whole padded rectangle for city-scale routes. |
Routing__RouteGraphAdaptiveCorridorWideningEnabled | Retries a wider route graph corridor when the first slice lacks endpoint coverage or a connected accessible path. |
Routing__RouteGraphProfileFailOnQualityGate | Fails graph profiling when configured artifact/latency budgets are exceeded. |
Secret rotation is documented in Secret Rotation. Do not use the checked-in development JWT placeholder in production.
Backend format, build, and tests:
dotnet format CodeConquerors.sln --verify-no-changes --verbosity minimal
dotnet build CodeConquerors.sln --configuration Release
dotnet test AccessCity.Tests/AccessCity.Tests.csproj --configuration Release --no-build --verbosity normal
Frontend lint and tests:
cd AccessCity.App
npm ci
npm run lint
npm run test:ci
Dependency vulnerability checks:
dotnet list CodeConquerors.sln package --vulnerable --include-transitive
cd AccessCity.App
npm audit --audit-level=high --registry=https://registry.npmjs.org
Container and Kubernetes config checks:
docker compose config --quiet
docker compose --profile worker config --quiet
kubectl kustomize deploy/kubernetes >/tmp/accesscity-kustomize.yaml
CI gates are documented in CI/CD. Test architecture is documented in Test Architecture.
Profile a real city OSM extract through the offline graph preprocessing path:
tools/profile-city-route-graph.sh
The script downloads a Birmingham extract by default, builds source shards, packs graph artifacts, profiles warmup routes, and writes:
data/route-graph-artifacts/profile-report.json
Use fail mode in release validation:
Routing__RouteGraphProfileFailOnQualityGate=true \
Routing__RouteGraphProfileMaxRedisPayloadBytes=8388608 \
Routing__RouteGraphProfileMaxArtifactUnpackMilliseconds=150 \
tools/profile-city-route-graph.sh
The profile report is intentionally strict. A failed quality gate does not mean the app is broken; it means a city graph or route bundle exceeds the configured production budget and should be split, cached differently, or preprocessed more aggressively before rollout.
Render manifests:
kubectl kustomize deploy/kubernetes
Apply the base stack:
kubectl apply -k deploy/kubernetes
The Kubernetes manifests include:
Before production, replace example secrets, configure a managed Postgres/PostGIS or CloudNativePG path, point READONLY_DATABASE_URL at a read pooler/replica, and run the distributed k6 job in Distributed Load Testing.
The local observability stack is under deploy/observability:
SLOs include safe-path p95, API 5xx rate, route computation saturation, external dependency fallback rate, and shared cache hit ratio. See SLO and Scaling.
Jwt__PreviousKeys.AccessCity.API/ .NET 9 API, modules, workers, routing, geospatial services
AccessCity.App/ Expo React Native client
AccessCity.Tests/ xUnit integration, routing, architecture, stress, and benchmark tests
AccessCity.SoakTestRunner/ standalone soak/allocation harness
deploy/kubernetes/ Kubernetes production manifests and load/soak jobs
deploy/observability/ OpenTelemetry, Prometheus, Grafana, and alerts
docs/ architecture, operations, scaling, security, and test reports
tools/ city route graph profiling tooling
data/ local OSM extracts and generated graph artifacts
Open an issue or pull request with a clear problem statement, reproduction steps, and the validation commands you ran. For routing changes, include profile-specific route quality tests or benchmark fixtures whenever behavior changes.
See Contributing and Code of Conduct.
AccessCity is licensed under the MIT License.