core
A variant of Infrastructure Asset Registry.
View the interactive variant page →
Infrastructure Asset Registry
Part of the worlds-biggest-software-project initiative.
An open-source, AI-native platform for managing the full lifecycle of physical infrastructure assets -- from inventory and condition assessment to capital planning and compliance reporting -- without vendor lock-in to proprietary GIS platforms.
Infrastructure Asset Registry provides municipalities, transportation departments, and utilities with a structured, GIS-linked inventory of roads, bridges, pipes, culverts, signals, and other long-lived assets. It replaces reactive, complaint-driven maintenance with condition-based priority planning backed by data. The system records location, condition, maintenance history, and financial data for every asset, connecting inspection workflows to capital improvement programmes so agencies can make defensible investment decisions.
Why Infrastructure Asset Registry?
- Proprietary GIS lock-in is the norm. Nearly every incumbent (Trimble Unity, OpenGov/Cartegraph, AssetWorks) requires Esri ArcGIS licences, significantly increasing total cost of ownership. No open-source alternative with comparable condition management depth exists today.
- Enterprise platforms price out small agencies. IBM Maximo and Infor EAM require specialist consultants and six-figure implementation budgets, putting modern asset management out of reach for smaller municipalities and school districts.
- Incumbent mobile apps are unreliable. OpenGov/Cartegraph's mobile app is reported as battery-draining and crash-prone; frequent UI changes create retraining burdens for field crews who need simple, stable tools.
- Compliance reporting is manual and fragmented. GASB 34 and grant-application reporting requires assembling data across multiple systems. No incumbent offers automated, data-driven compliance report generation out of the box.
- AI capabilities are siloed or absent. Only iFactory and IBM Maximo offer meaningful AI, but iFactory is a prediction overlay (not a full registry) and Maximo's AI is locked inside IBM's ecosystem. Transparent, explainable AI for condition assessment remains an open gap.
Key Features
Asset Inventory and Hierarchy
- Unique identification and classification for every asset with full attributes: type, location, dimensions, material, installation date, replacement cost, responsible department
- Hierarchical organisation from network to segment to component
- Support for both horizontal (roads, pipes, sewers) and vertical (buildings, facilities) asset types
- Import wizard with AI-assisted field mapping for migrating legacy spreadsheet, GIS, and paper records
GIS Integration (Vendor-Neutral)
- Spatial data linking via open standards: GeoJSON, OGC API Features, PostGIS
- Map-based search, proximity analysis, and network-level views without Esri licence dependency
- Compatible with QGIS, OpenStreetMap, Leaflet, and OpenLayers
- Near real-time data synchronisation with external GIS sources
Condition Inspection and Rating
- Mobile-friendly inspection recording with photo capture and offline support for remote field locations
- Standardised scoring frameworks: Pavement Condition Index (PCI/ASTM D6433), Bridge Health Index (NBI), CCTV pipe grading, Asset Condition Index (ACI)
- AI-assisted condition scoring from inspection photos using computer vision
- Multi-standard condition index support in a unified scoring model
Capital Planning and Scenario Modelling
- Replacement cost forecasting by asset class and condition band
- Scenario modelling showing long-term funding impact of different investment levels, including cost of deferral
- AI-recommended CIP investment allocations based on deterioration models
- Predictive deterioration modelling with maintenance deferral cost analysis
Work Order Management and Maintenance
- Work order creation, assignment, tracking, and completion
- Preventive maintenance scheduling with automated work order generation
- Natural language work order creation from field voice or text notes
- Job costing and cost tracking per asset
Reporting and Compliance
- GASB 34 and ISO 55001-aligned reporting templates
- Automated grant-application report generation
- AI-synthesised plain-language reports for elected officials and non-technical stakeholders
- Natural language query interface for asset data retrieval and ad-hoc reporting
Community and Stakeholder Access
- Citizen/constituent issue submission portal linked to asset records
- Community-facing transparency dashboards showing asset conditions and planned capital works
- Role-based access control for field crews, supervisors, administrators, and finance staff
AI-Native Advantage
Unlike incumbents that bolt AI onto legacy platforms or offer it only as a proprietary overlay, Infrastructure Asset Registry integrates AI as a core capability. Computer vision automates condition scoring from inspection photos, replacing subjective manual ratings. Predictive deterioration models forecast asset failure likelihood based on condition trends, age, material, and environmental factors, giving agencies 30-60 days of advance warning. Natural language interfaces let non-technical staff query asset data and generate reports without BI skills. Automated data migration uses AI to map and transform legacy spreadsheet formats into structured registry schemas, dramatically reducing implementation time.
Tech Stack & Deployment
- GIS foundation: PostGIS, GeoJSON, OGC API Features -- no proprietary GIS licence required
- Frontend mapping: Leaflet or OpenLayers for browser-based map views; QGIS integration for advanced spatial analysis
- Mobile: Offline-capable mobile inspection app for field crews in low-connectivity environments
- Deployment: Self-hosted, cloud, or hybrid
- Integration: REST API for connectivity to financial systems, ERP (SAP, Oracle, Munis, Tyler), and SCADA
- Standards: PCI (ASTM D6433), NBI bridge inspection methodology, ISO 55001 asset management framework, GASB 34 financial reporting
Market Context
The global infrastructure asset management software market serves municipalities, transportation departments, and utilities managing assets worth billions in replacement value. Incumbent pricing follows annual SaaS subscriptions tiered by asset count or municipality population, with enterprise platforms like IBM Maximo and Infor EAM requiring substantial implementation services on top of licence fees. Primary buyers are public works directors, asset management coordinators, and municipal CIOs under increasing regulatory pressure from GASB 34 requirements and federal/state infrastructure funding programmes that mandate demonstrated asset management capability.
Running It
docker compose up -d # PostGIS 16-3.4 :54439, Redis :63439, MinIO :59439
cd target && uv sync
uv run alembic upgrade head # the same command the platform release: step runs
uv run python scripts/seed_frameworks.py --destination dev # PCI, NBI as data
uv run python scripts/seed.py --destination dev # a populated demo agency
uv run honcho start # API on :8080, Celery worker, beat
curl -s localhost:8080/healthz # {"status":"ok","db":true,"redis":true,"storage":true}
Full walkthrough: user-docs/getting-started.md · Demo data, per destination: user-docs/demo-data.md · Tests: user-docs/testing.md · Commands: user-docs/useful-commands.md · API: user-docs/api-reference.md and the generated OpenAPI 3.1 document.
Configuration
Every option the application reads is listed below. There is exactly one place
that reads configuration — Settings in target/src/iar/config.py — and no
service anywhere in the codebase touches os.environ, which a contract test
enforces by scanning the source tree.
There is no DATABASE_URL and no REDIS_URL. The platform injects discrete
DATABASE_HOST/_PORT/_NAME/_USER/_PASSWORD/_SSL and
REDIS_HOST/_PORT/_NAMESPACE/_TLS variables and the application composes its
connection strings from them. A settings object with a database_url field works
on a laptop and silently fails to connect on every deployed destination.
Destinations never layer. .env.<destination> is the only file consulted
for that destination — there is no base file underneath it. Every key a
destination needs appears in its own template, which is why the three templates
repeat each other rather than sharing a common part:
| Destination | Template | Notes |
|---|---|---|
dev | .env.dev.example | run from the IDE against the compose stack |
prod-parity | .env.prod-parity.example | local full-parity compose deployment |
aws | .env.aws.example | placeholders only; secrets come from the platform |
On aws the whole DATABASE_* and REDIS_* namespace, the S3 bucket and
credentials, and AUTH_CLIENT_SECRET are deliberately absent from the
template. The platform injects them, and a key in the file that the platform also
injects shadows the injected value — which points the application at the wrong
database with no error at all. Their defaults, shown below, apply there.
Runtime
| Option | Default | What it does |
|---|---|---|
APP_NAME | 439-infrastructure-asset-registry-core | Service name in every log line. |
APP_ENV | local | Free-text environment label; appears in logs. |
APP_URL | http://localhost:8080 | The externally reachable base URL, used to build absolute links. |
LOG_LEVEL | INFO | Root log level. Logs are one-line JSON on stdout, mapped to the OTel Logs Data Model. |
PORT | 8080 | The platform contract. A framework default of 3000 or 8000 works locally and is unreachable when deployed. |
IAR_WEB_DIST | (unset) | Directory holding the built SPA. Unset means web/dist relative to the working directory, which is what the container image provides. |
Database
DATABASE_SSL=true is honoured with a real TLS context — RDS injects it as true.
Credentials are percent-encoded when the DSN is composed, because an unescaped
@ in a platform-generated password would otherwise point the application at a
different host entirely.
| Option | Default | What it does |
|---|---|---|
DATABASE_HOST | localhost | Injected by the platform. |
DATABASE_PORT | 5432 | Injected by the platform. |
DATABASE_NAME | iar | Injected by the platform. |
DATABASE_USER | iar | Injected by the platform. |
DATABASE_PASSWORD | (empty) | Injected by the platform. Never committed. |
DATABASE_SSL | false | true opens the connection with a verified TLS context. |
DATABASE_POOL_SIZE | 10 | Connections kept open per process. |
DATABASE_MAX_OVERFLOW | 10 | Additional connections allowed under burst. |
DATABASE_ECHO | false | Logs every SQL statement. Keep it false outside a debugging session: it is the fastest way to get row values into the log. |
Redis
Redis is a broker and a cache only, declared durable: false. Every job's source
of truth is the Postgres jobs table and every task is idempotent, so a queue
entry lost to a failover is re-derivable.
| Option | Default | What it does |
|---|---|---|
REDIS_HOST | localhost | Injected by the platform. |
REDIS_PORT | 6379 | Injected by the platform. |
REDIS_DB | 0 | Logical database index. Managed Redis often exposes only 0; REDIS_NAMESPACE is what actually keeps applications apart. |
REDIS_NAMESPACE | iar | Mandatory key prefix applied to every key the application writes — cache entries, rate-limit buckets, and the Celery broker's global_keyprefix. Cache-mode Redis may be shared. |
REDIS_TLS | false | true selects the rediss:// scheme. |
Object storage
Inspection media and rendered reports. Only object keys are stored in Postgres.
Locally this is the MinIO service in docker-compose.yaml; on aws it is the
bucket declared by s3.enabled, with versioning requested and re-checked at
runtime by MediaStore.ensure_versioning().
| Option | Default | What it does |
|---|---|---|
S3_BUCKET | iar-media | Bucket name. Injected on aws. |
S3_REGION | us-east-1 | Bucket region. |
S3_ENDPOINT_URL | (unset) | Point at MinIO locally; leave empty on aws so boto3 uses the real endpoint. |
S3_PUBLIC_ENDPOINT_URL | (unset) | The endpoint a browser must use to follow a presigned download URL, when it differs from the one the application talks to. Set on the local compose stack (http://localhost:59439), where the app reaches MinIO as minio:9000 and no browser can resolve that name; empty everywhere else. The host is part of the SigV4 signature, so the URL is signed for this endpoint rather than rewritten afterwards. |
S3_ACCESS_KEY_ID | (unset) | Injected on aws (IRSA). |
S3_SECRET_ACCESS_KEY | (unset) | Injected on aws (IRSA). |
S3_FORCE_PATH_STYLE | false | true for MinIO, which does not do virtual-host-style addressing. |
MEDIA_MAX_BYTES | 26214400 (25 MB) | Largest accepted inspection photo. |
Authentication
Sign-in goes through the platform HAP (OAuth 2.0 + OIDC, PKCE S256). The
application never presents an isolated app-only login to a user who already holds
a platform session, and users are keyed on sub, never on email.
AUTH_ISSUERonawsis an unresolved placeholder. The platform documentation giveswbsp-auth.wbsp-demo.comand the HAP documentation givesauth.wbsp-demo.comfor what is described as the same service (TODO(HAP_ISSUER_HOSTNAME), constitution §Unresolved Platform Constraints). Confirm with the operator before the firstawsdeploy. Do not guess: a plausible wrong issuer deploys cleanly and fails every sign-in.
| Option | Default | What it does |
|---|---|---|
AUTH_ISSUER | (empty) | OIDC issuer URL. Empty disables authentication wiring entirely. |
AUTH_CLIENT_ID | (empty) | OIDC client id. |
AUTH_CLIENT_SECRET | (empty) | OIDC client secret. Declared under secrets: in wbsp.yaml; a declared secret with no value fails the deploy, which is the intended fail-closed behaviour. |
AUTH_REDIRECT_URI | (empty) | Must match the registered redirect URI exactly. |
AUTH_POST_LOGOUT_REDIRECT_URI | (empty) | Where the HAP returns the browser after sign-out. |
AUTH_SCOPES | openid profile email | Scope list, comma- or space-separated. The committed templates use commas: uv run --env-file abandons parsing an entire file at the first unquoted space and loads nothing but a warning, at which point every key silently takes its default — including SESSION_COOKIE_SECURE. |
SESSION_SECRET | change-me | Signing key for the session cookie. Replace on every deployed destination. |
SESSION_COOKIE_NAME | iar_session | Configurable so two deployments on sibling hostnames cannot overwrite each other's cookie. |
SESSION_COOKIE_SECURE | true | Local destinations set this false deliberately: browsers drop a Secure cookie over http://localhost, and the symptom is a sign-in loop with no error. |
SESSION_MAX_AGE_SECONDS | 28800 (8 h) | Session lifetime — a working day, after which the HAP is asked again. |
AUTH_DEV_LOGIN | false | Local unattended runs only. Signs in as one named existing account without an OIDC round trip, so the Impeccable pass, the E2E suite and the screenshot capture can reach authenticated views with nobody at the keyboard. Enabling it on a non-local APP_ENV is a startup failure, not a warning. See user-docs/login-bypass.md. |
AUTH_DEV_LOGIN_SUB | (empty) | Which existing account AUTH_DEV_LOGIN signs in as, by sub. No default: a bypass that picks an account for you is one nobody can audit. It grants no authority — roles are read from the database per request, exactly as for a real session. |
AUTH_HAP_ISSUER | (empty) | Injected by the platform, never set by hand. The shared demo HAP issuer, supplied to every demo/sandbox pod at launch. Do not put it in a .env file and do not declare it under secrets: — a demo deploy is fail-closed on declared secrets, so declaring credentials the platform supplies blocks the lane on values nobody can look up. |
AUTH_HAP_ID | (empty) | Injected alongside AUTH_HAP_ISSUER. The shared demo client id, whose redirect is a wildcard across *.wbsp-demo.com — which is what makes sign-in work on a sandbox URL without registering one per host. |
AUTH_HAP_SECRET | (empty) | Injected alongside AUTH_HAP_ISSUER. When all three are present they replace AUTH_ISSUER / AUTH_CLIENT_ID / AUTH_CLIENT_SECRET at startup; when any is missing the baked-in client is kept, so a half-injected client cannot break a working configuration. |
Email — optional
| Option | Default | What it does |
|---|---|---|
SMTP_HOST | (unset) | Unset means notifications are in-app only and the API reports email_status: skipped_no_config (FR-079). Nothing else degrades. |
SMTP_PORT | (unset) | |
SMTP_USER | (unset) | |
SMTP_PASSWORD | (unset) | |
SMTP_FROM | (unset) | Required alongside SMTP_HOST for email to be considered configured. |
SMTP_TLS | true | STARTTLS. |
Assisted capabilities — optional
With no model access configured, GET /api/v1/capabilities reports every
capability false, each AI endpoint returns 503 capability_unavailable, and
everything else in the product works normally (FR-051). That is a tested
contract, not a degraded mode.
| Option | Default | What it does |
|---|---|---|
AI_MODEL_CHAT | (unset) | Enables natural-language query and report synthesis. |
AI_MODEL_VISION | (unset) | Enables computer-vision condition assessment. |
AI_API_KEY | (unset) | Provider credential. |
AI_API_BASE | (unset) | Override for a self-hosted or proxied endpoint. Access routes through a provider-neutral abstraction; no single AI vendor is ever required to run the system. |
AI_VISION_CONFIDENCE_THRESHOLD | 0.75 | Below this an assessment is flagged requires_human_review. Vision scores are advisory and always overridable, with the override recorded. |
Limits and pagination
| Option | Default | What it does |
|---|---|---|
RATE_LIMIT_AUTHENTICATED_PER_MINUTE | 300 | Per user (FR-066). Exceeded → 429 with Retry-After. |
RATE_LIMIT_PUBLIC_PER_MINUTE | 20 | Per IP on the citizen surface (FR-039). |
PAGINATION_DEFAULT_LIMIT | 50 | Page size when the caller names none. |
PAGINATION_MAX_LIMIT | 500 | Hard cap on limit. |
Continuity
| Option | Default | What it does |
|---|---|---|
BACKUP_BASIS | managed | Which facility recovery rests on. managed uses the platform's own backups as the RPO basis, with this application owning automated restore verification. self_managed_dump activates the application-owned pg_dump-to-S3 contingency, so a withdrawn PostGIS grant is a configuration change rather than a rewrite. See user-docs/backup-restore.md. |
Project Status
This project is in the research and specification phase.
Contributions, feedback, and domain expertise are welcome.
Contributing
We welcome contributions from developers, domain experts, and potential users. See CONTRIBUTING.md for guidelines.
Important: All contributions must be your own original work or clearly attributed open-source material with a compatible licence. Copyright infringement and licence violations will not be tolerated and will result in immediate removal of the offending contribution. If you are unsure whether a piece of code, text, or other material is safe to contribute, open an issue and ask before submitting.
Licence
Licence to be determined. See discussion for context.