leistungsbilanz-ts/docs/building-structure.md
Grovy311 cd89c4a499 Add buildings above floors and a building structure page
Projects with several buildings could not be structured: floors and rooms
hung directly off the project. Floors can now belong to a building
(migration 0009: table buildings, nullable floors.building_id). Rooms and
distribution boards keep their floor; their building follows from it.
Existing floors stay without a building.

Buildings use the location-structure command store with
project-building.insert/.update/.delete, inverses and persistent Undo/Redo;
deleting a building with assigned floors is rejected. Floor commands carry
buildingId since command version 2. Version 1 floor commands from existing
history predate buildings and are upgraded with buildingId = null before
they are executed and persisted, so forward and inverse keep one version.

Project snapshot schema 7 stores buildings and floor.buildingId; versions
1-6 are upgraded without buildings. Restore and portable transfer include
buildings, and the transfer remaps building ids.

Buildings, floors and rooms move from the project overview to their own
page /projects/:id/struktur with three columns (Gebäude -> Etagen -> Räume)
that filter each other, and a sidebar entry. Floor selects in the board and
room dialogs are grouped by building. Unchanged dialogs close without a
command. Details in docs/building-structure.md; see issue #6.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 12:52:34 +02:00

4 KiB
Raw Blame History

Gebäudestruktur (Gebäude → Etagen → Räume)

Projekte mit mehreren Gebäuden werden über eine eigene Ebene Gebäude gegliedert. Etagen können einem Gebäude zugeordnet sein, Räume und Verteilungen hängen wie bisher an der Etage. Das Gebäude eines Raums oder einer Verteilung ergibt sich also aus der Etage; eine zweite, konkurrierende Zuordnung gibt es nicht. Abstimmung mit Julian: Issue #6.

Datenmodell

Tabelle Feld Bedeutung
buildings id, project_id (FK, cascade), name, sort_order Gebäude eines Projekts
floors building_id (nullable FK → buildings, ON DELETE set null) optionales übergeordnetes Gebäude

Migration 0009_buildings. Bestehende Etagen behalten building_id = null und erscheinen in der Oberfläche als „Ohne Gebäude“. Es gibt keine Zwangsmigration und kein automatisch angelegtes Standardgebäude.

Befehle, Undo/Redo

Alle Änderungen laufen über die bestehende Orts-Struktur (ProjectLocationStructureProjectCommandRepository) mit Revision, Inverse und persistentem Undo/Redo:

  • project-building.insert / project-building.delete mit vollständigem Gebäude-Snapshot (Schema-Version 1)
  • project-building.update: ändert nur den Namen
  • Löschen eines Gebäudes wird abgelehnt, solange Etagen zugeordnet sind („Das Gebäude kann nicht gelöscht werden, solange Etagen zugeordnet sind.“)
  • Etagenbefehle project-floor.insert/.update/.delete haben seit Schema-Version 2 das Feld buildingId. project-floor.update darf Name und/oder Gebäude ändern, nicht aber sortOrder. Ein referenziertes Gebäude muss zum Projekt gehören.
  • Version-1-Etagenbefehle aus bestehender Historie bleiben ausführbar. Sie stammen aus der Zeit vor den Gebäuden und werden vor der Ausführung mit buildingId = null auf Version 2 gehoben; auch die daraus neu gespeicherten Vorwärts- und Inversbefehle sind Version 2. Das ist bei linearer Historie exakt: Wird ein Gebäude später zugeordnet, liegt dieser neuere Befehl im Undo-Stapel vor dem alten Befehl und wird zuerst zurückgenommen.
  • Raumbefehle bleiben unverändert (Version 1).

Snapshots und Transfer

Projekt-Snapshot-Schema 7 enthält buildings und floors[].buildingId. Alle älteren unterstützten Versionen (1–6) werden beim Einlesen mit leerer Gebäudeliste und buildingId = null hochgestuft; gespeicherte Sicherungspunkte bleiben wiederherstellbar. Die Relationen werden geprüft (Gebäude gehört zum Projekt, buildingId verweist auf ein Gebäude des Snapshots). Restore löscht und schreibt Gebäude zusammen mit den Etagen; der Projekt-Transfer vergibt neue Gebäude-IDs und stellt die Etagenverweise um.

API

  • GET /api/projects/:projectId/buildings – Gebäude sortiert nach sortOrder, Name
  • POST /api/projects/:projectId/buildings – { "name": "Haus A", "expectedRevision": 3 }
  • PUT /api/projects/:projectId/buildings/:buildingId – { "name": "Haus B", "expectedRevision": 4 }
  • DELETE /api/projects/:projectId/buildings/:buildingId – { "expectedRevision": 5 }
  • POST/PUT /api/projects/:projectId/floors[/:floorId] akzeptieren zusätzlich optional buildingId (string | null). Fehlt das Feld, bleibt beim Bearbeiten das bisherige Gebäude erhalten; ältere Clients funktionieren unverändert.

Oberfläche

Gebäude, Etagen und Räume werden auf der eigenen Seite /projects/:projectId/struktur („Gebäudestruktur“) gepflegt, erreichbar über die Seitenleiste und die Kennzahlen der Projektübersicht. Drei Spalten Gebäude → Etagen → Räume filtern sich gegenseitig: Klick auf ein Gebäude zeigt nur dessen Etagen, Klick auf eine Etage nur deren Räume, „Alle“ hebt den Filter auf. Hinzufügen, Bearbeiten und Löschen laufen über Icon-Buttons wie in der Stromkreisliste.

Offen

  • Revit: Das Gebäude kann später aus einem Revit-Parameter kommen und über die bestehende CSV-Zuordnung gemappt werden (Frage an Julian in Issue #6).
  • Sortierung von Gebäuden per Drag-and-drop ist noch nicht umgesetzt; neue Gebäude werden hinten angehängt.