Skip to content
Updated Sep 28, 2026 by Pablo Coufal · Owner: analysisactiveentity Edit on GitHub

Entity: readingEntry ​

Entity Type: Database table (tenant schema)

Description: One manual reading as the user enters it: a gauge, the moment the meter was read, and what belongs to that moment as a whole — the note and the supporting documents. The measured values stay in reading, one row per series (tariff, direction, channel); every reading row with the same gaugeId and readAt and source = manual belongs to the entry. A remote or invoice reading has no entry: it carries no note and no document.

Why a table of its own. A note or a photo of the meter describes the act of reading, not one tariff. Stored on reading, it would be repeated on every row of the same moment and could disagree between them; stored as a JSON column on reading, it would sit on a hypertable whose rows are written by the remote sync in bulk. The documents attached to an entry are a list that is queried from the other side ("where is this document used"), so they live in readingEntryDocument rather than in a JSON array here.

Data Attributes Table ​

Attribute NameDescriptionData TypeDefault ValueRequired (= Nullable)UniqueFormatValidationsIndexExample
idPrimary key of the entity.UUIDGenerated in code (app layer)YesYesUUID v7-Primary Key019247a1-5c3e-7d10-8a2b-1f4c6e8d9a01
tenantIdTenant the entry belongs to.UUID-YesNoUUID v7Matches the tenant of the request context.name: idx_reading_entry_tenant_id, type: btree018f6e2a-1b2c-7d3e-9f40-5a6b7c8d9e0f
gaugeIdGauge the reading was taken on. Loose reference, as on reading: the gauge belongs to another part of the domain model.UUID-YesPart of composite uniqueUUID v7Resolved through the gauge lookup; the gauge must allow manual readings.name: uq_reading_entry_gauge_read_at, type: btree (unique, partial)018f7a10-2c3d-7e4f-8a5b-6c7d8e9f0a1b
readAtMoment the meter was read. Equal to the readAt of every reading row of the entry; changing it moves those rows with it.Timestamp with time zone-YesPart of composite uniqueISO 8601 — YYYY-MM-DDTHH:mm:ss.SSSZBetween 1990-01-01 and now.Part of the unique index above2026-05-04T08:40:00.000Z
noteFree text the user wrote about this reading — why a value looks unusual, who read it, what was found on site. One note per entry, edited in place; earlier versions are in the audit trail.StringnullNoNo-Max 2 000 characters.-Odečteno při kontrole rozvaděče, displej špatně čitelný.
createdAtTimestamp of record creation.Timestamp with time zonenow() — set in codeYesNoISO 8601 — YYYY-MM-DDTHH:mm:ss.SSSZCannot be null.-2026-05-04T09:41:12.000Z
updatedAtTimestamp of the last update.Timestamp with time zonenow() — set in codeYesNoISO 8601 — YYYY-MM-DDTHH:mm:ss.SSSZCannot be null.-2026-05-06T14:12:40.000Z
deletedAtSoft-delete marker, set when the reading is deleted. The entry's reading rows are removed; the entry stays so that its note and documents remain traceable from the audit trail.Timestamp with time zonenullNoNoISO 8601 — YYYY-MM-DDTHH:mm:ss.SSSZImmutable once set. Active rows: WHERE deletedAt IS NULL.-null
createdByActor who created the record.String-YesNotype:actorNon-empty.-user:018ed0b3-…
updatedByActor who last updated the record.String-YesNotype:actorNon-empty.-user:018ed0b3-…

Indexes ​

NameColumnsTypeWhy
uq_reading_entry_gauge_read_atgaugeId, readAt where deletedAt is nullUnique, partialOne manual reading per gauge and moment; a deleted entry must not block entering the same moment again.
idx_reading_entry_tenant_idtenantIdbtreeTenant predicate on every read.

Audited fields ​

Recorded on created (in full), updated (changed only) and deleted (in full): gaugeId, readAt, note.

Excluded: tenantId — fixed by the request context and identical on every entry of a tenant, so it carries no information about the change. The values of the entry are audited on reading; the attached documents on readingEntryDocument.