Merge origin/main into feature/user-management

Renumber the users migration to 0013_users so it follows the upstream
0012_good_gateway (logical board feeds); AGENTS.md deferred-work list keeps
both the new feed items and the auth items.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Grovy311 2026-09-28 21:46:21 +02:00
commit 95bfba2f67
63 changed files with 5546 additions and 443 deletions

View file

@ -67,10 +67,13 @@ Prüfsumme; Ersetzen übernimmt die Grobbilanzen atomar und mit Undo/Redo,
Duplizieren vergibt neue IDs. Transferformat 1 bleibt ohne Grobbilanzen
importierbar.
Das aktuelle Projekt-Snapshot-Schema 8 enthält außerdem die optionale
Netto-Raumfläche `rooms[].areaM2`. Snapshot-Versionen 1–7 werden dafür mit
Das aktuelle Projekt-Snapshot-Schema 9 enthält die logischen Einspeisungsverweise
der Verteilungen; Versionen 1–8 werden mit leeren Verweisen hochgestuft. Schema 8
enthält außerdem die optionale Netto-Raumfläche `rooms[].areaM2`.
Snapshot-Versionen 1–7 werden dafür mit
`areaM2 = null` hochgestuft. Restore, Export und Import erhalten vorhandene
Flächen; eine eigene Transferformat-Version ist nicht nötig, weil Format 2 den
Flächen und Einspeisungsverweise; beim Duplizieren werden Board- und Circuit-IDs
neu zugeordnet. Eine eigene Transferformat-Version ist nicht nötig, weil Format 2 den
versionierten Projektsnapshot einbettet.
The public dispatcher supports the Circuit and CircuitDeviceRow commands
@ -254,23 +257,30 @@ commands. Endpoints, payloads and calculation rules: `docs/estimate-balance.md`.
- stale revisions return `409 PROJECT_REVISION_CONFLICT`
- `PUT /projects/:projectId/distribution-boards/:distributionBoardId`
- body:
`{ "floorId": null, "supplyType": "AV", "simultaneityFactor": 1, "expectedRevision": 13 }`
`{ "floorId": null, "supplyType": "AV", "simultaneityFactor": 1, "feedingDistributionBoardId": "board_hv", "feedingCircuitId": "circuit_out", "expectedRevision": 13 }`
- optional info-card fields: `boardNumber` (max. 50), `location`,
`fedFrom` (max. 200 each) and `remark` (max. 2000); strings are trimmed
and an empty string is stored as `null`
- executes `distribution-board.update`; all submitted values, including the
- `feedingDistributionBoardId` and `feedingCircuitId` are optional nullable
fields. A feeding circuit requires a feeding board and must belong to it;
self-links and cycles are rejected. A board-only link creates hierarchy
without assigning its load to an upstream circuit.
- executes `distribution-board.update` schema version 2; all submitted values, including the
submitted info fields, are restored together by persistent Undo/Redo
- `fedFrom` is free text until the logical feed link is modeled
- `fedFrom` remains free text for external feeds such as HAK, metering,
transformer or generator and for supplementary notes
- `POST /projects/:projectId/distribution-boards/:distributionBoardId/copy`
- body: `{ "name": "UV-02 Kopie", "expectedRevision": 14 }`
- duplicates the complete distribution-board subtree with new owning UUIDs
while preserving project-device and room links
while preserving project-device, room and incoming feeding links
- response includes the new `distributionBoard`, its `circuitList`, the
revision and current history state
- `DELETE /projects/:projectId/distribution-boards/:distributionBoardId`
- body: `{ "expectedRevision": 15 }`
- removes the complete, exactly captured distribution-board subtree in one
transaction
- rejects deletion while another board references this board or one of its
circuits as a feeder; circuit and populated-group deletion use the same guard
- response includes `distributionBoardId`, the revision and current history
state
- Copy and deletion use `distribution-board.insert-subtree` and
@ -327,12 +337,17 @@ commands. Endpoints, payloads and calculation rules: `docs/estimate-balance.md`.
### Tree Endpoint
- `GET /projects/:projectId/circuit-trees`
- returns all circuit trees for one project from one project-wide read and is
used by the print view and feeding-board selection
- `GET /projects/:projectId/circuit-lists/:circuitListId/tree`
- Purpose: returns fixed header components, grouped sections with optional
protection components, complete circuit/device-row blocks and auxiliary
footer components. Circuit and component protection devices use their
separate one-to-one DTOs. Calculated row, circuit, section and board totals
remain included.
remain included. Circuit totals contain the demand of linked downstream
boards. `downstreamBoardLoads` exposes those contributions as read-only rows;
`feedingReference` resolves the current board/circuit labels by id.
Response sketch:

