ADR-0039: Field cardinality and required
Kontext
Jedes Feld hat einen Typ; Pflicht (required) lag schon in field_definitions, war in der UI aber unsichtbar und beim Anlegen fest false. Kardinalität fehlte. Nutzer brauchen beides immer — wie Typ und Scope an der Entität. Unbounded n reicht nicht: Fachmodelle setzen oft eine feste Obergrenze (wenige Werte, nie unbegrenzt).
Entscheidung
- Jedes Feld hat Kardinalität
n(unbegrenzt) oder 1–99 und Pflicht (Ja / Nein). Beide sind Pflichtangaben. Default1und nicht Pflicht. - UI: ein Feld mit Eingabe (
noder 1–99) und Pfeil-Auswahl derselben Werte.list-Typen werden aufngesetzt, bleiben aber auf 1–99 änderbar. - Spalten auf
field_definitions(nicht nurconfigJSON). Legacyone/manywird beim Schreiben auf1/nnormalisiert. - Validierung: alles außer
1erwartet ein Array des Feldtyps; eine Zahl begrenzt die Länge; Pflicht lehnt[]ab.field_type=listbleibt das verschachtelte Listen-Modell (Item-Typ/Gruppe), die Kardinalität begrenzt die Item-Anzahl. - Create/Edit-Dialog und Feldliste zeigen Kardinalität und Pflicht immer.
| Gate | Recommendation | Why it fits here | Rejected alternative and why |
|---|---|---|---|
| Modell | cardinality (n | 1–99) + required getrennt |
Entspricht XSD maxOccurs vs minOccurs; Cap 99 hält die Auswahl endlich |
Ein 4-Wege-Enum 0..1 / 1 / 0..* / 1..* — vermischt Pflicht und Anzahl |
| Speicher | eigene Text-Spalte | Immer gesetzt, API/QGIS lesen ohne JSON-Pfad; n bleibt das unbegrenzte Zeichen |
Nur Integer + Sentinel, oder nur config |
list-Typ |
behalten, Default n |
Seed-Felder und Nested-Groups bleiben | list streichen — Bruch ohne Gewinn |
Begründung (für dieses Setup)
GIS-Fachmodelle (INSPIRE/XPlanung) trennen Multiplizität und Pflicht. n deckt unbegrenzte Listen ab; 1–99 ist die feste maxOccurs ohne offenes Integer-Feld. JSONB-attrs speichern alles außer 1 als Array; QGIS liest weiter die Felddefs.
Verworfene Alternativen
| Alternative | Warum verworfen |
|---|---|
Nur Pflicht, Kardinalität implizit über list |
list ist ein Typ (verschachtelte Gruppe), keine Anzahl |
Nur one / many |
Keine feste Obergrenze (2…99) |
Unbegrenztes Integer max_occurs |
UI und Check ohne Bedarf über 99 |
Pflicht aus Kardinalität ableiten (1 = Pflicht) |
Nutzer wollen beide Schalter getrennt |
Folgen
- Alembic
0016_field_cardinalityplus0018_cardinality_n_or_count(Tenant0004/0006). - API
FieldDefinitionIn/Out.cardinality:noder"1"–"99"(schreibt auch legacyone/many). - Plugin bleibt apply-only; Formulare lesen die neuen Attribute.
- Enum/Liste und Auswahllisten: ADR-0042.