FireBIM

FireBIM Backend Architecture

Documentation of the FireBIM system architecture, backend capabilities, rule and graph execution model, lexicon layer, IFC/IDS workflows, authentication model, and operational API surface.

11 API routers
118 route decorators
13 app modules
9 runtime services
Architecture documentation. This document describes the open source FireBIM reference platform also known as the "backend system": the technical layers, runtime services, rule graph and check execution model, lexicon architecture, IFC and IDS workflows, and the authentication, admin, user, and security model. The chapters are organized for developers first, while still giving product, audit, and domain readers a coherent view of how FireBIM turns building data, rules, ontologies, and checks into explainable API capabilities.
Chapter 01
Backend Architecture Overview

# FireBIM Backend Architecture Overview

Source scope: firebim-api-server architecture view documents. Purpose: provide the executive and technical entry point for the static HTML architecture document.

Scope And System Boundary

The FireBIM backend is a graph-oriented API platform for BIM compliance workflows. It accepts source artifacts, stores graph-compatible domain data, exposes ontology-aware interpretation services, and executes traceable rule checks over building graph data.

The backend boundary includes:

  • API services exposed through FastAPI routers
  • authentication and user ownership through Authentik-backed JWT validation
  • file and metadata workflows for IFC and IDS artifacts
  • graph publication and schema extraction
  • stable rule artifacts and rule element composition
  • check execution with explicit true, false, and unknown paths
  • ontology-aware Lexicon services for catalogs, mappings, profiles, handshakes, reconstruction, and conformity
  • storage through PostgreSQL, S3/MinIO, and graph-store datasets
  • asynchronous worker execution through Celery and RabbitMQ

The backend boundary does not include the future firebim-webapp architecture. Frontend behavior is referenced only where it consumes or enforces backend capabilities.

Architecture Principles

The backend is organized around explicit boundaries and clear trade-offs:

  • The API layer exposes resource-oriented endpoints and typed contracts.
  • Domain modules own business behavior rather than pushing domain logic into routers.
  • Durable artifacts are separated by storage type: relational metadata, object storage, graph datasets, and user-scoped JSON documents.
  • Long-running or file-heavy work is moved to workers.
  • Rule execution prioritizes explainability over raw speed.
  • Unknown outcomes are modeled explicitly by rule authors instead of being treated as accidental engine failures.
  • Ontology drift is handled through Lexicon mapping and transformation capabilities rather than by rewriting stable rule artifacts.
  • Security is layered through external identity, token validation, local user projection, ownership checks, and future explicit admin policy.

High-Level Backend Map

High-Level Backend MapOpen full screenClose
Clients and API consumersFastAPI backendAuthentication and usersIFC and IDS artifactsBuilding graphsRules and rule elementsChecks runtimeLexicon and ontologyadaptationCelery workerS3 / MinIOPostgreSQLGraph datasets
Diagram definition
flowchart TB
    clients["Clients and API consumers"] --> api["FastAPI backend"]
    api --> auth["Authentication and users"]
    api --> ifcids["IFC and IDS artifacts"]
    api --> graphs["Building graphs"]
    api --> rules["Rules and rule elements"]
    api --> checks["Checks runtime"]
    api --> lexicon["Lexicon and ontology adaptation"]

    ifcids --> worker["Celery worker"]
    worker --> objectStorage[("S3 / MinIO")]
    api --> objectStorage
    api --> postgres[("PostgreSQL")]
    graphs --> graphStore[("Graph datasets")]
    rules --> graphStore
    checks --> graphStore
    lexicon --> objectStorage

Core Technical Layers

LayerResponsibility
API boundaryFastAPI routers, request validation, error translation, response contracts
Domain servicesRules, checks, lexicon, ontologies, graph processing, file workflows
Runtime enginesRule compilers, check solvers, Lexicon query runtime, IFC/IDS workers
PersistencePostgreSQL metadata, S3/MinIO objects and JSON documents, graph datasets
IdentityAuthentik OIDC, JWKS validation, local user projection
ObservabilityRequest IDs, profiling headers, timing metrics, DB checkout metrics

The live API documentation is available at:

This static architecture document also points to the API architecture view document firebim-api-staging-architecture view.html.

Reading Guide

This HTML document is composed from the source Markdown files in this architecture documentation set:

1. architecture-architecture view.md describes the assembled technical shape of the backend. 2. rules-graphs-checks-synergies.md explains the core rule/graph/check execution model. 3. lexicon-architecture.md explains ontology-aware adaptation and reconstruction. 4. ifc-ids-architecture.md explains file-based BIM interoperability and worker processing. 5. authentication-admin-users-security.md explains identity, users, admin posture, and security.

The sections are intentionally layered from high-level context to component details. This mirrors the backend architecture itself: system boundary first, then services, persistence, execution flows, and security posture.

Chapter 02
Backend Technical Architecture

FireBIM API Server Architecture

assembled: 2026-05-20T09:40:45+00:00 Source: C:\Users\krnj\OneDrive - Danmarks Tekniske Universitet\Dokumenter\Software\FireBIM\firebim-api-server

This architecture view describes the current technical shape of firebim-api-server. It is assembled from the codebase and is intended as a repeatable architecture baseline: high-level first, then runtime containers, API surface, internal modules, data flow, and assembled evidence.

The document is declarative. It states what the current system structure is, based on the scanned repository. Curated architecture analysis can build on top of this architecture view, but the architecture view itself remains grounded in source files, Docker Compose, Kubernetes manifests, FastAPI routers, Python imports, and project metadata.

1. Architectural Role

firebim-api-server is the backend boundary for FireBIM. It exposes HTTP APIs, authenticates users through OIDC/JWT integration, stores and retrieves graph-oriented artifacts, compiles and executes rule checks, and coordinates local runtime dependencies such as PostgreSQL, MinIO/S3, RabbitMQ, and Authentik.

The API server is not only a CRUD service. It is a graph-oriented application layer for rules, building graphs, ontology/lexicon resources, and check execution.

Architectural RoleOpen full screenClose
FireBIM user / clientFireBIM API serverAuthentik OIDCPostgreSQLMinIO / S3 object storageRabbitMQ broker
Diagram definition
flowchart LR
    user["FireBIM user / client"]
    api["FireBIM API server"]
    auth["Authentik OIDC"]
    db[("PostgreSQL")]
    s3[("MinIO / S3 object storage")]
    mq[("RabbitMQ broker")]
    user --> api
    api --> auth
    api --> db
    api --> s3
    api --> mq

2. Technical Layers

The backend is organized around clear technical layers. Requests enter through FastAPI routers, move into domain modules, use repositories and infrastructure clients for persistence, and return typed schema responses.

Technical LayersOpen full screenClose
Clients and frontend workflowsFastAPI routersPydantic schemasDomain services and enginesRules, checks, lexicon,ontologiesRepository layerPostgreSQLS3 / MinIORDF / TTL processingRequest context andobservability
Diagram definition
flowchart TB
    client["Clients and frontend workflows"] --> api["FastAPI routers"]
    api --> schemas["Pydantic schemas"]
    api --> domain["Domain services and engines"]
    domain --> rules["Rules, checks, lexicon, ontologies"]
    domain --> storage["Repository layer"]
    storage --> postgres[("PostgreSQL")]
    storage --> s3[("S3 / MinIO")]
    domain --> rdf["RDF / TTL processing"]
    api --> observability["Request context and observability"]

The layers have these responsibilities:

LayerResponsibility
API routersHTTP endpoints, request orchestration, response models, error translation
SchemasPydantic contracts for API requests and responses
Domain modulesRules, checks, graph processing, ontology services, lexicon runtime, rulebuilder logic
Storage modulesRepository interfaces for graph, ontology, lexicon, building, and workspace state
InfrastructureConfiguration, S3 client, observability, database initialization, workers
Runtime servicesPostgreSQL, MinIO/S3, RabbitMQ, Authentik, Mailpit, PgAdmin

3. Runtime Containers

The local runtime is defined by Docker Compose. The API container depends on durable storage, object storage, message broker infrastructure, and identity infrastructure. The Celery worker shares key backend dependencies and executes background work through the configured broker.

Runtime ContainersOpen full screenClose
apidocker/api/Dockerfilecelery-workerdocker/worker/Dockerfilerabbitmqrabbitmq:4-management-alpinepostgrespostgres:17-alpineminiominio/minio:latestmailpitaxllent/mailpit:latestauthentik-serverghcr.io/goauthentik/server:2025.12authentik-workerghcr.io/goauthentik/server:2025.12pgadmindpage/pgadmin4:latest
Diagram definition
flowchart TB
    api["api\ndocker/api/Dockerfile"]
    celery_worker["celery-worker\ndocker/worker/Dockerfile"]
    rabbitmq["rabbitmq\nrabbitmq:4-management-alpine"]
    postgres["postgres\npostgres:17-alpine"]
    minio["minio\nminio/minio:latest"]
    mailpit["mailpit\naxllent/mailpit:latest"]
    authentik_server["authentik-server\nghcr.io/goauthentik/server:2025.12"]
    authentik_worker["authentik-worker\nghcr.io/goauthentik/server:2025.12"]
    pgadmin["pgadmin\ndpage/pgadmin4:latest"]
    api --> postgres
    api --> minio
    api --> rabbitmq
    api --> authentik_server
    celery_worker --> postgres
    celery_worker --> rabbitmq
    celery_worker --> minio
    authentik_server --> postgres
    authentik_server --> mailpit
    authentik_worker --> postgres
    authentik_worker --> mailpit
    pgadmin --> postgres
ServiceRuntimeDepends onPorts
apidocker/api/Dockerfilepostgres, minio, rabbitmq, authentik-server8000:8000
celery-workerdocker/worker/Dockerfilepostgres, rabbitmq, minio-
rabbitmqrabbitmq:4-management-alpine-5672:5672, 15672:15672
postgrespostgres:17-alpine-5432:5432
miniominio/minio:latest-9000:9000, 9001:9001
mailpitaxllent/mailpit:latest-8025:8025, 1025:1025
authentik-serverghcr.io/goauthentik/server:2025.12postgres, mailpit9080:9000, 9443:9443
authentik-workerghcr.io/goauthentik/server:2025.12postgres, mailpit-
pgadmindpage/pgadmin4:latestpostgres5050:5050

Kubernetes manifests detected: api.yaml, minio.yaml, namespace.yaml, postgres.yaml, worker.yaml.

4. Request And Runtime Flow

