leistungsbilanz-ts/docs/spec/revit-excel-integration-requirements.md
Julian Appel 85cbdbf8e0 Specify Revit assignment dialog and per-project socket limit
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 21:10:23 +01:00

655 lines
30 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Revit-Integration über Linear-Excel – verbindliche Anforderungen
Stand: 29.09.2026. Dieses Dokument ist die fachliche und technische
Arbeitsgrundlage für die neue Phase 14. Es ersetzt die frühere CSV-/IfcGUID-
Spezifikation. Der Umsetzungsstand steht im
[R0–R10-Plan](revit-excel-phase-14-plan.md); der geprüfte Ausgangszustand im
[R0-Audit](revit-excel-r0-audit.md).
## 1. Ziel und Grenzen
Der Austausch mit Revit erfolgt ausschließlich über den XLSX-Export/-Import
des Linear-Plugins. Eine vollständige Revit-Bauteilliste wird importiert, in
Leistungsbilanz geplant und mit gleichem Tabellenaufbau an Linear
zurückgegeben. Linear ordnet enthaltene Zeilen anhand der Worksharing-ID zu.
Nicht Teil dieser Phase sind Dynamo, Revit-API, JSON-Transport, automatische
Stromkreisbildung, Übernahme vorhandener Revit-Stromkreiswerte,
Teilimporte, mehrere Modellquellen, PostgreSQL und neue Rollen/Rechte.
Die Integration bleibt optional. Manuelle Projekte, Räume, ProjectDevices,
Stromkreise und Gerätezeilen funktionieren ohne externes Modell. Der
Circuit-First-Aufbau, stabile interne UUIDs und BMKs, ausdrückliche
Neunummerierung sowie die gemeinsame Project-Command-Transaktionsgrenze
bleiben unverändert.
## 2. Verbindliche fachliche Regeln
- Import erzeugt keine `CircuitDeviceRow`, keinen `Circuit` und kein BMK.
- Quellwerte, lokale Planungswerte und Overrides bleiben getrennt.
- Ein Folgeimport überschreibt keine lokale Planung still.
- Fehlende Objekte werden markiert und erst nach ausdrücklicher Bestätigung
entfernt.
- Mehrfachsteckdosen sind unteilbare externe Objekte. Ihre wirksame Menge kann
größer als eins sein.
- Die Row-Menge ist
`manualQuantity + Summe(effectiveQuantity der verknüpften Objekte)`.
- Nach einer Row-Zuordnung ist die `CircuitDeviceRow` die Planungsebene für
alle verknüpften Objekte.
- Bestehende ProjectDevices bleiben kanonische Vorlagen und werden durch
Importe nie verändert.
- Sortieren, Filtern, Importieren, Zuordnen und Verschieben nummeriert keine
Stromkreise automatisch neu.
## 3. Linear-XLSX-Profil
Die lokale Referenzdatei `docs/spec/kbp-Stromkreis.xlsx` enthält vertrauliche
Projektdaten. Sie wird nicht committed und nicht in Tests eingebettet. Tests
erzeugen synthetische Workbooks. Der lokale Referenzprüfer erhält den Pfad als
Argument.
Beobachtetes Profil:
- genau ein Arbeitsblatt; Blattname nach Excel-Regel maximal 31 Zeichen;
- Kopfzeile in Zeile 1, Zeile 2 leer, Daten ab Zeile 3, erste Datenspalte A;
- Spalte A `Worksharing-ID` im Format `<GUID>-<8 Hex>`;
- Parameterbindungen stehen als klassische Excel-Kommentare in den übrigen
Kopfzellen;
- Zahlen sind typisierte Excel-Zahlen; importierte Werte bleiben unverändert,
fachlich verwendete Leistung wird auf 0,01 W projiziert;
- Objektzeilen dürfen keinen MEP-Raum besitzen;
- eine Schluss-/Summenzeile ohne ID kann vorkommen und wird weder importiert
noch zurückgegeben.
Die Referenzdatei enthält 487 Objektzeilen, eindeutige Worksharing-IDs und
keine doppelten nichtleeren IfcGUIDs bei exaktem, case-sensitivem Vergleich.
Ihre Summenzeile steht in Spalte B (`CAx_Auswahlkenner`), während
`Familie und Typ` leer ist.
### Zeilen ohne Worksharing-ID
Nur eine Zeile ohne Worksharing-ID, aber mit befülltem Feld
`Familie und Typ`, gilt als verdächtige Objektzeile. Sie erzeugt einen Hinweis
und wird übersprungen; sie blockiert den Import nicht. Andere Zeilen ohne ID,
einschließlich einer nur in Spalte B befüllten Summenzeile, werden ohne Hinweis
übersprungen. Eine Objektzeile ist für den Import eine Zeile mit nichtleerer
Worksharing-ID.
Worksharing-ID und IfcGUID werden stets exakt, ordinal und mit
Groß-/Kleinschreibung verglichen. Es findet kein Trimmen, Normalisieren oder
Case-Folding für die Identität statt. Eine nichtleere Worksharing-ID mit
unerlaubten äußeren Leerzeichen oder falschem Format blockiert. Doppelte
Worksharing-IDs blockieren. IfcGUID ist optional, kein Schlüssel und darf
doppelt vorkommen; Duplikate erzeugen lediglich einen Hinweis.
## 4. Upload und Transportadapter
Der Server akzeptiert ausschließlich Dateien mit Endung `.xlsx` bis 10 MiB.
`.xls` und `.xlsm` werden abgelehnt. Parsing findet serverseitig statt. Nach
dem Einlesen gelten feste Zeilen-, Spalten- und Zellgrenzen, die in R2 anhand
synthetischer Grenztests festgelegt und zentral definiert werden. Es gibt in
dieser Phase keinen eigenen ZIP-Prüfer und keinen Parser-Worker.
Der Adapter unter `src/external-model/xlsx` liest eine transportneutrale
Zellmatrix. Eine Zelle ist `string`, `number`, `boolean` oder `empty`.
Zusätzlich werden Blattname, Originalzeilennummer, Kopfzeilenkommentare,
Spaltenbreiten und die für Hinweise nötigen Formelmetadaten erfasst.
Domain-Services kennen weder ExcelJS noch XLSX, React oder SQLite.
Formeln werden niemals ausgeführt. Ist ein gecachter skalarer Wert vorhanden,
wird er verwendet und als Hinweis ausgewiesen. Fehlt er oder ist er ein
Fehlerwert, bleibt das Feld leer; bei der Worksharing-ID oder einem anderen
Pflichtfeld blockiert dies die betreffende Objektzeile beziehungsweise den
Import.
Genau eine gepflegte Bibliothek wird ergänzt. Vorgesehen ist `exceljs`, sofern
R2 die Node-24-Verträglichkeit und den Roundtrip von Kopfkommentaren,
Blattname, Spaltenbreiten, Formaten und Zelltypen bestätigt.
## 5. Projektkonfiguration
Die Konfiguration ist projektweit, revisionssicher und besitzt keine eigene
Versionszählung. Jeder Plan und jedes Apply tragen `expectedRevision`.
Da die Projektrevision auch bei Undo/Redo strikt steigt, wird ein alter Plan
automatisch ungültig. Jeder Importbatch speichert eine vollständige Kopie der
beim Import verwendeten Konfiguration.
Das Einstellungsmodal auf der Revit-Seite erkennt aus einer zustandslos
hochgeladenen Musterdatei Kopfzeile, erste Datenzeile und erste Datenspalte.
Diese Werte bleiben editierbar; Standard ist 1 / 3 / A. Es gibt nur ein Feld
für die Identitätsspalte: `columns.worksharingId`. Ein separates
`layout.idColumn` existiert nicht.
Zielvertrag:
```ts
interface ExternalModelConfiguration {
schemaVersion: 2;
layout: {
headerRow: number;
firstDataRow: number;
firstDataColumn: number;
};
circuitMode: "combined" | "separate";
columns: {
worksharingId: string;
ifcGuid: string | null;
roomNumber: string | null;
roomName: string | null;
familyAndType: string;
selectionMarker: string | null;
socketCount: string | null;
sourceRemark: string | null;
circuitCombined: string | null;
boardName: string | null;
circuitIdentifier: string | null;
designation: string | null;
electricalPowerW: string | null;
voltageV: string | null;
currentA: string | null;
};
deviceTypes: DeviceTypeConfiguration[];
familyTypeRules: FamilyTypeRule[];
}
```
Schema-Version 2 ergänzt nur das Geräteart-Merkmal `isSocket`
(Abschnitt 6). Konfigurationen der Version 1 – auch Kopien in Importbatches,
History-Commands und Snapshots – werden beim Lesen hochgestuft.
Der Steckdosen-Höchstwert je Stromkreis ist **keine** Revit-Einstellung,
sondern eine allgemeine Projekteinstellung der Leistungsbilanz:
`Project.maxSocketsPerCircuit` (positive ganze Zahl oder `null` = keine
Grenze), auftraggeberabhängig und in den Projekteinstellungen gepflegt. Er
wird über `project.update-settings` (Schema-Version 4) geändert; Versionen
1–3 bleiben ausführbar und lassen den Wert unverändert. Snapshot-Schema 11
und der Projekttransfer enthalten ihn; ältere Stände werden mit `null`
hochgestuft.
Standardzuordnung:
| Schlüssel | Bedeutung | Standardspalte |
| --- | --- | --- |
| `worksharingId` | externe Identität, Pflicht | `Worksharing-ID` |
| `ifcGuid` | optionale Redundanz | `IfcGUID` |
| `roomNumber` | Raumnummer | `MEP-Raum: Nummer` |
| `roomName` | Raumname | `MEP-Raum: Name` |
| `familyAndType` | Familie und Typ, Pflicht | `Familie und Typ` |
| `selectionMarker` | CAx-Auswahlkenner | `CAx_Auswahlkenner` |
| `socketCount` | Anzahl Einzelsteckdosen | `CAX_AnzahlObjekte` |
| `sourceRemark` | Anmerkung | `CAx_Anmerkung` |
| `circuitCombined` | Stromkreis gesamt | `kbp_Stromkreisnummer` |
| `boardName` | Verteiler | `kbp-E-Verteiler` |
| `circuitIdentifier` | Stromkreis-BMK | `kbp-E-Stromkreis` |
| `designation` | Bezeichnung | `kbp-E-Bezeichnung` |
| `electricalPowerW` | elektrische Leistung [W] | `kbp-E-Elektrische Leistung` |
| `voltageV` | Spannung [V] | `kbp-E-Spannung` |
| `currentA` | Stromstärke [A] | `kbp-E-Stromstärke` |
`worksharingId` und `familyAndType` sind Pflichtmappings. Im Modus
`combined` ist `circuitCombined` für den Rückexport Pflicht; im Modus
`separate` sind `boardName` und `circuitIdentifier` Pflicht. Fehlende optionale
Rückgabespalten `designation`, `electricalPowerW`, `voltageV` und `currentA`
werden mit Hinweis übersprungen und blockieren den Export nicht.
Jedes interne Feld besitzt im Modal ein Dropdown aus den Kopfzellen und eine
freie Eingabe. Exakte kbp-Standardnamen werden vorbelegt. Typ und Einheit aus
dem Linear-Kommentar werden angezeigt. Nicht gemappte Spalten bleiben beim
Rückexport unverändert.
## 6. Gerätearten und Familie-und-Typ-Regeln
Eine Geräteart besitzt stabile interne UUID, Name, Kategorie
`lighting | single_phase | three_phase` sowie optionale Standardwerte für
Leistung je Einheit in W, GZF, cosPhi und Kostengruppe. Jede exakte
`Familie und Typ`-Regel verweist auf genau eine Geräteart und verwendet die
Mengenregel `1` oder `socketCount`.
Jede Geräteart trägt zusätzlich das Merkmal `isSocket` („Steckdose“). Nur
Objekte solcher Gerätearten zählen für den Steckdosen-Höchstwert je
Stromkreis (Abschnitt 11), unabhängig von ihrer Kategorie. Beim Hochstufen
einer Konfiguration der Version 1 und beim Anlegen im Wizard wird `isSocket`
mit `true` vorbelegt, wenn eine Familienregel dieser Geräteart die
Mengenregel `socketCount` verwendet; der Planer kann das Merkmal ändern.
Mehrere Revit-Familien dürfen auf dieselbe Geräteart zeigen. Jedes Revit-
Objekt bleibt trotzdem einzeln über seine Worksharing-ID nachverfolgbar.
Unbekannte Familien müssen im Importwizard zugeordnet oder über eine neue
Geräteart klassifiziert werden; andernfalls blockiert Apply.
Planungsstartwerte folgen dieser Reihenfolge:
1. ausdrücklich verknüpftes ProjectDevice;
2. Geräteart-Standard;
3. leer.
Der Anzeigename wird aus CAx-Auswahlkenner, dann Geräteartname, dann
`Familie und Typ` vorgeschlagen. Ein fehlender GZF wird mit `1` vorbelegt,
ohne zusätzliche Bestätigung. Standardwerte sind Startwerte, keine dauerhafte
Synchronisierung.
## 7. Persistenter externer Zustand
Pro Projekt existiert genau eine implizite Revit-XLSX-Quelle. Ein externes
Objekt besitzt eine interne UUID und ist je `(sourceId, worksharingId)`
eindeutig. `worksharingId` ist NOT NULL; `ifcGuid` ist nullable und nicht
eindeutig. Interne Relationen verwenden ausschließlich interne UUIDs.
Gespeichert werden:
- akzeptierte Quellwerte einschließlich aller Rückgabefelder;
- lokale Planungswerte und Override-Felder;
- Geräteart;
- optionales Raum-Mapping, abweichender Verteiler, ProjectDevice und
`CircuitDeviceRow`;
- Anwesenheitsstatus und Verweis auf den zuletzt relevanten Import;
- effektive Menge als fachlicher Wert des unteilbaren Objekts.
Der effektive Verteiler eines verknüpften Objekts ist immer der Verteiler
seiner Row. Für ein unzugeordnetes Objekt gilt zuerst die explizite
Objektabweichung, danach der Standardverteiler seines Raum-Mappings. Ändert
sich der Standardverteiler eines Raums, betrifft das nur unzugeordnete
Objekte; verknüpfte Objekte bleiben über ihre Row unverändert und die Änderung
wird deshalb nicht gesperrt.
## 8. Importbatch-Aufbewahrung, Snapshot und Transfer
Der aktive Projektzustand enthält den letzten Importbatch vollständig:
Originalbytes, klassifizierte Matrix, Dateiname, SHA-256, Zeitpunkt,
Objektzahl, Importart, Projektrevision und Konfigurationskopie. Ältere Batches
werden zu Metadaten reduziert: Datum, Dateiname, SHA-256 und Objektzahl.
Sie enthalten keine Originalbytes, Matrix oder Konfigurationskopie mehr.
Snapshot-Schema 10 und portabler Projekttransfer übernehmen genau diese
Aufteilung. Beim Duplizieren werden alle internen UUIDs und Links remapped;
Worksharing-IDs, optionale IfcGUIDs, Quellwerte und das letzte Workbook bleiben
unverändert.
Versionen 1–9 ohne externe CSV-Daten werden verlustfrei auf Version 10
hochgestuft. Enthält ein alter Stand eine CSV-Konfiguration oder einen nicht
leeren CSV-Zustand, wird er mit klarer deutscher Fehlermeldung abgelehnt.
Alte CSV-History-Commands werden ebenfalls vor jedem Write abgelehnt und nie
stillschweigend übersprungen.
## 9. Erstimport
Der Ablauf ist Upload → zustandslose Vorschau/Planung → erneute
Dateiübertragung bei Apply. Apply prüft SHA-256, `expectedRevision`,
Konfigurationskopie, Matrix und sämtliche Entscheidungen erneut. Nur Apply
liest die Excel-Datei erneut ein.
Undo und Redo lesen keine Excel-Datei und parsen keine gespeicherten Bytes.
Sie arbeiten ausschließlich auf den im Command gespeicherten vollständigen
Vorher-/Nachher-Zuständen. Dadurch bleiben sie nach Neustart deterministisch
und unabhängig vom Parser.
Der Wizard umfasst:
1. Vorschau mit Objektzahl, übersprungenen und verdächtigen Zeilen,
doppelten Worksharing-IDs, doppelten IfcGUID-Hinweisen, unbekannten
Familien, nicht lesbaren Zahlen und Formeln;
2. Räume anlegen oder vorhandenen Räumen/Ebenen zuordnen;
3. Standardverteiler je Raum, Sammelzuordnung, Objektabweichungen und Objekte
ohne Raum;
4. Familien exakt Gerätearten und einer Mengenregel zuordnen;
5. optional vorhandene oder neu angelegte ProjectDevices verknüpfen;
6. Zusammenfassung und ausdrückliche Bestätigung.
Die Übernahme ist ein atomarer Command und ein Undo-Schritt. Im Import
entstehen keine Rows. Neu angelegte Räume und ProjectDevices verwenden ihre
vorhandenen Commands und bleiben eigene Undo-Schritte.
## 10. Objektplanung und Revit-Seite
Route: `/projects/:projectId/revit`, erreichbar aus der Projektnavigation.
Der Revit-Button und das CSV-Modal auf der Projektübersicht entfallen.
Die Seite besitzt:
- Statuskarte mit letztem Import, Objektzahl, ohne Verteiler, ohne
Stromkreis, fehlend und Abweichung zu Revit;
- Aktionen `Import`, `Rückgabe-Excel`, `Einstellungen`;
- einklappbare Geräteart-/Familienregel-Übersicht;
- kompakte Objekttabelle mit Suche, Spaltenfiltern, Sortierung,
Mehrfachauswahl und Sammelzuordnung für Verteiler, ProjectDevice und
Planungswerte.
Die kompakte Liste wird einmal geladen, vollständig im Client gefiltert und
sortiert und virtualisiert dargestellt. Es gibt keine Server-Pagination.
Originalbytes, Matrix und Command-Payloads gehören nicht in dieses DTO.
Vor Row-Zuordnung lassen sich Leistung je Einheit, GZF, cosPhi,
Kostengruppe, Anzeigename und Bemerkung einzeln oder gesammelt ändern.
Geänderte Felder werden Overrides. Nach Row-Zuordnung werden diese Werte im
Grid an der Row bearbeitet. Beim ausdrücklichen Lösen erhält das Objekt die
aktuellen Row-Werte als Planungswerte und entsprechende Overrides.
## 11. Editor-Zuordnung und Löschen
Stand 30.10.2026: Dieser Abschnitt ersetzt den R7-Editorbereich (rechter
Drawer mit Gruppen-Drag direkt ins Grid). Der Drawer konnte gleichartige
Objekte eines Raums nur gesamt oder einzeln zuordnen und kannte keinen
Steckdosen-Höchstwert. Die drei R7-Zuordnungscommands bleiben für gespeicherte
History-Einträge ausführbar; die Editor-UI verwendet sie nicht mehr.
Umsetzung: Pakete R11–R14 im [Phasenplan](revit-excel-phase-14-plan.md).
### 11.1 Grundsatz
- Ein Revit-Objekt (eine Familieninstanz, z. B. eine Doppelsteckdose mit
wirksamer Menge 2) ist unteilbar. Es ist mit höchstens einer Row verknüpft
und gehört damit immer zu genau einem Stromkreis.
- Aufgeteilt wird ausschließlich auf Objektebene: Die 8 Doppelsteckdosen eines
Raums (16 wirksame Steckdosen) können auf mehrere Stromkreise verteilt
werden, eine einzelne Doppelsteckdose nie.
- Zugeordnet wird über den Zuordnungsdialog. Drag-and-drop findet innerhalb
des Dialogs statt, nicht direkt aus einer Seitenleiste ins Grid.
### 11.2 Zuordnungsdialog „Revit-Objekte zuordnen“
Öffnen:
- Werkzeugleiste des Editors: „Revit-Objekte zuordnen (N)“, N = Zahl der
zuordenbaren Objekte des Verteilers;
- Kontextmenü eines Stromkreises oder einer Row: derselbe Dialog mit
vorausgewähltem und sichtbar markiertem Ziel.
Gezeigt werden vorhandene (`present`), unzugeordnete Objekte, deren
effektiver Verteiler der aktuelle Verteiler ist. Objekte ohne Verteiler
erscheinen nur als Hinweis „N Objekte ohne Verteiler – auf der Revit-Seite
zuordnen“.
Der Dialog ist großflächig und zweigeteilt.
Links, Objektbereich:
- Baum Raum → Gruppe → Objekt. Raumknoten zeigen Nummer, Name und die Summe
der wirksamen Steckdosen. Gruppen verwenden die Schlüssel interner Raum,
Auswahlkenner, Geräteart, Kategorie, identische Planungswerte und
ProjectDevice-Link und zeigen Objektzahl und Mengensumme.
- Jede Objektzeile zeigt `Familie und Typ`, die wirksame Menge (z. B. „2ד)
und die Worksharing-ID (gekürzt, vollständig im Tooltip).
- Checkboxen auf allen Ebenen (Raum und Gruppe dreiwertig). Klick wählt aus,
Strg+Klick schaltet um, Umschalt+Klick wählt einen Bereich.
- Suche über Raum, Familie, Auswahlkenner und Worksharing-ID; Filter
Geräteart und „nur Steckdosen“.
- Fußzeile: „6 Objekte · 12 Steckdosen · 2 Räume“ und die Aktionen
„Zuweisen an …“ und „Automatisch aufteilen …“.
Rechts, Zielbereich:
- Stromkreise des Verteilers nach Stromkreisgruppen, je Zeile BMK, Name und
Belegung „6 / 8 Steckdosen“ (ohne Höchstwert nur die Zahl).
- Aufklappbar bis auf die Rows einschließlich geplanter neuer Rows.
- Je Gruppe ein Ablagefeld „Neuer Stromkreis“.
- Geplante, noch nicht übernommene Zuordnungen sind farblich markiert und
lassen sich einzeln zurücknehmen oder per Drag zurück in den Objektbereich
legen.
### 11.3 Drag-and-drop und Tastatur
- Die aktuelle Auswahl (oder das gezogene Objekt, wenn es nicht ausgewählt
ist) wird auf ein Ziel im Zielbereich gezogen:
- auf eine Row: genau diese Row;
- auf einen Stromkreis: Row-Bildung nach 11.4;
- auf „Neuer Stromkreis“: neuer Stromkreis in dieser Gruppe, Row-Bildung
nach 11.4.
- Während des Ziehens sind gültige Ziele hervorgehoben. Ungültige Ziele
(andere Kategorie) sind ausgegraut und nennen den Grund im Tooltip. Ziele,
deren Höchstwert überschritten würde, bleiben gültig, zeigen aber die
künftige Belegung in Warnfarbe, z. B. „10 / 8“.
- Tastaturalternative: „Zuweisen an …“ öffnet eine Zielauswahl mit allen
Stromkreisen und „Neuer Stromkreis in Gruppe …“.
- Ein Drop schreibt nichts. Er erweitert den lokalen Zuordnungsplan des
Dialogs (11.7).
### 11.4 Row-Bildung im Zielstromkreis
Die einem Stromkreis zugewiesenen Objekte werden nach den Gruppenschlüsseln
aus 11.2 zusammengefasst; jede Teilgruppe ergibt einen Row-Vorschlag. Objekte
aus mehreren Räumen ergeben damit mehrere Rows im selben Stromkreis.
- Existiert im Stromkreis eine Row mit gleichem Raum, gleicher Kategorie,
gleichem Auswahlkenner und kompatiblem ProjectDevice-Link, wird sie als Ziel
vorgeschlagen. Der Planer kann je Vorschlag auf „neue Row“ umstellen.
- Neue Rows erhalten `manualQuantity = 0`, den Gruppenzustand als
Planungswerte und die Summe der wirksamen Mengen als Anzahl.
- Abweichende Planungswerte gegenüber einer bestehenden Row sind Konflikte
(11.7).
### 11.5 Steckdosen-Höchstwert
- Grundlage ist die Projekteinstellung `maxSocketsPerCircuit`
(Abschnitt 5). Im Dialog wird er angezeigt; geändert wird er in den
Projekteinstellungen.
- Belegung eines Stromkreises = Summe der wirksamen Mengen aller verknüpften
und geplanten Objekte, deren Geräteart `isSocket` trägt, über alle Rows des
Stromkreises. Manuelle Mengenanteile zählen nicht mit.
- Der Höchstwert ist eine Warnung, keine Sperre. Eine manuelle Zuweisung über
den Höchstwert ist erlaubt, muss aber vor der Übernahme ausdrücklich
bestätigt werden.
- Die automatische Aufteilung überschreitet den Höchstwert nie. Einzige
Ausnahme ist ein Einzelobjekt, das allein größer ist; es erhält einen
eigenen Stromkreis und wird als Überschreitung markiert.
### 11.6 Automatisch aufteilen
„Automatisch aufteilen …“ verteilt die ausgewählten Steckdosen-Objekte auf
neue Stromkreise einer gewählten, kategoriegleichen Stromkreisgruppe.
Nicht-Steckdosen in der Auswahl bleiben unberührt und werden genannt. Der
Höchstwert ist mit dem Projektwert vorbelegt und für diesen Lauf änderbar;
ohne Projektwert muss er eingegeben werden.
Raumweises Verfahren:
1. Räume nach Raumnummer (natürliche Sortierung), Objekte ohne Raum zuletzt;
innerhalb eines Raums nach Worksharing-ID.
2. Passt ein Raum vollständig in die Restkapazität des aktuellen neuen
Stromkreises, kommt er dorthin.
3. Sonst beginnt ein neuer Stromkreis, sofern der Raum vollständig in einen
leeren Stromkreis passt.
4. Sonst wird der Raum objektweise auf so viele neue Stromkreise verteilt wie
nötig, ohne ein Objekt zu teilen.
Das Ergebnis ist ein Plan, keine Übernahme. Er erscheint im Zielbereich und
kann per Drag-and-drop nachbearbeitet werden. Vorhandene Stromkreise werden
nicht automatisch aufgefüllt.
### 11.7 Zuordnungsplan und Übernahme
- Der Dialog sammelt alle Zuweisungen lokal. Nichts wird geschrieben, bevor
„Übernehmen“ bestätigt ist. Schließen mit offenem Plan fragt nach.
- Vor der Übernahme listet eine Prüfansicht jeden Planungswert-Konflikt
(Row, Feld, Row-Wert, Objektwert) und jede Höchstwert-Überschreitung. Beide
verlangen eine ausdrückliche Bestätigung. Ohne Konflikte und
Überschreitungen genügt „Übernehmen“.
- Die Übernahme ist ein atomarer Command
`external-object.apply-assignment-plan` mit `expectedRevision` und genau
einem Undo-Schritt. Er enthält:
- die vollständigen Snapshots neuer Stromkreise (stabile UUID,
Gruppe, BMK, abgeleitete Spannung, erforderlicher Standardschutz);
- die vollständigen Snapshots neuer Rows;
- die erwarteten Vorher-Zustände aller betroffenen Rows und Objekte;
- alle Link-Übergänge, die ausdrücklich bestätigten Konflikte und die
Mengenänderungen bestehender Rows.
- BMKs neuer Stromkreise werden beim Planen einmal vergeben: höchste
Nummer der Gruppe + 1, + 2, … ohne Lückenfüllung. Redo rechnet sie nicht neu.
- Die Inverse entfernt nur unverändert gebliebene erzeugte Stromkreise und
Rows und stellt Links und Mengen exakt wieder her.
- Bei 409 lädt der Dialog neu, prüft den Plan erneut und entfernt nicht mehr
gültige Zuweisungen mit Hinweis; gültige bleiben erhalten.
### 11.8 Verknüpfte Objekte an der Row
- An Rows zeigt das Badge „Revit N“ die Zahl verknüpfter Objekte. Ein Klick
öffnet eine Liste mit Worksharing-ID, Familie, Raum und wirksamer Menge.
- In der Liste lassen sich einzelne Objekte oder alle ausdrücklich lösen.
Gelöste Objekte erhalten die aktuellen Row-Werte als Planungswerte und
Overrides.
- „Anzahl“ bleibt gesperrt; „Anz. manuell“ und „Anz. Revit“ gelten wie
bisher.
Wird eine Row, ein Circuit oder eine Gruppe mit verknüpften Revit-Objekten
gelöscht, zeigt die UI vor Bestätigung:
`X Revit-Objekte werden wieder unzugeordnet`. Derselbe Löschcommand löst die
Objekte, entfernt die Struktur und speichert alle Links in seiner Inversen.
Undo stellt Struktur und Links exakt wieder her. Diese Löschungen werden nicht
gesperrt.
Das Löschen eines Verteilers oder Raums mit referenzierten externen Objekten
bleibt gesperrt. Der Nutzer muss die Verknüpfungen beziehungsweise Zuordnungen
zuvor ausdrücklich ändern. Die Regel gilt auch für Unterbaum- und History-
Pfade.
## 12. Rückgabe-Excel
Umsetzungsstand R8: Die Revit-Objekttabelle bietet alle drei Rückgabeumfänge
an und lädt eine aus dem letzten vollständigen Import erzeugte XLSX herunter.
Die Serverprojektion verwendet für verknüpfte Objekte die aktuellen Row- und
Circuit-Werte, für freie Objekte die Planungswerte und schreibt Zahlen als
Excel-Zahlen. Hinweise zu nicht berechenbaren Werten und fehlenden optionalen
Spalten werden nach dem Download angezeigt. Der append-only Exportnachweis
liegt außerhalb von Projektrevision, Undo/Redo, Snapshots und Transfer.
Der Export ist eine Leseoperation ohne Projektrevision. Ein append-only
Nachweis speichert Projektrevision, zugrunde liegenden letzten Import,
Zeitpunkt, Dateiname, SHA-256, Konfigurationskopie beziehungsweise ihren Hash
und Objektzahl.
Umfang:
- alle im letzten Import vorhandenen Objekte (Standard);
- nur Objekte mit Abweichung zum zuletzt importierten Revit-Wert;
- Auswahl aus der Objekttabelle.
Die Rückgabe basiert auf einer Kopie des zuletzt importierten Workbooks.
Zeilen oberhalb der ersten Datenzeile, Kopfkommentare, Formate,
Spaltenbreiten, Blattname und Spaltenreihenfolge bleiben erhalten. Danach
folgen nur die gewählten Objektzeilen in ihrer Originalreihenfolge. Alle
Spalten bleiben enthalten; Summenzeilen entfallen.
Stromkreiswerte:
- `combined`: `DistributionBoard.name + Circuit.equipmentIdentifier`, ohne
Trennzeichen;
- `separate`: Verteilername und unverändertes BMK in getrennten Spalten;
- ohne Circuit: Stromkreisfeld beziehungsweise beide Felder leer.
Die Wahl des Verteilerwerts liegt in genau einer Funktion und verwendet
zunächst `DistributionBoard.name`.
Weitere Rückgabewerte:
- Bezeichnung = Row-`displayName`, ohne Row Planungs-Anzeigename;
- Leistung [W] = effektive Menge × Einzelleistung, ohne GZF;
- Spannung = Circuit-Spannung, sonst Projektstandard der Kategorie;
- Strom = `P / (U × cosPhi)` beziehungsweise
`P / (sqrt(3) × U × cosPhi)`, auf 0,01 A;
- nicht berechenbar = leere Zelle plus Hinweis.
Zahlen werden als Excel-Zahlen geschrieben. Fehlende optionale Zielspalten
werden mit Hinweis ausgelassen. Nur fehlende Stromkreisspalten des gewählten
Modus blockieren. Dateiname:
`<Projektname>_Revit-Rueckgabe_<YYYY-MM-DD>.xlsx`.
## 13. Verbindliche R2-Abnahme mit Linear
R2 endet mit einer Rückgabedatei, die aus der lokalen realen Musterdatei
erzeugt wurde und einige klar identifizierbare Rückgabewerte verändert. Diese
Datei wird nicht committed. Der Nutzer testet sie in Linear. R3 darf erst nach
erfolgreichem Linear-Rückimport beginnen.
Die korrigierte R2-Rückgabedatei wurde am 30.09.2026 erfolgreich in Linear
eingelesen. Damit ist diese Abnahme erfüllt und R3 freigegeben.
Scheitert der Linear-Import, wird vor R3 eine Alternative zur Freigabe
vorgelegt: Die Original-XLSX wird direkt auf OOXML-Ebene kopiert und nur die
erforderlichen Zellwerte/-typen sowie Zeilenbereiche angepasst. Die
Alternative bleibt hinter demselben transportneutralen Adaptervertrag.
## 14. Folgeimport
Jeder Import ist eine vollständige Projektbauteilliste. Matching erfolgt
ausschließlich über exakt und case-sensitiv verglichene Worksharing-ID.
- neu: Wizard-Schritte nur für neue Objekte und unbekannte Familien;
- geänderte Quellwerte: Einzel- oder Sammelentscheidung;
- akzeptierte Mengenänderung: verknüpfte Row-Menge im selben Command;
- fehlend: markieren, Link und Menge zunächst beibehalten;
- Löschen: erst nach gesonderter Bestätigung;
- abweichende Rückgabefelder: Hinweis `in Revit noch nicht aktualisiert`,
keine Übernahmeentscheidung.
`external-import.apply-follow-up` ist atomar und ein Undo-Schritt.
Unveränderte Objekte erzeugen keine unnötigen Objekt- oder Row-Änderungen.
Der neue vollständige Batch wird letzter Batch; der zuvor letzte Batch wird
auf Metadaten reduziert.
Umsetzungsstand R9: Der sechsstufige Folgeimportwizard, die erneute
Apply-Prüfung, die getrennte Rückgabeabweichungsanzeige und der atomare
`external-import.apply-follow-up`-Command sind umgesetzt. Akzeptierte
Mengenänderungen aktualisieren verknüpfte Row-Summen im selben Command.
Fehlende Objekte bleiben zunächst samt Link und Menge erhalten und erscheinen
in der virtuellen Objekttabelle als `fehlend`. Ihre gesondert bestätigte
Löschung verwendet `external-model-object.delete-missing`; Undo stellt
Objekte, Links und Row-Mengen exakt wieder her.
## 15. Commands, Persistenz und Sicherheit
Projektbezogene Writes verwenden typisierte Commands mit vollständiger
Gegenrichtung, `expectedRevision`, Anmeldung, CSRF-Header und
`project-command-transaction.persistence.ts`. Dazu gehören mindestens:
- `external-model-configuration.update`;
- `external-import.apply-initial`;
- `external-import.apply-follow-up`;
- `external-model-object.update-planning`;
- `external-model-object.update-distribution-board`;
- `external-model-room-mapping.update`;
- `external-model-object.update-project-device-link`;
- `external-object.update-row-assignment`;
- `external-object.assign-to-new-row`;
- `external-object.assign-to-new-circuit`;
- `external-model-object.delete-missing`;
- die erweiterten Row-/Circuit-/Gruppen-Löschcommands mit Objekt-Link-
Transitionen.
Die Konfiguration selbst ist Teil der erwarteten/gewünschten Snapshots, aber
hat keinen eigenen monotonen Zähler. Importbatches halten eine unveränderliche
Konfigurationskopie. Preview/Plan sind zustandslos. Apply überträgt und parst
die Datei erneut; Undo/Redo führt nur gespeicherte Zustandsübergänge aus.
Neue Migrationen sind additiv. Vor Anwendung wird die Datenbank gesichert und
das generierte SQL geprüft. Da nur Entwicklungsdaten existieren, darf die
Migration alte externe CSV-Daten verwerfen. Vor dem Löschen externer Objekte
werden betroffene Row-Mengen auf `manualQuantity` zurückgesetzt. Der Verlust
des alten externen Entwicklungszustands wird dokumentiert.
## 16. Abnahme und Leistung
Die Oberfläche muss mehrere Tausend Objekte flüssig bedienen. R10 misst
Import, Command-/Snapshot-Größe, Speicherbedarf und Client-Interaktion mit
synthetischen großen Workbooks. Die virtualisierte Tabelle rendert nur den
sichtbaren Ausschnitt, während Filterung, Sortierung und Auswahl auf der einmal
geladenen kompakten Liste arbeiten.
Umsetzungsstand R10: Die vollständige Kette ist mit dateibasierter SQLite-
Persistenz und Neustart getestet. Der synthetische Lasttest verarbeitet 5.000
Objekte, misst Transport, Planung, Transaktionen, Command-/Snapshotgröße,
Heap und Clientprojektion und prüft Restore sowie Projektduplikat. Große
Zustandsersetzungen verwenden begrenzte Insertblöcke innerhalb derselben
atomaren Transaktion. Die Ergebnisse sind in der
[R10-Abnahme](revit-excel-r10-validation.md) dokumentiert.
Jedes Paket R1–R10 führt fokussierte Tests sowie aus:
```text
npm test
npm run build:api
npm run build:web
npm run typecheck:scripts
npx tsc --noEmit -p tsconfig.next.json
```
Jedes Paket erhält einen eigenen knappen imperativen Commit. Die konkrete
Paketfolge und ihre Freigabepunkte stehen im
[R0–R10-Plan](revit-excel-phase-14-plan.md).