Data Architecture
OffGridFlow uses a single canonical data model with strict tenant isolation. Every record traces back to its source through an immutable audit chain.
End-to-End Traceability Chain
Every compliance output can be traced back through this chain to the original activity data.
Entity Definitions
Core tables in the OffGridFlow data model. All tables are tenant-scoped — one tenant cannot access another's data.
Tenant (Organization)Multi-tenant root. Every record is scoped to a tenant. One tenant cannot see or affect another.
UserAuthenticated account within a tenant. Roles control access.
ActivityA single emissions data point — the atomic unit of carbon accounting.
Emission FactorConversion factor from activity quantity to kg CO2e. Sourced from EPA, IEA, DEFRA, IPCC.
Calculation LedgerImmutable record of every emissions calculation. Cannot be modified after creation.
Factor SnapshotA locked set of emission factors for a reporting period. Ensures reproducibility.
Compliance ReportGenerated compliance output for a specific framework and year.
Approval WorkflowTracks review and approval state for reportable entities.
Audit LogImmutable event trail. Every significant action is recorded with actor attribution.
Change LogField-level modification history for data governance and forensic review.
Key Relationships
| From | To | Relationship | Constraint |
|---|---|---|---|
| Activity | Tenant | belongs to | CASCADE delete |
| Activity | Calculation Ledger | calculated by | FK activity_id |
| Calculation Ledger | Factor Snapshot | uses factors from | FK factor_snapshot_id |
| Calculation Ledger | User | calculated by | FK calculated_by |
| Compliance Report | Tenant | belongs to | CASCADE delete |
| Compliance Report | User | generated / approved by | FK generated_by, approved_by |
| Approval Workflow | Compliance Report | governs | FK entity_id |
| Audit Log | Tenant + User | records actions by | FK tenant_id, user_id |
| Change Log | any entity | tracks field changes | entity_type + entity_id |
| Factor Snapshot | Tenant | belongs to | CASCADE delete, UNIQUE per period |
Tenant Isolation
Every database query includes a tenant filter (WHERE tenant_id = $1). This is enforced at the application layer through middleware that extracts the tenant ID from the authenticated JWT session. There is no admin endpoint that can query across tenants. Soft deletes use deleted_at timestamps, and unique constraints include the WHERE deleted_at IS NULL predicate to prevent namespace collisions.