Appearance
Entity: gaugeUsageAllocation
Entity Type: Database table
Description: How the consumption of one channel is attributed to usage types (účel užití) from a given day on. One record per channel and validity; the record valid on a day is the one with the highest validFrom not after it (D02 — local day of the channel's daily aggregate). Three modes: single — one usage for 100 % of the channel; estimated — explicit monthly percentage shares per usage, every month summing to exactly 100 % (D03, no remainder); measured — measured parts taken from sub-gauge channels plus exactly one usage that receives the remainder of the parent (O01). The split itself is never stored: variant C computes it at read time from the daily aggregate and the allocation valid on that day (consumption_daily_by_usage, Epic 3.1 / 3.2), so a change needs no reprocessing and consumption keeps one row per channel and slot. Replaces gauge.usageType (one value per physical meter) — decisions R1–R3, 1 Oct 2026; rules D01–D09 confirmed by the product owner. Versioning follows the append-only pattern of gaugeSerialHistory with one addition: a backdated correction supersedes the version it replaces (supersededById) instead of creating a second effective version for the same day (UC-06).
Data Attributes Table
| Attribute Name | Description | Data Type | Default Value | Required (= Nullable) | Unique | Format | Validations | Index | Example |
|---|---|---|---|---|---|---|---|---|---|
| id | Primary key of the entity. | UUID | Generated in code (app layer) | Yes | Yes | UUID v7 | - | Primary Key | 01960000-0000-7000-8000-000000000801 |
| tenantId | Tenant that owns this record. Denormalised from gauge for uniform data-scoping. | UUID | - | Yes | No | UUID v7 | Foreign Key → tenant; must equal the parent gauge.tenantId. | name: idx_gaugeUsageAllocation_tenantId, type: btree | 01960000-0000-7000-8000-000000000099 |
| gaugeId | The channel whose consumption is allocated. Consumption channels only (purpose consumption; not export / production in v1 — K3; never KVP). | UUID | - | Yes | No | UUID v7 | Foreign Key → gauge; must exist and be a consumption channel with a medium the usage catalogue covers. | name: idx_gaugeUsageAllocation_gaugeId_validFrom, type: btree (composite, validFrom DESC) | 01960000-0000-7000-8000-000000000005 |
| validFrom | First local day the allocation applies to (inclusive). | Date | - | Yes | No | ISO 8601 date | At most one effective (non-superseded) record per gaugeId and validFrom. | name: idx_gaugeUsageAllocation_gaugeId_validFrom, type: btree (composite) | 2026-10-01 |
| mode | single · estimated · measured (kapitola 4.4 of the gauge form specification). | String | - | Yes | No | enum | single → exactly one item with no shares and no sources; estimated → ≥ 2 items with 12 shares each, every month summing to 100 %; measured → ≥ 1 item with sourceGaugeIds and exactly one item with isRemainder = true. | - | estimated |
| supersededById | The correction that replaced this version (UC-06). Null for the effective version. | UUID | null | No | No | UUID v7 | Foreign Key → gaugeUsageAllocation; same gaugeId and validFrom. | name: idx_gaugeUsageAllocation_supersededById, type: btree | null |
| note | Optional free text (why the split was set this way). | String | null | No | No | - | Max 500 characters. | - | Odhad podle projektu kotelny |
| createdAt | Timestamp of entity creation. Immutable. | Timestamp with time zone | Set in code | Yes | No | ISO 8601 | - | - | 2026-10-05T10:00:00Z |
| createdBy | Identifier of the actor who created this record. | String | - | Yes | No | type:actor | - | - | user:01960000-0000-7000-8000-000000000099 |
Notes
- Append-only with supersession. A new
validFromadds a version; a correction of an existing version (samegaugeId, samevalidFrom) adds a record and setssupersededByIdon the old one. One day never has two effective versions; reads use the effective version only; superseded versions stay for the audit trail (who corrected what, when). - Validation is atomic (UC-13): the record and its items are saved together or not at all; the backend validates the usage offer against usageType
.allowedFor, the monthly sums, duplicate usages (N04), source channels (D04: same medium, inside the parent's balance boundary, not the channel itself, no overlapping branches), and refuses an inactive usage for a new assignment (N09). - Missing data is never zero (D05): when the parent's daily aggregate or a measured source is missing or incomplete for a day, that day's known total stays unassigned with a reason; no fallback to the estimate, no clipping. Measured parts exceeding the parent flag the day as inconsistent (D09); no negative remainder.
- Sub-gauge creation copies the parent channel's effective allocation as the child's own first version (R5, D07, N07): usages and shares verbatim,
sourceGaugeIdsonly where valid for the child (never a reference to itself); the child is independent afterwards. - Migration (M8): EM2
gauge_consumption_usagecodes 1, 2, 5, 6, 7 →single; 4 →estimatedwith the monthly shares ofgauge_consumption_usage_combi(EM2's implicit remainder → explicitheatingshare so months sum to 100 %); 3 / 8 →measuredwith the sub-gauge channel as source and the other usage as remainder; 0 → no record.validFrom= migration date unless EM2 carries a date. - Read model:
GET /v1/gauges/:id/usage-allocations(versions) andGET /v1/gauges/:id/usage-allocations/effective?at=for the form;consumption_daily_by_usagejoins the effective version for each day of the daily aggregate and multiplies byshares[month]or subtracts measured sources.