Version-Workflow (Architekten-Paket-Modell)
Jedes Projekt ist eine lineare Kette von Architekten-Paketen. Ein Paket bündelt drei Dinge zu einer Einheit:
- die Architekten-IFC des Pakets,
- unsere Overrides auf genau dieser IFC (Roombook · Heizlast · Auslegung · Presets),
- alle stamped Review-IFCs, die wir aus diesem Paket exportiert haben (unter
exports/).
Eine neue Version entsteht nur, wenn der Architekt eine Revision liefert. Das Exportieren eines Reviews ist ein Datei-Artefakt innerhalb des aktuellen Pakets, nicht eine neue Version.
V1 Paket = { Arch V1 IFC, Overrides auf V1, exports/ (z.B. 2026-04-20T10-03_review.ifc)}
↓ (Architekt liefert Revision)
V2 Paket = { Arch V2 IFC, Overrides auf V2 (aus V1 migriert), exports/ … }
Kernregeln
VALID_SOURCES={architect_original, architect_revision}—our_reviewist keine Versionsquelle mehr. v2→v3-Migration faltet alle altenour_review-Zeilen in ihr Eltern-Paket ein.- Frozen ⇔ hat Kind. Ein Paket ist eingefroren, sobald ein neueres Paket
es als
parent_idreferenziert. Das Exportieren eines Reviews friert nichts mehr ein. - Nur aktives Paket schreibbar. Jeder Save-on-Blur-Endpoint
(
/roombook/*/override,/heizlast_presets/*,/heizlast/*/surface-*,/sizing/*) prüft die aktive Version und gibt 409 zurück, wenn das Paket eingefroren ist. Das Frontend zeigt dann den History-Banner (siehe unten). - Niemals-Cascade-Delete. Eine Version mit Nachfolger:innen ist nicht löschbar. 409 mit klarer Fehlermeldung.
On-Disk-Layout (schema_version 3)
uploads/<project>/
project.json # {schema_version: 3, active_version_id, versions[]}
logs/ # Projekt-Ebene
migration.log
job_history.jsonl
version_lifecycle.jsonl
compare_cache/ # Diff-Bundles, sha256-keyed
versions/
v1/
<stem>.ifc # Architekten-IFC (+ ggf. MEP-Dateien)
<stem>.roombook.json # Overrides für genau DIESE IFC
<stem>.heizlast.json
<stem>.sizing.json
<stem>.heizlast_presets.json
<stem>.spaces.json
<stem>.connection_graph.json
<stem>.wall_zones_normal.json
room_fingerprints.json
logs/
exports/ # stamped Review-IFCs, exportiert aus V1
2026-04-20T10-03_review.ifc
2026-04-20T10-03_review.json # Sidecar: stats + disclaimer + timestamp + label
v2/ …
Lazy-Migration
- pre-v2 → v2: Flat-Layout-Dateien werden nach
versions/v1/verschoben, Backup inproject.json.v1.bak. - v2 → v3:
tools/_version_migration_v3.pyfaltet jedeour_review-Zeile in ihr Eltern-Paket ein (Caches überschreiben Eltern-Caches, stamped IFC wandert in<parent>/exports/<created_at>_review.ifc). Jedesarchitect_revision, dessen Eltern-Row ein gelöschterour_reviewwar, wird auf den echten Architekten-Vorgänger reparent.frozenwird aushas_childneu berechnet. Backup inproject.json.v2.bak.
Beide Migrationen laufen idempotent beim ersten Touch eines Projekts.
Frontend
Header-Chip
Datum-basiert, ohne Source-Icons. Optional mit 🕓-Badge, wenn auf ein historisches Paket gepinnt. Dropdown listet alle Pakete (neuestes zuerst) — eine Zeile pro Paket, nicht mehrere.
Versionen-Tab (#versions)
Vertikale Architekten-Timeline. Jede Karte ist ein Paket mit:
- Arch-Version + Datum,
- Badges:
aktiv/🕓 historisch/🔒, - Metadaten: Parent-Referenz, Dateianzahl, Größe,
- Migration-Report (falls Revision),
- Cache-Dots pro Cache-Typ,
- Exports-Liste (ausklappbar): pro Export Zeitstempel, Räume-Count, Σ kW, Download- und Lösch-Button,
- Aktionen: Aktiv setzen · Vergleichen mit… · Architekten-IFC ⬇ · Auftauen · Löschen.

Workflow-Wizard (Detail-View)
Persistent 3-Step-Strip, Source-agnostisch — kein Verzweigen nach
active.source mehr. Button-Text in Schritt 2 öffnet das Export-Panel am
#export-Hash, nicht mehr das alte Modal.

Export-Panel (#export)
Einzelne, full-width Seite (kein Modal), die alle Werte listet, die in die gestempelte Review-IFC geschrieben werden. Gruppiert nach IFC-Element-Typ:
IfcSpace— Heizlast-Loads (Pset_SpaceThermalLoad+VflowPset_HeatingDesign, immer)IfcWall/IfcWindow/IfcDoor/IfcSlab—Pset_*Common.ThermalTransmittancepro Sub-Range, per-Leaf-ToggleIfcProject—VflowPset_ReviewMeta(immer)
Pro Gruppe Bulk-Buttons (alle ✔ / alle ☐), global Alle auswählen · Nur
Overrides · Alle abwählen. Nur Overrides tickt automatisch alle Oberflächen
an, deren U-Quelle override oder iso13370 ist.
Der Stamp-Button oben rechts ruft
POST /projects/<p>/versions/<vid>/export-review auf — als Ergebnis landet
eine neue Datei in versions/<vid>/exports/ mit Download-Link im Panel.

History-Banner
Schmaler gelber Banner oben, wenn auf ein nicht-aktuelles Paket gepinnt. Enthält eine Zur aktuellen Version springen-CTA. Save-on-Blur-Endpunkte geben in diesem Modus 409 mit der gleichen Erklärung zurück.

Heizlast-Oberflächen-Zeile
Die vier per-Feld-Writeback-Checkboxen (U / A / Adj / f_k) wurden durch einen einzelnen grünen Status-Dot ersetzt. Dieser ist read-only; ein Klick navigiert zum Export-Panel, wo die eigentliche Flagging-Entscheidung fällt.
API-Endpunkte
| Methode | Pfad | Zweck |
|---|---|---|
GET |
/projects/<p>/versions |
Liste aller Pakete + Health + Exports pro Paket |
POST |
/projects/<p>/versions/<vid>/activate |
Aktiv setzen (Pinning auf historisch → Read-Only) |
DELETE |
/projects/<p>/versions/<vid> |
Löschen (409 wenn Kinder) |
POST |
/projects/<p>/versions/<vid>/unfreeze |
Explizit auftauen (nur leaf ohne Kinder) |
POST |
/projects/<p>/versions/<vid>/export-review |
Review-IFC in exports/ stempeln (→ Job). Keine neue Version. |
GET |
/projects/<p>/versions/<vid>/exports |
Exports-Liste (newest first) |
GET |
/projects/<p>/versions/<vid>/exports/<eid>/download |
Stamped IFC herunterladen |
DELETE |
/projects/<p>/versions/<vid>/exports/<eid> |
Einzelnen Export löschen (IFC + Sidecar) |
POST |
/projects/<p>/versions/<vid>/upload-revision |
Revision → neues architect_revision-Paket + Override-Migration (→ Job) |
POST |
/projects/<p>/versions/compare?a=&b= |
Diff starten (immer Job) |
GET |
/projects/<p>/versions/compare?a=&b= |
Gecachten Diff abrufen |
GET |
/projects/<p>/versions/<vid>/download-ifc |
Architekten-IFC eines Pakets downloaden |
GET |
/projects/<p>/logs/history |
Jobs + Lifecycle-History |
Schritt-für-Schritt
- Initialer Upload. Architekt liefert IFC.
POST /projects/…/uploadlegt bei leerem Projekt automatischv1(architect_original) an. - Bearbeitung. Overrides in Roombook, Presets anpassen, Heizflächen- Kandidaten in Auslegung setzen — alles auf der aktiven Version.
- Export Preview. Detail-Tab → Export-Panel öffnen (oder Nav-Tab
Export). Toggles pro Gruppe/Oberfläche setzen, Disclaimer lesen,
Export stamp & save drücken. Die Datei landet sofort unter
versions/ v1/exports/<timestamp>_review.ifc— keine neue Version entsteht. - Download + Versand. Aus dem Panel oder der Versionen-Timeline die stamped IFC herunterladen und dem Architekten zusenden.
- Revision hochladen. Wenn die überarbeitete IFC zurückkommt: Revision
hochladen im Workflow-Wizard. Die neue Version (
architect_revision) wird alsv2angelegt, Overrides werden per StableRoomKey / GID / Fingerprint-Matching (≥ 80 % Konfidenz automatisch) aufv2migriert.v1wird dadurch automatisch frozen. - Vergleichen. Compare-Tab zeigt Differenzen zwischen zwei beliebigen Architekten-Paketen.
- Nächster Zyklus. Auf
v2starten wir den nächsten Export Preview, die Kette wächst weiter.
Einschränkungen (MVP)
- Keine
IfcSpaceHeater-Geometrie-Erzeugung (Pset-Daten sind für die meisten Tools ausreichend). - Keine automatische Email-Zustellung an den Architekten.
- Compare-Visualisierung nur als Tabelle, nicht in 3D eingefärbt.
- Delete von Versionen mit Kindern bleibt verboten (kein Cascade-Pfad).
Tests
tests/test_versions_unit.py— Lifecycle + Migration + frozen = has-child + Exports-Helpers.tests/test_versions_migration_v3.py— v2→v3-Faltung, dreiteiligige Reparent-Pfad, Idempotency.tests/test_versions_e2e.py— Export-flow schreibt nachexports/, erzeugt keine neue Version; Download; Delete-Export; Frozen-409 auf Mutation; Compare als Job.tests/test_versions_ui.py— Timeline, 3-Step-Wizard, Export Preview (Tree + Bulk + Toggle-Persistence), History-Banner, Surface-Row ohne Writeback-Checkboxen.tests/test_version_migration_unit.py/test_version_diff_unit.py/test_version_diff_fuzz.py/test_ifc_writeback_unit.py/test_project_logger_unit.py— unverändertes Verhalten in v3.