This document complements the conceptual data model documentation. It is intended for backend, data, and analytics engineers working directly with the database.
Focus areas:
- Query patterns
- Data invariants
- Anti-patterns and common mistakes
- Operational guidance for safe reads & writes
Think of the system as event-sourced–like, even though it is relational:
- User intent → immutable inputs
- System interpretation → derived factor snapshot
- System output → immutable result
- Workflow state → explicit status transitions
Never assume “latest row = truth” without a rule.
- An
organizationcan have multipleorganization_datarows (history). - ACTIVE/OUTDATED Status: The
statuscolumn inorganization_dataonly usesACTIVEorOUTDATED. - Accreditation is Derived: An organization is "accredited" if it has an
ACTIVEorganization_datawith anAPPROVEDsubmission. - Invariants:
- At most one ACTIVE Draft (no submission) per organization.
- At most one ACTIVE Under Review (PENDING submission) per organization.
- At most one ACTIVE Approved (APPROVED submission) per organization.
- When a new version is approved, all other
ACTIVErecords for that organization must be markedOUTDATEDin the same transaction. - When a submission is rejected, the
organization_datais markedOUTDATEDimmediately to allow for a clean new draft.
Violation symptom:
- Multiple
ACTIVErecords of the same substate (e.g., two approved versions). - Inability to determine the single source of truth for current organization data.
- Every
carbon_inventoryreferences exactly one methodology_version - That methodology version must belong to the same country as the inventory’s organization (if any)
- Only one ACTIVE
methodology_versionexists per country
Violation symptom:
- Inconsistent totals across inventories
- Impossible comparisons year-over-year
For carbon_inventory_line:
- Multiple ACTIVE lines can exist for the same
(carbon_inventory_id, subcategory_id)combination - DELETED lines are never reused
- Lines never store quantities, factors, or selections
If you need numbers or selections → you are in the wrong table.
For carbon_inventory_line_input:
- Exactly one active input per line
- Old inputs remain for history but are inactive
- Inputs are immutable once deactivated
Never update an input row to “fix” data. Create a new one and deactivate the old.
For carbon_inventory_line_factor:
- Exactly one factor row per input
- Factor represents the post-conversion value
- EXPERT and DIRECT modes may have
emission_factor_id = NULL
Invariant:
The factor row must fully explain how the result was computed.
For carbon_inventory_line_result:
- Exactly one result per input
- Results are purely derived
- Audit fields (
created_by_id,updated_by_id) are kept for administrative tracking purposes, but results themselves are system-generated and not attributed to user actions
If a result changes, something upstream changed.
For submission:
- A
submission_subjectcan have multiplesubmissionrecords (history of attempts). - Business Rule: Only one PENDING or APPROVED submission is allowed per subject.
- This is enforced via a partial unique index on
subject_idwherestatus IN ('PENDING', 'APPROVED'). carbon_inventory_idandorganization_data_idmust be unique across their respective subject relation tables.
SELECT
l.id AS line_id,
sc.name AS subcategory,
i.input_type,
i.quantity,
mu.abbreviation AS unit,
r.total_emissions
FROM carbon_inventory_line l
JOIN subcategory sc ON sc.id = l.subcategory_id
JOIN carbon_inventory_line_input i
ON i.line_id = l.id AND i.is_active = true
LEFT JOIN measurement_unit mu ON mu.id = i.measurement_unit_id
LEFT JOIN carbon_inventory_line_result r
ON r.line_input_id = i.id
WHERE l.carbon_inventory_id = :inventory_id
AND l.status = 'ACTIVE';Key idea:
You never join directly from line → result.
You always go through the active input.
SELECT
i.id AS input_id,
i.quantity,
f.applied_factor_value,
r.total_emissions,
f.derivation_details
FROM carbon_inventory_line_input i
JOIN carbon_inventory_line_factor f ON f.line_input_id = i.id
JOIN carbon_inventory_line_result r ON r.line_input_id = i.id
WHERE i.id = :input_id;This query must remain valid forever.
SELECT
ef.*,
dv1.value AS dim_1,
dv2.value AS dim_2
FROM carbon_inventory_line_factor lf
LEFT JOIN emission_factor ef ON ef.id = lf.emission_factor_id
LEFT JOIN emission_factor_dimension_value dv1
ON dv1.id = ef.dimension_value_1_id
LEFT JOIN emission_factor_dimension_value dv2
ON dv2.id = ef.dimension_value_2_id
WHERE lf.line_input_id = :input_id;Do not attempt to “re-derive” factor selection in queries.
SELECT SUM(r.total_emissions) AS inventory_total
FROM carbon_inventory_line l
JOIN carbon_inventory_line_input i
ON i.line_id = l.id AND i.is_active = true
JOIN carbon_inventory_line_result r
ON r.line_input_id = i.id
WHERE l.carbon_inventory_id = :inventory_id
AND l.status = 'ACTIVE';Never sum results without:
- ACTIVE lines
- ACTIVE inputs
SELECT od.*
FROM organization_data od
JOIN submission_subject_organization_data ssod ON ssod.organization_data_id = od.id
JOIN submission s ON s.subject_id = ssod.subject_id
WHERE od.organization_id = :org_id
AND od.status = 'ACTIVE'
AND s.status = 'APPROVED';SELECT *
FROM organization_data
WHERE organization_id = :org_id
AND status = 'ACTIVE'
AND id NOT IN (SELECT organization_data_id FROM submission_subject_organization_data);- Status defines lifecycle
- Do not infer state from timestamps
- Do not use booleans like
is_deleted
Example anti-pattern:
WHERE deleted_at IS NULL -- ❌Correct:
WHERE status_id = (
SELECT id FROM status_catalog
WHERE scope = 'CARBON_INVENTORY'
AND code = 'ACTIVE'
)- Mark previous input as inactive
- Insert new input row
- Insert factor row
- Insert result row
All steps should be in one transaction.
- Never update existing emission factors
- Create new factor rows
- Mark old ones as OUTDATED
Existing inventories must remain reproducible.
Factors are input-specific, not inventory-wide.
Breaks historical traceability.
Always read stored results.
JSON is for explanations, not rules.
selection_1_id ≠ selection_2_id by accident.
Note: Selections are stored in carbon_inventory_line_input, not in carbon_inventory_line.
- Index:
(line_id) WHERE is_active = trueon inputs(carbon_inventory_id, status)on lines
- Avoid scanning historical inputs unless auditing
- Pre-aggregate per inventory if dashboards require it
When numbers look wrong:
- Is the line ACTIVE?
- Is there exactly one active input?
- Does the factor row exist?
- Does the result reference the same input?
- Is the methodology version correct?
- Are you summing inactive data?
99% of bugs are violations of these rules.
If a query feels “clever”, it is probably wrong.
Prefer:
- Explicit joins
- Clear filters
- Redundant clarity
This schema rewards correctness over shortcuts.