leistungsbilanz-ts/docs/building-structure.md

6.2 KiB
Raw Permalink 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. Abgestimmt in Issue #6: Das Modell ist so bestätigt, und Gebäude mit zugeordneten Etagen lassen sich nicht löschen.

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
rooms area_m2 (nullable REAL) optional gepflegte Netto-Raumfläche in m²

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. Vor dem Anwenden der Migration auf eine bestehende Datenbank ist wie bei jeder Schemamigration eine separate Datenbanksicherung anzulegen.

Migration 0011_glossy_norman_osborn ergänzt ausschließlich das nullable Feld rooms.area_m2. Bestehende Räume behalten damit eine unbekannte Fläche. Vor dem Anwenden auf eine bestehende Datenbank ist ebenfalls eine separate Datenbanksicherung erforderlich.

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 project-room.insert/.update/.delete haben seit Schema-Version 2 das Feld areaM2. Version-1-Befehle werden beim Einlesen mit areaM2 = null hochgestuft. Vor einem alten Update oder Delete wird weiterhin der vollständige erwartete Datensatz verglichen; eine inzwischen vorhandene Fläche kann deshalb nicht unbemerkt gelöscht werden.

Snapshots und Transfer

Projekt-Snapshot-Schema 8 enthält zusätzlich rooms[].areaM2. Version 7 wird mit areaM2 = null hochgestuft; die älteren unterstützten Versionen 1–6 werden außerdem 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 und Projekttransfer erhalten die Raumfläche. Das portable Transferformat bleibt Version 2, weil es den versionierten Projektsnapshot bereits einbettet; beim Duplizieren werden nur IDs und Relationen umgesetzt.

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.
  • POST/PUT /api/projects/:projectId/rooms[/:roomId] akzeptieren zusätzlich optional areaM2 (number | null, endlich und ≥ 0). Beim Anlegen bedeutet ein fehlendes Feld null; beim Bearbeiten bleibt die vorhandene Fläche erhalten, wenn das Feld fehlt.

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.

Der Raumdialog pflegt die optionale Fläche [m²] mit deutscher Dezimaltrennzeichen-Eingabe. Gemeint ist die Netto-Raumfläche, wie sie der Revit-Raumparameter „Fläche“ liefert, nicht eine Flächenart nach DIN 277. Die Fläche wird ohne fachliche Rundung gespeichert und mit zwei Nachkommastellen angezeigt. Die Gebäudestruktur zeigt die Fläche je Raum sowie Summen je Etage, je Gebäude, „Ohne Etage“ und „Ohne Gebäude“. Fehlende Flächen werden nicht als Nullfläche ausgegeben, sondern separat gezählt, damit Teilsummen erkennbar bleiben.

Offen

  • Revit: Eine Übernahme des Gebäudes aus Revit ist derzeit nicht geplant. Die abgeschlossene Phase 14 verwendet Linear-XLSX; das Modell steht der expliziten Raumzuordnung im Importwizard nicht im Weg.
  • Raumflächen werden derzeit ausschließlich manuell gepflegt. Ein späterer Revit-Abgleich muss die Phase-14-Regeln mit externem Modellzustand, Vorschau und ausdrücklicher Bestätigung einhalten.
  • Eine W/m²-Auswertung oder Übernahme der Raumfläche in Flächenlasten ist nicht Teil dieser Funktion; das ist Folgethema von Issue #20.
  • Sortierung von Gebäuden per Drag-and-drop ist noch nicht umgesetzt; neue Gebäude werden hinten angehängt.