264 lines
15 KiB
Markdown
264 lines
15 KiB
Markdown
# Austauschformat für Vorlagen
|
|
|
|
Eine Vorlage lässt sich als JSON-Datei exportieren und wieder einspielen. Diese Datei beschreibt
|
|
das Format — für jemanden, der eine Vorlage von Hand schreiben oder ein Skript dafür bauen will.
|
|
|
|
Die Prüfung liegt in [`src/lib/vorlagen-format.ts`](../src/lib/vorlagen-format.ts), Export und
|
|
Import in [`src/server/services/vorlagen-austausch.ts`](../src/server/services/vorlagen-austausch.ts).
|
|
Beide benutzen dasselbe Schema: was hier steht, gilt für den Export, den Import und den Editor.
|
|
|
|
## Wozu das Format da ist
|
|
|
|
Eine exportierte Vorlage soll sich in eine **andere** Laufzettel-Installation einspielen lassen.
|
|
Deshalb enthält das Dokument nur das, was eine Vorlage inhaltlich ausmacht: Kopfdaten, Variablen,
|
|
Abschnitte, Schritte. Alles, was nur in der Quellinstallation eine Bedeutung hat, bleibt draußen.
|
|
|
|
**Nicht im Dokument enthalten:**
|
|
|
|
- **Kennungen** (`id`, `versionId`, `abschnittId`) — sie zeigen in der Zielinstallation ins Leere
|
|
- **Zeitstempel** (`erstelltAm`, `geaendertAm`, `veroeffentlichtAm`) und der veröffentlichende
|
|
Benutzer
|
|
- **Kundenbezug** (`kundeId`) — eine eingespielte Vorlage gilt zunächst für alle Kunden; wer sie
|
|
einem Kunden zuordnen will, tut das danach in der Oberfläche
|
|
- **`position`** — die Reihenfolge steckt in der Reihenfolge der Listen. Zwei Wahrheiten über
|
|
dieselbe Reihenfolge laufen früher oder später auseinander.
|
|
- **Läufe**, Schrittergebnisse, Kommentare und das Protokoll — das ist Betriebsgeschehen, keine
|
|
Vorlage
|
|
- der Status der Version und das Archiv-Kennzeichen
|
|
|
|
## Beispiel
|
|
|
|
Das folgende Dokument ist vollständig: zwei Abschnitte, zwei Variablen und ein `BEFEHL`-Schritt mit
|
|
Platzhaltern. **JSON kennt keine Kommentare** — die Zeilen mit `//` müssen vor dem Import raus.
|
|
|
|
```jsonc
|
|
{
|
|
// Fassung des Austauschformats, derzeit immer 1.
|
|
"format": 1,
|
|
"name": "Onboarding Notebook",
|
|
"beschreibung": "Neue Person, neues Gerät.",
|
|
"kategorie": "Onboarding",
|
|
"schlagworte": ["notebook", "eintritt"],
|
|
// Nur zur Information: welche Version der Quelle exportiert wurde. Beim
|
|
// Import wird der Wert gelesen und nicht übernommen.
|
|
"version": 3,
|
|
"struktur": {
|
|
// Wird beim Start eines Laufs abgefragt und füllt die Platzhalter.
|
|
"variablen": [
|
|
{ "schluessel": "vorname", "beschriftung": "Vorname", "typ": "TEXT", "pflicht": true },
|
|
{
|
|
"schluessel": "abteilung",
|
|
"beschriftung": "Abteilung",
|
|
"typ": "AUSWAHL",
|
|
"optionen": ["IT", "Vertrieb", "Buchhaltung"]
|
|
}
|
|
],
|
|
// Die Reihenfolge dieser Liste ist die Reihenfolge in der Ansicht.
|
|
"abschnitte": [
|
|
{
|
|
"titel": "Vorbereitung",
|
|
"schritte": [
|
|
{ "titel": "Gerät auspacken", "pflicht": true },
|
|
{
|
|
"titel": "Seriennummer erfassen",
|
|
"hilfetext": "Aufkleber auf der Unterseite. **Nicht** die Artikelnummer.",
|
|
"typ": "TEXT",
|
|
"pflicht": true,
|
|
"konfig": { "mehrzeilig": false },
|
|
"dokuUrl": "https://intern.example/seriennummern"
|
|
},
|
|
{
|
|
"titel": "Arbeitsspeicher prüfen",
|
|
"typ": "ZAHL",
|
|
"konfig": { "min": 8, "max": 64, "einheit": "GB" }
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"titel": "Konto",
|
|
"schritte": [
|
|
{
|
|
"titel": "Benutzerkonto anlegen",
|
|
"typ": "BEFEHL",
|
|
"pflicht": true,
|
|
// Die Platzhalter werden erst beim Abarbeiten ersetzt; hier stehen
|
|
// sie wörtlich.
|
|
"konfig": {
|
|
"shell": "powershell",
|
|
"befehl": "New-ADUser -Name \"{{vorname}}\" -Department \"{{abteilung}}\""
|
|
}
|
|
},
|
|
{ "titel": "Eintrittsdatum hinterlegen", "typ": "DATUM" }
|
|
]
|
|
}
|
|
]
|
|
}
|
|
}
|
|
```
|
|
|
|
## Felder
|
|
|
|
### Kopf
|
|
|
|
| Feld | Pflicht | Bedeutung |
|
|
| -------------- | -------- | ------------------------------------------------------------------------------- |
|
|
| `format` | Pflicht | Fassung des Austauschformats. Derzeit `1`; ein anderer Wert wird abgewiesen. |
|
|
| `name` | Pflicht | Name der Vorlage, nicht leer. Namen sind **nicht** eindeutig. |
|
|
| `seedSchluessel` | optional | **Nur für mitgelieferte Vorlagen.** Siehe unten — beim Import verfällt das Feld. |
|
|
| `beschreibung` | optional | Ein bis zwei Sätze, was die Vorlage abdeckt. |
|
|
| `kategorie` | optional | Freitext, gruppiert die Vorlagenliste (etwa `Onboarding`). |
|
|
| `schlagworte` | optional | Liste nicht leerer Texte; Standard `[]`. |
|
|
| `version` | optional | Versionsnummer der exportierten Quelle. Reine Information, siehe unten. |
|
|
| `struktur` | Pflicht | Objekt mit `variablen` und `abschnitte`. |
|
|
|
|
### `struktur`
|
|
|
|
| Feld | Pflicht | Bedeutung |
|
|
| ------------ | -------- | ---------------------------------------------------------- |
|
|
| `variablen` | optional | Liste von Variablen in Abfragereihenfolge; Standard `[]`. |
|
|
| `abschnitte` | optional | Liste von Abschnitten in Anzeigereihenfolge; Standard `[]`. |
|
|
|
|
### Variable
|
|
|
|
| Feld | Pflicht | Bedeutung |
|
|
| -------------- | -------- | ------------------------------------------------------------------------- |
|
|
| `schluessel` | Pflicht | Der Name im Platzhalter `{{schluessel}}`. Regeln siehe unten. |
|
|
| `beschriftung` | Pflicht | Was im Startformular über dem Feld steht, nicht leer. |
|
|
| `typ` | optional | `TEXT`, `ZAHL`, `AUSWAHL` oder `DATUM`; Standard `TEXT`. |
|
|
| `optionen` | optional | Nur bei `AUSWAHL`: die Auswahlwerte in Anzeigereihenfolge; Standard `[]`. |
|
|
| `pflicht` | optional | `true` verlangt eine Eingabe beim Start; Standard `false`. |
|
|
|
|
Ein Schlüssel darf in einem Dokument nur **einmal** vorkommen. Ein zweiter Eintrag mit demselben
|
|
Schlüssel ist ein Fehler und kein stilles Überschreiben — sonst verschwände eine Variable, ohne
|
|
dass es jemand merkt.
|
|
|
|
### Abschnitt
|
|
|
|
| Feld | Pflicht | Bedeutung |
|
|
| ---------- | -------- | ----------------------------------------------------------------------------- |
|
|
| `titel` | Pflicht | Überschrift, nicht leer und **ohne** Nummer — siehe unten. |
|
|
| `schritte` | optional | Liste von Schritten in Abarbeitungsreihenfolge; Standard `[]`. |
|
|
|
|
Abschnitte werden überall mit einer zweistelligen Nummer angezeigt (`01 · Vorbereitung`). Diese
|
|
Nummer wird **aus der Position abgeleitet und nie gespeichert**. Stünde sie im Titel, wäre sie beim
|
|
ersten Umsortieren falsch — und niemand ginge hinterher durch und zöge sie nach. Trägt ein Titel
|
|
dennoch eine vorangestellte Nummer mit `·` als Trenner (ältere Dateien taten das), wird sie beim
|
|
Öffnen im Editor entfernt, damit nicht `01 · 01 · Vorbereitung` dasteht; mit dem nächsten Speichern
|
|
gilt der bereinigte Titel. Andere Trenner bleiben unangetastet: „2. Etage prüfen“ ist ein Titel und
|
|
keine Nummerierung.
|
|
|
|
### Schritt
|
|
|
|
| Feld | Pflicht | Bedeutung |
|
|
| ----------- | -------- | -------------------------------------------------------------------------------- |
|
|
| `titel` | Pflicht | Was zu tun ist, nicht leer. Darf Platzhalter enthalten. |
|
|
| `hilfetext` | optional | Markdown, in der Abarbeitungsansicht ausklappbar. **Kein rohes HTML.** |
|
|
| `typ` | optional | Einer der Schritt-Typen unten; Standard `HAKEN`. |
|
|
| `pflicht` | optional | Pflichtschritte müssen vor dem Abschluss erledigt oder ausdrücklich als nicht zutreffend markiert sein; Standard `false`. |
|
|
| `konfig` | optional | Typabhängige Einzelheiten; Standard `{}`. Siehe unten. |
|
|
| `dokuUrl` | optional | Link auf eine Anleitung. Muss eine gültige Adresse sein. |
|
|
|
|
## Schritt-Typen und ihre `konfig`
|
|
|
|
| Typ | Was der Techniker tut | Schlüssel in `konfig` |
|
|
| --------- | ------------------------------ | -------------------------------------------------------------- |
|
|
| `HAKEN` | abhaken | keine |
|
|
| `TEXT` | Text eintragen | `mehrzeilig` (`true`/`false`) |
|
|
| `ZAHL` | Zahl eintragen | `min`, `max` (Zahlen), `einheit` (Text, höchstens 40 Zeichen) |
|
|
| `AUSWAHL` | aus einer Liste wählen | `optionen` (Liste nicht leerer Texte, in Anzeigereihenfolge) |
|
|
| `DATUM` | Datum wählen | keine |
|
|
| `BEFEHL` | Befehl kopieren und ausführen | `shell` (`powershell`, `bash` oder `cmd`), `befehl` (Text) |
|
|
|
|
`min` und `max` sind Hinweise: ein Wert außerhalb wird markiert, nicht blockiert.
|
|
|
|
`konfig` wird **nachsichtig** geprüft. Unbekannte Schlüssel bleiben erhalten — eine Datei aus einer
|
|
späteren Fassung verliert hier nichts, auch wenn diese Fassung die Schlüssel nicht kennt. Was die
|
|
Anwendung kennt, wird geprüft: `shell` etwa akzeptiert nur die drei genannten Werte.
|
|
|
|
Ein Schlüssel, der nicht zum Typ passt, ist kein Fehler; er wird schlicht nicht beachtet. Wer den
|
|
Typ eines Schritts ändert, räumt die `konfig` also besser selbst auf.
|
|
|
|
## Platzhalter und Variablenschlüssel
|
|
|
|
Ein Variablenschlüssel muss der Form `^[a-z][a-z0-9_]{0,39}$` entsprechen: Beginn mit einem
|
|
Kleinbuchstaben, danach Kleinbuchstaben, Ziffern und Unterstrich, höchstens 40 Zeichen.
|
|
`vorname`, `ad_gruppe` und `raum2` sind in Ordnung; `Vorname`, `mit-strich`, `2te_wahl` und ein
|
|
leerer Schlüssel nicht.
|
|
|
|
Die Strenge hat einen Grund: der Schlüssel steht als `{{schluessel}}` in Titeln, Hilfetexten und
|
|
Befehlen. Ein Platzhalter wird genau mit diesem Muster wiedererkannt. Wäre `Vor-Name` erlaubt,
|
|
müsste der Suchausdruck Groß- und Kleinschreibung, Striche und Leerzeichen auseinanderhalten — und
|
|
`{{Vor-Name}}` in einem PowerShell-Befehl wäre nicht mehr von dessen eigener Syntax zu trennen.
|
|
Deshalb: ein Zeichensatz, eine Regel, keine Ausnahmen.
|
|
|
|
Geschweifte Klammern dürfen Leerzeichen enthalten (`{{ vorname }}` wird erkannt). Neben den
|
|
Variablen der Vorlage gibt es eingebaute Platzhalter — `{{generiertes_passwort}}` etwa —, die nicht
|
|
im Austauschdokument stehen und auch nirgends gespeichert werden.
|
|
|
|
## Was beim Import passiert
|
|
|
|
1. Das Dokument wird gegen das Schema geprüft. Schlägt das fehl, wird **nichts** geschrieben.
|
|
2. Es entsteht eine **neue Vorlage** — der Import schreibt nie in eine bestehende hinein.
|
|
3. Die Vorlage bekommt genau eine Version: `version = 1`, Status **`ENTWURF`**. Eine eingespielte
|
|
Vorlage wird bewusst nicht sofort veröffentlicht; der Redakteur sieht sie sich erst an,
|
|
ergänzt vielleicht etwas und veröffentlicht dann. Erst danach lässt sich ein Lauf daran starten.
|
|
4. `position` wird aus der Reihenfolge der Listen abgeleitet (0, 1, 2 …).
|
|
5. Das mitgeschickte `version`-Feld wird nicht übernommen. Eine Vorlage, die in der Quelle auf
|
|
Version 7 stand, fängt hier wieder bei 1 an — die Versionsgeschichte der Quelle wandert nicht mit.
|
|
6. Der Vorlagenname kommt so an, wie er im Dokument steht. Gibt es ihn schon, ist das kein Fehler
|
|
und es wird nichts angehängt: Vorlagennamen sind nicht eindeutig.
|
|
7. Alles geschieht in einer Transaktion. Ein Fehler auf halbem Weg hinterlässt keine halbe Vorlage.
|
|
8. Ein Protokolleintrag mit der Aktion `Vorlage importiert` hält fest, wer die Vorlage eingespielt hat.
|
|
|
|
Wird das Dokument abgewiesen, nennt die Meldung die **erste** Beanstandung samt Pfad, etwa:
|
|
|
|
```
|
|
struktur.abschnitte.1.schritte.2.titel: Ein Schritt braucht einen Titel.
|
|
```
|
|
|
|
## Wie sich das Format ändern darf
|
|
|
|
Das Feld `format` ist die Fassung des Formats, nicht die der Anwendung. Es gilt:
|
|
|
|
- **Neue optionale Felder** und neue `konfig`-Schlüssel erhöhen `format` **nicht**. Alte Dateien
|
|
bleiben gültig, und weil `konfig` nachsichtig geprüft wird, überleben neue Schlüssel auch einen
|
|
Rundlauf durch eine ältere Fassung.
|
|
- **Neue Schritt- und Variablentypen** erhöhen `format` ebenfalls nicht. Eine Fassung, die den Typ
|
|
nicht kennt, weist die Datei allerdings ab, weil der Typ eine geprüfte Aufzählung ist.
|
|
- Erst eine Änderung, die alte Dateien **unbrauchbar** macht — ein umbenanntes Pflichtfeld, eine
|
|
andere Verschachtelung —, erhöht `format` auf `2`.
|
|
- Ein unbekannter `format`-Wert wird mit einer klaren Meldung abgewiesen, nie geraten. Ein Import,
|
|
der die Hälfte versteht und die andere Hälfte still verwirft, wäre schlimmer als ein Fehlschlag.
|
|
|
|
Die Zahl steht als `FORMAT_VERSION` in `src/lib/vorlagen-format.ts` an genau einer Stelle.
|
|
|
|
## `seedSchluessel` — nur für mitgelieferte Vorlagen
|
|
|
|
Die sieben Vorlagen, die Laufzettel mitbringt, tragen in ihrer Datei ein zusätzliches Feld:
|
|
|
|
```json
|
|
{ "format": 1, "name": "PC Neuinstallation", "seedSchluessel": "pc-neuinstallation" }
|
|
```
|
|
|
|
Daran erkennt der Seed sie wieder. Vorher ging das über den **Namen** — und wer eine mitgelieferte
|
|
Vorlage umbenannte, bekam beim nächsten Seed-Lauf eine zweite, samt doppeltem Schnellstart auf der
|
|
Geräteseite (#021).
|
|
|
|
**Was der Schlüssel nicht tut:**
|
|
|
|
- Er macht eine Vorlage **nicht unveränderlich.** Umbenennen, umbauen, archivieren — alles bleibt
|
|
erlaubt. Der Seed erkennt sie danach wieder und lässt sie in Ruhe.
|
|
- Er erlaubt dem Seed **nicht**, eine bearbeitete Vorlage zu überschreiben. Gibt es die Vorlage, legt
|
|
er nichts an und ändert nichts. Das war vorher so und bleibt so.
|
|
- Er ist **keine Kennung über Installationen hinweg.** Zwei Installationen haben für dieselbe
|
|
mitgelieferte Vorlage denselben Schlüssel, aber verschiedene `id`s — der Schlüssel sagt nur
|
|
„diese Zeile stammt aus dem Seed“.
|
|
|
|
**Beim Import verfällt das Feld.** Wer eine mitgelieferte Vorlage exportiert und wieder einspielt,
|
|
bekommt eine gewöhnliche Vorlage ohne Schlüssel. Das ist Absicht: die Kopie soll nicht den Platz des
|
|
Originals einnehmen, sonst hielte der Seed sie dafür und würde das Original ein zweites Mal anlegen.
|
|
Der Export schreibt das Feld deshalb auch nicht — ein Feld, das beim Einlesen verfällt, verwirrt nur.
|
|
|
|
Eigene Vorlagen brauchen den Schlüssel nicht und sollten ihn nicht bekommen. Er ist eindeutig, wo er
|
|
gesetzt ist; eine zweite Vorlage mit demselben Schlüssel weist die Datenbank ab.
|