A normal API request enters FastAPI, receives request context and observability metadata, reaches a router, calls domain logic, and uses repositories or runtime engines to perform the work. Responses are returned through typed schemas or explicit response classes.

Request And Runtime FlowOpen full screenClose
ClientFastAPIRouterDomainStorageRuntimeHTTP requestrequest id and observabilitycontextroute handlerservice / engine callrepository read/write when neededcompile, evaluate, parse, ortransform when neededcomputed resultpersisted artifact or metadatadomain resulttyped response
Diagram definition
sequenceDiagram
    participant Client
    participant FastAPI
    participant Router
    participant Domain
    participant Storage
    participant Runtime

    Client->>FastAPI: HTTP request
    FastAPI->>FastAPI: request id and observability context
    FastAPI->>Router: route handler
    Router->>Domain: service / engine call
    Domain->>Storage: repository read/write when needed
    Domain->>Runtime: compile, evaluate, parse, or transform when needed
    Runtime-->>Domain: computed result
    Storage-->>Domain: persisted artifact or metadata
    Domain-->>Router: domain result
    Router-->>Client: typed response

This flow is visible in app/main.py, where routers are registered and request observability middleware wraps each request.

5. API Surface

The API surface is grouped by FastAPI routers. Each router maps a bounded functional area to a URL prefix. The current architecture view detects 11 routers and 118 route decorators.

API SurfaceOpen full screenClose
FastAPI appapp/main.py/1 routesapp.api.build_info/checks7 routesapp.api.checks/graphs6 routesapp.api.graphs/1 routesapp.api.health/ids-files4 routesapp.api.ids/lexicon41 routesapp.api.lexicon/ifc-models4 routesapp.api.models/ontologies20 routesapp.api.ontologies/rulebuilder8 routesapp.api.rulebuilder/rules25 routesapp.api.rules/1 routesapp.auth.router
Diagram definition
flowchart LR
    app["FastAPI app\napp/main.py"]
    app_api_build_info["/\n1 routes\napp.api.build_info"]
    app --> app_api_build_info
    app_api_checks["/checks\n7 routes\napp.api.checks"]
    app --> app_api_checks
    app_api_graphs["/graphs\n6 routes\napp.api.graphs"]
    app --> app_api_graphs
    app_api_health["/\n1 routes\napp.api.health"]
    app --> app_api_health
    app_api_ids["/ids-files\n4 routes\napp.api.ids"]
    app --> app_api_ids
    app_api_lexicon["/lexicon\n41 routes\napp.api.lexicon"]
    app --> app_api_lexicon
    app_api_models["/ifc-models\n4 routes\napp.api.models"]
    app --> app_api_models
    app_api_ontologies["/ontologies\n20 routes\napp.api.ontologies"]
    app --> app_api_ontologies
    app_api_rulebuilder["/rulebuilder\n8 routes\napp.api.rulebuilder"]
    app --> app_api_rulebuilder
    app_api_rules["/rules\n25 routes\napp.api.rules"]
    app --> app_api_rules
    app_auth_router["/\n1 routes\napp.auth.router"]
    app --> app_auth_router
PrefixModuleRoutesExamples
/app.api.build_info1GET /build-info
/checksapp.api.checks7GET /checks/health<br>POST /checks/run<br>POST /checks/run-vertical<br>POST /checks/run-horisontal<br>POST /checks/run-diagnostic<br>POST /checks/run-blind<br>POST /checks/compatibility
/graphsapp.api.graphs6GET /graphs/health<br>GET /graphs<br>POST /graphs/publish<br>DELETE /graphs/{graph_id}<br>GET /graphs/{graph_id}<br>POST /graphs/extract-schema
/app.api.health1GET /health
/ids-filesapp.api.ids4POST /ids-files<br>GET /ids-files/{id}<br>GET /ids-files<br>GET /ids-files/{id}/download
/lexiconapp.api.lexicon41GET /lexicon/health<br>GET /lexicon/catalog/{ontology_family}/{country}/{version}/terms<br>GET /lexicon/catalog/{ontology_family}/{country}/{version}/terms/{term_id}<br>POST /lexicon/catalog/resolve-terms<br>POST /lexicon/catalog/compare<br>POST /lexicon/catalog/similarity<br>POST /lexicon/catalog/similarity-matrix<br>POST /lexicon/catalog/rule-ontology-similarity<br>... 33 more
/ifc-modelsapp.api.models4POST /ifc-models<br>GET /ifc-models/{id}<br>GET /ifc-models<br>GET /ifc-models/{id}/download
/ontologiesapp.api.ontologies20GET /ontologies/health<br>POST /ontologies/publish<br>POST /ontologies/conversions/dictionary-json-to-ttl<br>POST /ontologies/candidates/dictionaries<br>GET /ontologies/candidates/dictionaries<br>GET /ontologies/candidates/dictionaries/{candidate_id}<br>GET /ontologies/candidates/dictionaries/{candidate_id}/summary<br>GET /ontologies/candidates/dictionaries/{candidate_id}/json<br>... 12 more
/rulebuilderapp.api.rulebuilder8POST /rulebuilder/workspaces<br>POST /rulebuilder/rules/{rule_id}/workspace<br>PUT /rulebuilder/workspaces/{workspace_id}<br>GET /rulebuilder/workspaces<br>GET /rulebuilder/workspaces/{workspace_id}<br>DELETE /rulebuilder/workspaces/{workspace_id}<br>POST /rulebuilder/workspaces/delete-batch<br>POST /rulebuilder/workspaces/{workspace_id}/export-rule-elements
/rulesapp.api.rules25GET /rules/health<br>POST /rules/validate<br>POST /rules/compile<br>POST /rules/decompile<br>POST /rules/publish<br>GET /rules/list<br>POST /rules/fetch<br>POST /rules/delete<br>... 17 more
/app.auth.router1GET /users/me

The API surface currently exposes capabilities for authentication, health/build metadata, model and IDS file handling, graph publication, ontology workflows, lexicon workflows, rule authoring, rule publishing, rulebuilder workspaces, and check execution.

6. Internal Components

The internal module graph collapses app.* imports to first-level packages. This keeps the assembled diagram high-level enough for architecture review while still showing actual dependency direction from the codebase.

Internal ComponentsOpen full screenClose
app.apiFastAPI route layer andrequest/responseorchestration.app.authOIDC/JWT authenticationintegration.app.checksGraph/rule check planning,compilation, execution, andresult models.app.coreConfiguration, observability,and shared infrastructureclients.app.graphs_and_checksPublishing helpers thatconnect graph and checkworkflows.app.lexiconLexicon resources, matching,profiles, and query runtime.app.modelsDatabase models and databaseinitialization.app.ontologiesOntology service logic anddictionary ontology support.app.rulebuilderRulebuilder layout andassembly support.app.rulesRule DSL, composition, SHACLgeneration, and rule executionsupport.app.schemasPydantic API schemas.app.storageRepositories and persistenceadapters for database, objectstorage, graph, and ontologyapp.workersCelery worker application andbackground task entrypoint.
Diagram definition
flowchart LR
    api["app.api\nFastAPI route layer and request/response orchestration."]
    auth["app.auth\nOIDC/JWT authentication integration."]
    checks["app.checks\nGraph/rule check planning, compilation, execution, and result models."]
    core["app.core\nConfiguration, observability, and shared infrastructure clients."]
    graphs_and_checks["app.graphs_and_checks\nPublishing helpers that connect graph and check workflows."]
    lexicon["app.lexicon\nLexicon resources, matching, profiles, and query runtime."]
    models["app.models\nDatabase models and database initialization."]
    ontologies["app.ontologies\nOntology service logic and dictionary ontology support."]
    rulebuilder["app.rulebuilder\nRulebuilder layout and assembly support."]
    rules["app.rules\nRule DSL, composition, SHACL generation, and rule execution support."]
    schemas["app.schemas\nPydantic API schemas."]
    storage["app.storage\nRepositories and persistence adapters for database, object storage, graph, and ontology state."]
    workers["app.workers\nCelery worker application and background task entrypoint."]
    api --> auth
    api --> checks
    api --> core
    api --> graphs_and_checks
    api --> lexicon
    api --> models
    api --> ontologies
    api --> rulebuilder
    api --> rules
    api --> schemas
    api --> storage
    api --> workers
    auth --> core
    auth --> models
    auth --> schemas
    checks --> graphs_and_checks
    checks --> rules
    graphs_and_checks --> rules
    graphs_and_checks --> storage
    lexicon --> core
    lexicon --> graphs_and_checks
    lexicon --> rules
    lexicon --> schemas
    lexicon --> storage
    models --> core
    ontologies --> schemas
    ontologies --> storage
    rulebuilder --> schemas
    rules --> storage
    storage --> core
    storage --> models
    storage --> rules
    storage --> schemas
    workers --> core
    workers --> models
PackageResponsibilityInternal dependencies
app.apiFastAPI route layer and request/response orchestration.app.auth, app.checks, app.core, app.graphs_and_checks, app.lexicon, app.models, app.ontologies, app.rulebuilder, app.rules, app.schemas, app.storage, app.workers
app.authOIDC/JWT authentication integration.app.core, app.models, app.schemas
app.checksGraph/rule check planning, compilation, execution, and result models.app.graphs_and_checks, app.rules
app.coreConfiguration, observability, and shared infrastructure clients.-
app.graphs_and_checksPublishing helpers that connect graph and check workflows.app.rules, app.storage
app.lexiconLexicon resources, matching, profiles, and query runtime.app.core, app.graphs_and_checks, app.rules, app.schemas, app.storage
app.modelsDatabase models and database initialization.app.core
app.ontologiesOntology service logic and dictionary ontology support.app.schemas, app.storage
app.rulebuilderRulebuilder layout and assembly support.app.schemas
app.rulesRule DSL, composition, SHACL generation, and rule execution support.app.storage
app.schemasPydantic API schemas.-
app.storageRepositories and persistence adapters for database, object storage, graph, and ontology state.app.core, app.models, app.rules, app.schemas
app.workersCelery worker application and background task entrypoint.app.core, app.models

The most important architectural clusters are:

  • app.api: HTTP boundary and orchestration layer.
  • app.rules: rule DSL, rule composition, SHACL generation, publishing, and decompilation support.
  • app.checks: check compilation, solver selection, runtime execution, diagnostics, and result models.
  • app.storage: repositories and graph/object persistence adapters.
  • app.lexicon and app.ontologies: vocabulary, ontology, mapping, and query-oriented domain logic.
  • app.workers: asynchronous worker entrypoint and Celery application setup.

