Chapter 1 · Platform guide

Data model

How battery passport information is split between product families and individual units, and how that maps to screens in this application.

What you have today

The platform follows the regulatory split described in Data Model.md §1.1 and docs/manufacturer-flows.md: enter static, family-level data once per battery model, then register one passport per physical unit with serial identity and dynamic state.

This matches DIN / DKE practice (model code + serialised units) and the existing BatteryModel and Passport entities in the database.

Two layers at a glance

Enter once per product family

LMT reference catalogue optional
BatteryModel
Carbon / metadata on model
attribute_value holder = MODEL

Per physical battery

Passport serial + public_id
attribute_value holder = PASSPORT
Dynamic SoH / cycles via BMS ingest
Inheritance (every passport belongs to one model) Optional provisioning from reference catalogue

Shared vendor specs (materials, circularity, primary BOM) live on the model; passports carry unit identity, optional overrides, lifecycle state, and time-series readings.

Core entities

Entity Purpose Typical identifiers
organization Tenant workspace (manufacturer, repairer, supplier, …). All customer data is scoped by tenant_id. Public org id, legal name
battery_model Product family / type approval unit. Shared regulatory static data for every passport of this model. public_model_code, optional reference_code from LMT catalogue
passport One row per manufactured battery unit. Links to exactly one model. public_id (QR), serial_number
attribute_definition Catalogue of ~95 DIN fields (and future delegated acts). Metadata drives UI, validation, and compliance. attribute_key (e.g. circ.recycled_content_pct)
attribute_value Actual field values, bound polymorphically to MODEL or PASSPORT (and other holders in later phases). Holder kind + holder UUID
bom / bom_line Bill of materials. Primary BOM is on the model; legacy per-passport BOM rows still resolve as fallback. Model-scoped mass balance

Attribute-as-data (not columns per field)

Regulatory attributes are not individual columns on passport or battery_model. Each field is defined in attribute_definition and stored in attribute_value rows. Adding a new DIN field is a catalogue migration, not a DDL change.

Catalogue flags control where values live and how passports read them:

is_model_level
Values may only be authored on the MODEL holder. Passports never store a separate row for this key.
inherits_from_model
Passport UI and compliance use the effective value: model value unless the unit has an explicit PASSPORT override.

Examples of model-level / inherited fields in Phase 1: recycled content %, recovery targets, repairability index, hazardous substances declaration, cathode/anode chemistry where shared across units.

LMT reference catalogue

The LMT reference catalogue is tenant-agnostic reference data (28 demo e-bike packs locally). A model may optionally provision from a catalogue entry via reference_code when creating or importing a model — copying baseline attributes without re-keying the datasheet.

In the app: LMT reference catalogue (manufacturer workspace). Model CSV import can set reference_code to link a row to catalogue data.

Carbon, BOM, and JSON metadata

  • Carbon footprint — declared on the model (metadata_json.carbon): class, kg CO₂e/kWh, lifecycle stages. Shown on passport detail by read-through from the model.
  • Primary BOM — stored with battery_model_id and null passport_id. Passport BOM screens redirect to model BOM editing; mass balance for compliance resolves model BOM first.
  • Passport static draft — production date on the entity; plant and notes in metadata_json.static until full version locking (Project 1.1).

Dynamic and time-series data

State of health, cycle counts, and BMS readings are per passport (and eventually TimescaleDB hypertables in production). They do not belong on the model row.

The REST ingest API (/api/v1/...) and manufacturer performance views attach readings to the passport identity, not the model family.

Effective values in the application

When you open a passport’s Materials or Circularity tab, the UI shows effective attributes: inherited from the model plus any unit-specific override. Inherited fields display a banner and link to Edit on model rather than duplicating vendor specs on every serial number.

Completeness and fleet compliance use the same resolution — a passport is not marked incomplete for recycled content that is already declared on its model.

Where to work in the application

What you are editing Holder / entity Route in this app
Register product family BatteryModel /app/models/new
Import vendor datasheet (CSV) MODEL attributes + model row /app/models → Import CSV
Materials & composition (shared) MODEL attribute_value /app/models/{id}/materials/edit
Circularity & recycled content (shared) MODEL attribute_value /app/models/{id}/circularity/edit
Bill of materials (primary) MODEL bom /app/models/{id}/bom
Carbon declaration Model metadata_json Model detail / carbon form (from models list)
Register physical unit Passport /app/passports/new
Bulk serial units (CSV) Passport rows only /app/passports → Import (columns: public_id, model_code, serial_number)
Passport detail (read inherited + unit data) Effective MODEL ∪ PASSPORT /app/passports/{id}
Unit static data override PASSPORT /app/passports/{id}/edit
Public QR / Art. 77 surface Passport public_id /p/{publicId} (anonymous)
LMT catalogue browse Reference data /app/catalog/lmt-batteries

Routes under /app/... require a signed-in manufacturer (or appropriate partner) session. Help pages are public at /help/**.

Recommended manufacturer workflow

  1. Create or import a battery model (and optionally link LMT reference code).
  2. Complete model-level materials, circularity, carbon, and BOM once.
  3. Create passports (form or CSV) with serial numbers pointing at that model code.
  4. Fill unit-specific fields and dynamic data per passport; use passport detail for lifecycle, NB audit, and market placement.

Further reading

  • Data Model.md — full entity domains, §6 attribute tables, versioning, multi-tenant rules.
  • docs/manufacturer-flows.md — Phase 1 workflow decisions (WF-01 … WF-13).
  • docs/din-attribute-catalog.md — catalogue CSV columns including is_model_level and inherits_from_model.