634 lines
41 KiB
Markdown
634 lines
41 KiB
Markdown
# Aktuelle Systemarchitektur
|
||
|
||
## Status und unterstützter Pfad
|
||
|
||
Der unterstützte Editor ist Circuit-First:
|
||
|
||
`Project → DistributionBoard → CircuitList → CircuitSection → Circuit → CircuitDeviceRow`
|
||
|
||
Ein Stromkreis ist nicht dasselbe wie eine Gerätezeile. BMK, Schutz- und Kabeldaten
|
||
gehören zum Stromkreis; Last-, Raum- und Kategoriedaten gehören zur Gerätezeile.
|
||
|
||
Die frühere Consumer-Oberfläche, ihre API, Tabellen und Upgrade-Werkzeuge sind
|
||
entfernt. Neue Funktionen bauen ausschließlich auf dem Circuit-First-Modell auf.
|
||
|
||
## Laufzeit
|
||
|
||
```text
|
||
Browser :3001
|
||
│
|
||
▼
|
||
Next.js App Router ── /api/* Rewrite ──▶ Express API :3000
|
||
│
|
||
▼
|
||
Repository / Transaktion
|
||
│
|
||
▼
|
||
data/leistungsbilanz.db (SQLite)
|
||
```
|
||
|
||
Im Docker-Entwicklungssetup laufen Frontend und API in getrennten Containern. Das
|
||
Frontend leitet `/api/*` über `API_INTERNAL_URL` an die API weiter. Die Datenbank
|
||
liegt über einen Host-Mount außerhalb des Containers.
|
||
|
||
## Wichtige Einstiegspunkte
|
||
|
||
- `src/app/projects/page.tsx` – Projektliste und globale Gerätebibliothek
|
||
- `src/app/projects/[projectId]/page.tsx` – Projektstammdaten, Verteilungen,
|
||
Räume und Projektgeräte
|
||
- `src/app/projects/[projectId]/circuit-lists/[circuitListId]/tree-edit/page.tsx`
|
||
– unterstützte Editorroute
|
||
- `src/frontend/components/circuit-tree-editor.tsx` – Editorzustand,
|
||
Befehlsausführung, Drag-and-drop und der schrittweise Historien-Cutover
|
||
- `src/frontend/components/circuit-grid-*.ts` – reine Grid-Projektion,
|
||
Zellbesitz, Einfügen und Sicherheitsregeln
|
||
- `src/frontend/utils/api.ts` – typisierte Frontend-API-Aufrufe
|
||
- `src/server/index.ts` und `src/server/routes/` – API-Komposition
|
||
- `src/domain/services/` – fachliche Command- und Synchronisierungsregeln
|
||
- `src/server/composition/` – Verdrahtung fachlicher Services mit konkreten
|
||
SQLite-Repositories
|
||
- `src/db/repositories/` – Abfragen, Persistenzmapper und Transaktionsadapter
|
||
- `src/db/schema/` und `src/db/migrations/` – SQLite-Schema und Migrationen
|
||
|
||
## Daten- und Befehlsfluss
|
||
|
||
1. Das Grid projiziert den geladenen Circuit-Tree in sichtbare Zeilen.
|
||
2. Eine Benutzeraktion wird im Frontend validiert und als API-Befehl gesendet.
|
||
3. Controller validieren Requestdaten mit Zod.
|
||
4. Domain-Services prüfen fachliche Regeln wie BMK-Eindeutigkeit,
|
||
Abschnittszuordnung und Reserveverhalten.
|
||
5. Repositories schreiben Daten. Kritische Mehrfachschreibvorgänge besitzen
|
||
explizite SQLite-Transaktionsadapter mit Commit-/Rollback-Integrationstests.
|
||
6. Das Frontend lädt den Circuit-Tree neu und stellt Auswahl beziehungsweise
|
||
Viewport soweit möglich wieder her.
|
||
|
||
Der Editor besitzt keinen sitzungslokalen Undo-/Redo-Stapel mehr. Beim initialen
|
||
Laden und nach jedem Tree-Reload liest er den persistenten History-Status und
|
||
gleicht dessen Revision mit `currentRevision` des Trees ab. Das Datenmodell
|
||
besitzt einen projektbezogenen Revisionszähler sowie getrennte Revision-/Change-Set-
|
||
Tabellen. Eine direkt getestete Persistence-Funktion schreibt diese
|
||
Historienmetadaten innerhalb der zentralen Command-Transaktion optimistisch und
|
||
atomar fort. Vorwärts- und Rückwärtskommandos besitzen einen
|
||
versionierten, JSON-sicheren Umschlag; Typ und Payload können dadurch nach
|
||
einem Neustart verlustfrei rekonstruiert werden. Alle aktuell unterstützten
|
||
Circuit-, Gerätezeilen-, Projektgeräte-, Projektstruktur- und
|
||
Projekteinstellungsänderungen
|
||
verwenden typisierte Command-Stores, die Fachänderung, automatisch erzeugtes
|
||
inverses Kommando, Revision und Historienstapel gemeinsam committen
|
||
beziehungsweise zurückrollen.
|
||
Gerätezeilen-Kommandos bewahren dabei auch lokale ProjectDevice-Overrides und
|
||
prüfen Projektzugehörigkeit von Verknüpfungen und Räumen. Projektweite,
|
||
persistente Undo-/Redo-Stacks verwalten die zulässige LIFO-Reihenfolge und
|
||
verwerfen den Redo-Zweig bei einem neuen Benutzerkommando. Ihr Status ist über
|
||
`GET /api/projects/:projectId/history` lesbar. Die unveränderliche,
|
||
absteigend paginierte Revisions-Timeline ist ohne Befehls-Payloads über
|
||
`GET /api/projects/:projectId/history/revisions` lesbar. Ein zentraler
|
||
Dispatcher führt die nachfolgend beschriebenen typisierten Kommandos über
|
||
öffentliche Command-, Undo- und Redo-Endpunkte aus.
|
||
Alle unterstützten Runtime-Project-Command-Stores einschließlich der
|
||
vollständigen Snapshot-Wiederherstellung verwenden dabei
|
||
`project-command-transaction.persistence.ts` als gemeinsame äußere
|
||
Transaktionsgrenze. Sie führt Fachänderung, Revisions-Append und
|
||
History-Transition in fester Reihenfolge innerhalb derselben SQLite-Transaktion
|
||
aus. Für CircuitDeviceRow-Feldänderungen übernimmt eine typisierte Variante den
|
||
während der Fachänderung um Override-Metadaten ergänzten Forward-Command. Die
|
||
fachlichen Validierungs-, Forward- und Inversenregeln bleiben im jeweiligen
|
||
Store.
|
||
Die Low-Level-Funktion `appendProjectRevision` bleibt ein internes Detail dieser
|
||
Persistenzgrenze und wird direkt mit einer realen SQLite-Transaktion getestet.
|
||
Ein eigenständiges Runtime-Revisions-Repository existiert nicht.
|
||
`ProjectDeviceSyncService` und `CircuitNumberingService` kennen nur schmale,
|
||
fachlich benannte Reader-Interfaces. Ihre SQLite-Repositories werden
|
||
ausschließlich in `src/server/composition/` erzeugt und injiziert.
|
||
Auch die allgemeinen Projekt-, Geräte-, Raum-, Geschoss- und Circuit-
|
||
Repositories verlangen einen expliziten `AppDatabase`-Kontext. Ihre
|
||
Anwendungsinstanzen werden zentral in
|
||
`src/server/composition/application-repositories.ts` erzeugt; Controller
|
||
importieren weder den globalen SQLite-Client noch konkrete Repository-Klassen.
|
||
`circuit-device-row.insert` und `circuit-device-row.delete` sind atomare
|
||
Strukturkommandos. Beim Löschen wird die vollständige Zeile im inversen
|
||
Kommando gesichert, sodass Undo dieselbe UUID und alle Fachwerte wiederherstellt.
|
||
`circuit.insert` und `circuit.delete` behandeln einen
|
||
Stromkreis mit null, einer oder mehreren Gerätezeilen als vollständigen Block.
|
||
Undo bewahrt dabei sämtliche Circuit-/Row-UUIDs und ändert keine
|
||
Betriebsmittelkennzeichen. Bestehende Circuit- und Gerätezeilen-Zelländerungen
|
||
sowie eigenständiges Einfügen und Löschen verwendet das Grid bereits über die
|
||
öffentliche Command-Grenze. Neue Circuits und Gerätezeilen erhalten ihre stabile
|
||
UUID vor dem Command; Löschen und Undo bewahren diese Identität. Der Tree liefert
|
||
dazu `currentRevision`; Undo/Redo für diese Aktionen läuft über die projektweite
|
||
Serverhistorie. Direkte Feld-PATCH-, Struktur-POST-, Move-, Circuit- und
|
||
Gerätezeilen-DELETE-Endpunkte sind entfernt. Gerätezeilen-Moves,
|
||
Stromkreis-Reorders und die explizite Neunummerierung im Grid verwenden die
|
||
persistenten Kommandos. Die Toolbar leitet ihre Undo-/Redo-Verfügbarkeit direkt
|
||
aus den serverseitigen Stack-Tiefen ab, sodass ein Reload die Bedienbarkeit
|
||
nicht unterbricht.
|
||
|
||
Benannte logische Projektstände werden in `project_snapshots` getrennt von
|
||
Datenbank-Backups gespeichert. `POST /api/projects/:projectId/snapshots`
|
||
erzeugt bei passender erwarteter Revision transaktional einen vollständigen,
|
||
schema-versionierten Projektzustand mit SHA-256-Prüfwert. Enthalten sind
|
||
Projekteinstellungen, Verteiler, Stromkreislisten, Bereiche, Stromkreise und
|
||
Gerätezeilen sowie Projektgeräte, Geschosse und Räume. Globale Geräte sind nicht
|
||
Teil des Projekt-Snapshots.
|
||
Create/List verändern weder Projektrevision noch Undo-/Redo-Stapel.
|
||
`kind` unterscheidet benannte und automatische Stände. Die zentrale
|
||
Revisionspersistenz erzeugt nach jeweils 25 weiteren Projektänderungen
|
||
transaktional einen automatischen Stand. Pro Projekt bleiben die neuesten 12
|
||
automatischen Stände erhalten; ältere automatische Stände werden in derselben
|
||
Transaktion entfernt. Benannte Stände und die unveränderliche Revisionshistorie
|
||
sind von dieser Aufbewahrung ausdrücklich ausgeschlossen.
|
||
`POST /api/projects/:projectId/snapshots/:snapshotId/restore` prüft Payload,
|
||
Prüfsumme, erwartete Revision und den unmittelbar zuvor gelesenen
|
||
Projektzustand. Der Restore ersetzt alle unterstützten Projektdaten in einer
|
||
Transaktion und schreibt dabei eine neue Revision mit Quelle `restore` sowie
|
||
ein vollständiges inverses Kommando. Undo und Redo können deshalb auch einen
|
||
Restore nach einem Neustart exakt zurücknehmen oder wiederholen.
|
||
Die Projektseite bindet diese APIs in einem einklappbaren Bereich
|
||
„Versionen und Sicherungspunkte“ ein. Dort können Benutzer Sicherungspunkte
|
||
benennen, jeden aufgeführten benannten oder automatischen Stand nach
|
||
expliziter Bestätigung wiederherstellen und die paginierte Revisions-Timeline
|
||
mit deutschen Quellen- und Änderungsbezeichnungen lesen. Die Snapshot-Liste
|
||
ordnet jede positive `sourceRevision` serverseitig ihren unveränderlichen
|
||
Revisionsmetadaten zu. Dadurch zeigt auch ein älterer automatischer Stand die
|
||
auslösende Änderung, ohne eine zweite frei formulierte Beschreibung zu
|
||
speichern oder von den zuletzt paginiert geladenen Timeline-Einträgen
|
||
abzuhängen. Revision null wird als Projektstart dargestellt.
|
||
Projektweites Rückgängig/Wiederholen bleibt im Kopf dieses Bereichs auch im
|
||
eingeklappten Zustand erreichbar. Die Verfügbarkeit stammt direkt aus den
|
||
persistierten Server-Stacks; nach einer Historienaktion oder einem Restore lädt
|
||
die Seite sämtliche Projektdaten neu.
|
||
`circuit-device-row.move` verschiebt oder sortiert eine oder mehrere Zeilen
|
||
zwischen vorhandenen Stromkreisen derselben Liste. Erwartete und neue
|
||
Stromkreis-/Sortierpositionen machen Forward und Inverse deterministisch;
|
||
Reservewerte aller beteiligten Stromkreise werden atomar neu abgeleitet. Das
|
||
Kompositkommando `circuit-device-row.move-with-new-circuit` bildet auch das
|
||
Verschieben auf einen freien Platz ab: Ein Zielstromkreis mit stabiler UUID und
|
||
BMK wird zusammen mit allen Zeilenbewegungen erzeugt. Undo stellt die exakten
|
||
Quellpositionen wieder her und löscht den erzeugten Stromkreis nur, wenn dessen
|
||
Felder und vollständiger Zeilenbestand unverändert sind.
|
||
Der Editor erzeugt die vollständigen Move-Zuweisungen aus dem geladenen Tree,
|
||
vergibt für neue Ziele vor dem Kommando eine stabile UUID und führt das
|
||
Toolbar-Undo/Redo über die projektweite Historie aus.
|
||
Die Projektgerätepalette belegt keine permanente Layoutspalte mehr. Sie wird
|
||
über die Editor-Toolbar als überlagernder Drawer geöffnet, während das
|
||
Stromkreis-Grid standardmäßig die gesamte verfügbare Breite nutzt. Auswahl,
|
||
Schnelleinfügen und die vorhandenen Drag-and-drop-Payloads bleiben im Drawer
|
||
unverändert verfügbar; während eines aktiven Projektgeräte-Drags kann er nicht
|
||
geschlossen werden. Der Drawer liegt am rechten Fensterrand und verdeckt damit
|
||
nicht die führenden BMK- und Anzeigenamenspalten. Das Grid zeigt Geräte- und
|
||
Stromkreisleistungen in einer gemeinsamen Spalte `Gesamtsumme`: Gerätezeilen
|
||
verwenden `rowTotalPower`, Stromkreis-Sammelzeilen `circuitTotalPower`.
|
||
Zahlen werden ausschließlich für die Anzeige deutsch und begrenzt formatiert;
|
||
gespeicherte Werte und Bearbeitungsentwürfe behalten ihre volle Genauigkeit.
|
||
Jeder Abschnitt liefert und zeigt seine aufsummierte Stromkreisleistung. Die
|
||
Stromkreisliste zeigt außerdem die ungefilterte Gesamtleistung des Verteilers,
|
||
den am Verteiler gespeicherten Gleichzeitigkeitsfaktor und die daraus
|
||
abgeleitete Gesamtleistung unter Berücksichtigung dieses Faktors. Sortierung
|
||
und Filter verändern diese fachlichen Summen nicht.
|
||
Reihenfolge und Sichtbarkeit der Grid-Spalten sind reine UI-Präferenzen. Sie
|
||
werden im Browser unter einem projektspezifischen Schlüssel gespeichert und
|
||
deshalb beim Wechsel zwischen Verteilern desselben Projekts wiederverwendet,
|
||
ohne Projektrevisionen oder fachliche Snapshots zu erzeugen.
|
||
`circuit.reorder-section` speichert die erwartete und neue Sortierposition
|
||
jedes Stromkreises eines vollständigen Abschnitts. Forward, Undo und Redo
|
||
ändern ausschließlich `sortOrder`; Stromkreisblöcke, Gerätezeilen und BMKs
|
||
bleiben unverändert. `circuit.renumber-section` bildet die getrennte,
|
||
ausdrücklich ausgelöste Neunummerierung ab. Es speichert alle erwarteten und
|
||
neuen BMKs des Abschnitts, löst Tauschkollisionen über temporäre Werte und
|
||
ändert weder Sortierung noch Gerätezeilen.
|
||
Die Bereichsaktion erzeugt die vollständigen erwarteten und neuen BMKs aus
|
||
Präfix und aktueller Stromkreisreihenfolge und verwendet das persistente
|
||
Kommando für Toolbar-Undo/Redo. Die früheren direkten Renumber- und
|
||
Identifier-Restore-Endpunkte sowie ihr separater Transaktionsadapter sind
|
||
entfernt.
|
||
Drag-and-drop verwendet `circuit.reorder-section`. Die explizite Übernahme
|
||
einer sortierten Ansicht verwendet `circuit.reorder-sections`, damit alle
|
||
betroffenen Bereiche in einer Transaktion und als ein Undo-Schritt gespeichert
|
||
werden. Direkte Reorder-Endpunkte existieren nicht mehr.
|
||
`project-device.sync-rows` persistiert Synchronisierung, Trennen und erneutes
|
||
Verknüpfen als atomaren Mehrzeilen-Command. Jede betroffene Zeile enthält den
|
||
vollständigen erwarteten und neuen Stand aller synchronisierbaren Felder,
|
||
einschließlich ProjectDevice-Verknüpfung und lokaler Override-Metadaten. Damit
|
||
werden stille Überschreibungen veralteter Zeilen verhindert und Undo/Redo stellt
|
||
exakt die vorherigen lokalen Werte wieder her. Die Synchronisieren- und
|
||
Trennen-Endpunkte sowie die Projektseite verwenden diesen Command mit
|
||
optimistischer Revisionsprüfung. Rückgängig/Wiederholen erfolgt dort
|
||
einheitlich über die persistente projektweite Historie; der frühere
|
||
sitzungslokale Spezial-Undo und separate direkte Restore-/Reconnect-Schreibwege
|
||
existieren nicht mehr.
|
||
`project-device.update` versioniert Änderungen an den kanonischen
|
||
Projektgerätefeldern unabhängig davon. Der Store erzeugt die Inverse aus dem
|
||
gespeicherten Gerät und schreibt Geräteänderung, Revision und Historienstapel
|
||
atomar. Verknüpfte Stromkreiszeilen werden dabei bewusst nicht automatisch
|
||
synchronisiert. Der ProjectDevice-`PUT`-Endpunkt und die Projektseite verwenden
|
||
diesen Command mit optimistischer Revisionsprüfung.
|
||
`project-device.insert` und `project-device.delete` versionieren außerdem den
|
||
Lebenszyklus eines Projektgeräts mit stabiler UUID. Beim Löschen speichert das
|
||
inverse Insert den vollständigen Gerätestand sowie vollständige, nach dem
|
||
Löschen erwartete Snapshots aller zuvor verknüpften Gerätezeilen. Undo setzt
|
||
die Links nur zurück, wenn diese Zeilen weiterhin zum Projekt gehören,
|
||
unverknüpft und vollständig unverändert sind. Gerät, Linkänderungen, Revision
|
||
und Historienstapel teilen dieselbe Transaktion. Create, Import aus der globalen
|
||
Gerätebibliothek und Delete laufen über dieselbe Command-Grenze; ihre Antworten
|
||
liefern Gerät und aktualisierten Historienstand an die Projektseite zurück.
|
||
`project.update-settings` versioniert Projektname, interne und externe
|
||
Projektnummer, Bauherr, Beschreibung, die Kennzeichnung als öffentliches
|
||
Gebäude, beide Standardspannungen sowie die im Projekt freigeschalteten
|
||
Verteiler-Netzarten als eine atomare Änderung. Die Gebäudekennzeichnung ist
|
||
der spätere Eingang für die Auswahl halogenfreier Kabel und Leitungen. Der
|
||
Systemkatalog besteht aus `AV`, `SV`, `EV`, `USV`, `MSR` und `SiBe`; mindestens
|
||
eine Netzart muss aktiv bleiben und eine bereits von einer Verteilung
|
||
verwendete Netzart kann nicht deaktiviert werden. Die Projektseite bearbeitet diese Angaben in einem
|
||
beschrifteten Einstellungsmodal statt in einer permanenten Formularkarte. Der
|
||
Store leitet das inverse Kommando aus dem gespeicherten Projekt ab und schreibt
|
||
Werte, Revision und Historienstapel gemeinsam. `PUT /api/projects/:projectId`
|
||
verlangt deshalb `expectedRevision`, liefert Projekt plus aktualisierten
|
||
Historienstand und besitzt keinen separaten direkten Settings-Schreibweg mehr.
|
||
Kommando- und Snapshot-Payloads müssen dem aktuellen Baseline-Schema entsprechen.
|
||
Die Projektseite zeigt Verteilungen, Etagen und Räume als kompakte
|
||
Bestandsübersichten; ihre versionierten Erstellwege öffnen beschriftete Modals
|
||
statt dauerhafter Eingabezeilen. Projektgeräte werden als durchsuchbare,
|
||
fünfspaltige Übersicht dargestellt. Manuelle Anlage, Übernahme aus der globalen
|
||
Bibliothek und vollständige Bearbeitung erfolgen in einem gemeinsamen Modal.
|
||
Die anschließende Vorschau verknüpfter Stromkreiszeilen bleibt davon getrennt,
|
||
damit Änderungen weiterhin niemals still synchronisiert werden.
|
||
`GET /api/projects/:projectId/export` verpackt denselben vollständigen
|
||
Projektzustand in ein portables, format- und schema-versioniertes JSON-Dokument
|
||
mit SHA-256-Prüfsumme. `POST /api/projects/:projectId/import` prüft Format,
|
||
Snapshot-Relationen und Prüfsumme vor jedem Schreibzugriff. Der Modus `replace`
|
||
läuft über `project.restore-state` und ist dadurch eine atomare, dauerhaft
|
||
rückgängig machbare Projektrevision. Der Modus `duplicate` ordnet Projekt-,
|
||
Struktur-, Gruppen-, Verteilerkomponenten-, Raum-, Stromkreis- und
|
||
Gerätezeilen-UUIDs sowie Schutzgeräte-Referenzen vollständig neu zu und legt
|
||
die Kopie mit Revision `0` in einer Transaktion an. Fachliche Verknüpfungen
|
||
innerhalb des unterstützten Laufzeitmodells bleiben
|
||
erhalten. Die
|
||
Projektübersicht verwendet dafür den separaten Collection-Endpunkt
|
||
`POST /api/projects/import`, der ausschließlich eine neue Kopie anlegt und
|
||
deshalb weder eine bestehende Projekt-ID noch `expectedRevision` annimmt. Das
|
||
Ersetzen eines Projekts bleibt auf dessen Einstellungsmodal und den
|
||
projektgebundenen Endpunkt beschränkt.
|
||
`distribution-board.insert` versioniert die Anlage einer Verteilung mit
|
||
Command-Schema 1 als vollständigen Block aus Verteilung, Stromkreisliste, den
|
||
drei Gruppen `Beleuchtung 1`, `1-phasig 1`, `3-phasig 1`, Hauptschalter `-Q0`
|
||
und Überspannungsableiter `-FA`.
|
||
Alle UUIDs entstehen vor dem Command und bleiben über Undo/Redo stabil.
|
||
`distribution-board.delete` ist die persistierte Inverse und entfernt nur den
|
||
vollständig unveränderten, weiterhin stromkreislosen Block. Controller und
|
||
Projektseite übergeben die erwartete Projektrevision; der frühere direkte
|
||
Controller-Schreibweg ist entfernt. Verteilungen besitzen eine optionale
|
||
Etagenreferenz sowie eine Netzart aus dem Projektkatalog. Anlage und
|
||
nachträgliche Bearbeitung prüfen die Projektzugehörigkeit der Etage und die
|
||
Freigabe der Netzart in den Projekteinstellungen.
|
||
Bereits befüllte Verteilungen werden über
|
||
`distribution-board.insert-subtree` und `distribution-board.delete-subtree`
|
||
als vollständiger Unterbaum kopiert beziehungsweise gelöscht. Der Snapshot
|
||
umfasst Verteilung, Stromkreisliste, Gruppen, Stromkreise, Gerätezeilen,
|
||
Verteilerkomponenten und alle zugehörigen Schutzgeräte. Beim Kopieren werden
|
||
sämtliche besitzenden UUIDs neu vergeben, während fachliche Verknüpfungen zu
|
||
Projektgeräten und Räumen erhalten bleiben. Beide Aktionen sind atomare
|
||
Projektrevisionen und bleiben nach einem Neustart über Undo/Redo umkehrbar. Die
|
||
Projektseite bietet sie im Einstellungsmodal der jeweiligen Verteilung an;
|
||
Löschen verlangt dort eine ausdrückliche Bestätigung.
|
||
`distribution-board-component.insert` und
|
||
`distribution-board-component.delete` sowie
|
||
`distribution-board-component.update` versionieren Anlage, Entfernung,
|
||
Bearbeitung und Sortierung veränderlicher Gruppen-Schutzgeräte und zusätzlicher
|
||
Verteilergeräte. Die vollständigen Snapshots enthalten stabile
|
||
Komponenten-UUIDs und, für Gruppen-Schutzgeräte, die getrennte
|
||
1:1-Schutzgerätekonfiguration. Updates tauschen einen exakt erwarteten gegen
|
||
einen vollständigen Zielzustand aus; ID, Eigentum, Rolle und Platzierungszone
|
||
bleiben dabei unverändert. Projekt-, Listen- und Gruppenzugehörigkeit sowie
|
||
veraltete Zustände werden innerhalb derselben Transaktion geprüft. Die festen
|
||
Kopfkomponenten Hauptschalter und Überspannungsableiter sind von diesen
|
||
allgemeinen Commands ausgeschlossen. Veränderliche Gruppen- und Fußkomponenten
|
||
werden im Editor über eigene Modale und diese Commands verwaltet.
|
||
Leere Stromkreisgruppen werden über `circuit-group.insert`,
|
||
`circuit-group.update` und `circuit-group.delete` verwaltet. Ihr vollständiger
|
||
Snapshot koppelt Kategorie, positive Gruppennummer und daraus abgeleiteten
|
||
BMK-Präfix; allgemeine Updates ändern ausschließlich den Anzeigenamen.
|
||
Löschen verlangt einen exakt unveränderten Zustand ohne Stromkreise und ohne
|
||
Gruppenkomponenten. Befüllte Gruppen verwenden getrennt davon den vollständigen
|
||
`circuit-group.delete-subtree`-Command mit ausdrücklicher Warnung.
|
||
`circuit-group.reorder` sortiert Gruppen als vollständige Stromkreislisten-
|
||
Zuordnung. Jede vorhandene Gruppe muss mit erwarteter und neuer Position
|
||
enthalten sein. Der Command verändert ausschließlich `sortOrder`; Nummern,
|
||
Präfixe und Stromkreis-BMKs bleiben stabil. Die gesamte Sortierung bildet eine
|
||
Revision und einen Undo/Redo-Schritt.
|
||
`src/domain/services/circuit-group-renumbering.ts` plant explizite
|
||
Gruppennummerierungen deterministisch. Der reine Plan erhält
|
||
Stromkreis-Endnummern, leitet Gruppenpräfixe und optionale `.0`-Komponenten-BMKs
|
||
neu ab und prüft Nummerntausch sowie Kollisionen mit unveränderten Gruppen.
|
||
`circuit-group.renumber` führt diesen Plan über die gemeinsame
|
||
Projekt-Command-Transaktion aus. Vor dem Schreiben müssen alle betroffenen
|
||
Gruppen, Stromkreise und Gruppenkomponenten exakt dem erwarteten Zustand
|
||
entsprechen. Nummerntausch verwendet kollisionsfreie temporäre Präfixe und
|
||
BMKs über beide BMK-Tabellen; anschließend werden alle Zielwerte finalisiert.
|
||
Der vollständige inverse Plan ermöglicht dauerhaftes Undo/Redo.
|
||
`src/domain/services/circuit-group-move-planning.ts` plant den Wechsel eines
|
||
vollständigen Stromkreises zwischen zwei verschiedenen Gruppen derselben
|
||
Kategorie. Die Ziel-BMK verwendet die höchste vorhandene Stromkreis-Endnummer
|
||
der Zielgruppe plus eins; Lücken werden nicht gefüllt. Quell-/Zielgruppe,
|
||
Quell-/Zielposition und beide BMKs werden festgeschrieben, damit eine spätere
|
||
Wiederholung nichts neu berechnet.
|
||
`circuit.move-group` führt den geplanten Wechsel als eine Projekt-Revision aus.
|
||
Nur `sectionId`, `equipmentIdentifier` und `sortOrder` des Stromkreises ändern
|
||
sich. Gerätezeilen und das getrennte 1:1-Schutzgerät bleiben über die stabile
|
||
Stromkreis-UUID verbunden. Der inverse Wechsel speichert Quellgruppe, BMK und
|
||
Position vollständig für dauerhaftes Undo/Redo.
|
||
`CircuitGroupSubtreeSnapshot` ist der kanonische Vertrag für destruktive
|
||
Gruppenoperationen. Er umfasst Gruppe, optionale Gruppenkomponenten samt
|
||
1:1-Schutzdaten, vollständige Stromkreise samt 1:1-Schutzdaten und sämtliche
|
||
Gerätezeilen einschließlich Link- und Override-Metadaten. Seine
|
||
Warnzusammenfassung liefert Vorsicherung/FI sowie Stromkreis- und
|
||
Gerätezeilenanzahl.
|
||
`circuit-group.delete-subtree` nimmt den aktuellen Unterbaum unmittelbar vor
|
||
dem Löschen erneut auf und verlangt exakte Übereinstimmung mit dem bestätigten
|
||
Snapshot. `circuit-group.restore-subtree` schreibt ihn in FK-sicherer Reihenfolge
|
||
mit denselben UUIDs zurück. Beide Richtungen laufen als vollständige inverse
|
||
Projekt-Commands; späte Fehler hinterlassen weder Teillöschungen noch
|
||
Teilwiederherstellungen.
|
||
Der Circuit-Tree liefert zusätzlich `headerComponents`,
|
||
gruppenbezogene `components` und `footerComponents`. Abschnitte enthalten
|
||
optionale Gruppenkategorie und -nummer; Stromkreise und Gruppenkomponenten
|
||
enthalten ihre getrennte Schutzgerätekonfiguration. Die
|
||
1:1-Schutzgerätetabellen sind die einzige unterstützte Quelle dieser Daten.
|
||
Separate aktive Read-Repositories lesen Komponenten- und beide
|
||
Schutzgerätetabellen; Schreibzugriffe bleiben ausschließlich in Commands.
|
||
`src/frontend/utils/circuit-structure-projection.ts` projiziert diesen Tree
|
||
rein und deterministisch in die drei Zonen Kopf, vollständige Gruppen und Fuß.
|
||
Innerhalb einer Gruppe folgen auf die Überschrift optionale Schutzkomponenten,
|
||
vollständige Stromkreisblöcke und der freie Einfügeplatz. Leere Gruppen bleiben
|
||
sichtbar; Komponenten werden stabil nach `sortOrder` und ID sortiert.
|
||
`circuit-grid-projection.ts` normalisiert diese Struktur zusammen mit den
|
||
bisherigen kompakten und mehrzeiligen Stromkreisblöcken für den Editor. Kopf-,
|
||
Gruppen- und Fußkomponenten erscheinen als Zeilen über die volle Tabellenbreite
|
||
und nehmen nicht an Zellauswahl oder Tastatur-Einfügen teil. Hauptschalter und
|
||
Überspannungsableiter bleiben feste, schreibgeschützte Kopfkomponenten.
|
||
Optionale Gruppenvorsicherungen, Gruppen-FIs und zusätzliche Verteilergeräte
|
||
werden über beschriftete Modale angelegt, bearbeitet und nach Bestätigung
|
||
entfernt. Der Frontend-API-Adapter serialisiert dafür die vorhandenen
|
||
`distribution-board-component.*`-Commands; die verbindliche
|
||
geräteabhängige Validierung und atomare Revision bleiben serverseitig.
|
||
Neue Stromkreisgruppen erhalten im Editor die höchste vorhandene
|
||
Gruppennummer ihrer Kategorie plus eins und ein daraus abgeleitetes Präfix.
|
||
Das Bearbeiten ändert ausschließlich den Anzeigenamen. Nur vollständig leere
|
||
Gruppen können über `circuit-group.delete` entfernt werden; für befüllte
|
||
Gruppen bleibt die Aktion bis zum gesonderten Warn- und Unterbaumdialog
|
||
gesperrt.
|
||
`circuit-protection.update` bildet die eigene persistente Schreibgrenze für
|
||
die neue 1:1-Stromkreisschutztabelle. Der Command vergleicht den vollständigen
|
||
erwarteten Datensatz, validiert Typ und abhängige Felder, prüft die
|
||
Projektzugehörigkeit und schreibt Schutzgerät, Revision und Historienübergang
|
||
atomar. Benutzer können Schutzdaten anlegen oder ändern, aber nicht entfernen;
|
||
Undo einer erstmaligen Anlage darf den zuvor fehlenden Datensatz exakt
|
||
wiederherstellen.
|
||
Der vollständige `CircuitSnapshot` enthält den zugehörigen
|
||
`protectionDevice`-Datensatz, sofern einer vorhanden ist. Neue Stromkreise und
|
||
durch Geräteverschiebung erzeugte Zielstromkreise verwenden die vereinbarten
|
||
Kategorie-Standardwerte und schreiben Schutzgerät, Stromkreis sowie
|
||
Gerätezeilen atomar. Delete/Undo erfasst denselben Datensatz vollständig.
|
||
Im Editor sind die Schutzspalten deshalb eine
|
||
schreibgeschützte Projektion der 1:1-Daten; Änderungen erfolgen über ein
|
||
geräteabhängiges Schutzgeräte-Modal und `circuit-protection.update`.
|
||
Gruppen lassen sich im Editor schrittweise nur gegenüber einer benachbarten
|
||
Gruppe derselben Kategorie verschieben. Der Client sendet dabei immer die
|
||
vollständige erwartete und gewünschte Sortierreihenfolge über
|
||
`circuit-group.reorder`; Gruppennummer, Präfix und Kind-BMK bleiben unverändert.
|
||
Eine separate, ausdrücklich bestätigte Editoraktion erzeugt dagegen einen
|
||
vollständigen `circuit-group.renumber`-Plan für genau eine Kategorie. Sie
|
||
nummeriert deren Gruppen gemäß aktueller Reihenfolge ab eins und ändert
|
||
Gruppenpräfixe, optionale Gruppen-Schutz-BMK und Stromkreis-BMK gemeinsam;
|
||
die Stromkreisnummer hinter dem letzten Punkt bleibt erhalten.
|
||
Das vorhandene Stromkreis-Drag-Handle kann außerdem genau einen vollständigen
|
||
Stromkreis in eine andere Gruppe derselben Kategorie verschieben. Der atomare
|
||
`circuit.move-group`-Befehl erhält Gerätezeilen und Schutzdaten, setzt die
|
||
Zielposition und vergibt dort die höchste vorhandene Stromkreisnummer plus eins;
|
||
Lücken werden nicht automatisch gefüllt.
|
||
Befüllte Gruppen werden im Editor erst nach einer Warnung mit Anzahl der
|
||
enthaltenen Stromkreise, Gerätezeilen und Gruppenschutzgeräte gelöscht. Der
|
||
Client sendet dafür den vollständigen aktuellen Unterbaum an
|
||
`circuit-group.delete-subtree`; der Server vergleicht ihn innerhalb derselben
|
||
Transaktion mit dem Datenbankstand. Undo stellt Gruppe, Schutzgeräte,
|
||
Stromkreise, Gerätereihen und Verknüpfungs-/Override-Metadaten vollständig
|
||
wieder her.
|
||
`distribution-board.update` versioniert Etage, Netzart und den
|
||
verteilerweiten Gleichzeitigkeitsfaktor gemeinsam und stellt alle Werte über
|
||
dauerhaftes Undo/Redo wieder her. Der Faktor liegt zwischen `0` und `1` und
|
||
ist für bestehende sowie neu angelegte Verteilungen standardmäßig `1`.
|
||
Snapshot-Schema 5 enthält zusätzlich den manuellen Mengenanteil jeder
|
||
Gerätezeile. Version 4 wird mit `manualQuantity = quantity` hochgestuft und
|
||
enthält bereits den vollständigen externen Modellzustand
|
||
aus Quelle, Batches, Raum-Mappings und Objekten. Es enthält außerdem die
|
||
projektweite Revit-CSV-Konfiguration, die Gebäudekennzeichnung sowie den Gleichzeitigkeitsfaktor,
|
||
Gruppenkategorie und -nummer, Verteilerkomponenten sowie die getrennten
|
||
1:1-Schutzgerätedaten. Capture,
|
||
benannte und automatische Snapshots, Wiederherstellung, Undo/Redo und beide
|
||
JSON-Importmodi verwenden denselben vollständigen Zustand. Die unterstützte
|
||
Version 3 wird mit leerem externem Modellzustand und Version 2 zusätzlich mit
|
||
leerer externer Konfiguration hochgestuft. Die unterstützte
|
||
Baseline-Version 1 wird zusätzlich mit `isPublicBuilding = false` hochgestuft; Formate vor
|
||
dieser Baseline werden nicht eingelesen.
|
||
Persistente Insert-, Update- und Delete-Commands versionieren Anlage,
|
||
Bearbeitung und Löschung von Geschossen und Räumen mit stabilen UUIDs und
|
||
exakten Vorher-/Nachher-Snapshots. Ein Geschoss wird nur
|
||
entfernt, solange ihm weder ein Raum noch eine Verteilung zugeordnet wurde. Ein
|
||
Raum wird nur entfernt, solange keine CircuitDeviceRow auf ihn verweist. Alle
|
||
Schreibendpunkte verlangen `expectedRevision` und liefern den aktualisierten
|
||
Historienstand.
|
||
|
||
## Projektgeräte
|
||
|
||
Die Projektgerätekategorie `lighting`, `single_phase` oder `three_phase` ist die
|
||
fachliche Klassifikation und Zielgruppe. `phaseType` ist keine separate
|
||
Benutzereingabe, sondern wird daraus für Spannung, Verknüpfung und spätere
|
||
Dimensionierung abgeleitet.
|
||
|
||
Beim Einfügen entsteht eine verknüpfte `CircuitDeviceRow`. Der Anzeigename wird
|
||
kopiert, aber nicht still synchronisiert. Spätere Änderungen am Projektgerät
|
||
werden als Diff angezeigt und nur für ausdrücklich gewählte Felder und Zeilen
|
||
übernommen.
|
||
|
||
Die globale Gerätebibliothek ist ein einfacher, datenbankweiter Vorlagenbestand.
|
||
Kopieren in ein Projekt erzeugt ein eigenständiges Projektgerät.
|
||
|
||
## Persistenz und Migration
|
||
|
||
- SQLite ist die aktuell unterstützte Datenbank.
|
||
- Fremdschlüssel werden für jeden Datenbankkontext aktiviert.
|
||
- `npm run db:migrate` richtet mit Baseline-Migration `0000` und den folgenden
|
||
additiven Migrationen das aktuelle Schema ein.
|
||
- `npm run db:verify:circuit-schema` prüft erforderliche und entfernte Spalten.
|
||
- `npm run db:backup` erzeugt ein konsistentes und verifiziertes Online-Backup.
|
||
- `npm run typecheck:scripts` prüft die TypeScript-Wartungsskripte, ohne Code zu
|
||
erzeugen.
|
||
- Die Baseline ersetzt alle vorigen Entwicklungsmigrationen. Datenbanken,
|
||
Snapshots und persistierte Commands aus Vor-Baseline-Ständen werden bewusst
|
||
nicht unterstützt. Ab der ersten veröffentlichten Version sind angewendete
|
||
Migrationen unveränderlich und Änderungen erfolgen additiv.
|
||
- Allgemeine Circuit-, Gerätezeilen-, CircuitList- und DistributionBoard-
|
||
Repositories stellen im Anwendungspfad nur noch benötigte Leseabfragen bereit.
|
||
Fachliche Schreibvorgänge liegen in den typisierten Command-Repositories.
|
||
- Die vollständige Verteilungs-Testfixture liegt unter
|
||
`tests/support/distribution-board-fixture.ts` und ist kein exportierter
|
||
Produktions-Schreibweg.
|
||
- Die Baseline bildet die relationale Grundlage für geschützte Stromkreisgruppen
|
||
und Verteilerkomponenten. Separate
|
||
1:1-Tabellen halten Stromkreis- und Komponenten-Schutzgeräte. Die früheren
|
||
flachen Stromkreis-Schutzfelder sind aus der Baseline entfernt.
|
||
Ein triggergeführtes Register erzwingt bereits eine normalisierte,
|
||
stromkreislistenweite BMK-Eindeutigkeit über Stromkreise und
|
||
Verteilerkomponenten. Snapshot- und Transfer-Integration verwenden aktuell
|
||
Snapshot-Schema 5. Persistente Insert/Delete/Update-Commands für
|
||
veränderliche Verteilerkomponenten, Gruppen einschließlich befüllter
|
||
Unterbäume sowie vollständige Gruppensortierung sind integriert. Der Editor
|
||
zeigt die geschützte Struktur an und bearbeitet veränderliche Gruppen- und
|
||
Fußkomponenten über dedizierte Command-Modale. Gruppenanlage, -umbenennung,
|
||
-sortierung, explizite Neunummerierung, Same-Category-Stromkreiswechsel,
|
||
geschütztes Unterbaumlöschen und Stromkreisschutz sind integriert.
|
||
|
||
PostgreSQL ist bewusst nicht implementiert. Die Domainregeln und
|
||
Transaktionsgrenzen sollen portabel bleiben; Schema und Betriebsmodell benötigen
|
||
bei einem späteren Wechsel trotzdem einen eigenen PostgreSQL-Adapter.
|
||
|
||
## Revit-CSV-Grundlage
|
||
|
||
Der reine Adapter unter `src/external-model/csv` validiert die projektweite
|
||
Transport- und Mappingkonfiguration und parst UTF-8-CSV verlustarm in eine
|
||
klassifizierte Zellmatrix. Er erkennt Metadaten, Header, Passthrough-, Objekt-
|
||
und Verdachtszeilen, prüft IFCGUIDs und serialisiert unveränderte Revit-Exporte
|
||
einschließlich BOM, CRLF und Quotierung bytegleich zurück. Der lokale Befehl
|
||
`npm run revit:verify-reference` prüft die bereitgestellte Referenzdatei.
|
||
|
||
`external_csv_configurations` enthält höchstens eine versionierte Konfiguration
|
||
je Projekt. `external-csv-configuration.update` schreibt Anlage, Änderung oder
|
||
Entfernung zusammen mit Revision und persistentem Undo/Redo. Snapshot-Schema 5,
|
||
Restore und portabler Projekttransfer enthalten diesen Zustand; beim Duplizieren
|
||
werden Konfigurations-UUID und Projektlink remapped.
|
||
|
||
Migration `0003` ergänzt die relationale Grundlage für genau eine implizite
|
||
`revit_csv`-Quelle je Projekt, geordnete Importbatches, normalisierte
|
||
Quellraummappings und über `(sourceId, ifcGuid)` eindeutige externe Objekte.
|
||
Batches halten Konfigurationssnapshot, Originalbytes und die klassifizierte
|
||
Zellmatrix zusammen. Migration `0004` ergänzt die monotone projektweite
|
||
Konfigurationsversion am Batch, getrennt von der Schema-Version des
|
||
Konfigurationsformats. Quellwerte, lokale Planungswerte und Override-Metadaten
|
||
der Objekte sind getrennt; optionale Links auf Raum, Verteilung, ProjectDevice
|
||
und CircuitDeviceRow bleiben nullable. `ExternalModelStateRepository` liest den
|
||
vollständigen Zustand deterministisch und unterscheidet unbekannte von noch
|
||
nicht importierten Projekten. Der letzte bestätigte Batch wird aus der
|
||
Batchreihenfolge abgeleitet statt redundant an der Quelle gespeichert.
|
||
Snapshot/Transfer v5 erfasst zusätzlich `manualQuantity`; Version 4 wird mit
|
||
dem bisherigen Gesamtwert als manuellem Anteil hochgestuft. Originalbytes,
|
||
Matrix und alle internen Links werden weiterhin vollständig erfasst,
|
||
stellt sie in Fremdschlüsselreihenfolge wieder her und remappt beim
|
||
Projektduplikat jede interne UUID; IFCGUID und Quelltransport bleiben
|
||
unverändert. `external-import.apply-initial` ist die atomare Schreibgrenze für
|
||
einen bestätigten Erstimport. Vor dem Insert prüft sie den aktuellen
|
||
Konfigurationsstand, SHA-256 und Base64-Kanonizität, parst die Originalbytes
|
||
erneut, vergleicht Matrix, vollständige IFCGUID-Menge und Quellwerte und
|
||
validiert alle Raum-, Verteiler- und ProjectDevice-Links gegen das Projekt.
|
||
Nicht explizit als Override markierte Planungswerte müssen dem regelbasierten
|
||
Vorschlag entsprechen. Der Command erzeugt und verknüpft ausdrücklich keine
|
||
CircuitDeviceRow; Undo entfernt den vollständigen unveränderten Importzustand,
|
||
Redo verwendet dieselben UUIDs und Bytes. Bloße Vorschau und Importplanung
|
||
erzeugen weiterhin keine dieser Zeilen.
|
||
|
||
Migration `0005` trennt bei `CircuitDeviceRow` den manuellen Mengenanteil vom
|
||
weiterhin materialisierten Gesamtwert. Bestehende Daten werden mit
|
||
`manualQuantity = quantity` übernommen. Die Fachregel für spätere externe
|
||
Zuordnungs-Commands lautet `quantity = manualQuantity + Summe der
|
||
effectiveQuantity aller verknüpften ExternalModelObjects`; Link und beide
|
||
Mengenwerte müssen innerhalb desselben Projekt-Commands wechseln.
|
||
`external-object.update-row-assignment` ist diese atomare Schreibgrenze für
|
||
bestehende Gerätezeilen. Sie weist mehrere externe Einzelobjekte zu, verschiebt
|
||
sie zwischen vorhandenen Rows oder löst ihre Links. Vor dem Schreiben werden
|
||
die vollständigen erwarteten Row- und Objektsnapshots, Projektzugehörigkeit,
|
||
Verteilung, Gruppenkategorie, Raum und Selektionskennzeichen geprüft.
|
||
Abweichende lokale Planungswerte benötigen eine explizite Konfliktbestätigung;
|
||
unterschiedliche Räume, Kategorien oder Selektionskennzeichen werden nicht
|
||
still zusammengeführt. Alle betroffenen materialisierten Mengen werden aus dem
|
||
unveränderten manuellen Anteil und sämtlichen Ziel-Objektlinks validiert. Die
|
||
Gegenrichtung enthält dieselben vollständigen Snapshots und funktioniert nach
|
||
Neustart; beim Lösen des letzten Objekts bleibt die Row bestehen.
|
||
`external-object.assign-to-new-row` fügt unzugeordnete Objekte atomar als neue
|
||
Gerätezeile in einen vorhandenen Stromkreis ein. Der manuelle Anteil dieser Row
|
||
ist null; Gesamtmenge, Raum, Verteilung, Kategorie, Selektionskennzeichen und
|
||
Planungswerte werden vor dem Schreiben geprüft. Undo löst exakt diese Objekte
|
||
und löscht die erzeugte Row nur, wenn sie und ihre Linkmenge unverändert sind.
|
||
Der Löschbefehl ist ausschließlich für die Projekthistorie zugelassen; eine
|
||
normale spätere Trennung lässt die Row gemäß der allgemeinen Zuordnungsregel
|
||
bestehen.
|
||
`external-object.assign-to-new-circuit` erzeugt einen neuen Stromkreis mit
|
||
vorab festgeschriebenem BMK, abgeleiteter Projektspannung, genau einer
|
||
externen Row und verpflichtendem Standardschutz zusammen mit den Objektlinks.
|
||
Verteilungs-, Gruppen-, Raum-, Mengen- und Planungsregeln werden vor dem Insert
|
||
gegen den aktuellen Projektstand geprüft. Der historische Gegenbefehl ist kein
|
||
allgemeiner Löschpfad: Er entfernt den vollständigen Circuit-Teilbaum nur bei
|
||
unverändertem Snapshot und unveränderter Objektlinkmenge. Redo verwendet exakt
|
||
dieselben IDs, dasselbe BMK und denselben Schutzsnapshot.
|
||
Die drei Zuordnungsadapter teilen sich
|
||
`external-object-assignment.persistence.ts` für Snapshotvergleich,
|
||
Kompatibilitätsregeln und link-sichere Updates.
|
||
`GET /api/projects/:projectId/circuit-lists/:circuitListId/external-objects`
|
||
liefert die verteilungsbezogene Read-Projektion für den späteren Editor-Drawer.
|
||
Die CircuitList bestimmt den Verteiler serverseitig; die Antwort enthält nur
|
||
dessen externe Objekte, sortiert unzugeordnet vor zugeordnet, sowie kompakte
|
||
Quell-, Raum-, Planungs- und Linkangaben. Originalbytes und vollständige
|
||
Command-Snapshots werden nicht an diese Oberfläche gegeben. Ohne optionalen
|
||
Revit-Import ist die Projektion leer.
|
||
`GET` und `PUT /api/projects/:projectId/external-csv/configuration` lesen oder
|
||
ändern die Konfiguration; der PUT plant Identität und nächsten
|
||
Konfigurationsstand serverseitig und verwendet den typisierten Command.
|
||
`POST /api/projects/:projectId/external-csv/preview` nimmt Dateiname und
|
||
Base64-kodierte CSV bis 18 MB entgegen. Der zustandsfreie Service liefert Hash,
|
||
Dialekt, Header, Klassifikationszahlen, Verdachtszeilen und gemappte
|
||
Objektquellwerte. Er schreibt weder Entwurf noch Projektdaten.
|
||
`POST /api/projects/:projectId/external-csv/initial-import/plan` verwendet
|
||
denselben begrenzten Transport, setzt eine gespeicherte Konfiguration und einen
|
||
noch leeren externen Projektzustand voraus und bleibt ebenfalls zustandsfrei.
|
||
Die Antwort gruppiert Quellräume, schlägt bei genau einer identischen
|
||
Raumnummer den vorhandenen Raum vor, gruppiert exakte Familie-und-Typ-Werte,
|
||
liefert regelbasierte Objektplanungswerte und Konfliktzahlen und enthält die
|
||
vorhandenen Ebenen, Räume, Verteilungen und ProjectDevices als Auswahlkataloge.
|
||
Unbekannte Familien, ungültige Leistungen/Mengen und Objekte ohne Raum bleiben
|
||
sichtbare Warnungen; es wird keine Entscheidung automatisch bestätigt.
|
||
`POST /api/projects/:projectId/external-csv/initial-import/apply` nimmt Datei,
|
||
erwarteten Hash, Konfigurationsversion und Projektrevision erneut entgegen.
|
||
Vollständige Entscheidungen ordnen jeden Quellraum optional einem vorhandenen
|
||
Raum und einer Standardverteilung sowie jede exakte Familiengruppe optional
|
||
einem vorhandenen ProjectDevice zu. Unklassifizierte Familien oder fehlende
|
||
Gruppenentscheidungen blockieren. Der Server parst und plant erneut, erzeugt
|
||
stabile interne UUIDs und übergibt den vollständigen Zustand an
|
||
`external-import.apply-initial`; CSV-Stromkreiswerte bleiben reine Quellwerte
|
||
und alle `circuitDeviceRowId` bleiben `null`.
|
||
Die Projektseite öffnet über „Revit-CSV“ ein deutsches Modal für Dialekt,
|
||
Spaltenzuordnung, zusätzliche Quellfelder und exakte Familie-und-Typ-Regeln.
|
||
Nach dem revisionierten Speichern kann eine lokale CSV gewählt und über den
|
||
zustandsfreien Endpunkt geprüft werden. Die Oberfläche zeigt Kennzahlen und nur
|
||
die ersten 25 erkannten Objekte; die vollständigen Objekte bleiben in der
|
||
Response verfügbar, ohne alle Zeilen in den DOM einzufügen. Der anschließende
|
||
Erstimport-Wizard gruppiert Quellräume und exakte Familie-und-Typ-Werte. Er
|
||
zeigt eindeutige, mehrdeutige und neue Raumtreffer, lässt vorhandene Räume,
|
||
Standardverteilungen und ProjectDevices explizit zuordnen und blockiert die
|
||
Übernahme bei unklassifizierten Familien. Erst nach einem Bestätigungsdialog
|
||
wird der vollständige Import als eine persistente, rückgängig machbare
|
||
Projektrevision angewendet. Dabei entstehen keine Stromkreise oder Gerätezeilen.
|
||
Fehlende Räume und ProjectDevices können direkt aus der jeweiligen Gruppe über
|
||
die regulären Projektformulare angelegt werden. Revit-Werte befüllen diese
|
||
Formulare vor, werden aber vor dem Speichern sichtbar vom Nutzer bestätigt.
|
||
Die Kataloganlage ist jeweils ein eigener Projekt-Command; der Wizard übernimmt
|
||
den neuen Datensatz anschließend in seinen lokalen Auswahlkatalog und markiert
|
||
ihn für die betroffene Gruppe.
|
||
|
||
## Noch nicht unterstützt
|
||
|
||
- Mehrbenutzerbetrieb und Konfliktauflösung
|
||
- Editor-Oberfläche für die vorhandene Zuordnungslogik, Folgeimport und
|
||
strukturtreuer Revit-Rückexport
|
||
- vollständige elektrische Dimensionierung
|
||
- Produktionsdeployment
|
||
|
||
Details: [Bekannte Einschränkungen](circuit-list-editor-known-limitations.md) und
|
||
[Zukunftsarchitektur](project-history-and-external-model-architecture.md).
|