7. Data And Storage Flow

Durable state is represented through repository modules, PostgreSQL-backed models, S3/MinIO object storage, RDF/TTL resources, and assembled ontology/demo content bootstrapping.

Data And Storage FlowOpen full screenClose
API routesChecks engineRules / DSL / SHACLLexicon and ontology runtimeRepository layerPostgreSQLS3 / MinIORDF / TTL resources
Diagram definition
flowchart LR
    api["API routes"]
    checks["Checks engine"]
    rules["Rules / DSL / SHACL"]
    lexicon["Lexicon and ontology runtime"]
    storage["Repository layer"]
    db[("PostgreSQL")]
    s3[("S3 / MinIO")]
    rdf[("RDF / TTL resources")]
    api --> checks
    api --> rules
    api --> lexicon
    checks --> storage
    rules --> storage
    lexicon --> storage
    storage --> db
    storage --> s3
    lexicon --> rdf

The storage model is graph-oriented. Rules, building graphs, ontology resources, lexicon mappings, and assembled demo content are treated as artifacts that can be published, fetched, transformed, and analyzed.

8. Rules, Graphs, And Checks Layer

Rules, Graphs, and Checks form a core architecture axis in the API server.

Rules, Graphs, And Checks LayerOpen full screenClose
Rules APIrulebook datasetGraphs APIbuildings datasetChecks APICompatibilityRule compilerSolver runtimesTraceable results
Diagram definition
flowchart LR
    rules["Rules API"] --> rulebook[("rulebook dataset")]
    graphs["Graphs API"] --> buildings[("buildings dataset")]
    rulebook --> checks["Checks API"]
    buildings --> checks
    checks --> compatibility["Compatibility"]
    checks --> compiler["Rule compiler"]
    checks --> solvers["Solver runtimes"]
    checks --> traces["Traceable results"]

This layer is described in detail in rules-graphs-checks-synergies.md. In this architecture view the layer is represented as a technical fact: rules and building graphs are stored as graph-compatible artifacts, and checks execute one against the other with compatibility, compilation, solver selection, and diagnostics.

9. Architecture Evidence

The architecture view is assembled from these source signals:

