Appearance
Entity: climateData
Entity: climateData
Description: Stores actual measured or reported climate values (heating days, average temperature) for a specific weather station and time period. Each record represents one time slot at a given granularity (monthly, daily or hourly). Records are written once and never modified — corrections are represented by a new row with a later validFrom for the same (weatherStationId, date, granularity) combination; the previous row is retained permanently as an immutable historical fact. Used as the source for climate data tables in the client UI and as an input to the degree-day normalisation calculation together with climateNormal. Stations with a richer data source may report additional parameters beyond heating days and temperature — these are stored in extraParameters.
Entity Type: database table
Append-only entity. Records are written once and never modified or deleted.
updatedAt,updatedByanddeletedAtare intentionally omitted. The lifecycle of a record is expressed by itsdate,granularityandvalidFrom. Corrections are handled via versioning (a new row with a latervalidFrom), never by mutating an existing row.
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 | 018ed0b3-c298-7c7a-96d5-8b36f5a7f8d2 |
tenantId | Tenant this record belongs to. Mirrors the tenantId of the parent weather station. null for global station data. | UUID | - | No | No | UUID v7 or null | Foreign Key: tenant (when non-null); must exist | name: idx_climateData_tenantId, type: btree | 018fa51f-fda1-79f4-8461-2cb8f1cabc10 |
weatherStationId | The weather station this record belongs to. | UUID | - | Yes | No | UUID v7 | Foreign Key: weatherStation.id; must exist | name: idx_climateData_weatherStationId_date, type: btree (composite with date, granularity, validFrom) | 018ed0b3-c298-7c7a-96d5-8b36f5a7f8d2 |
date | Start of the time period this record covers. For monthly granularity: first day of the month. For daily: the day. For hourly: the start of the hour. | timestamp with time zone | - | Yes | No | ISO 8601 | Part of composite unique constraint (weatherStationId, date, granularity, validFrom) | name: idx_climateData_weatherStationId_date, type: btree (composite with weatherStationId, granularity, validFrom) | 2024-01-01T00:00:00Z |
granularity | Time resolution of this record. | string (enum) | - | Yes | No | enum — see Granularity (source Confluence page; not yet migrated to the local enum catalog) | Must be one of the valid values | - | monthly |
validFrom | Timestamp when this version of the value became the recorded truth. Not the weather period itself (that's date) — this is the versioning dimension that enables corrections. | timestamp with time zone | createdAt — set in code | Yes | No | ISO 8601 | Part of composite unique constraint (weatherStationId, date, granularity, validFrom) — prevents duplicate imports at the exact same instant while allowing corrections | - | 2025-06-01T09:00:00Z |
heatingDays | Meaning depends on granularity: daily → 0/1 (heating day yes/no); monthly → count of heating days; hourly and finer → null. Derived automatically for source = remote stations. Set directly by the admin for manual entries (or as a manual correction of an automatically computed value). | integer | 0 / null (depending on granularity) | No | No | - | 0–1 for daily; 0–31 for monthly; null for hourly/finer | - | 18 |
avgTemp | Average outdoor temperature for the period in °C. Derived automatically for source = remote stations. null for hourly and finer. Set directly by the admin for manual entries (or as a manual correction of an automatically computed value). | decimal | - | No | No | °C, two decimal places | - | -2.40 | |
extraParameters | Additional optional climate parameters, as reported by the station's data source. Free-form — keys and units are not enumerated or validated by the system; whatever the source provides is stored as-is. | JSONB | null | No | No | JSON — free-form, no fixed shape (see note below) | - | - | {"solarRadiation": 4.2, "precipitation": 12.5, "windSpeed": 3.1} |
source | Origin of this data record. Distinguishes remote from manual entry. | string (enum) | - | Yes | No | enum — see ClimateDataSource (source Confluence page; not yet migrated to the local enum catalog) | - | - | remote |
createdAt | Timestamp of when the record was created. Immutable after insert. | timestamp with time zone | now() — set in code | Yes | No | ISO 8601 — YYYY-MM-DDTHH:mm:ss.SSSZ | Cannot be null; cannot be modified after creation | - | 2025-03-16T18:00:00Z |
createdBy | Identifier of the actor who created the record. | string | - | Yes | No | type:actor — e.g. user:uuid or system:climate-import | Non-empty | - | system:climate-import |
Note — no
updatedAt/updatedBy/deletedAt. This is an append-only entity (see above); the standard audit quintet is intentionally reduced tocreatedAt/createdByonly.
Note —
extraParametersJSON shape not documented. The source Confluence page describes this JSONB column as genuinely free-form ("keys and units are not enumerated or validated by the system; whatever the source provides is stored as-is"). Per the foundations doc (§8.1) a JSONB column should get a sibling JSON-DAT documenting its internal shape; no sibling file was created here because there is no fixed shape to document faithfully without inventing one. Flagging for review — a maintainer may want a JSON-DAT that explicitly documents "no fixed shape" rather than omitting it, or may know of a de-facto key set worth capturing.
Audited fields
Recorded on created only — this entity is explicitly append-only (no updatedAt/updatedBy/deletedAt at all; a correction is a new row with a later validFrom, never a mutation of an existing one): weatherStationId, date, granularity, validFrom, heatingDays, avgTemp, extraParameters, source.
Excluded: none.
Every entry would carry subjectEntityType = weatherStation / subjectEntityId = weatherStationId — climateData has no human-readable key of its own; the station plus the (date, granularity, validFrom) triple on the entry itself is what identifies one record.
Not registered for entityName resolution, and has no independent human-readable attribute to register — identified by its weatherStationId/date/granularity/validFrom scope.