Appearance
Neue Sektion hinzufügen
Diese Seite beschreibt die Implementierungs-Touchpoints, die beim Hinzufügen einer neuen persistierten Protokollsektion normalerweise notwendig sind.
Sie bildet die aktuelle Architektur in formtest ab. Der Generator nimmt die mechanischen Basisschritte ab, ersetzt aber nicht die fachliche Prüfung von Server-Vertrag, PDF-Ausgabe, Protokoll leeren und Tests.
Für die konzeptionelle Einordnung der Section-Registry, Wrapper und Form-Composables siehe auch /section-architecture.
Neue Sektion via Generator
Für normale persistierte Sektionen ist der Generator der bevorzugte Einstieg. Er erstellt das technische Grundgerüst und verdrahtet die wiederkehrenden Stellen, die sonst leicht vergessen werden.
bash
bun run generate:section --name=<entity> --type=table --component --accordion --i18nDer Generator kann interaktiv laufen, wenn Flags fehlen. Dann fragt er fehlende Werte wie Typ, Component, Accordion, i18n, Section-Key, Icon und Label im Terminal ab. Für Reviews und wiederholbare Änderungen ist ein ausgeschriebener Command trotzdem besser, weil die Absicht direkt sichtbar ist.
Der Generator passt besonders gut, wenn die Section eine eigene persistierte Entity bekommt, über den normalen Store-/Dexie-Flow läuft und als Standard-Accordion-Section sichtbar werden soll. Wenn die Section eigene Sync-Regeln, Bildlogik, Spezialvalidierung, Setup-Editoren oder komplexe PDF-Regeln braucht, starte trotzdem mit dem Generator, aber plane danach die manuelle fachliche Verdrahtung ein.
| Weg | Was passiert? | Wann passt das? |
|---|---|---|
| Generator | Erstellt das technische Grundgerüst und verdrahtet die wiederkehrenden Registries. | Standard-Sektion mit Persistenz, Store, Accordion-Anbindung und einfacher Start-Komponente. |
| Manuell | Jede Datei wird bewusst selbst angelegt oder erweitert. | Sonderfälle, bestehende Stores, komplexe Fachlogik, spezielle Bild-/PDF-Regeln oder wenn der Generator bewusst nicht genutzt werden soll. |
Eingaben für den Generator
| Eingabe | Pflicht? | Bedeutung | Werte/Beispiele | Command |
|---|---|---|---|---|
| Entity-Name | ja | Technischer Basisname der Section. Daraus entstehen Schema, Store-ID, Dexie-Tabelle und Standardnamen. | damage | --name damage |
| UI-Typ | empfohlen | Grundmuster der Form. Bestimmt, welches Component-Grundgerüst erzeugt wird. | table, singleton, setup-driven | --type table |
| Form-Komponente erzeugen? | empfohlen | Legt eine Vue-Komponente unter app/components/<Section>/ an. Ohne Komponente entstehen nur Persistenz-/Registry-Teile. | ja/nein | --component oder --no-component |
| Im Accordion sichtbar? | empfohlen | Verdrahtet Descriptor, Runtime und Component-Mapping, damit die Section in der Protokollansicht auftauchen kann. | ja/nein | --accordion oder --no-accordion |
| i18n-Grundtexte erzeugen? | empfohlen | Ergänzt deutsche Basistexte in i18n/locales/de.json. | ja/nein | --i18n oder --no-i18n |
| sichtbarer Section-Key | nur bei Abweichung | Key, den Setup, Accordion, URL und PDF verwenden. Nur setzen, wenn er nicht dem Entity-Namen entspricht. | schaeden | --section-key schaeden |
| Server-Endpunkt | nur bei Abweichung | API-Pfad zum Laden und Speichern der Section. Nur setzen, wenn die automatische Ableitung nicht passt. | /damages | --server-endpoint /damages |
| Label-Key | nur bei Abweichung | i18n-Key für den Section-Titel. | damage.title | --label-key damage.title |
| i18n-Domain | nur bei Abweichung | Objektname im deutschen Locale-File. | damage | --i18n-domain damage |
| Komponentenordner | nur bei Abweichung | Ordnername unter app/components/. | Damage | --component-dir Damage |
| Komponentenname | nur bei Abweichung | Basisname der erzeugten Vue-Komponente. | Damage | --component-name Damage |
| Icon | sinnvoll bei sichtbarer Section | Icon für Accordion, Fallback-Section und Empty-State. | i-heroicons-exclamation-triangle | --icon i-heroicons-exclamation-triangle |
Unterschiede der UI-Typen
| UI-Typ | Wann verwenden? | Typischer Store-Inhalt | Typisches UI |
|---|---|---|---|
table | Wenn eine Section mehrere gleichartige Einträge hat, zum Beispiel Schäden, Zähler oder Anlagen. | Viele Datensätze pro Protokoll. | CollectionSection mit Tabellenzeilen, Add-Button und Löschen pro Zeile. |
singleton | Wenn es pro Protokoll genau einen fachlichen Datensatz gibt, zum Beispiel eine einzelne Bewertung oder ein einzelner Textblock. | Ein aktiver Datensatz pro Protokoll. | SectionWrapper mit Formularfeldern, ohne klassische Tabellenliste. |
setup-driven | Wenn Felder, Optionen oder Sichtbarkeit stark aus /setup kommen. | Persistierte Daten plus Setup-Konfiguration. | Komponente liest Setup-Daten über useSetupStore() und baut daraus die Eingabe. |
Daraus entsteht zum Beispiel:
bash
bun run generate:section --name damage --type table --component --accordion --i18n --section-key schaeden --server-endpoint /damages --label-key damage.title --i18n-domain damage --component-dir Damage --component-name Damage --icon i-heroicons-exclamation-triangleWenn ein Feld der Standardableitung entspricht, kann die Flag weggelassen werden. Für Reviews ist ein vollständig ausgeschriebener Command trotzdem oft besser, weil er die Absicht eindeutig zeigt.
Kurzreferenz der Flags:
--name=<entity>: fachlicher Entity-Name; wird zu camelCase/PascalCase normalisiert--type=table|singleton|setup-driven: UI-Grundmuster der Sektion.tableist für mehrere Zeilen,singletonfür genau einen Datensatz,setup-drivenfür setupgesteuerte Sektionen.--componentoder--no-component: ob eine Form-Komponente erzeugt wird--accordionoder--no-accordion: obsectionDescriptors.ts,sectionRuntime.tsundsectionComponents.tsverdrahtet werden--i18noder--no-i18n: ob deutsche Grundtexte ini18n/locales/de.jsonergänzt werden--section-key=<key>: kanonischer Section-Key, falls er vom Entity-Namen abweicht--server-endpoint=/pfad: Endpoint, falls die automatische Pluralisierung nicht passt--component-dir=<name>: Komponentenordner, falls der PascalCase-Standardname nicht passt--component-name=<name>: Komponentenname, falls er vom Ordnernamen abweichen soll--label-key=<key>: i18n-Key für den sichtbaren Section-Titel--i18n-domain=<key>: i18n-Objekt, in dem die Grundtexte erzeugt werden--icon=<icon>: Icon für sichtbare Sections, Fallback-Sections und Empty-States
Das Script erzeugt bzw. aktualisiert Schema, Entity-Registry, Store, Standard-Store-Registry, Dexie-Version, optionale Komponente, Section-Descriptor, Runtime-Registry, Komponenten-Mapping und i18n-Grundgerüst. Danach müssen Server-/Mock-Server-Vertrag, PDF-Ausgabe, spezielle Validierung, Setup-Wiring und fachliche UI-Logik weiterhin geprüft werden.
Generierte Form-Komponenten zeigen im Dev-Modus bewusst eine Warnung:
Diese generierte Sektion ist nur ein technisches Grundgerüst. Nächste Schritte: 1. Server-Endpunkt in
app/utils/sectionRuntime.tsprüfen und im Mock-ServerW:/Protocol_App/protocols-mock-srvumsetzen. 2. Felder inapp/schemas/<entity>.tsundapp/components/<Section>/<Section>Form.vuefachlich ersetzen. 3. Falls die Section ins PDF gehört: Generator inapp/utils/pdf/sections/anlegen, inapp/utils/pdf/section-generators.tsregistrieren und Daten inapp/utils/pdf/section-data.tsergänzen. 4. Speichern, Löschen undProtokoll leerenmanuell prüfen. 5. passende Tests untertest/unitodertest/nuxtergänzen.
Die Warnung darf erst entfernt werden, wenn diese Punkte erledigt oder bewusst als nicht zutreffend dokumentiert wurden.
Zum Entfernen eines generierten Grundgerüsts gibt es:
bash
bun run remove:section --name=<entity>Wenn beim Anlegen abweichende Optionen wie --section-key, --component-dir, --component-name, --label-key oder --i18n-domain verwendet wurden, müssen dieselben Werte auch beim Entfernen angegeben werden.
Typische Touchpoints
Wenn eine neue persistierte Sektion hinzukommt, braucht die Codebasis normalerweise Änderungen in diesen Bereichen:
app/schemas/<entity>.tsapp/schemas/entities.tsapp/stores/entityStores.tsoder ein spezialisierter Store unterapp/stores/<entity>.ts- optional
app/stores/<entity>.tsals expliziter Wrapper-Exportpfad fuer Standard-Stores app/stores/registry.ts, falls die Sektion nicht ueber die Standard-Store-Registry laeuftapp/db/index.tsapp/utils/sectionDescriptors.tsapp/utils/sectionRuntime.tsapp/utils/sectionComponents.tsapp/utils/pdf/section-data.tsapp/utils/pdf/section-generators.tsi18n/locales/de.json
Je nach Sektion kann zusätzlich Setup-/Config-Wiring in app/schemas/setup.ts, in Setup-Editoren und im /setup-Handling nötig sein. Wenn die Sektion Verantwortlichkeiten verwenden soll, folgt sie dem Scope-Vertrag aus /responsibility-scopes.
Neue Sektion manuell anlegen
Der manuelle Weg ist für Sektionen gedacht, die nicht sauber in das Generator-Grundmuster passen. Typische Gründe sind setup-getriebene Felder, eigene Store-Logik, Sondervalidierung, Bildlogik oder eine PDF-Ausgabe mit Fachregeln. Der Ablauf ist trotzdem immer derselbe: erst den Vertrag festlegen, dann Persistenz und Store, danach UI, Server, PDF und Tests.
Die Beispiele verwenden durchgehend eine fiktive Section damage. Sie zeigen alle nötigen Imports. Wenn du ein Beispiel in eine bestehende Datei einfügst, übernimm nur die Imports, die dort noch fehlen.
1. Erst den Vertrag festlegen
Bevor du Dateien anlegst, lege die technischen Namen fest. Das spart später Umbauten in Aliassen, Store-IDs und Endpunkten.
| Entscheidung | Beispiel | Bedeutung |
|---|---|---|
| Entity-/Store-Key | damage | Persistenz-Key, Store-ID und Dexie-Tabelle |
| Descriptor-ID | damage | interner Key in Descriptor, Runtime, Component und PDF-Mapping |
| sichtbarer Section-Key | schaeden | Key aus Setup, Accordion, URL und PDF |
| Aliase | ['damage'] | Zusätzliche Keys, die dieselbe Section meinen. Nötig, wenn Setup/PDF den sichtbaren Key schaeden verwenden, Store/Entity oder Backend aber weiterhin damage liefern. |
| Server-Endpunkt | /damages | Lade-/Speicher-Endpunkt der Section |
| i18n-Domain | damage | Textblock in i18n/locales/de.json |
| UI-Muster | table | Formaufbau: Tabelle, Singleton oder setup-getrieben |
Wenn der Server bereits einen Section-Key liefert, verwende diesen als sichtbaren key. Wenn Entity-Name und sichtbarer Key unterschiedlich sind, löse das über aliases, nicht über doppelte Einträge in Consumer-Dateien.
aliases sind nur alternative Eingangsnamen für dieselbe fachliche Section. Sie erzeugen keine zweite Section, keinen zweiten Store, keinen zweiten Endpoint und keinen zweiten PDF-Block. Typische Fälle sind: der Store heißt technisch damage, das Setup liefert aber schaeden; ein Backend-Payload verwendet noch einen alten Key; oder bestehende lokale Daten enthalten einen früheren Namen. Der kanonische sichtbare Name bleibt immer key.
2. Persistenz anlegen
Persistenz besteht aus drei Schritten: eigenes Schema, Registrierung in ENTITIES, dann Dexie-Version erhöhen.
Lege zuerst app/schemas/damage.ts an:
ts
import * as v from 'valibot'
import { BaseEntitySchema, DBEntitySchema, defineEntity } from './core'
export const DamageSchema = v.object({
...BaseEntitySchema.entries,
name: v.pipe(v.string(), v.minLength(0)),
description: v.pipe(v.string(), v.minLength(0)),
})
export const DamageDBSchema = v.object({
...DamageSchema.entries,
...DBEntitySchema.entries,
})
export type IDamage = v.InferOutput<typeof DamageSchema>
export const DamageEntity = defineEntity({
name: 'damage',
schema: DamageSchema,
createEmpty: (): IDamage => {
const now = new Date().toISOString()
return {
id: crypto.randomUUID(),
clientCreatedAt: now,
clientUpdatedAt: now,
name: '',
description: '',
}
},
})Der name in defineEntity(...) ist der Entity-/Store-Key. Er muss zu Store-ID, Dexie-Tabelle und Registry passen.
Registriere die Entity danach in app/schemas/entities.ts:
ts
import { DamageEntity } from './damage'
export * from './damage'
export const ENTITIES = {
// ...
damage: DamageEntity,
} as constWenn eine neue persistierte Entity in ENTITIES hinzukommt, erhöhe in app/db/index.ts die Dexie-Version:
ts
import { buildStoresFromConfig } from '@/schemas/entities'
this.version(31).stores({
acceptances: 'id',
...buildStoresFromConfig(),
// ...
})Keine Versionserhöhung ist nötig, wenn du nur UI, Labels, PDF-Ausgabe oder eine nicht persistierte Ansicht ergänzt.
3. Store anbinden
Starte immer mit der Frage: Reicht ein Standard-Store? Für einfache Collection- oder Singleton-Sektionen ist die Antwort meistens ja. Ein Standard-Store kann Einträge anlegen, Felder aktualisieren, löschen, laden, speichern und Dirty-State verwalten.
Für Standard-Stores ergänze app/stores/entityStores.ts:
ts
import { DamageEntity } from '@/schemas/damage'
import { getSectionStoreDexieOptions } from '@/utils/sectionRuntime'
const STANDARD_ENTITY_STORE_DEFINITIONS = {
// ...
damage: {
createEmpty: DamageEntity.createEmpty!,
...getSectionStoreDexieOptions('damage'),
},
} as const
export const STANDARD_ENTITY_STORE_REGISTRY = {
// ...
damage: createStandardEntityStore('damage', STANDARD_ENTITY_STORE_DEFINITIONS.damage),
} as constgetSectionStoreDexieOptions(...) kommt immer aus @/utils/sectionRuntime. Wenn dieser Import in entityStores.ts schon vorhanden ist, füge nur die neue Entity hinzu. createStandardEntityStore(...) ist ein lokaler Helper in entityStores.ts; dafür gibt es keinen Import.
Lege zusätzlich den expliziten Store-Export app/stores/damage.ts an:
ts
import { STANDARD_ENTITY_STORE_REGISTRY } from './entityStores'
export const useDamageStore = STANDARD_ENTITY_STORE_REGISTRY.damageEin Spezialstore ist erst nötig, wenn der Store mehr leisten muss als generisches CRUD. Beispiele: eigene computed values, gruppierte Einträge, addEmpty() mit Setup-Daten, gemeinsame Feldupdates, eigenes Reset-Verhalten, isSectionInvalid oder ein Spezialvertrag beim Sync. Andere Spalten, Labels oder einfache Felder sind noch kein Spezialstore; das gehört in Schema, Component oder PDF.
Für Spezialstores sieht das Grundmuster so aus:
ts
import { acceptHMRUpdate, defineStore } from 'pinia'
import { DamageEntity } from '@/schemas/entities'
import { getSectionStoreDexieOptions } from '@/utils/sectionRuntime'
import { createBaseStoreSetup } from '@/utils/storeFactory'
export const useDamageStore = defineStore(
'damage',
() => {
const base = createBaseStoreSetup('damage', {
createEmpty: DamageEntity.createEmpty!,
})
return {
...base,
// eigene computed values/actions hier ergänzen
}
},
{
dexie: {
...getSectionStoreDexieOptions('damage'),
autoHardDelete: true,
},
},
)
if (import.meta.hot) {
import.meta.hot.accept(acceptHMRUpdate(useDamageStore, import.meta.hot))
}Spezialstores müssen zusätzlich direkt in app/stores/registry.ts stehen. Standard-Stores sind über STANDARD_ENTITY_STORE_REGISTRY bereits für getStoreInstances() sichtbar. Diese Sichtbarkeit ist wichtig für Acceptance-Hydration, IndexedDB-Fallback, Dirty-State, Speichern, Protokoll leeren und PDF-Datenaufbau.
4. Section sichtbar machen
Damit die Section im Editor auftaucht, braucht sie drei Metadaten-Einträge: Descriptor, Runtime und Component. useMainAccordionSections.ts baut daraus die sichtbare Accordion-/Sidebar-Registry. Neue Standardsektionen werden dort nicht mehr direkt eingetragen.
Ergänze zuerst app/utils/sectionDescriptors.ts:
ts
damage: {
key: 'schaeden',
aliases: ['damage'],
defaultLabelKey: 'damage.title',
},key ist der sichtbare Setup-/Accordion-/PDF-Key. aliases nehmen zusätzliche Namen auf, unter denen dieselbe Section erkannt werden soll. Im Beispiel ist schaeden der sichtbare Section-Key, während damage als Entity-/Store- oder Backend-Key weiterhin auf dieselbe Section zeigt. defaultLabelKey muss in i18n/locales/de.json existieren.
Ergänze danach app/utils/sectionRuntime.ts:
ts
damage: {
icon: 'i-heroicons-exclamation-triangle',
store: {
storeId: 'damage',
serverEndpoint: '/damages',
loadText: 'damage.title',
},
},Ergänze zuletzt app/utils/sectionComponents.ts:
ts
import type { Component } from 'vue'
import type { SectionDescriptorId } from '@/utils/sectionDescriptors'
import DamageForm from '@/components/Damage/DamageForm.vue'
export const SECTION_COMPONENTS = {
// ...
damage: DamageForm,
} satisfies Record<SectionDescriptorId, Component>Wenn der Server die Section noch nicht im Setup liefert, wird sie als Fallback-Section angezeigt. Wenn der Server sie mit isActive: false liefert, bleibt sie bewusst ausgeblendet.
5. Form-Komponente bauen
Die Form-Komponente ist nur für UI und Store-Aufrufe zuständig. Sie schreibt nicht direkt in Dexie und ruft keine APIs direkt auf.
Für Tabellen-Sektionen ist CollectionSection.vue der Standard. Ein minimales Beispiel mit allen Imports:
vue
<script setup lang="ts">
import type { IDamage } from '@/schemas/damage'
import type { TableColumn } from '@nuxt/ui'
import { computed } from 'vue'
import { useI18n } from 'vue-i18n'
import CollectionSection from '@/components/Section/CollectionSection.vue'
import { useDamageStore } from '@/stores/damage'
import { entityActionsColumn, textColumn } from '@/utils/sectionTableColumns'
const { t } = useI18n()
const damageStore = useDamageStore()
const columns = computed<TableColumn<IDamage>[]>(() => [
textColumn<IDamage, 'name'>('name', t('damage.columns.name'), {
update: damageStore.updateFieldByKey,
placeholder: t('damage.placeholders.name'),
}),
entityActionsColumn<IDamage>((entry) => ({
deleteTitle: t('damage.deleteConfirm'),
onDelete: () => damageStore.remove(entry.id),
})),
])
</script>
<template>
<CollectionSection
:store="damageStore"
:data="damageStore.activeEntries"
:columns="columns"
:empty-title="t('damage.emptyTitle')"
:empty-description="t('damage.emptyDescription')"
:add-label="t('damage.add')"
empty-icon="i-heroicons-exclamation-triangle"
by="id"
@add="damageStore.addEmpty()"
/>
</template>Für Singleton-Sektionen nimm useSingletonSection(store) zusammen mit SectionWrapper.vue. Für setup-getriebene Sektionen kommt die Konfiguration aus useSetupStore(); lege dafür keine zweite Setup-Ladelogik an.
6. Texte ergänzen
Alle sichtbaren Texte gehören in i18n/locales/de.json. Keine Inline-Fallbacktexte in Komponenten verwenden.
json
"damage": {
"title": "Schäden",
"add": "Schaden hinzufügen",
"deleteConfirm": "Schaden löschen?",
"emptyTitle": "Keine Schäden vorhanden",
"emptyDescription": "Dokumentieren Sie Schäden für dieses Protokoll.",
"columns": {
"name": "Bezeichnung",
"description": "Beschreibung"
},
"placeholders": {
"name": "Bezeichnung eingeben",
"description": "Beschreibung eingeben"
}
}7. Server und Mock-Server umsetzen
Wenn die Section persistiert und synchronisiert wird, muss auch W:\Protocol_App\protocols-mock-srv den Vertrag kennen. Für Collection-Endpunkte sind normalerweise diese Pfade nötig:
GET /damages?acceptanceId=<id>POST /damages?acceptanceId=<id>
Die Antwort sollte success, data und bei Hard-Deletes optional deletedIds enthalten. deletedAt-Tombstones müssen serverseitig vorhandene Einträge löschen. Aktive Einträge werden je nach Endpoint-Vertrag upserted oder ersetzen den Serverstand.
Ein 404 auf einem neuen Section-Endpunkt darf die Acceptance-Seite nicht als fehlend behandeln. Der Client fällt dafür auf lokale Section-Daten zurück. Trotzdem ist der Endpunkt vor fachlicher Freigabe Pflicht, sonst sind Laden und Speichern nicht vollständig.
8. Clear- und Save-Verhalten prüfen
Neue persistierte Sektionen müssen mit Aktionen -> Protokoll leeren zusammenspielen. Der Clear-Flow löscht nicht sofort serverseitig, sondern erzeugt lokal einen Löschentwurf:
- bestehende Server-Einträge werden im Store mit
deletedAtmarkiert - rein lokale, noch nicht gespeicherte Einträge werden entfernt
- Bilder werden lokal ausgeblendet und erst beim manuellen Speichern als Pending-Deletes verarbeitet
- Auto-Save wird für diesen Zustand übersprungen
Auf Server speichernöffnet ein Entscheidungsmodal; erst dessen Bestätigung schreibt den aktuellen lokalen Stand nach dem Leeren auf den ServerZurücknehmenbeziehungsweiseAbbrechenverwirft den lokalen Löschentwurf und stellt den Stand von vor dem Leeren wieder her
Der Server-Endpunkt muss deletedAt-Tombstones akzeptieren. Wenn der Client autoHardDelete nutzt, sollte der Server gelöschte IDs in deletedIds zurückgeben.
9. PDF ergänzen, falls die Section ausgegeben werden soll
Wenn die Section ins PDF gehört, ergänze zuerst einen Generator unter app/utils/pdf/sections/<entity>.ts:
ts
import type { Content } from 'pdfmake/interfaces'
import type { SectionGenerator } from '@/utils/pdf/types'
export const damageGenerator: SectionGenerator = (data, section, createHeader) => {
const damages = data.damages ?? []
if (damages.length === 0) return []
const content: Content[] = [createHeader(section.label)]
content.push({
ul: damages.map((damage) => damage.name || '-'),
margin: [0, 0, 0, 8],
})
return content
}Registriere ihn danach in app/utils/pdf/section-generators.ts:
ts
import { damageGenerator } from './sections/damage'
export const SECTION_PDF_GENERATORS = {
// ...
damage: damageGenerator,
}Wenn neue Daten gebraucht werden, erweitere SectionData in app/utils/pdf/types.ts und befülle sie zentral in app/utils/pdf/section-data.ts. pdfTextTop und pdfTextBottom nicht im Generator rendern; das macht app/utils/pdf/section-registry.ts.
Wenn die Section Bildanhänge hat, verwende buildPdfImagesForEntries(...) aus app/utils/pdf/singlePageImages.ts für normale Tabellenbilder und pdfSinglePage.
10. Tests und manuelle Prüfung
Wähle die kleinste sinnvolle Testebene:
- Metadaten/Reihenfolge:
test/unit/sections - Store- oder Sync-Sonderlogik:
test/unit/stores - Nuxt-, Component- oder IndexedDB-Verhalten:
test/nuxt - echte Editor-Flows nur bei Bedarf als E2E
Prüfe manuell mindestens:
- Section ist im Accordion oder in der Sidebar sichtbar
- Section bleibt sichtbar, wenn sie nur lokal als Fallback existiert
- Speichern lädt keinen 404-Redirect auf
/history Protokoll leeren -> Auf Server speichern -> Modal bestätigenlöscht ServerdatenProtokoll leeren -> Zurücknehmenlädt Serverdaten zurück- Offline-Fallback lädt lokale Daten
- PDF enthält die Section oder die Nicht-PDF-Entscheidung ist dokumentiert
Nach dem Generator: Mindestprüfung
Nach generate:section ist die Sektion erst dann vollständig, wenn diese Punkte bewusst erledigt oder als nicht zutreffend markiert wurden:
- Server-Endpoint im Client passt zu
W:\Protocol_App\protocols-mock-srv - Mock-Server kann aktive Einträge speichern und
deletedAt-Tombstones löschen Protokoll leeren -> Auf Server speichern -> Modal bestätigenlöscht die Sektion serverseitigProtokoll leeren -> Zurücknehmenlädt den aktuellen Serverstand wieder- Store ist in
STORE_REGISTRYoder überSTANDARD_ENTITY_STORE_REGISTRYsichtbar - PDF-Ausgabe ist ergänzt oder bewusst nicht vorgesehen
- deutsche i18n-Keys sind vollständig
- Dexie-Version ist erhöht
- sinnvoller Regressionstest ist ergänzt oder als späterer Task benannt