SignalCurrent use
app/main.pyFastAPI app setup, router inclusion, middleware, startup behavior
app/api/*.py and app/auth/router.pyRouter prefixes, route counts, route examples
Python imports under app/*First-level internal package dependency graph
docker-compose.ymlLocal runtime containers, dependencies, ports
k8s/manifests/*.yamlDeployment artifact inventory
pyproject.tomlTechnology and dependency signals

Detected project dependencies: alembic, S3 client / boto3, Celery, email-validator, FastAPI, fastapi-cli, HTTPX, psycopg2-binary, Pydantic, pydantic-settings, pyjwt, python-multipart, RDFLib, SQLModel, uuid, uvicorn.

10. Architecture Outputs

The architecture document directory contains this Markdown file, a machine-readable inventory.json, and standalone Mermaid diagram files under diagrams/.

The standalone diagram files are:

  • 01-system-context.mmd
  • 02-container-view.mmd
  • 03-api-routes.mmd
  • 04-python-modules.mmd
  • 05-data-flow.mmd

These files can be embedded in documentation systems or rendered independently when a Markdown renderer does not support Mermaid directly.

Chapter 03
Rules, Graphs And Checks

# Rules, Graphs And Checks: Architecture, Synergies, And Product Potential

Source: firebim-api-server Primary audience: developers building and extending FireBIM. Frontend experiences, rule-authoring tools, product workflows, and audit-facing views are built on top of this architecture.

Purpose

FireBIM uses rules, graphs, and checks as three connected architectural concepts:

  • Rules describe fire-safety requirements, decision logic, explicit branches, and terminal outcomes.
  • Graphs describe building data as RDF/Turtle graph data.
  • Checks execute a selected rule against a selected building graph and return transparent, traceable outcomes.

The architecture is graph-oriented by design. Rules and building data are both represented as graph-compatible artifacts, which allows FireBIM to reason about requirements, available data, missing information, ontology mappings, runtime behavior, and explainability in one connected model.

System Model

The system flow is:

1. Rule authoring sends rule definitions to the Rules API. 2. Building graph import sends building graph TTL to the Graphs API. 3. The Rules API stores rule TTL in the rulebook dataset. 4. The Graphs API stores building graph TTL in the buildings dataset. 5. The Checks API fetches both artifacts, computes compatibility, compiles the rule, selects a solver, and returns traceable results.

System ModelOpen full screenClose
Rule authoringRules APIBuilding graph importGraphs APIrulebook datasetbuildings datasetChecks APICompatibilityRule compilerFireBIM solversTraceable results
Diagram definition
flowchart LR
    author["Rule authoring"] --> rules["Rules API"]
    importer["Building graph import"] --> graphs["Graphs API"]

    rules --> rulebook[("rulebook dataset")]
    graphs --> buildings[("buildings dataset")]

    rulebook --> checks["Checks API"]
    buildings --> checks

    checks --> compatibility["Compatibility"]
    checks --> compiler["Rule compiler"]
    checks --> solvers["FireBIM solvers"]
    checks --> results["Traceable results"]

The model has a deliberate separation of concerns:

  • Rules define what can be evaluated and how every branch behaves.
  • Graphs define what building information exists.
  • Checks determine how a rule behaves against a specific building graph.

This separation allows FireBIM to validate rule structure, inspect building data readiness, execute checks, and explain outcomes without collapsing all logic into one opaque validation step.

Rules

Rules are stable compliance artifacts. They can exist in many versions, and those versions can later be transformed, migrated, or mapped when ontologies evolve. The lexicon architecture is the natural place for ontology-aware rule transformation and mapping; that topic belongs in a separate document.

Rules API responsibilities include:

  • validating rule payloads
  • compiling rule payloads to SHACL/Turtle
  • publishing full rules to the rulebook dataset
  • publishing reusable rule elements
  • fetching and decompiling rules back into structured JSON-like data
  • assembling rules from stored rule elements
  • connecting and disconnecting rule branches
  • checking rule completeness
  • extracting target classes, property paths, and target/property pairs

Rules are not only stored. They are analyzable graph artifacts.

A rule element contains explicit branch behavior. Decision nodes include true, false, and unknown paths. This is a core FireBIM design decision and not a conventional SHACL-only interpretation.

RulesOpen full screenClose
Decision nodeTrue pathFalse pathUnknown pathContinue or terminateContinue or terminateAuthor-defined behavior
Diagram definition
flowchart TB
    decision["Decision node"] --> truePath["True path"]
    decision --> falsePath["False path"]
    decision --> unknownPath["Unknown path"]

    truePath --> trueOutcome["Continue or terminate"]
    falsePath --> falseOutcome["Continue or terminate"]
    unknownPath --> unknownOutcome["Author-defined behavior"]

Explicit Unknown Paths

Unknown is a first-class rule outcome. It is not an accidental runtime failure.

FireBIM assumes that users and building models may not contain all information required by a rule. A rule author with domain knowledge decides what happens when information cannot be found. Every unknown must therefore have an explicit path in the rule graph.

Examples of valid unknown behavior:

  • Stop with a terminal message such as: “Unknown: please provide the room area; the rule cannot continue without it.”
  • Continue into a conservative branch such as “treat the room as below 50 m2 when area is missing.”
  • Route to a domain-specific assessment path that asks for further clarification.

This makes unknown behavior transparent and intentional. The runtime does not guess what missing information means. The rule graph encodes the decision.

This supports the intended FireBIM modeling strategy: trust and validity are built one step at a time. Authority rules often contain many scenarios, exceptions, and assessments. FireBIM can eventually model complete rule sets with all scenarios and all combinations, but the practical path is incremental rule construction where each explicit decision can be inspected, tested, and trusted.

Graphs

Graphs represent building data as RDF/Turtle artifacts in the buildings dataset.

Graphs API responsibilities include:

  • publishing building graph TTL
  • fetching building graph TTL
  • deleting building graphs
  • listing available building graphs
  • checking storage health
  • extracting graph schema information

Graph schema extraction is central to the architecture. It identifies:

  • observed classes
  • observed properties
  • class-to-class edges
  • forward and reverse predicates by class pair
  • warnings about schema extraction issues

This allows FireBIM to understand what a building graph can support before or during check execution.

Checks

Checks connect one rule artifact with one building graph artifact.

Checks API responsibilities include:

  • fetching rule TTL from rulebook
  • fetching building graph TTL from buildings
  • computing compatibility between required rule terms and observed graph terms
  • compiling rule TTL into FireBIM runtime structures
  • selecting and running a solver
  • returning summaries, target traces, terminal outputs, timings, diagnostics, and compatibility data

A check result is not just pass/fail. It is an explainable traversal of rule logic over building data.

SHACL And FireBIM Solvers

SHACL is a central architectural choice because it is graph-oriented, standardized, and usable outside the FireBIM backend. Rules can be serialized as Turtle and understood as graph artifacts, which supports interoperability, auditability, and future integration with other graph-based systems.

FireBIM also extends the execution model with explicit unknown paths. This is why the backend contains custom solvers. Standard SHACL validation alone does not express the full FireBIM rule traversal model where true, false, and unknown are all explicit domain decisions.

The current solver entrypoint is app.checks.solver_selector.CheckSolverSelector, which builds a CheckEngine with one of three implemented runtime strategies.

Solver: Standard

Source module: app.checks.runtime.CheckRuntime

Standard solver flow:

1. Rule TTL is compiled by RuleCompiler into a CompiledRuleSet. 2. Building graph TTL is loaded and target nodes are resolved by TargetResolver. 3. CheckRuntime traverses the compiled rule graph for each target. 4. Each decision node evaluates evidence and follows the explicit true, false, or unknown branch. 5. The runtime returns a RuleRunResult with summaries, traces, evidence, and terminal outcomes.

Solver: StandardOpen full screenClose
Rule TTLRuleCompilerCompiledRuleSetBuilding graph TTLTargetResolverStandard CheckRuntimeRuleRunResult
Diagram definition
flowchart TB
    ruleTTL["Rule TTL"] --> compiler["RuleCompiler"]
    compiler --> compiled["CompiledRuleSet"]
    graphTTL["Building graph TTL"] --> resolver["TargetResolver"]
    compiled --> runtime["Standard CheckRuntime"]
    resolver --> runtime
    runtime --> result["RuleRunResult"]

The standard solver is the default compiled runtime traversal. It compiles rule TTL, resolves targets in the building graph, evaluates decision nodes, follows true/false/unknown branches, and produces a traceable result.

The standard solver is the baseline implementation. It is the easiest mode to reason about, debug, and compare against other solver strategies.

Solver: Horizontal

Source module: app.checks.runtime_horizontal_layered.HorizontalLayeredCheckRuntime

Horizontal solver flow:

1. All relevant targets are grouped for evaluation. 2. The runtime evaluates one decision layer across the target set. 3. Targets are grouped by branch outcome. 4. The next decision layer is evaluated for each branch group. 5. Terminal outcomes are aggregated by target, branch, and end node.

Solver: HorizontalOpen full screenClose
All relevant targetsEvaluate one decision layerTrue branch groupFalse branch groupUnknown branch groupNext decision layerTerminal aggregation
Diagram definition
flowchart TB
    targets["All relevant targets"] --> layer["Evaluate one decision layer"]
    layer --> trueGroup["True branch group"]
    layer --> falseGroup["False branch group"]
    layer --> unknownGroup["Unknown branch group"]
    trueGroup --> nextLayer["Next decision layer"]
    falseGroup --> nextLayer
    unknownGroup --> nextLayer
    nextLayer --> terminal["Terminal aggregation"]

The horizontal solver evaluates rule logic layer by layer across many targets. It is designed for situations where many building objects move through similar decision stages.

This strategy creates room for performance improvements because work can be grouped by decision layer, target class, property path, and branch outcome. It is also useful for aggregate diagnostics because many targets are evaluated in comparable batches.

Solver: Vertical

Source module: app.checks.runtime_vertical_pathway.VerticalPathwayCheckRuntime

Vertical solver flow:

1. A target enters the rule graph at the entry node. 2. The runtime evaluates the current decision node. 3. The selected branch determines the next node. 4. The target continues through the pathway until it reaches a terminal outcome. 5. The result preserves the pathway as an explanation trace.

Solver: VerticalOpen full screenClose
One building objectEntry nodeDecision nodeSelected branchNext nodeTerminal outcomeExplanation trace
Diagram definition
flowchart TB
    target["One building object"] --> entry["Entry node"]
    entry --> decisionA["Decision node"]
    decisionA --> branch["Selected branch"]
    branch --> decisionB["Next node"]
    decisionB --> terminal["Terminal outcome"]
    terminal --> trace["Explanation trace"]

The vertical solver walks pathway segments through the rule graph. It emphasizes step-by-step traversal and is well aligned with explainability.

This strategy is useful when FireBIM needs to show how a specific building object reached a specific terminal outcome. It supports transparent reasoning from requirement to rule node, from rule node to observed evidence, and from observed evidence to pass, fail, or unknown.

Solver: Blind SHACL Construct

Source module: app.checks.blind_runner.BlindShaclRuleRunner

Blind SHACL construct flow:

1. Rule TTL and building graph TTL are passed into the SHACL construct runner. 2. The runner executes the construct-oriented validation path. 3. The output contains terminal outputs and aggregate counts. 4. The output does not contain the same per-target decision trace as the compiled FireBIM runtimes.

The blind SHACL construct runner is an alternative execution path. It returns terminal outputs and aggregate counts, but it does not provide the same per-target decision trace as the FireBIM compiled runtimes.

This mode is valuable as a comparison point, benchmark path, and interoperability-oriented execution mode. It is not the primary explanation model.

Explainability First

Checks optimize for explainability before raw speed.

FireBIM is built for transparent validation. A user must be able to understand why a rule passed, failed, or followed an unknown path. Performance remains important, and the multiple solver strategies create room for commercial optimization, open-source experimentation, and future runtime innovation. The architectural priority is still clear: validation must be inspectable and trustworthy.

Compatibility And Readiness

Compatibility is the bridge between rule structure and graph structure.

Compatibility flow:

1. The rule graph exposes required target classes and required properties. 2. The building graph exposes observed classes, properties, and class-to-class edges. 3. Compatibility analysis compares required terms with observed terms. 4. The result becomes a readiness signal for execution, authoring feedback, data-quality feedback, and frontend workflow decisions.

Compatibility And ReadinessOpen full screenClose
Rule graphRequired termsBuilding graphObserved schemaCompatibility analysisReadiness signalExecution inputAuthoring feedbackData-quality feedback
Diagram definition
flowchart TB
    ruleGraph["Rule graph"] --> required["Required terms"]
    buildingGraph["Building graph"] --> observed["Observed schema"]

    required --> compatibility["Compatibility analysis"]
    observed --> compatibility

    compatibility --> readiness["Readiness signal"]
    compatibility --> execution["Execution input"]
    compatibility --> authoring["Authoring feedback"]
    compatibility --> dataQuality["Data-quality feedback"]

The backend already supports compatibility analysis through /checks/compatibility. This compares required rule classes and properties against observed graph classes and properties.

Compatibility is a backend capability. Whether compatibility blocks execution is a frontend and product decision. The backend exposes the signal; the frontend decides how strongly to enforce it in a specific workflow.

Compatibility supports:

  • rule readiness checks
  • graph readiness checks
  • authoring feedback
  • data-quality feedback
  • namespace and ontology mapping workflows
  • solver selection inputs

Rule Authoring Synergy

Rules and graph schema extraction together enable data-aware rule authoring.

A frontend can use the backend architecture to show:

  • target classes that actually exist in selected building graphs
  • property paths observed for a selected target class
  • rules that cannot currently run meaningfully on a selected graph
  • rule elements that are reused across multiple rules
  • target/property pairs shared by related rules
  • namespace drift between rule terms and graph terms

This turns rule authoring into an evidence-based workflow. The rule author still makes the domain decision, but the system exposes the available data and the consequences of missing data.

Unknown As User-Defined Behavior

Unknown does not automatically count as a compliance failure. Unknown is user-defined rule behavior.

The rule author decides whether missing data:

  • stops execution
  • routes to a conservative branch
  • routes to a request-for-information branch
  • routes to an alternative assessment path
  • routes to an explicit failure or explicit pass

The compliance meaning of unknown is therefore encoded in the rule graph. FireBIM does not impose one global interpretation.

This is a major difference from validation systems where missing data is treated as an implicit failure, warning, or engine error. In FireBIM, missing data is part of the modeled decision process.

Traceability From Requirement To Building Object

Traceability flow:

1. A requirement is represented by a stable rule artifact. 2. The rule artifact is compiled into rule nodes. 3. A rule node evaluates a building object. 4. The evaluator reads observed evidence from the building graph. 5. The evidence selects a true, false, or unknown branch. 6. The branch leads to a terminal outcome with an explainable path.

Traceability From Requirement To Building ObjectOpen full screenClose
RequirementVersioned rule artifactRule nodeBuilding objectObserved evidenceTrue / false / unknownTerminal outcomeExplanation
Diagram definition
flowchart LR
    requirement["Requirement"] --> rule["Versioned rule artifact"]
    rule --> node["Rule node"]
    node --> target["Building object"]
    target --> evidence["Observed evidence"]
    evidence --> branch["True / false / unknown"]
    branch --> terminal["Terminal outcome"]
    terminal --> explanation["Explanation"]

This traceability supports:

  • technical debugging
  • frontend explanations
  • compliance reports
  • audit trails
  • issue generation
  • regression testing between building graph versions
  • comparison between rule versions

The check result can explain not only what happened, but where in the rule graph it happened and which building data caused that path.

Versioned Rule Artifacts And Ontology Change

Rules are stable artifacts, but they are not frozen forever. They can exist in many versions and be transformed when ontology terms change.

The lexicon layer is the architectural foundation for mapping and transformation. It can support workflows such as:

  • adapting rules to ontology updates
  • mapping rules from one ontology family to another
  • comparing term usage across rule versions
  • identifying local-name collisions and namespace drift
  • preserving stable compliance semantics while changing the underlying vocabulary

This topic requires its own document because it connects rules, lexicon, ontology management, and transformation strategy.

Product Capabilities Built On This Architecture

The architecture enables several concrete capabilities.

Compatibility Matrix

A compatibility matrix compares multiple rules against one graph or multiple graphs against one rule.

It contains:

  • required target classes
  • required properties
  • observed matching classes
  • observed matching properties
  • missing terms
  • compatibility score
  • readiness status

This is the natural foundation for “which checks can this model support?” workflows.

Graph Readiness

Graph readiness evaluates whether a building graph contains enough information to support a selected rule package.

It can answer:

  • which rules are ready to run
  • which rules will likely route to unknown
  • which missing properties affect the largest number of rules
  • which ontology mappings would unlock the most checks

Rule Readiness

Rule readiness evaluates whether a rule is complete, executable, versioned, and compatible with selected building graph schemas.

It combines:

  • branch completeness
  • entry node validity
  • terminal node coverage
  • target/property availability
  • ontology mapping status

Unknown Reason Classification

Unknown reason classification makes unknown outcomes actionable.

A check can classify unknown paths by cause:

  • missing target class
  • missing property
  • property exists but not on the relevant target
  • datatype mismatch
  • relationship/pathway not present
  • explicitly modeled request for information
  • explicitly modeled conservative assumption

The classification belongs in the result model and supports frontend explanation, reporting, and model improvement workflows.

Solver Recommendation

Solver recommendation selects the most appropriate runtime strategy based on rule structure, graph shape, target count, and output needs.

The decision model can use:

  • number of targets
  • number of decision nodes
  • rule graph depth
  • branch fan-out
  • required trace detail
  • diagnostic mode
  • graph schema complexity

The recommendation remains explainability-first. Performance is optimized within that constraint.

Architectural Position

FireBIM rules are graph-native, stable, versioned artifacts with explicit unknown behavior. FireBIM building models are graph-native data artifacts. FireBIM checks are transparent executions that connect these artifacts and expose both results and reasoning.

The system is not only a validation engine. It is a platform for rule authoring, graph readiness, compliance traceability, ontology-aware transformation, and explainable model checking.

Chapter 04
Lexicon Architecture

# Lexicon Architecture: Ontology-Aware Rules, Mappings, And Evidence

Source: firebim-api-server Primary audience: developers building and extending FireBIM.

Purpose

The Lexicon layer is the ontology-aware interpretation layer in FireBIM. It connects rules, ontology catalogs, building graph evidence, mappings, and user-confirmed reconstruction workflows.

The Lexicon is not only a term lookup API. It is the backend layer that makes rule execution portable across vocabularies, countries, ontology versions, and model data realities.

Lexicon supports these core responsibilities:

  • expose ontology terms as navigable catalogs
  • resolve and compare terms across selected ontologies
  • score similarity between terms and between rules and ontologies
  • derive execution profiles from rules
  • evaluate whether profiles are covered by building graphs
  • validate and persist mappings
  • support handshakes where users accept evidence and mappings
  • reconstruct canonical graph data from accepted lexicon evidence
  • check reconstructed graph conformity against expected ontology/profile requirements

Architectural Position

Lexicon sits between four major FireBIM concepts:

  • ontology resources
  • rules and rule elements
  • building graphs
  • user-confirmed mappings and evidence
Architectural PositionOpen full screenClose
Ontology resourcesLexicon layerRules and rule elementsBuilding graphsUser mappingsAccepted evidenceExecution profilesCoverage and readinessCanonical graph reconstructionConformity checks
Diagram definition
flowchart LR
    ontologies["Ontology resources"] --> lexicon["Lexicon layer"]
    rules["Rules and rule elements"] --> lexicon
    buildingGraphs["Building graphs"] --> lexicon
    mappings["User mappings"] --> lexicon
    handshakes["Accepted evidence"] --> lexicon

    lexicon --> profiles["Execution profiles"]
    lexicon --> coverage["Coverage and readiness"]
    lexicon --> reconstruction["Canonical graph reconstruction"]
    lexicon --> conformity["Conformity checks"]

The layer has two modes of operation:

ModeDescription
Transient analysisCatalog lookup, term resolution, similarity scoring, graph evidence summaries, derived profiles
Persisted user stateStored profiles, mappings, and handshakes scoped through S3-backed repositories

Main Backend Modules

ModuleResponsibility
app.api.lexiconHTTP API boundary, request validation, auth-scoped profile/mapping/handshake operations, error translation
app.lexicon.serviceMain orchestration service for ontology bundles, profiles, mappings, graph reconstruction, conformity, and coverage
app.lexicon.query_runtimeMerged ontology runtime for term resolution, graph evidence summaries, and source pattern evaluation
app.lexicon.custom_evalLightweight hierarchy evaluator for subclass checks and target-class subject lookup
app.schemas.lexiconAPI contracts for catalogs, profiles, mappings, handshakes, evidence, reconstruction, and conformity
app.storage.lexicon_profile_repositoryUser-scoped S3 persistence for derived/stored lexicon execution profiles
app.storage.lexicon_mapping_repositoryUser-scoped S3 persistence for mappings and semantic assertions
app.storage.lexicon_handshake_repositoryUser-scoped S3 persistence for accepted evidence and handshake state
app.storage.ontology_repositorySource of ontology TTL resources used to build lexicon catalogs
app.storage.building_repositorySource of building graph TTL used for evidence and coverage analysis

Ontology Catalogs

The Lexicon service resolves ontology resources into cached ontology bundles. A bundle contains:

  • ontology context: family, country, version, canonical URIs, TTL
  • parsed RDF graph
  • declared classes and properties
  • catalog terms built from RDF/OWL/RDFS metadata
  • FireBIM ontology metadata such as class-property relations, property sets, units, and related properties
Ontology CatalogsOpen full screenClose
yesnoCatalog requestResolve ontology bundleBundle cache hit?Cached ontology bundleOntologyRepositoryOntology TTLParse RDF graphBuild term catalogTerms, details, relations
Diagram definition
flowchart TB
    request["Catalog request"] --> resolver["Resolve ontology bundle"]
    resolver --> cache{"Bundle cache hit?"}
    cache -->|yes| bundle["Cached ontology bundle"]
    cache -->|no| repo["OntologyRepository"]
    repo --> ttl["Ontology TTL"]
    ttl --> parse["Parse RDF graph"]
    parse --> catalog["Build term catalog"]
    catalog --> bundle
    bundle --> response["Terms, details, relations"]

Catalog terms are not simple labels. A term can expose structural relationships that frontend tools and rule authoring flows can use directly:

Term fieldMeaning
term_id and uriLocal and fully qualified identity
kindClass or property
label, definition, descriptionHuman-facing term metadata
parent_term_ids, child_term_idsClass hierarchy navigation
property_term_idsProperties associated with a class or property set
property_set_term_idsProperty sets that contain or relate to the term
belongs_to_class_term_idsClasses associated with a property
related_property_term_idsExplicit related-property metadata
unitExpected unit metadata when available
is_property_setClass-like property grouping
is_predefined_typeClass-like predefined type marker

Term Resolution And Similarity

Lexicon can build a merged runtime from selected ontologies. The merged runtime is used for term resolution, similarity scoring, and graph evidence interpretation.

Term Resolution And SimilarityOpen full screenClose
Selected ontologiesOntology bundlesMerged resolution datasetResolve input termsCompare termsSimilarity scoringGraph evidence summary
Diagram definition
flowchart LR
    selected["Selected ontologies"] --> bundles["Ontology bundles"]
    bundles --> merged["Merged resolution dataset"]
    merged --> resolve["Resolve input terms"]
    merged --> compare["Compare terms"]
    merged --> similarity["Similarity scoring"]
    merged --> evidence["Graph evidence summary"]

Term resolution supports direct URI matches, exact term IDs, exact labels, contains matches, and definition-based matches. Similarity scoring compares catalog terms through multiple components rather than treating ontology mapping as a raw string comparison problem.

This is important for FireBIM because rule terms can be stable compliance concepts while ontology terms evolve over time or differ across countries and ontology families.

Rule-Ontology Similarity

Lexicon can compare rule terms against selected ontologies. It extracts target classes and property paths from rules, resolves them against ontology catalogs, and returns matches and summary scores.

Rule-Ontology SimilarityOpen full screenClose
Rule or stored rule idExtract target classes andproperty pathsSelected ontologiesMerged lexicon runtimeScore each rule termRule-ontology similaritysummary
Diagram definition
flowchart TB
    rule["Rule or stored rule id"] --> terms["Extract target classes and property paths"]
    selected["Selected ontologies"] --> runtime["Merged lexicon runtime"]
    terms --> scoring["Score each rule term"]
    runtime --> scoring
    scoring --> summary["Rule-ontology similarity summary"]

This capability is the foundation for ontology migration and mapping workflows. It can identify which rule terms already align with a target ontology and which terms require mapping or transformation.

Execution Profiles

A Lexicon execution profile is a structured view of what a rule needs from a graph. It is derived from one or more rules and contains:

  • rule ids
  • entry node
  • node count
  • completeness/open/broken status
  • target classes
  • property paths
  • relation paths
  • target-specific property requirements
  • rule nodes and branch references
  • warnings
Execution ProfilesOpen full screenClose
Rule id, rule ids, rule draft,or rule draftsLoad and normalize rulesDecompile rule TTL when neededLexiconExecutionProfileProfile summaryOptional stored profile
Diagram definition
flowchart LR
    ruleSource["Rule id, rule ids, rule draft, or rule drafts"] --> load["Load and normalize rules"]
    load --> decompile["Decompile rule TTL when needed"]
    decompile --> profile["LexiconExecutionProfile"]
    profile --> summary["Profile summary"]
    profile --> storage["Optional stored profile"]

Execution profiles are the bridge between authoring and evidence. They describe the information that rules require without running the full check engine.

Profile Coverage

Stored or derived profiles can be checked against rules and building graphs.

Rules Coverage

Rules coverage compares a base profile against one or more rules. It answers whether those rules are fully supported, partially supported, or unsupported by the profile.

Graph Coverage

Graph coverage compares an execution profile against a building graph evidence summary. It answers which target classes and required properties are present in the graph, and which are missing.

Graph CoverageOpen full screenClose
Execution profileExpected target classes andpropertiesBuilding graphGraph evidence summaryCoverage analysisCovered termsMissing termsMatched source objects
Diagram definition
flowchart TB
    profile["Execution profile"] --> expected["Expected target classes and properties"]
    graph["Building graph"] --> evidence["Graph evidence summary"]
    expected --> coverage["Coverage analysis"]
    evidence --> coverage
    coverage --> covered["Covered terms"]
    coverage --> missing["Missing terms"]
    coverage --> associations["Matched source objects"]

Coverage is a readiness capability. It can be used before check execution to show whether a model contains enough evidence to support a rule package.

Mappings

Mappings describe how source ontology terms, source patterns, or graph evidence can produce target ontology assertions.

The current mapping model supports:

Mapping kindDescription
class_to_classA source class term maps to a target class term
property_to_propertyA source property term maps to a target property term
semantic_assertionA source pattern produces one or more target assertions

A mapping can be simple or pattern-based:

  • simple mappings use source_term and target_term
  • semantic assertions use source_pattern and target_assertions
  • source patterns support nested all_of and any_of clauses
  • entity-scoped patterns keep matched terms on the same source object
  • target assertions can assert class membership, property existence, or property values
MappingsOpen full screenClose
Source term or source patternLexicon mappingTarget term or targetassertionsBuilding graphEvaluate mappingMatched source objectsMissing conditions
Diagram definition
flowchart LR
    source["Source term or source pattern"] --> mapping["Lexicon mapping"]
    mapping --> target["Target term or target assertions"]
    graph["Building graph"] --> evaluate["Evaluate mapping"]
    mapping --> evaluate
    evaluate --> matches["Matched source objects"]
    evaluate --> missing["Missing conditions"]

Mappings are validated before persistence. Validation checks that source and target terms resolve to the expected kind and that pattern/assertion shapes are structurally valid.

Handshakes

A handshake stores the user's accepted interpretation of rule needs, evidence, mappings, and target objects.

The handshake workflow is the explicit human-in-the-loop part of Lexicon. It allows FireBIM to ask for missing or ambiguous evidence, let the user accept mappings and targets, and then reconstruct canonical graph data from the accepted payload.

HandshakesOpen full screenClose
RuleDerived execution profileUser accepted payloadLexicon handshakeSelected mappingsCanonical graph reconstructionConformity check
Diagram definition
flowchart TB
    rule["Rule"] --> profile["Derived execution profile"]
    user["User accepted payload"] --> handshake["Lexicon handshake"]
    profile --> handshake
    mappings["Selected mappings"] --> reconstruction["Canonical graph reconstruction"]
    handshake --> reconstruction
    reconstruction --> conformity["Conformity check"]

A handshake contains:

  • selected ontology context
  • canonical target ontology
  • execution profile
  • accepted mapping ids
  • accepted targets
  • evidence items
  • timestamps

The next-needed operation compares the accepted payload against the profile and returns remaining target classes or properties. This makes missing information actionable and explicit.

Reconstruction And Conformity

Lexicon reconstruction builds canonical RDF/Turtle graph data from accepted entities or handshake evidence.

Reconstruction inputs can come from:

  • explicit LexiconEntityInput values
  • accepted handshake targets
  • mapping-derived target assertions
  • evidence values accepted by the user

Conformity checks validate reconstructed TTL against the selected ontology context and, optionally, an expected execution profile.

Conformity reports include:

  • unknown classes
  • unknown properties
  • subjects missing rdf:type
  • missing profile target classes
  • missing profile properties
  • structure/semantic/execution readiness flags
Reconstruction And ConformityOpen full screenClose
Accepted evidenceReconstruct canonical TTLCanonical graph TTLConformity checkExpected profileStructure, semantic, andprofile alignment report
Diagram definition
flowchart LR
    accepted["Accepted evidence"] --> reconstruct["Reconstruct canonical TTL"]
    reconstruct --> ttl["Canonical graph TTL"]
    ttl --> conformity["Conformity check"]
    profile["Expected profile"] --> conformity
    conformity --> report["Structure, semantic, and profile alignment report"]

Relationship To Rules, Graphs, And Checks

Lexicon does not replace Rules, Graphs, or Checks. It makes them more portable and explainable.

LayerLexicon contribution
RulesExtracts execution profiles and rule terms, supports ontology similarity and future rule transformation
GraphsSummarizes observed evidence and measures profile coverage
ChecksProvides readiness, mapping, and reconstructed canonical graph inputs that can improve check execution
FrontendSupplies term catalogs, mapping candidates, next-needed prompts, and user-confirmed evidence workflows

The Lexicon is therefore the natural home for ontology migration and rule transformation work. Stable rule artifacts can remain compliance artifacts while Lexicon provides the machinery to adapt their vocabulary to evolving or alternative ontologies.

Technical Data Flow

Technical Data FlowOpen full screenClose
ClientLexiconAPILexiconServiceOntologyRepoBuildingRepoS3Reposcatalog/profile/mapping/handshakerequestvalidate and delegatefetch ontology TTL when neededbuild or reuse ontology bundlecachefetch building graph TTL whenevidence is neededpersist profiles, mappings, orhandshakes when requestedstructured lexicon responsetyped API response
Diagram definition
sequenceDiagram
    participant Client
    participant LexiconAPI
    participant LexiconService
    participant OntologyRepo
    participant BuildingRepo
    participant S3Repos

    Client->>LexiconAPI: catalog/profile/mapping/handshake request
    LexiconAPI->>LexiconService: validate and delegate
    LexiconService->>OntologyRepo: fetch ontology TTL when needed
    LexiconService->>LexiconService: build or reuse ontology bundle cache
    LexiconService->>BuildingRepo: fetch building graph TTL when evidence is needed
    LexiconService->>S3Repos: persist profiles, mappings, or handshakes when requested
    LexiconService-->>LexiconAPI: structured lexicon response
    LexiconAPI-->>Client: typed API response

API Capability Groups

The /lexicon router currently exposes these capability groups:

Capability groupRepresentative endpoints
Health/lexicon/health
Catalog browsing/catalog/{ontology_family}/{country}/{version}/terms, term detail, related class/property endpoints
Term resolution and similarity/catalog/resolve-terms, /catalog/compare, /catalog/similarity, /catalog/similarity-matrix
Rule-ontology similarity/catalog/rule-ontology-similarity
Graph evidence/graphs/evidence-summary
Mappings/mappings/validate, /mappings/evaluate, /mappings, /mappings/{mapping_id}
Handshakes/handshakes, /handshakes/{id}/accept, /next-needed, /reconstruction, /conformity
Profiles/profiles/derive, /profiles/summary, /profiles, /profiles/{id}, coverage and mapping candidate endpoints
Reconstruction and conformity/reconstruction, /conformity/check

Architectural Position

Lexicon is the ontology-aware adaptation layer in FireBIM. It keeps the rule system stable while allowing ontology terms, country variants, building graph evidence, and user-approved mappings to evolve.

The layer supports a key product principle: FireBIM can build trust step by step. A rule can define what it needs, Lexicon can expose what the ontology and building graph can provide, the user can accept or add evidence, and the backend can reconstruct canonical graph data for transparent validation.

Chapter 05
IFC And IDS

# IFC And IDS Architecture: Source Models, Specifications, And Graph-Native Validation

Source: firebim-api-server Primary audience: developers building and extending FireBIM.

Purpose

IFC and IDS represent the file-based BIM interoperability layer in FireBIM.

  • IFC files provide source building model data.
  • IDS files provide exchange requirements and model checking specifications.
  • FireBIM Graphs provide the graph-native representation used by Rules, Lexicon, and Checks.
  • FireBIM Rules provide explicit decision logic, including true, false, and unknown paths.

The current backend supports IFC and IDS as uploaded user-owned artifacts stored in S3/MinIO and tracked in PostgreSQL. IFC files can be processed asynchronously by a Celery worker with IfcOpenShell. The worker also contains an IDS validation task using IfcTester.

The strategic architecture is that IFC and IDS are not the final validation model. They are important source and interoperability formats that can feed FireBIM's graph-native rule, lexicon, and check architecture.

Architectural Position

Architectural PositionOpen full screenClose
IFC model file/ifc-models APIIDS specification file/ids-files APIS3 / MinIO models/*S3 / MinIO ids/*PostgreSQL ifc_modelsPostgreSQL ids_filesCelery workerIfcOpenShellIfcTesterS3 / MinIO results and checks
Diagram definition
flowchart LR
    ifc["IFC model file"] --> uploadModel["/ifc-models API"]
    ids["IDS specification file"] --> uploadIds["/ids-files API"]

    uploadModel --> s3Models[("S3 / MinIO models/*")]
    uploadIds --> s3Ids[("S3 / MinIO ids/*")]

    uploadModel --> dbModels[("PostgreSQL ifc_models")]
    uploadIds --> dbIds[("PostgreSQL ids_files")]

    s3Models --> worker["Celery worker"]
    s3Ids --> worker

    worker --> ifcopenshell["IfcOpenShell"]
    worker --> ifctester["IfcTester"]
    worker --> results[("S3 / MinIO results and checks")]

The current implementation has three clear areas:

AreaCurrent role
IFC APIUpload, list, fetch metadata, download source IFC files
IDS APIUpload, list, fetch metadata, download source IDS files
Worker layerProcess IFC files and run IFC-vs-IDS validation tasks

Current Backend Modules

ModuleResponsibility
app.api.models/ifc-models endpoints for IFC upload, listing, metadata, and download
app.api.ids/ids-files endpoints for IDS upload, listing, metadata, and download
app.models.models.IfcModelSQLModel table for IFC model metadata and processing status
app.models.models.IdsFileSQLModel table for IDS file metadata
app.models.models.CheckResultSQLModel table intended for IFC/IDS check result metadata
app.workers.celery_worker.process_modelAsync IFC processing task using IfcOpenShell
app.workers.celery_worker.check_model_with_idsAsync IDS validation task using IfcTester
app.workers.celery_appCelery application configured from FireBIM settings
docker/worker/DockerfileWorker image with ifcopenshell, ifctester, and worker dependency group

IFC Model Lifecycle

The IFC upload lifecycle is implemented by /ifc-models.

IFC Model LifecycleOpen full screenClose
ClientAPIS3DBCeleryWorkerUpload .ifc fileValidate .ifc extensionStore models/{model_id}/{filename}Create IfcModel row with pendingstatusQueue process_model(model_id,s3_key)Store task id and processingstatusExecute process_modelDownload IFC source fileParse with IfcOpenShellStoreresults/{model_id}/stats.jsonMark model processed and storeresult_key
Diagram definition
sequenceDiagram
    participant Client
    participant API as IFC API
    participant S3 as S3 / MinIO
    participant DB as PostgreSQL
    participant Celery
    participant Worker

    Client->>API: Upload .ifc file
    API->>API: Validate .ifc extension
    API->>S3: Store models/{model_id}/{filename}
    API->>DB: Create IfcModel row with pending status
    API->>Celery: Queue process_model(model_id, s3_key)
    API->>DB: Store task id and processing status
    Celery->>Worker: Execute process_model
    Worker->>S3: Download IFC source file
    Worker->>Worker: Parse with IfcOpenShell
    Worker->>S3: Store results/{model_id}/stats.json
    Worker->>DB: Mark model processed and store result_key

The current worker processing extracts a simple object count by IFC element type. This establishes the asynchronous processing pipeline and proves that IFC files can be opened and inspected in the worker runtime.

Current IFC metadata includes:

FieldMeaning
idStable model identifier
filenameOriginal uploaded filename
s3_keyObject storage location
user_idOwner used for authorization
processedWorker processing completion flag
task_idCelery task id
result_keyS3 key for assembled processing result
processing_statusPending/processing style status field
created_at, updated_atMetadata timestamps

IDS File Lifecycle

The IDS upload lifecycle is implemented by /ids-files.

IDS File LifecycleOpen full screenClose
ClientAPIS3DBUpload .ids fileValidate .ids extensionStore ids/{ids_id}/{filename}Create IdsFile rowFetch metadata or downloadVerify ownershipDownload IDS when requested
Diagram definition
sequenceDiagram
    participant Client
    participant API as IDS API
    participant S3 as S3 / MinIO
    participant DB as PostgreSQL

    Client->>API: Upload .ids file
    API->>API: Validate .ids extension
    API->>S3: Store ids/{ids_id}/{filename}
    API->>DB: Create IdsFile row
    Client->>API: Fetch metadata or download
    API->>DB: Verify ownership
    API->>S3: Download IDS when requested

IDS files are currently stored as user-owned XML-based artifacts. The API provides upload, metadata lookup, listing, and download.

Current IDS metadata includes:

FieldMeaning
idStable IDS identifier
filenameOriginal uploaded filename
s3_keyObject storage location
user_idOwner used for authorization
created_at, updated_atMetadata timestamps

IFC And IDS Validation Worker

The worker contains check_model_with_ids, which validates an IFC model against an IDS file using IfcTester.

IFC And IDS Validation WorkerOpen full screenClose
IFC file from S3check_model_with_ids taskIDS file from S3ifcopenshell.openifctester.open(validate=True)ids.validate(ifc_model)ifctester.reporter.Jsonchecks/{check_id}/result.json
Diagram definition
flowchart TB
    modelS3["IFC file from S3"] --> worker["check_model_with_ids task"]
    idsS3["IDS file from S3"] --> worker
    worker --> ifcOpen["ifcopenshell.open"]
    worker --> idsOpen["ifctester.open(validate=True)"]
    ifcOpen --> validation["ids.validate(ifc_model)"]
    idsOpen --> validation
    validation --> reporter["ifctester.reporter.Json"]
    reporter --> result["checks/{check_id}/result.json"]

The task performs these steps:

1. Download the IFC file from S3/MinIO. 2. Download the IDS file from S3/MinIO. 3. Open the IFC model with IfcOpenShell. 4. Open and validate the IDS file with IfcTester. 5. Run the IDS validation against the IFC model. 6. Produce a JSON report with ifctester.reporter.Json. 7. Store the check result JSON in S3/MinIO under checks/{check_id}/result.json.

The current API layer does not expose a dedicated endpoint that starts check_model_with_ids. The task exists in the worker layer and the CheckResult table exists as a persistence shape, but the public orchestration endpoint is not part of the current implemented router surface.

File-Based Validation And Graph-Native Validation

IFC/IDS validation and FireBIM graph-native checks solve related but different problems.

Validation pathPrimary inputExecution modelOutput shape
IFC + IDSIFC STEP file and IDS XML fileIfcTester validationIDS-oriented JSON report
FireBIM Graphs + RulesBuilding graph TTL and rule TTLFireBIM compiled solversTraceable pass/fail/unknown results
Lexicon-assisted pathBuilding evidence, ontology terms, mappings, profilesOntology-aware reconstruction and coverageCanonical graph readiness and conformity

The file-based path is valuable for interoperability and standards alignment. The graph-native path is valuable for explicit rule traversal, explainability, unknown handling, ontology transformation, and long-term FireBIM compliance workflows.

Bridge To Graphs

The current Graphs layer expects building graph Turtle published to the buildings dataset. IFC source files are not yet automatically converted into building graph TTL by the current IFC upload endpoint.

The architectural bridge is:

Bridge To GraphsOpen full screenClose
IFC source fileIfcOpenShell parsingExtract entities, properties,relationshipsLexicon / ontology mappingBuilding graph TTLGraphs API / buildings datasetFireBIM Checks
Diagram definition
flowchart LR
    ifc["IFC source file"] --> parse["IfcOpenShell parsing"]
    parse --> extract["Extract entities, properties, relationships"]
    extract --> map["Lexicon / ontology mapping"]
    map --> ttl["Building graph TTL"]
    ttl --> graphs["Graphs API / buildings dataset"]
    graphs --> checks["FireBIM Checks"]

This bridge turns IFC from a file artifact into graph-native FireBIM evidence. Once a building graph exists, the existing Rules, Lexicon, and Checks layers can evaluate it.

Bridge To Lexicon

Lexicon is the natural adaptation layer between IFC terms and FireBIM rule terminology.

The codebase already contains IFC ontology resources and Lexicon support for:

  • IFC catalog browsing through ontology_family=ifc
  • rule-ontology similarity against IFC terms
  • graph evidence summaries using selected ontologies
  • mappings from source IFC terms or patterns to target ontology assertions
  • handshake workflows where users accept evidence and mappings
  • canonical graph reconstruction and conformity checks
Bridge To LexiconOpen full screenClose
IFC ontology termsLexiconFBO / national ontology termsStable FireBIM rulesExecution profileMappings and similarityCanonical graph reconstructionGraph-native checks
Diagram definition
flowchart TB
    ifcTerms["IFC ontology terms"] --> lexicon["Lexicon"]
    fboTerms["FBO / national ontology terms"] --> lexicon
    rules["Stable FireBIM rules"] --> profile["Execution profile"]
    lexicon --> mappings["Mappings and similarity"]
    profile --> mappings
    mappings --> reconstruction["Canonical graph reconstruction"]
    reconstruction --> checks["Graph-native checks"]

This is the key FireBIM direction: IFC can remain a source/interoperability format while Lexicon and Graphs provide the vocabulary adaptation and execution substrate.

Bridge To IDS

IDS is a standardized way to express information delivery requirements for IFC models. FireBIM can use IDS in two complementary ways.

IDS As Direct Validation Artifact

The worker can run IfcTester directly against IFC and IDS files. This produces an IDS-oriented report that is useful for standards-aligned validation.

IDS As Rule And Profile Input

IDS can also be treated as a source of structured requirements that can inform FireBIM rules or Lexicon profiles. In this direction, IDS requirements become part of the graph-native readiness and rule authoring workflow.

IDS As Rule And Profile InputOpen full screenClose
IDS specificationDirect IfcTester validationRequirement interpretationLexicon execution profileFireBIM rule artifactsGraph readinessFireBIM Checks
Diagram definition
flowchart LR
    ids["IDS specification"] --> direct["Direct IfcTester validation"]
    ids --> interpret["Requirement interpretation"]
    interpret --> profile["Lexicon execution profile"]
    interpret --> rules["FireBIM rule artifacts"]
    profile --> readiness["Graph readiness"]
    rules --> checks["FireBIM Checks"]

The current backend stores IDS files and contains worker support for IfcTester validation. IDS-to-FireBIM-rule transformation is a future architecture capability rather than an implemented API flow in the current code architecture view.

Relationship To Rules, Graphs, Checks, And Lexicon

LayerIFC/IDS role
IFC ModelsSource model files uploaded by users; parsed asynchronously by worker tasks
IDS FilesSource specification files uploaded by users; usable for IfcTester validation
GraphsTarget graph-native building representation used by FireBIM Checks
RulesStable FireBIM compliance artifacts with explicit true/false/unknown behavior
ChecksFireBIM graph-native execution against published building graphs and rules
LexiconOntology mapping and reconstruction layer between IFC/FBO/RIR/national vocabularies

IFC and IDS are therefore not isolated upload features. They are the outer interoperability layer around the graph-native FireBIM architecture.

Current API Capability Groups

Capability groupEndpointsCurrent behavior
IFC uploadPOST /ifc-modelsValidates .ifc, stores source file, creates metadata row, queues process_model
IFC metadataGET /ifc-models, GET /ifc-models/{id}Lists and fetches user-owned IFC metadata
IFC downloadGET /ifc-models/{id}/downloadDownloads the original IFC file from S3/MinIO
IDS uploadPOST /ids-filesValidates .ids, stores source file, creates metadata row
IDS metadataGET /ids-files, GET /ids-files/{id}Lists and fetches user-owned IDS metadata
IDS downloadGET /ids-files/{id}/downloadDownloads the original IDS file from S3/MinIO
Worker processingprocess_modelCounts IFC elements by type and stores result JSON
Worker validationcheck_model_with_idsRuns IfcTester validation and stores result JSON

Technical Dependencies

The worker dependency group includes:

  • ifcopenshell==0.8.5
  • ifctester==0.8.5
  • bcf-client==0.8.5

The API image installs the default backend dependencies. The worker image installs the additional worker dependency group, which is where IFC/IDS processing libraries are available.

Architectural Position

IFC and IDS are the standards-facing input layer for FireBIM. They provide compatibility with BIM authoring and information delivery workflows. FireBIM's deeper validation model is graph-native: IFC-derived evidence should be transformed into building graphs, IDS-derived requirements can inform profiles or rules, and Lexicon provides the vocabulary adaptation between source standards and FireBIM's stable rule artifacts.

The long-term architecture is not IFC versus graphs or IDS versus rules. It is a layered model:

1. IFC and IDS provide interoperable source artifacts. 2. Workers parse, validate, and extract evidence. 3. Lexicon maps and reconstructs canonical graph data. 4. Graphs store building evidence as RDF/Turtle. 5. Rules define explicit compliance logic. 6. Checks execute traceable validation with true, false, and unknown paths.

Chapter 06
Authentication, Admin, Users And Security

# Authentication, Users, Admin, And Security Architecture

Source: firebim-api-server Primary audience: developers building and extending FireBIM.

Purpose

Authentication in firebim-api-server is delegated to Authentik through OAuth2/OpenID Connect. The API validates Authentik-issued Bearer tokens, auto-provisions local user rows, and uses the local User model as the ownership anchor for user-scoped resources.

The current backend has authentication and user ownership. It does not yet implement a first-party role-based admin system inside the API. Administrative capabilities currently live in Authentik, infrastructure tooling, and operational access to backend services.

Architectural Position

Architectural PositionOpen full screenClose
UserFrontend / API clientAuthentik OIDCAccess tokenFireBIM APIAuthentik JWKSusers tableUser-scoped resources
Diagram definition
flowchart LR
    user["User"] --> frontend["Frontend / API client"]
    frontend --> authentik["Authentik OIDC"]
    authentik --> token["Access token"]
    token --> api["FireBIM API"]
    api --> jwks["Authentik JWKS"]
    api --> users[("users table")]
    api --> resources["User-scoped resources"]

The API trusts Authentik as the identity provider. The backend owns local user metadata only to support application authorization, ownership, and persistence relationships.

Main Backend Modules

ModuleResponsibility
app.auth.jwtBearer token extraction, JWKS lookup, JWT validation, local user provisioning, active-user checks
app.auth.router/users/me endpoint for the current authenticated user
app.schemas.authUser response schema
app.models.models.UserLocal SQLModel user table
app.models.databaseDatabase session management for request and auth flows
app.core.configAuthentik issuer/internal URLs and environment-driven security configuration
blueprints/firebim.yamlAuthentik application, OIDC provider, enrollment flow, password policy, and recovery flow
docker-compose.ymlLocal Authentik, Authentik worker, Mailpit, PostgreSQL, and API wiring

Identity Provider

Authentik is the identity provider for FireBIM. In the local stack it runs as two services:

  • authentik-server
  • authentik-worker

The Authentik blueprint configures:

  • FireBIM self-enrollment
  • username, email, password, and repeated password prompts
  • password strength policy using zxcvbn
  • user creation and login after enrollment
  • OAuth2/OpenID Connect provider
  • confidential client configuration
  • strict redirect URI matching
  • OIDC scopes: openid, email, profile
  • hashed user id subject mode
  • ID token claims
  • access token and refresh token validity
  • password recovery through email
  • FireBIM application entry on the Authentik dashboard
Identity ProviderOpen full screenClose
blueprints/firebim.yamlSelf-enrollment flowPassword recovery flowOAuth2/OIDC providerFireBIM applicationopenid / email / profileJWKS signing keys
Diagram definition
flowchart TB
    blueprint["blueprints/firebim.yaml"] --> enrollment["Self-enrollment flow"]
    blueprint --> recovery["Password recovery flow"]
    blueprint --> provider["OAuth2/OIDC provider"]
    provider --> app["FireBIM application"]
    provider --> scopes["openid / email / profile"]
    provider --> jwks["JWKS signing keys"]

Authentication Flow

The backend authentication flow is implemented in app.auth.jwt.get_current_user.

Authentication FlowOpen full screenClose
ClientAPIJWKSDBRequest with Authorization: BearertokenExtract HTTP Bearer credentialsResolve signing key from tokenVerify JWT signature and issuerRead sub, email,preferred_username claimsFind user by authentik_subSync email / username if claimschangedCreate local User rowCheck is_activeAuthorized route response
Diagram definition
sequenceDiagram
    participant Client
    participant API
    participant JWKS as Authentik JWKS
    participant DB as PostgreSQL

    Client->>API: Request with Authorization: Bearer token
    API->>API: Extract HTTP Bearer credentials
    API->>JWKS: Resolve signing key from token
    API->>API: Verify JWT signature and issuer
    API->>API: Read sub, email, preferred_username claims
    API->>DB: Find user by authentik_sub
    alt user exists
        API->>DB: Sync email / username if claims changed
    else first login
        API->>DB: Create local User row
    end
    API->>API: Check is_active
    API-->>Client: Authorized route response

JWT validation currently verifies:

CheckImplementation
Token transportHTTPBearer dependency extracts Authorization: Bearer ...
Signing keyPyJWKClient loads key from Authentik JWKS endpoint
AlgorithmRS256 and ES256 are accepted
Issuersettings.AUTHENTIK_ISSUER_URL is required as issuer
AudienceAudience verification is disabled with verify_aud: False
Subjectsub claim is required
Active local useris_active must be true

The JWKS client is cached in-process after first use.

Local User Model

The local user table is an application identity projection, not the primary identity system.

FieldMeaning
idFireBIM-local user id
authentik_subStable Authentik subject claim; unique and indexed
usernameSynced from preferred_username claim
emailSynced from email claim
is_activeLocal active flag enforced by get_current_active_user
created_at, updated_atLocal timestamps

Local users are auto-provisioned on first valid Authentik login. Existing users are synchronized when Authentik claim values change.

Local User ModelOpen full screenClose
yesnoJWT claimsLookup by authentik_subUser exists?Sync email / usernameCreate local UserCheck is_activeProtected route
Diagram definition
flowchart LR
    tokenClaims["JWT claims"] --> lookup["Lookup by authentik_sub"]
    lookup --> exists{"User exists?"}
    exists -->|yes| sync["Sync email / username"]
    exists -->|no| create["Create local User"]
    sync --> active["Check is_active"]
    create --> active
    active --> route["Protected route"]

User-Scoped Resources

The local User.id is used to scope application data.

Current user-scoped areas include:

Resource areaOwnership mechanism
IFC modelsIfcModel.user_id and explicit ownership checks
IDS filesIdsFile.user_id and explicit ownership checks
Rulebuilder workspacesRepository methods receive current_user
Ontology candidatesRepository methods receive current_user
Lexicon mappingsUser-scoped S3 JSON repository
Lexicon profilesUser-scoped S3 JSON repository
Lexicon handshakesUser-scoped S3 JSON repository

Some API areas are public or system-level by design, such as health/build metadata and graph/rule operations that do not currently require a user dependency on every endpoint. Authentication coverage is therefore endpoint-specific in the current codebase.

Admin Model

The current API does not define first-party admin roles, admin claims, or an is_admin field. There is no internal RBAC/ABAC model in the SQLModel user table.

Admin responsibility currently exists in these external or operational layers:

Admin surfaceCurrent role
Authentik adminIdentity provider administration, users, login/recovery/enrollment configuration, OIDC provider settings
Authentik blueprintDeclarative local application/provider/enrollment/recovery setup
PgAdminLocal database administration in Docker Compose
Docker Compose environmentLocal dev credentials, service wiring, bootstrap values
Infrastructure secretsRuntime credentials for PostgreSQL, S3/MinIO, Authentik, RabbitMQ

A future FireBIM admin layer can be built on top of Authentik claims or groups. The backend would then need explicit role extraction, role persistence or claim evaluation, and protected admin dependencies such as get_current_admin_user.

Admin ModelOpen full screenClose
futurefutureAuthentik users / groups /policiesToken claimsFireBIM APICurrent userAdmin dependency / RBACAdmin routes
Diagram definition
flowchart TB
    authentik["Authentik users / groups / policies"] --> claims["Token claims"]
    claims --> api["FireBIM API"]
    api --> current["Current user"]
    api -. future .-> admin["Admin dependency / RBAC"]
    admin -. future .-> adminRoutes["Admin routes"]

Protected Endpoint Pattern

Protected endpoints use FastAPI dependency injection:

current_user: User = Depends(get_current_active_user)

This pattern guarantees that the handler receives a local active user. The handler or repository then performs ownership checks.

Examples of current protected areas:

  • /users/me
  • /ifc-models
  • /ids-files
  • many /lexicon/mappings, /lexicon/profiles, and /lexicon/handshakes endpoints
  • user-scoped rulebuilder and ontology candidate workflows

Ownership checks are implemented either directly in routers or inside user-scoped repositories.

Security Architecture

Security is layered across identity, transport, token validation, persistence, and operational configuration.

Security ArchitectureOpen full screenClose
Identity provider securityJWT verificationLocal active-user gateResource ownership checksUser-scoped persistenceMetrics and request tracing
Diagram definition
flowchart TB
    identity["Identity provider security"] --> token["JWT verification"]
    token --> active["Local active-user gate"]
    active --> ownership["Resource ownership checks"]
    ownership --> storage["User-scoped persistence"]
    storage --> observability["Metrics and request tracing"]

Implemented Controls

ControlCurrent implementation
External identity providerAuthentik OIDC provider owns login, enrollment, recovery, password policy
Bearer token authenticationAPI uses FastAPI HTTPBearer
JWT signature validationPyJWKClient resolves Authentik signing keys
Issuer validationJWT decode requires configured Authentik issuer
Local user provisioningValid token creates or syncs local user row
Active-user gateget_current_active_user rejects inactive users
User ownershipIFC/IDS routers and user-scoped repositories enforce user ownership
Password policyAuthentik blueprint configures zxcvbn password policy
Redirect URI controlAuthentik provider uses strict redirect URI matching
Request observabilityAuthentication timings, DB lookup/provision/sync metrics, request id middleware
Secret handlingPydantic SecretStr is used for configured backend secrets

Security-Relevant Design Notes

Audience verification is currently disabled in JWT validation. This is acceptable only when the issuer and token source are tightly controlled and the API is intentionally accepting issuer-scoped tokens without audience enforcement. For production hardening, the API should validate audience or client id expectations explicitly.

Admin authorization is not implemented in the API. Any future admin endpoint must not rely only on is_active; it must use explicit role/group/claim checks.

Local development credentials appear in Docker Compose for Authentik, RabbitMQ, MinIO, PgAdmin, and related services. These are local-dev values and must not be reused in production environments.

The API auto-provisions users on first valid token. This is convenient and aligned with Authentik as source of identity, but it means access policy belongs primarily in Authentik and token issuance. If self-enrollment is enabled, product-level entitlement may require an additional authorization layer.

The is_active flag is local and enforced by the API, but there is no API endpoint in the current codebase for administrators to deactivate users. Operational deactivation currently belongs to database operations or future admin tooling.

Security Gaps And Future Hardening

AreaCurrent stateHardening direction
Audience validationDisabledValidate expected audience/client id for API tokens
Admin rolesNot implementedIntroduce Authentik group/claim mapping and backend admin dependency
Authorization policyEndpoint-specific ownership checksCentralize permission model for user, project, organization, and admin scopes
User lifecycle managementAuto-provision and sync from tokenAdd explicit admin/user management workflows if product requires them
Token claim modelUses sub, email, preferred_usernameDocument required claims and reject incomplete production identities
Secret postureLocal Docker defaults existSeparate local/dev/staging/prod secrets and enforce production checks
Protected surface consistencyMixed public/protected endpointsClassify endpoints as public, authenticated, owner-scoped, admin-scoped, or system-scoped

User And Admin Capability Model

The current capability model is:

ActorCurrent capabilities
Unauthenticated callerPublic endpoints only, such as selected health/build/system routes
Authenticated active userAccess protected endpoints and own user-scoped resources
Resource ownerRead/write/delete resources where routers or repositories enforce ownership
Authentik adminManage identity provider users, policies, flows, OIDC app/provider configuration
Infrastructure adminManage PostgreSQL, S3/MinIO, RabbitMQ, Authentik, PgAdmin, Docker/Kubernetes configuration
FireBIM application adminNot yet implemented as an API role

The next architectural step for admin is to make “FireBIM application admin” explicit rather than implicit in infrastructure access.

Future admin functionality should be layered on the existing Authentik integration:

1. Authentik owns identity, groups, and high-level policy. 2. Tokens include group or role claims relevant to FireBIM. 3. The API validates these claims after JWT verification. 4. The API exposes dedicated dependencies such as get_current_admin_user. 5. Admin endpoints are grouped under an explicit route namespace. 6. Admin actions are audited with user id, request id, action, target resource, and outcome.

Recommended Admin Architecture DirectionOpen full screenClose
Authentik groupRole/group claimValidated JWTAdmin dependencyAdmin routeAudit event
Diagram definition
flowchart LR
    group["Authentik group"] --> claim["Role/group claim"]
    claim --> jwt["Validated JWT"]
    jwt --> dependency["Admin dependency"]
    dependency --> route["Admin route"]
    route --> audit["Audit event"]

Architectural Position

Authentication is already a clear boundary: Authentik owns identity and the API owns local user projection and resource ownership. The current system is ready for user-scoped workflows, but not yet for first-party administrative workflows.

Security hardening should focus on explicit audience validation, explicit admin claims, endpoint classification, and a consistent authorization model across user-owned, shared, public, and system-level resources.