View file

@ -33,10 +33,13 @@
- Protection and cable values are planner-owned manual selections. The later
sizing/warning engine does not yet validate them against load, length or
voltage-drop rules.
- Distribution-board `fedFrom` is free text. The print overview derives its
supply structure and "Σ inkl. unterlagert" only from exact text matches with
board numbers/names and adds values without an upstream simultaneity factor
(see `docs/print-view.md`).
- One logical incoming feed per distribution board is supported. A second or
replacement feed with changeover semantics (for example SV/SiBe) is still a
follow-up. `fedFrom` remains the free-text field for external sources and
supplementary notes. Revit does not yet propose logical feed links.
- A logical link without a selected feeding circuit appears in the hierarchy,
but deliberately contributes no load to an upstream circuit until the planner
selects that circuit (see `docs/print-view.md`).
- The print view uses a kbp corporate design derived from logo and
presentation material. Snapshots do not record an editor, so the cover's
Planstände list shows the project's current editor for every entry. On screen, long

View file

@ -468,8 +468,22 @@ Derselbe Befehl versioniert die Felder der Verteiler-Infokarte
(`boardNumber`, `location`, `fedFrom`, `remark`, Migration `0007`). Die
Infokarte liegt im Bearbeiten-Dialog der Verteilung; die Werte sind lokale
Planungswerte und sollen später über den Revit-Abgleich nur nach Vorschau und
ausdrücklicher Bestätigung vorbelegt werden. `fedFrom` ist vorerst Freitext.
Snapshot-Schema 8 enthält zusätzlich die optionale Netto-Raumfläche
ausdrücklicher Bestätigung vorbelegt werden. `fedFrom` bleibt Freitext für
externe Einspeisungen und Hinweise.
`distribution-board.update` verwendet Schema-Version 2 für die optionalen
logischen Verweise `feedingDistributionBoardId` und `feedingCircuitId`.
Version-1-Befehle aus der Historie bleiben ausführbar und verändern diese
Verweise nicht. Der speisende Stromkreis muss zur speisenden Verteilung gehören;
Selbstverweise und Zyklen werden abgelehnt. Löschbefehle für referenzierte
Verteilungen und Stromkreise, einschließlich Unterbaum- und Undo-Pfaden, werden
vor der Datenbankänderung fachlich gesperrt.
Die projektweite Circuit-Tree-Projektion berechnet rekursiv die Lasten aller
Verteilungen. Die Leistung einer Unterverteilung nach ihrem eigenen
Verteiler-GZF wird als virtuelle, schreibgeschützte Zeile genau dem gewählten
Abgang zugerechnet. Eine Verknüpfung ohne Stromkreis bildet nur die Hierarchie.
Snapshot-Schema 9 enthält die beiden Einspeisungsverweise; Versionen 1–8 werden
mit `null` hochgestuft. Restore und Projektduplizierung erhalten beziehungsweise
remappen die Verweise. Snapshot-Schema 8 enthält zusätzlich die optionale Netto-Raumfläche
`rooms[].areaM2`; Versionen 1–7 werden dafür mit `null` hochgestuft.
Snapshot-Schema 7 enthält die Gebäude und die Gebäudezuordnung der Etagen;
ältere Versionen werden ohne Gebäude hochgestuft.
@ -580,7 +594,7 @@ Oberfläche: `/projects/:projectId/grobbilanz`. Details:
`toLowerCase()` gegen das vollständige Register der Stromkreisliste und wird
von jedem Anlage-/Umbenennungspfad für Stromkreise und Verteilerkomponenten
aufgerufen, auch dort, wo zuvor kein Vorab-Check existierte. Snapshot- und
Transfer-Integration verwenden aktuell Snapshot-Schema 8. Persistente
Transfer-Integration verwenden aktuell Snapshot-Schema 9. 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

