---
title: Prüfungsregeln
---

Prüfungsregeln legen fest, wann der Inhalt eines Feldes als korrekt gilt. Das Ergebnis wird als farbiges Symbol (**Badge**) neben dem Feld angezeigt und wirkt sich auf die Gesamtbewertung des Dokuments aus.

---

## Inhalt

1. [Die vier Zustände (Badges)](#die-vier-zustande-badges)
2. [Wo Regeln konfiguriert werden](#wo-regeln-konfiguriert-werden)
3. [Übersicht: Welche Prüfung in welchem Feld?](#ubersicht-welche-prufung-in-welchem-feld)
4. [Regeln pro Feldtyp](#regeln-pro-feldtyp)
    - [Zahlenfelder (Eingabe, Berechnet, Zeitspanne)](#zahlenfelder-eingabe-berechnet-zeitspanne)
    - [Auswahl (Select)](#auswahl-select)
    - [Schalter (Switch)](#schalter-switch)
    - [Mehrfachauswahl (Multiselect)](#mehrfachauswahl-multiselect)
    - [Dynamische Tabelle](#dynamische-tabelle)
5. [Praxis-Beispiele](#praxis-beispiele)
6. [Gut zu wissen](#gut-zu-wissen)

---

## Die vier Zustände (Badges) [#die-vier-zustande-badges]

Neben jedem geprüften Feld erscheint ein Badge mit einem von vier Zuständen:

| Badge | Bedeutung |
|:---:|---|
| 🟢 **OK** | Der eingetragene Wert erfüllt alle Regeln. |
| 🔴 **Fehler** | Der Wert verletzt mindestens eine Regel - bitte korrigieren. |
| ⚪ **Leer** | Es wurde noch kein Wert eingegeben. |
| ⚫ **Keine Regel** | Es sind keine Prüfungsregeln hinterlegt; der Wert wird nicht geprüft. |

Nur Felder im Zustand 🔴 **Fehler** blockieren die Freigabe eines Dokuments.

---

## Wo Regeln konfiguriert werden

Regeln werden pro Feld in der Template-Konfiguration als Liste hinterlegt:

```json
{
  "name": "temperatur",
  "type": "flexiInput",
  "label": "Temperatur",
  "rules": [
    "VALUE>100"
  ]
}
```

Mehrere Regeln werden als Liste geschrieben. Die genaue Bedeutung der Einträge hängt vom Feldtyp ab - siehe unten.

---

## Übersicht: Welche Prüfung in welchem Feld? [#ubersicht-welche-prufung-in-welchem-feld]

Die folgende Tabelle zeigt, welche Art von Prüfung bei welchem Feldtyp konfiguriert werden kann. Die Details zur Schreibweise stehen im nächsten Abschnitt.

Legende: ✅ = direkt möglich · ⚠ = mit Einschränkung (siehe Fußnote) · ❌ = nicht verfügbar

| Prüfung | Zahl¹ | Auswahl | Schalter | Mehrfachauswahl | Tabellenzeile |
|---|:---:|:---:|:---:|:---:|:---:|
| Mindestwert (`≥ n`) | ✅ | ✅ | ❌ | ❌ | ✅ |
| Höchstwert (`≤ n`) | ✅ | ✅ | ❌ | ❌ | ✅ |
| Echt größer als (`> n`) | ⚠² | ⚠² | ❌ | ❌ | ✅ |
| Echt kleiner als (`< n`) | ✅ | ✅ | ❌ | ❌ | ✅ |
| Genauer Wert (`== wert`) | ✅ | ✅ | ❌ | ✅ | ✅ |
| Wert muss ungleich sein (`!= wert`) | ✅ | ✅ | ❌ | ✅ | ✅ |
| Toleranzbereich (± p %) | ✅ | ❌ | ❌ | ❌ | ✅ |
| Toleranz einseitig nach unten (Min %) | ✅ | ❌ | ❌ | ❌ | ✅ |
| Toleranz einseitig nach oben (Max %) | ✅ | ❌ | ❌ | ❌ | ✅ |
| Schalter muss auf **An** stehen | ❌ | ❌ | ✅ | ❌ | ❌ |
| Schalter muss auf **Aus** stehen | ❌ | ❌ | ✅ | ❌ | ❌ |
| Anderes Feld nicht leer (Länge > 0) | ✅ | ✅ | ✅ | ✅ | ✅ |
| Anderes Feld hat bestimmten Wert | ❌ | ✅ | ✅ | ❌ | ❌ |
| Vergleich zweier Felder / Formel | ✅ | ❌ | ❌ | ❌ | ✅⁴ |
| Mehrere Alternativen (eine muss zutreffen) | ⚠³ | ✅ | ✅ | ✅ | ✅ |

¹ **Zahl** umfasst die Feldtypen *Eingabe* (`flexiInput`), *Berechnet* (`flexiCalculatedInput`) und *Zeitspanne* (`flexiTimeSpan`) - alle drei verhalten sich bei Regeln identisch.

² *Echt größer als* bei Zahl und Auswahl: `VALUE>n` wird aus historischen Gründen als `≥ n` (also wie *Mindestwert*) interpretiert. Wer einen **strikten** Vergleich `> n` braucht, verwendet `COMPARE:VALUE>n` - in `COMPARE`-Regeln gelten alle Operatoren strikt. In der dynamischen Tabelle ist `VALUE:field>n` bereits strikt.

³ *Alternativen* bei Zahl: Technisch möglich, praktisch aber problematisch, weil bei mehreren `VALUE`-Regeln in einem Zahlenfeld nur die **letzte** das Ergebnis bestimmt (siehe [Gut zu wissen](#gut-zu-wissen)). Für Alternativen bei Zahlen besser `COMPARE`-Regeln oder eine ergänzende `COMPONENT:feld.length>0`-Regel verwenden.

⁴ *Vergleich bei Tabellenzeilen*: Möglich sind Vergleiche zwischen zwei Spalten derselben Zeile sowie zwischen einer Spalte und einem Feld außerhalb der Tabelle (Section-Feld) per `@`-Prefix - siehe [Dynamische Tabelle](#dynamische-tabelle). **Formeln mit `+`/`-`** (wie `COMPARE:VALUE<=(soll+5)`) sind in Tabellen **nicht** verfügbar - dafür nur in Zahlenfeldern.

---

## Regeln pro Feldtyp

### Zahlenfelder (Eingabe, Berechnet, Zeitspanne)

Für **flexi-input**, **flexi-calculated-input** und **flexi-time-span** - immer dann, wenn eine Zahl eingetragen oder berechnet wird.

#### Verfügbare Regeln [#verfugbare-regeln]

**Vergleichsoperatoren** - direkter Zahlenvergleich:

| Schreibweise | Bedeutung |
|---|---|
| `VALUE>=n` | Wert muss **mindestens** `n` betragen. |
| `VALUE<=n` | Wert darf **höchstens** `n` betragen. |
| `VALUE<n` | Wert muss **strikt kleiner** als `n` sein. |
| `VALUE==n` | Wert muss **genau** `n` sein. |
| `VALUE!=n` | Wert darf **nicht** `n` sein. |
| `VALUE>n` | Aus historischen Gründen identisch mit `VALUE>=n` (Mindestwert). Für einen strikten *größer als* stattdessen `COMPARE:VALUE>n` verwenden. |

```json
"rules": ["VALUE>=100"]
```
> Wert = 100 → OK. Wert = 99 → Fehler.

```json
"rules": ["VALUE<=200"]
```
> Wert = 200 → OK. Wert = 201 → Fehler.

```json
"rules": ["VALUE==0"]
```
> Nur exakt 0 ist OK.

**`VALUE%p:ref`** (oder `VALUE:p%ref`) - Der Wert muss innerhalb von ± p % eines Referenzfeldes liegen.

```json
"rules": ["VALUE%5:programmierte_dosierung"]
```
> Wenn `programmierte_dosierung = 100`, dann ist jeder Wert zwischen 95 und 105 OK.

**`VALUE%MINp:ref`** - Das Referenzfeld darf nicht mehr als p % **unter** dem eigenen Wert liegen.

```json
"rules": ["VALUE%MIN5:konzentration_ist"]
```
> Wenn der eigene Wert 100 ist, muss `konzentration_ist` ≥ 95 sein. Sonst: Fehler.

**`VALUE%MAXp:ref`** - Das Referenzfeld darf nicht mehr als p % **über** dem eigenen Wert liegen.

```json
"rules": ["VALUE%MAX5:konzentration_ist"]
```
> Wenn der eigene Wert 100 ist, darf `konzentration_ist` höchstens 105 sein.

**`COMPONENT:feld.length>n`** - Ein anderes Feld muss mindestens `n` Zeichen enthalten. Wirkt als Alternative: Wenn dieses andere Feld ausgefüllt ist, gilt die Prüfung als erfüllt.

```json
"rules": [
  "VALUE%5:sollwert",
  "COMPONENT:bemerkung.length>0"
]
```
> Der Wert liegt innerhalb ± 5 % vom Sollwert **oder** es gibt eine Bemerkung → OK.

**`COMPARE:(ausdruck1)op(ausdruck2)`** - Zwei Ausdrücke werden verglichen. Unterstützt Konstanten, Referenzfelder, Addition und Subtraktion.

**Unterstützte Operatoren in `COMPARE`**: `>=`, `<=`, `<`, `>`, `==`, `!=`. Anders als bei `VALUE>n` sind hier `>` und `<` **strikt**.

```json
"rules": ["COMPARE:VALUE<=(sollwert+5)"]
```
> Der eigene Wert muss kleiner oder gleich `sollwert + 5` sein.

```json
"rules": ["COMPARE:veraenderung>=-50"]
```
> Das Feld `veraenderung` muss mindestens −50 sein.

```json
"rules": ["COMPARE:VALUE==sollwert"]
```
> Der eigene Wert muss exakt dem `sollwert` entsprechen.

```json
"rules": ["COMPARE:VALUE!=vorgabewert"]
```
> Der eigene Wert darf **nicht** dem `vorgabewert` entsprechen.

---

### Auswahl (Select)

Für **flexi-select** - Dropdown-Felder mit einer Auswahl.

#### Verfügbare Regeln [#verfugbare-regeln_1]

**Text-Vergleich** - für Auswahlfelder mit Text-Optionen:

| Schreibweise | Bedeutung |
|---|---|
| `VALUE==wert` | Auswahl muss exakt `wert` sein. |
| `VALUE!=wert` | Auswahl darf **nicht** `wert` sein. |

```json
"rules": ["VALUE==in Ordnung"]
```

```json
"rules": ["VALUE!=Nicht erforderlich"]
```

**`VALUE:Kategorie==wert`** - Gleiche Wirkung wie `VALUE==wert`. Der Teil vor `==` (hier `Kategorie`) dient nur als Lese-Hilfe und wird bei der Prüfung ignoriert.

```json
"rules": ["VALUE:Bewertung==bestanden"]
```

**Zahlen-Vergleich** - für Auswahlfelder mit numerischen Optionen:

| Schreibweise | Bedeutung |
|---|---|
| `VALUE>=n` | Auswahl muss `≥ n` sein. |
| `VALUE<=n` | Auswahl muss `≤ n` sein. |
| `VALUE<n` | Auswahl muss strikt `< n` sein. |
| `VALUE>n` | Identisch mit `VALUE>=n` (Legacy-Schreibweise). |

**Mehrere Auswahlmöglichkeiten** - Die Prüfung gilt bei der **ersten** Regel als erfüllt, die zutrifft. So lassen sich Alternativen definieren:

```json
"rules": [
  "VALUE==bestanden",
  "VALUE==teilweise bestanden"
]
```

**`COMPONENT:feld.length>n`** - Alternative: Ein anderes Feld ist ausgefüllt.

```json
"rules": [
  "VALUE==bestanden",
  "COMPONENT:bemerkung.length>0"
]
```

---

### Schalter (Switch)

Für **flexi-switch** - Ein-/Aus-Schalter mit boolean-Wert.

#### Verfügbare Regeln [#verfugbare-regeln_2]

**`VALUE:TRUE`** - Der Schalter muss auf **an** stehen.

```json
"rules": ["VALUE:TRUE"]
```

**`VALUE:FALSE`** - Der Schalter muss auf **aus** stehen.

```json
"rules": ["VALUE:FALSE"]
```

**`COMPONENT:feld.length>n`** - Alternative: Ein anderes Feld ist ausgefüllt (mindestens `n` Zeichen, Leerzeichen zählen nicht mit).

```json
"rules": [
  "VALUE:TRUE",
  "COMPONENT:bemerkung.length>0"
]
```
> Entweder Schalter an oder Bemerkung eingetragen → OK.

**`COMPONENT:feld.value==TRUE/FALSE`** - Der Schalter eines anderen Feldes muss einen bestimmten Zustand haben.

```json
"rules": ["COMPONENT:freigegeben.value==TRUE"]
```

---

### Mehrfachauswahl (Multiselect)

Für **flexi-multiselect** - Auswahl mehrerer Optionen.

#### Verfügbare Regeln [#verfugbare-regeln_3]

**`VALUE==wert`** - Mindestens eine der ausgewählten Optionen muss `wert` sein (bzw. `wert` enthalten, wenn die Auswahl aus einer dynamischen Quelle stammt).

```json
"rules": ["VALUE==in Ordnung"]
```

**`VALUE!=wert`** - `wert` darf **nicht** unter den ausgewählten Optionen sein.

```json
"rules": ["VALUE!=Nicht erforderlich"]
```

**Mehrere Alternativen** - Analog zum Select-Feld:

```json
"rules": [
  "VALUE==Option A",
  "VALUE==Option B"
]
```

**`COMPONENT:feld.length>n`** - Alternative: Ein anderes Feld ist ausgefüllt.

---

### Dynamische Tabelle

Für **flexi-dynamic-table** - Jede Zeile wird einzeln geprüft. Die Gesamt-Tabelle gilt nur dann als gültig, wenn **alle** Zeilen in Ordnung sind.

#### Verfügbare Regeln [#verfugbare-regeln_4]

**`VALUE:spalte>=n`** / **`>n`** / **`<=n`** / **`<n`** / **`==n`** / **`!=n`** - Wert einer Spalte der Zeile vergleichen. In der dynamischen Tabelle sind alle Operatoren strikt - `>` und `<` sind hier wirklich *echt größer* bzw. *echt kleiner*.

```json
"rules": ["VALUE:menge>=5"]
```
> In jeder Zeile muss die Spalte `menge` mindestens 5 sein.

```json
"rules": ["VALUE:status!=abgelehnt"]
```
> Keine Zeile darf im `status` den Wert `abgelehnt` haben.

Mehrere Varianten:
```json
"rules": ["VALUE:menge>=5", "VALUE:menge<=100"]
```
> Zulässige Mengen: 5 bis 100.

**`VALUE:spalte%p:refSpalte`** - Die Spalte `spalte` der Zeile muss innerhalb von ± p % von `refSpalte` (einer anderen Spalte derselben Zeile) liegen.

```json
"rules": ["VALUE:ist%5:soll"]
```
> In jeder Zeile darf der Wert in Spalte `ist` um höchstens ± 5 % vom Wert in Spalte `soll` abweichen.

**`VALUE:spalte%MINp:refSpalte`** - `refSpalte` darf nicht mehr als p % **unter** dem Wert in `spalte` liegen.

**`VALUE:spalte%MAXp:refSpalte`** - `refSpalte` darf nicht mehr als p % **über** dem Wert in `spalte` liegen.

Auch bei diesen Regeln kann mit `@`-Prefix stattdessen ein Feld **außerhalb der Tabelle** als Referenz verwendet werden. Der Prefix ist auf **beiden Seiten** erlaubt - so lässt sich auch eine Section-Vorgabe als Bezugspunkt für eine Spalte nutzen:

```json
"rules": ["VALUE:ist%5:@sollwert_section"]
```
> Die Spalte `ist` muss innerhalb von ± 5 % vom Section-Feld `sollwert_section` liegen. Prozentbasis ist das Section-Feld.

```json
"rules": ["VALUE:@prog_temp_soll%MAX5:temperatur_ist_max"]
```
> Die Spalte `temperatur_ist_max` darf höchstens 5 % über dem Section-Feld `prog_temp_soll` liegen. Prozentbasis ist **das Section-Feld** (linke Seite). Einseitige obere Grenze.

```json
"rules": ["VALUE:@prog_temp_soll%MIN5:temperatur_ist_min"]
```
> Analog für die untere Grenze: `temperatur_ist_min` darf höchstens 5 % unter `prog_temp_soll` liegen.

**`COMPONENT:spalte.length>n`** - Länge einer Text-Spalte.

**`COMPARE:spalte1>=spalte2`** - Zwei Spalten der Zeile vergleichen.

```json
"rules": ["COMPARE:veraenderung<=zulaessig"]
```
> Die Spalte `veraenderung` darf nicht größer als `zulaessig` sein.

**`COMPARE:spalte>=100`** - Spalte gegen Konstante.

**`COMPARE:spalte<op>@feld`** - Spalte der Zeile gegen ein Feld außerhalb der Tabelle (in derselben Section) vergleichen. Das `@` markiert den Operanden als externes Feld; ohne `@` wird der Name als Spalte der aktuellen Zeile gelesen. Unterstützte Operatoren: `>=`, `<=`, `<`, `>`, `==`, `!=` (alle strikt).

```json
"rules": ["COMPARE:menge<=@maxMenge"]
```
> In jeder Zeile darf `menge` nicht größer sein als das Section-Feld `maxMenge`.

Das `@`-Prefix kann auf beiden Seiten stehen und auch zweimal - so sind auch rein externe Vergleiche möglich:

```json
"rules": [
  "COMPARE:@schwellwert<=menge",
  "COMPARE:@min<=@max"
]
```

Ist das referenzierte Section-Feld leer oder nicht vorhanden, schlägt die Regel fehl (**Fehler**).

#### Pflichtfelder zusätzlich [#pflichtfelder-zusatzlich]

Ist eine Spalte als Pflichtfeld markiert und eine Zeile lässt sie leer, wird die Zeile automatisch als **Fehler** markiert - unabhängig von den Regeln.

---

## Praxis-Beispiele

### Temperatur im Toleranzbereich

```json
{
  "name": "messung_temperatur",
  "type": "flexiInput",
  "label": "Gemessene Temperatur",
  "rules": ["VALUE%5:sollwert_temperatur"]
}
```
> Die Messung darf um ± 5 % vom Sollwert abweichen.

### Bewertung mit Alternativen

```json
{
  "name": "bewertung",
  "type": "flexiSelect",
  "label": "Bewertung",
  "options": ["bestanden", "teilweise bestanden", "nicht bestanden"],
  "rules": [
    "VALUE==bestanden",
    "VALUE==teilweise bestanden"
  ]
}
```
> OK ist nur "bestanden" oder "teilweise bestanden".

### Freigabe mit Pflicht-Bemerkung bei "nein"

```json
{
  "name": "freigabe",
  "type": "flexiSwitch",
  "label": "Freigegeben?",
  "rules": [
    "VALUE:TRUE",
    "COMPONENT:grund.length>0"
  ]
}
```
> Entweder freigegeben oder ein Grund eingetragen → OK.

### Dynamische Tabelle mit Mengenprüfung [#dynamische-tabelle-mit-mengenprufung]

```json
{
  "name": "artikel",
  "type": "flexiDynamicTable",
  "rules": [
    "VALUE:menge>=1",
    "VALUE:menge<=1000",
    "COMPARE:rabatt<=preis"
  ]
}
```
> Jede Zeile: Menge zwischen 1 und 1000, Rabatt nicht größer als Preis.

### Tabellenzeile gegen Vorgaben aus der Section

```json
{
  "name": "messungen",
  "type": "flexiDynamicTable",
  "rules": [
    "COMPARE:ist>=@soll_min",
    "COMPARE:ist<=@soll_max"
  ]
}
```
> Jede Zeile: Der Ist-Wert in der Spalte `ist` muss zwischen den in der Section konfigurierten Feldern `soll_min` und `soll_max` liegen.

### Kombinierter Vergleich mit Konstante

```json
{
  "name": "temperatur_ist",
  "type": "flexiInput",
  "rules": [
    "COMPARE:VALUE>=(temperatur_soll-5)",
    "COMPARE:VALUE<=(temperatur_soll+5)"
  ]
}
```
> Ist-Temperatur muss innerhalb ± 5 vom Soll liegen.

---

## Gut zu wissen

### Die Reihenfolge von VALUE-Regeln in Zahlenfeldern

Bei Zahlenfeldern (Eingabe, Berechnet, Zeitspanne) gilt: Wenn mehrere `VALUE…`-Regeln hinterlegt sind, **entscheidet die letzte** über das Ergebnis. Für klare Prüfungen besser nur **eine** `VALUE`-Regel pro Feld verwenden und stattdessen `COMPARE`- oder `COMPONENT`-Regeln ergänzen.

### COMPARE-Regeln haben Priorität [#compare-regeln-haben-prioritat]

Sobald eine `COMPARE`-Regel in einem Zahlenfeld oder einer Tabellenzeile definiert ist, bestimmt sie das Ergebnis. Bestehen alle COMPARE-Regeln, gilt das Feld als OK - auch wenn eine vorherige `VALUE`-Regel fehlgeschlagen wäre. Umgekehrt genügt eine einzige fehlgeschlagene COMPARE, um das Feld auf Fehler zu setzen.

### `VALUE>n` ist nicht überall strikt [#valuen-ist-nicht-uberall-strikt]

Bei Zahlenfeldern und Auswahlfeldern verhält sich `VALUE>100` wie `VALUE>=100` (*Mindestwert* statt *echt größer als*). Das ist historisch bedingt und bleibt so, damit vorhandene Templates nicht plötzlich anders reagieren.

Wer einen **echt strikten** Vergleich `> n` braucht:

- **Zahlenfeld / Auswahl**: `COMPARE:VALUE>n` - innerhalb von `COMPARE` ist `>` strikt.
- **Tabellenzeile**: `VALUE:spalte>n` - in der dynamischen Tabelle ist `>` bereits strikt.

Ein klarer Mindestwert sollte mit `VALUE>=n` geschrieben werden - dann ist die Absicht auf einen Blick erkennbar.

### Alternativen mit COMPONENT

`COMPONENT:feld.length>0` ist der Standard-Weg, um eine Bemerkung oder ein anderes ergänzendes Feld als gültige Alternative zu einer fehlgeschlagenen Messung zu akzeptieren. So lassen sich typische Workflows abbilden: "Messung im Rahmen **oder** Bemerkung vorhanden".

### Groß-/Kleinschreibung bei Schaltern [#gro-kleinschreibung-bei-schaltern]

Die Schreibweise `VALUE:TRUE` und `VALUE:FALSE` muss **genau** so (Großbuchstaben) eingehalten werden. Abweichungen wie `VALUE:true` werden stillschweigend ignoriert.

### Leere Felder sind keine Fehler

Ein leeres Feld zeigt den Zustand ⚪ **Leer** an - und blockiert die Dokumentfreigabe **nicht**. Soll ein Feld zwingend ausgefüllt werden, ist es im Template als Pflichtfeld zu kennzeichnen; dann erscheint die Fehler-Markierung wie gewohnt.

### Referenzfelder in Prozent-Regeln

Wenn das Referenzfeld in einer `VALUE%…`-Regel leer ist, wird die Regel übersprungen und das Feld als **Leer** markiert. Das verhindert Fehlalarme, solange die Referenz nicht eingetragen ist.

### Dynamische Tabelle ohne Regeln

Eine Tabelle ohne Regeln gilt als gültig, solange alle Pflichtfelder ausgefüllt sind. Sobald eine Zeile Daten enthält, aber die Tabelle keine Regeln definiert, wird die Zeile mit ⚫ **Keine Regel** markiert und die Tabelle ist **nicht** freigabefähig. Soll so eine Tabelle ohne Prüfung auskommen, sollten keine Regeln und keine Pflichtfelder definiert werden.
