14 KiB
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 und ihre API sind entfernt. Die Tabelle
consumers sowie Mappings und Reports bleiben ausschließlich erhalten, damit
ältere Datenbanken über den expliziten Upgrade-Befehl migriert und geprüft werden
können.
Laufzeit
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ätebibliotheksrc/app/projects/[projectId]/page.tsx– Projektstammdaten, Verteilungen, Räume und Projektgerätesrc/app/projects/[projectId]/circuit-lists/[circuitListId]/tree-edit/page.tsx– unterstützte Editorroutesrc/frontend/components/circuit-tree-editor.tsx– Editorzustand, Befehlsausführung, Drag-and-drop und der schrittweise Historien-Cutoversrc/frontend/components/circuit-grid-*.ts– reine Grid-Projektion, Zellbesitz, Einfügen und Sicherheitsregelnsrc/frontend/utils/api.ts– typisierte Frontend-API-Aufrufesrc/server/index.tsundsrc/server/routes/– API-Kompositionsrc/domain/services/– fachliche Command- und Synchronisierungsregelnsrc/db/repositories/– Abfragen, Persistenzmapper und Transaktionsadaptersrc/db/schema/undsrc/db/migrations/– SQLite-Schema und Migrationen
Daten- und Befehlsfluss
- Das Grid projiziert den geladenen Circuit-Tree in sichtbare Zeilen.
- Eine Benutzeraktion wird im Frontend validiert und als API-Befehl gesendet.
- Controller validieren Requestdaten mit Zod.
- Domain-Services prüfen fachliche Regeln wie BMK-Eindeutigkeit, Abschnittszuordnung und Reserveverhalten.
- Repositories schreiben Daten. Kritische Mehrfachschreibvorgänge besitzen explizite SQLite-Transaktionsadapter mit Commit-/Rollback-Integrationstests.
- 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. Ein getestetes Repository kann diese Historienmetadaten optimistisch
und atomar fortschreiben. 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- 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.
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,
Legacy-Consumer und Migrationsberichte 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. Kompatible
Upgrade-only-Verknüpfungen und Migrationsnachweise bleiben erhalten, obwohl sie
nicht Bestandteil des logischen Snapshots sind.
Die Projektseite bindet diese APIs in einem einklappbaren Bereich
„Versionen und Sicherungspunkte“ ein. Dort können Benutzer Sicherungspunkte
benennen, nach expliziter Bestätigung wiederherstellen und die paginierte
Revisions-Timeline mit deutschen Quellen- und Änderungsbezeichnungen lesen.
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.
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 die beiden Projekt-Standardspannungen als
eine atomare Änderung. 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.
Projektgeräte
ProjectDevice verwendet ausschließlich die kanonischen Circuit-First-Felder:
phaseType, powerPerUnit, simultaneityFactor, cosPhi, remark sowie
optionale technische und kategorisierende Felder.
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:migratewendet Drizzle-Migrationen an.npm run db:verify:circuit-schemaprüft erforderliche und entfernte Spalten.npm run db:backuperzeugt ein konsistentes und verifiziertes Online-Backup.- Angewendete Migrationen werden niemals nachträglich verändert.
db:migrate:legacy-consumersist Upgrade-Werkzeug, kein Anwendungspfad.
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.
Noch nicht unterstützt
- Mehrbenutzerbetrieb und Konfliktauflösung
- Revit-/CSV-/IFCGUID-Round-trip
- vollständige elektrische Dimensionierung
- Produktionsdeployment
Details: Bekannte Einschränkungen und Zukunftsarchitektur.