View file

@ -5,8 +5,9 @@ Die Aktionen für Büroangaben und Logo speichern dagegen globale Einstellungen.
Projekt- und Verteilerangaben werden in den jeweiligen Bearbeitungsdialogen
über Projektbefehle mit Undo/Redo gepflegt.
Beim Laden werden die Projektrevisionen aller Stromkreislisten und ein
abschließend erneut gelesener Projektstand verglichen. Ändert sich das Projekt
Beim Laden werden alle Stromkreislisten in einer projektweiten Abfrage gelesen;
deren Projektrevision und ein abschließend erneut gelesener Projektstand werden
verglichen. Ändert sich das Projekt
währenddessen, wird statt eines gemischten Datenstands eine Aufforderung zum
Neuladen angezeigt. Eine bereits geladene Seitenansicht aktualisiert sich nicht
automatisch bei späteren Änderungen in einem anderen Tab.
@ -31,12 +32,14 @@ automatisch bei späteren Änderungen in einem anderen Tab.
erscheinen als orangefarbenes „[ergänzen]“.
2. **Verteilerübersicht (quer)** – Versorgungsstruktur und Tabelle je
Verteiler mit Stromkreisanzahl, P<sub>inst</sub> (Anzahl × Leistung je
Stück), P<sub>Geräte</sub> (mit Geräte-GZF), Verteiler-GZF,
P<sub>gl</sub>, I<sub>B</sub> und „Σ inkl. unterlagert“.
Stück, nur lokale Geräte), Leistung vor Verteiler-GZF einschließlich
gespeister Unterverteilungen, Verteiler-GZF, P<sub>gl</sub> einschließlich
Unterverteilungen und I<sub>B</sub>. Die Hierarchie folgt den logischen IDs.
3. **Verteilerpläne (quer, je Verteiler)** – Titelleiste mit
Verteilernummer, Bezeichnung, Örtlichkeit, Netzart, „Gespeist von“ und
P<sub>gl</sub>; darunter Kopfkomponenten, Gruppen, Stromkreise
(mehrzeilige mit Sammelzeile und eingerückten Gerätezeilen),
(mehrzeilige mit Sammelzeile, eingerückten Gerätezeilen und
schreibgeschützten Unterverteilungszeilen),
Gruppensummen und Verteilersumme. Fehlende Kabelangaben sind als „offen“
markiert. Die Titelleiste steht im Tabellenkopf und wiederholt sich beim
Drucken auf Folgeseiten.
@ -46,19 +49,25 @@ Seitenformat, Ränder und „Seite x von y“ kommen beim Drucken aus benannten
einfügt. Die Bildschirmansicht zeigt Blätter in Papiergröße; die exakte
Seitenaufteilung langer Verteilerpläne entsteht erst beim Drucken.
## Vorläufige Punkte
## Berechnung und offene Punkte
- **Einspeisung / Hierarchie:** `fedFrom` ist Freitext. Die Übersicht ordnet
einen Verteiler nur dann unter, wenn der Text eindeutig der Nummer oder
Bezeichnung eines anderen Verteilers entspricht (ohne Beachtung von
Groß-/Kleinschreibung und äußeren Leerzeichen). Mehrdeutige Treffer bleiben
ohne Zuordnung; „Σ inkl. unterlagert“ ist
eine einfache Summe ohne übergeordneten GZF. Die fachliche Verknüpfung
(Verteiler und/oder speisender Stromkreis) und die Summierungslogik sind
offen.
- **I<sub>B</sub>** ist ein symmetrischer Drehstromwert
S / (√3 · U<sub>3~</sub>) mit S aus P / cos φ je Gerätezeile
(fehlendes cos φ = 1) und Verteiler-GZF.
- **Einspeisung / Hierarchie:** `feedingDistributionBoardId` bestimmt die
Hierarchie. Ist zusätzlich `feedingCircuitId` gesetzt, fließt die Leistung
der Unterverteilung nach deren eigenem Verteiler-GZF als virtuelle Last in
genau diesen Abgang ein. Ketten werden rekursiv berechnet; mehrere
Unterverteilungen an einem Abgang sind erlaubt. Ohne Abgang bleibt es bei der
Hierarchie ohne Leistungsaufschlag. `fedFrom` bezeichnet nur externe Quellen
oder ergänzende Hinweise.
- **Keine Doppelzählung:** Die Abgangs- und Verteilersummen enthalten die
Unterverteilungsleistung bereits. Deshalb gibt es keine zusätzliche Spalte
„Σ inkl. unterlagert“. Die Summenzeile verwendet für hierarchische Leistungen
nur Wurzelverteilungen; P<sub>inst</sub> summiert weiterhin die lokalen Geräte.
- **I<sub>B</sub>:** S entsteht aus Σ(P / cos φ) für Geräte und den wirksamen
cos φ der Unterverteilungen, jeweils mit dem fachlich zugehörigen GZF. Bei
einem 1-phasigen speisenden Abgang gilt I = S / U<sub>1~</sub>, sonst
I = S / (√3 · U<sub>3~</sub>). Für externe oder nur bis zur Verteilung
bekannte Einspeisungen bleibt die bisherige Darstellung als symmetrischer
Drehstromwert bestehen.
- **Corporate Design:** Farben (`--pd-*` in
`src/frontend/print/print-document.css`) und Schrift (Arial) sind aus Logo
und kbp-Präsentationsmaterial abgeleitet und werden durch die offizielle
@ -118,10 +127,11 @@ ihren Wert.
## Bestehende Datenbanken
Vor dem Anwenden der additiven Migrationen `0007` und `0008` eine verifizierte
Vor dem Anwenden der additiven Migrationen einschließlich `0012` eine verifizierte
Datenbanksicherung mit `npm run db:backup` erstellen. Die neuen Projekt- und
Verteilerfelder bleiben bei bestehenden Datensätzen zunächst leer (`null`).
Snapshot-Schema 6 enthält beide Feldgruppen; die unterstützten Versionen 1–5
werden beim Lesen hochgestuft. Restore und Projektkopie erhalten die neuen
Angaben. Globale Büroangaben und Logo gehören zur Datenbanksicherung, nicht
Snapshot-Schema 9 enthält zusätzlich die logischen Einspeisungsverweise; die
unterstützten Versionen 1–8 werden mit leeren Verweisen hochgestuft. Restore und
Projektkopie erhalten beziehungsweise remappen die neuen Angaben. Globale
Büroangaben und Logo gehören zur Datenbanksicherung, nicht
zum logischen Projektsnapshot oder Projekttransfer.

View file

@ -149,9 +149,10 @@ The pre-release cleanup established the following compatibility boundary:
- [x] Rough power balance for LPH 2/3 by cost group, including the comparison
with the detailed balance and the explicit copy of one row as a
ProjectDevice.
- [x] Logical distribution-board feed link with an optional feeding circuit,
recursive load rollup and deletion guards (#3).
Open follow-ups (Gitea issues): logical feed link between distribution boards
(#3), bill of quantities export (#5), area-based loads in W/m² for
Open follow-ups (Gitea issues): bill of quantities export (#5), area-based loads in W/m² for
ProjectDevices and device rows (#20).
## Recommended Sequence