Skip to content
Updated Sep 26, 2026 by Barča Dvořáková · Owner: analysisactiveentityconfluence-migration Edit on GitHub

Entity: gaugeSerialHistory ​

Entity Type: Database table

Description: Append-only history of serial number changes for a gauge. Each physical meter replacement or serial number correction creates a new record with a validFrom timestamp; the previous record is never modified or deleted. The current serial number is the one with the highest validFrom that does not exceed the query time. This pattern is the source of truth for meter replacement history and enables Reading Management to detect counter resets when a new record appears with a validFrom that falls between two readings. gauge.serialNumber mirrors the most recent value for fast lookup and display — the two must be kept consistent by the application on every insert. This entity follows the versioned / append-only pattern (deviation #16): updatedAt, updatedBy, and deletedAt are intentionally omitted because records are written once and never modified or deleted in-place.

Data Attributes Table ​

Attribute NameDescriptionData TypeDefault ValueRequired (= Nullable)UniqueFormatValidationsIndexExample
idPrimary key of the entity.UUIDGenerated in code (app layer)YesYesUUID v7-Primary Key018ed0b3-c298-7c7a-96d5-8b36f5a7f8d2
tenantIdTenant that owns this record. Denormalised from gauge for uniform data-scoping. Must equal the parent gauge's tenantId; enforced by the application on insert.UUID-YesNoUUID v7Foreign Key → tenant; must exist; must equal parent gauge.tenantIdname: idx_gaugeSerialHistory_tenantId, type: btreee5f6a7b8-…
gaugeIdThe gauge whose serial number is recorded.UUID-YesNoUUID v7Foreign Key → gauge; must existname: idx_gaugeSerialHistory_gaugeId_validFrom, type: btree (composite with validFrom DESC)b2c3d4e5-…
serialNumberThe serial number of the physical meter that was in place from validFrom until the next record's validFrom (exclusive).String-YesNo-Max 100 characters; non-empty.-1EMH0004579834
validFromTimestamp from which this serial number became the active one. Records are applied to any query time that falls on or after this timestamp, up to the next record's validFrom. On the initial gauge creation this equals gauge.createdAt.Timestamp with time zone-YesNoISO 8601 — YYYY-MM-DDTHH:mm:ss.SSSZMust be unique per gaugeId (no two records for the same gauge at the same timestamp).name: idx_gaugeSerialHistory_gaugeId_validFrom, type: btree (composite with gaugeId)2025-06-01T08:00:00Z
replacedByOptional reference to the new gauge record that replaced this physical device, if the replacement involved installing a fundamentally different meter (e.g. new generation DO-capable device) that required a separate gauge record. Null for same-gauge serial number corrections.UUIDnullNoNoUUID v7Foreign Key → gauge; null when the replacement stays on the same gauge record.-f1a2b3c4-…
createdAtTimestamp of when this history record was created. Immutable after insert.Timestamp with time zonenow() — set in codeYesNoISO 8601 — YYYY-MM-DDTHH:mm:ss.SSSZCannot be null; cannot be modified after creation.-2025-06-01T08:00:00Z
createdByIdentifier of the actor who created the record (user ID, migration script, or system).String-YesNotype:actor — e.g. user:uuid or system:migrationNon-empty.-user:018ed0b3-c298-7c7a-96d5-8b36f5a7f8d2

Note. This entity is documented as intentionally omitting updatedAt, updatedBy and deletedAt (versioned/append-only pattern, deviation #16 in the source project) — carried over faithfully rather than padded out to the full audit quintet.

Audited fields ​

Recorded on created only — this entity is explicitly append-only (deviation #16: no updatedAt/updatedBy/deletedAt; a correction is a new row with a later validFrom, never a mutation of an existing one): gaugeId, serialNumber, validFrom, replacedBy.

Excluded: none.

Every entry would carry subjectEntityType = gauge / subjectEntityId = gaugeId — per the same rule applied to readingActionLog, this entity already being its own history mechanism for serial numbers is not a reason to exempt it from the generic trail.

Not registered for entityName resolution — renders id-only in the audit trail (architecture 61-audit-log.md §7.4 in the code repo: a valid, permanent state, not a gap). If registered, serialNumber is the natural candidate.