Appearance
Entity: uiLabel
Entity Type: Database table
Description: Stores editable UI text (form labels, field names, section titles, and similar display strings) shown across the EM3 application. This entity is a deliberate, documented exception to the standard rule that every entity carries a tenantId: a uiLabel record has no tenant scope — it is a single global value that applies identically across all tenants. Each label keeps exactly two values per language: a defaultValue (set only via deployment/seed, effectively read-only afterwards) and a currentValue (the value actually shown in the UI, editable only by a superadmin). No intermediate history is kept — resetting a label to its original text is simply copying defaultValue into currentValue for that language. Editing is restricted to a dedicated superadmin role, distinct from and above tenant-level administrator roles. Each record may additionally carry an optional hint — a single directly-editable text (no default/current split, not affected by reset) shown as an info tooltip next to the field.
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 |
| translationKey | Identifier of the label, shared across all locales of the same label. Namespaced by area for readability. | String | - | Yes | No | Dot-notation, e.g. gauge.form.levelLabel, gauge.directionLabel.electricity.import | Must not be empty; must follow the project's key-naming convention. | name: idx_uiLabel_translationKey_locale, type: btree (composite with locale) | gauge.form.levelLabel |
| locale | Language this record's values are written in. | String | - | Yes | No | Enum — Locale (cs, en, sk reserved for future use) | Must be one of the defined enum values. | (part of composite index above) | cs |
| type | Categorises what kind of UI text this label represents. Filtering metadata only — does not affect behaviour. | String | - | Yes | No | Enum — UiLabelType | Must be one of the defined enum values. | name: idx_uiLabel_type, type: btree | formField |
| component | Application area this label belongs to. Filtering metadata only — does not affect behaviour. | String | - | Yes | No | enum | Must be one of the defined enum values. | name: idx_uiLabel_component, type: btree | assets |
| defaultValue | The original ("factory") text for this label and locale, as shipped by development. Not editable via the superadmin UI/API — changes to this value only happen via deployment/seed. | String | - | Yes | No | - | Max 300 characters; must not be empty. | - | Úroveň měřidla |
| currentValue | The text actually shown in the UI for this label and locale. Editable by a superadmin. Defaults to defaultValue when the record is first seeded. | String | = defaultValue at seed time | Yes | No | - | Max 300 characters; must not be empty. | - | Úroveň měřáku |
| hint | Optional contextual help text shown as an info icon next to the field, for this label and locale. Null = no icon shown. | String | null | No | No | - | Max 500 characters; may be null or empty (null = no icon). | - | Kontaktní osoba pro technické záležitosti |
| 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 |
| updatedAt | Timestamp of the last update to currentValue. Set on insert (equal to createdAt) and updated whenever currentValue changes. | Timestamp with time zone | now() — set in code | Yes | No | ISO 8601 — YYYY-MM-DDTHH:mm:ss.SSSZ | Cannot be null. | - | 2025-03-16T18:00:00Z |
| deletedAt | Timestamp of soft deletion. Null means the record is active. Once set, this value is immutable and cannot be changed. Deletion is only expected as part of a developer-driven cleanup when a label key is retired from the codebase — never as a superadmin action. | Timestamp with time zone | - | No | No | ISO 8601 — YYYY-MM-DDTHH:mm:ss.SSSZ | Immutable once set. Active records: WHERE deletedAt IS NULL | - | null |
| createdBy | Identifier of the actor who created the record (typically a system/migration actor at seed time). | String | - | Yes | No | type:actor — e.g. user:uuid or system:migration | Non-empty. | - | system:migration-v1 |
| updatedBy | Identifier of the actor who last updated currentValue (the superadmin who made the change, or a system actor at seed time). | String | - | Yes | No | type:actor — e.g. user:uuid or system:migration | Non-empty. | - | user:018ed0b3-c298-7c7a-96d5-8b36f5a7f8d2 |
Note on uniqueness. The combination (translationKey, locale) must be unique — there is exactly one row per label per language, globally (no tenant dimension).
Note. This entity is a documented exception to the project's mandated tenantId column — see description above.
Audited fields
Recorded on created (in full) and updated (changed only) — no deleted entry is expected from ordinary use (this entity's own description states deletion happens only as a developer-driven cleanup when a key is retired from the codebase, never as a superadmin action), though the column exists and a deleted entry would still fire if that path is ever exercised: translationKey, locale, type, component, defaultValue, currentValue, hint.
Excluded: none — though defaultValue is documented as not editable via the superadmin UI/API (set only at deployment/seed), so in practice it would appear only in a created entry, never in an updated entry's changed fields, the same shape as organisation.isSelf or gauge.medium.
No subjectEntityType/subjectEntityId and no tenantId — a documented, deliberate exception (single global value shared identically across every tenant). Not registered for entityName resolution (architecture 61-audit-log.md §7.4/§7.6 in the code repo: a valid, permanent state, not a gap). If registered, translationKey is the natural candidate (paired with locale, since the natural key is the pair together).