leistungsbilanz-ts/docs/spec/revit-excel-r0-audit.md

35 KiB
Raw Permalink Blame History

R0 – Audit der Linear-Excel-Anbindung

Stand: 29.09.2026. Geprüfter Code: cf022b2.

Status: R0 abgeschlossen und mit Korrekturen für R1 freigegeben. Dieser Bericht ist ein Umsetzungsvorschlag, kein Nachweis einer bereits implementierten Excel-Anbindung. Der neue Nutzerauftrag ersetzt die CSV-/IfcGUID-Vorgaben und die alte Phasenliste 14.0–14.6. R1 bereinigt die bestehenden Dokumente; R0 ändert weder Laufzeitcode noch Datenbank noch Oberfläche.

Die 13 Freigabekorrekturen vom 29.09.2026 sind in den verbindlichen Anforderungen und im R0–R10-Plan eingearbeitet. Bei Abweichungen gelten diese beiden R1-Dokumente.

1. Geprüfter Bestand und Keep/Change/Remove

Gelesene Grundlagen: AGENTS.md, docs/current-architecture.md, docs/project-history-and-external-model-architecture.md, docs/spec/revit-csv-integration-requirements.md und docs/spec/revit-csv-phase-14-audit-and-plan.md. Der alte Plan widerspricht sich bereits intern: Sein Status nennt die Erstübernahme noch nicht vorhanden, während Implementierung und Tests sie nachweisen. Alte Erledigt-Markierungen werden deshalb nicht übernommen.

Bereich / Codebeleg Entscheidung Begründung und Änderung
src/db/repositories/project-command-transaction.persistence.ts Keep Eine Grenze für Fachänderung, Inverse, Revision und History; auch automatische Snapshots bleiben darin.
src/db/repositories/external-model-state.repository.ts, src/db/schema/external-*.ts Change Quelle, Batches, Raum-Mappings und Objekte wiederverwenden; neue Identität, Konfiguration und typisierte Matrix. Schlanke Objekt-Reads von großen Batch-Blobs trennen.
src/domain/models/external-initial-import-project-command.model.ts, zugehöriger Store Change Vollständiger erwarteter/Zielzustand und Row-freier Import bleiben; Worksharing-ID, Gerätearten und atomare Regelübernahme ergänzen.
src/external-model/application/external-initial-import-plan.ts, external-initial-import-target.ts Change Raumvorschläge, Kataloge, vollständige Entscheidungen und stabile UUIDs behalten. Objektentscheidungen und Gerätearten ergänzen.
src/db/repositories/external-object-assignment.persistence.ts und drei Zuordnungs-Stores Change Mengeninvariante und exakte Inversen behalten; Geräteart, effektiven Verteiler, Anwesenheit und Übernahme der Row-Werte beim Lösen ergänzen.
CircuitDeviceRow.manualQuantity, bestehende Mengenprüfungen Keep quantity = manualQuantity + Summe(externer effektiver Mengen); Mehrfachsteckdosen bleiben unteilbar.
src/external-model/application/external-circuit-list-objects.ts Change Listen-/Projektprüfung behalten; vollständige Planungswerte, Geräteart, effektiver Verteiler, Status und Row-Anzahlen liefern.
src/domain/models/project-state-snapshot.model.ts, Snapshot-Persistenz und Transfer Change Schema 10; historische CSV-Zustände ausdrücklich ablehnen; alle neuen internen Referenzen remappen.
src/external-model/csv/*, CSV-Preview, CSV-Validierungen und Controller Remove/replace XLSX ersetzt CSV vollständig; kein zweiter aktiver Transportpfad.
src/frontend/components/revit-csv-modal.tsx, Einbindung auf Projektseite Remove/replace Eigene Revit-Seite; Einstellungen nur im Modal, Import in eigenem Wizard.
src/frontend/components/Sidebar.tsx, src/frontend/utils/api.ts, src/frontend/types.ts Change Route revit, neue DTOs und Endpunkte, CSV-Imports entfernen.
src/frontend/components/circuit-tree-editor.tsx, Grid-Drop-/Projektionsmodule Change Separater externer Drag-Payload; Row-, Circuit- und Freiplatz-Ziele bewusst unterscheiden. Bestehende Grid-Bedienung behalten.
Raum-/ProjectDevice-Formulare und Commands Keep Sichtbar vorbelegte, ausdrücklich bestätigte Anlage als eigener Undo-Schritt.
scripts/verify-revit-reference-csv.ts, Transporttests Replace Pfadargument für lokalen XLSX-Prüfer; ausschließlich synthetische Workbooks in Tests.

Konkrete Lücken gegenüber dem Auftrag

  • external-model-contracts.ts importiert heute CSV-Verträge. Die neutralen Konfigurations-/Matrixverträge gehören künftig in external-model/domain; nur external-model/xlsx darf ExcelJS kennen.
  • ifc_guid ist derzeit NOT NULL und je Quelle eindeutig; Matching, Snapshots, DTOs und Commands setzen diese Identität voraus.
  • internalDeviceType ist derzeit ein freier String in Planungswerten. Es gibt keinen Geräteart-Katalog mit stabilen IDs und Standardwerten.
  • Der Erstimport setzt den ProjectDevice-Link, verwendet im Target aber weiterhin suggestedPlanningValues. Die neue Priorität ProjectDevice vor Geräteart muss ausdrücklich implementiert werden; ein Link allein genügt nicht. Revit-Leistung wird künftig nicht automatisch zum Planungswert.
  • Der Import-Target setzt distributionBoardId = null; die Raumvorgabe liegt separat im Mapping. Projektion und Zuordnungsprüfung vergleichen heute direkt das Objektfeld. Eine zentrale Auflösung des effektiven Verteilers fehlt und ist vor der Editor-Nutzung erforderlich.
  • Die bisherige Row-Zuordnung darf laut Validator am Objekt ausschließlich circuitDeviceRowId ändern; der Store schreibt auch nur dieses Feld. Lösen mit aktuellen Row-Planungswerten benötigt eine neue Command-Version.
  • Die Kompatibilitätsprüfung vergleicht Raum, Kategorie, Auswahlkenner und Planungswerte, aber keine stabile Geräteart. Unterschiedliche Gerätearten dürfen nicht versehentlich in dieselbe Row aggregiert werden.
  • Rows speichern powerPerUnit in kW, externe Planung powerPerUnitW in W. Eine zentrale bidirektionale Konvertierung ist nötig; Exportleistung darf nicht um Faktor 1000 falsch sein.
  • Externe FKs auf Row, ProjectDevice, Raum-Mapping und Verteiler verwenden teilweise ON DELETE SET NULL. Bestehende allgemeine Löschpfade sichern externe Objektübergänge nicht durchgängig in ihren Inversen. Auch Unterbaum-/History-Löschungen müssen abgesichert werden.
  • Ein Editor-Drawer, projektweite Objekttabelle, Exportnachweis und ausführbarer Folgeimport fehlen. follow_up als vorhandener Enumwert ist kein implementierter Folgeimport.
  • Konfigurationsversionen steigen heute nur bei normalen Updates gegenüber dem aktuellen Wert; Undo setzt alte Versionen zurück. Für eine tatsächlich monotone Generation muss diese Semantik korrigiert werden.
  • XLSX-Parsing ist asynchron. Das heutige erneute synchrone CSV-Parsing innerhalb der SQLite-Transaktion darf nicht einfach durch await ersetzt werden.

2. Prüfung der lokalen Musterdatei

docs/spec/kbp-Stromkreis.xlsx wurde ausschließlich lesend auf ZIP-/OOXML- Ebene untersucht; keine Inhalte wurden hochgeladen oder in Fixtures kopiert. Die Datei ist unversioniert und darf nicht committed werden.

Befund Ergebnis
Dateigröße / entpackte ZIP-Einträge 56.765 / 337.740 Bytes
Arbeitsblätter / Blattnamenlänge 1 / 31 Zeichen
Zellbereich A1:O490
Kopfzeile / Leerzeile / Objekte / Abschluss 1 / 2 / 3–489 / 490
Objektidentitäten 487 syntaktisch passende Worksharing-IDs, keine Duplikate
Kopfzeilenkommentare 14, zu den 14 Spalten nach der ID-Spalte
Fehlende Raumangaben 67 Objekte ohne Raumnummer und Raumname
IfcGUID-Duplikate Keine bei exaktem, case-sensitivem Vergleich
Formeln Keine; synthetische Tests dafür erforderlich
Spaltendefinitionen 16, obwohl nur 15 Datenspalten vorhanden sind

Das beobachtete Profil aus dem Auftrag wird damit bestätigt. Zusätzliche Spaltenformatdefinitionen dürfen beim Export nicht auf die gemappten Spalten gekürzt werden. Das Muster enthält die neuen getrennten Stromkreisfelder und die Bezeichnung noch nicht. Fehlende Rückgabespalten werden angezeigt; sie dürfen nicht ohne Linear-Parameterbindung erfunden werden.

Die frühere Angabe von zwei IfcGUID-Duplikatgruppen war falsch: PowerShells standardmäßiges Gruppieren verglich ohne Beachtung der Groß-/Kleinschreibung. Ein erneuter ordinaler, case-sensitiver Vergleich ergab keine Duplikate. Die Summenzeile hat nur in B490 einen Wert; Familie und Typ ist leer.

Nicht nachgewiesen: erfolgreicher Rückimport in Linear, dessen genaue Auswertung der Kommentar-/VML-Metadaten und der ExcelJS-Roundtrip. R2 endet deshalb mit einer aus der Musterdatei erzeugten Rückgabedatei und einem verbindlichen Linear-Test durch den Nutzer vor R3.

3. Bibliothek, Adapter und Uploadgrenzen

Vorschlag: genau eine neue direkte Abhängigkeit exceljs. Seine öffentliche API unterstützt XLSX, Zellnotizen, Formate, Spaltenbreiten und typisierte Werte. Das passt zum beobachteten klassischen Kommentarformat. Version und transitive Abhängigkeiten werden in R2 festgeschrieben und geprüft. Die veröffentlichte Version ist laut Paketregister 4.4.0; eine aktuelle Releasepflege ist damit nicht bewiesen. Dies ist ein ausdrückliches Wartungsrisiko, kein als erfüllt abgehakter Bibliotheksnachweis.

Quellen, am 29.09.2026 geprüft: ExcelJS-Projekt, offizielle Paketdokumentation. Keine Bibliothek wird in R0 installiert. R2 muss vor Integration Kommentar- Roundtrip, Node-24-Verträglichkeit und Abhängigkeitsrisiken prüfen; bei einem Blocker wird die Bibliotheksentscheidung neu vorgelegt.

Vorgeschlagene Grenzen, zentral konfiguriert und synthetisch getestet:

  • ausschließlich .xlsx, kein .xls oder .xlsm;
  • maximal 10 MiB Upload;
  • genau ein Arbeitsblatt und keine Formelausführung;
  • feste Zeilen-, Spalten- und Zellgrenzen nach dem Einlesen.

Es gibt keinen eigenen ZIP-Prüfer und keinen Parser-Worker.

Neutrale Matrix: Blattname, Kopfzeilen-/Startpositionen, Spaltenmetadaten (Index, Name, Kommentartext, erkannter Parametertyp/Einheit), geordnete Zeilen mit Originalzeilennummer und Klasse sowie Zellen als diskriminierte Union string | number | boolean | empty. Formeltext und Cache-Status sind optionale Transportmetadaten; fachlich zählt nur der gecachte skalare Wert. Fehlender Cache oder Fehlerwert erzeugt einen Hinweis bzw. bei Pflichtfeldern einen Blocker. Originalbytes bleiben unverändert gespeichert.

Eine Zeile ohne Worksharing-ID ist nur verdächtig, wenn Familie und Typ gefüllt ist. Sie erzeugt einen Hinweis und wird übersprungen, ohne zu blockieren. Andere ID-lose Zeilen, auch die Summenzeile mit Inhalt in B, werden still übersprungen. Nicht passende nichtleere IDs blockieren. Worksharing-ID und IfcGUID bleiben als Quelltext erhalten und werden exakt, ordinal und case-sensitiv verglichen; ungültige äußere Leerzeichen werden gemeldet statt still korrigiert. IfcGUID wird optional gespeichert, doppelte Werte sind nur Hinweise. Numerische Projektion rundet Leistung auf 0,01 W, nicht die gespeicherte Quellzelle. Mengen aus socketCount müssen positive ganze Zahlen sein.

Rückgabe lädt eine Kopie der Originalbytes, bewahrt den Bereich oberhalb der ersten Datenzeile samt Kommentaren, Formatierung und Spaltenbreiten und ersetzt den Datenbereich durch gewählte Objektzeilen in Originalreihenfolge. Alle Spalten bleiben enthalten; Summenzeilen entfallen. Unveränderte Zellen behalten ihre importierten Werte und Typen. Formeln in Objektzeilen werden als gecachte Werte ausgegeben, damit Zeilenauswahl keine falschen relativen Bezüge erzeugt; dies wird vor Export als Hinweis ausgewiesen. Keine Formeln werden berechnet. Roundtrip bedeutet strukturelle/semantische Gleichheit, nicht identische ZIP-Bytes.

4. Konfigurationsschema

Neuer neutraler Vertrag ExternalModelConfiguration, Schema-Version 1:

{
  schemaVersion: 1,
  layout: {
    headerRow: 1, firstDataRow: 3, firstDataColumn: 1
  },
  circuitMode: "combined" | "separate",
  columns: {
    worksharingId: string, familyAndType: string,
    ifcGuid: string | null, roomNumber: string | null,
    roomName: string | null, 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: [{
    id: UUID, name: string,
    category: "lighting" | "single_phase" | "three_phase",
    defaults: {
      powerPerUnitW: number | null, simultaneityFactor: number | null,
      cosPhi: number | null, costGroup: string | null
    }
  }],
  familyTypeRules: [{
    id: UUID, exactFamilyAndType: string, deviceTypeId: UUID,
    quantityRule: "one" | "socketCount"
  }]
}

Zeilen/Spalten sind intern 1-basiert; UI stellt Spalten als A, B, … dar. Es gibt nur columns.worksharingId und kein separates layout.idColumn. Jede gemappte Kopfzeile muss eindeutig auflösbar sein; doppelte Ausgabebelegungen werden abgelehnt. Freie Eingabe bleibt zulässig, aber ein nicht existierender Name erzeugt vor Import/Export einen konkreten Fehler. Erkennung und Vorbelegung nutzen die exakten Standardnamen aus dem Auftrag. Unbekannte Spalten bleiben ohne Mapping erhalten.

Geräteart-IDs sind interne UUIDs, keine Namen als Relationsschlüssel. Regeln sind exakt und je Familien-/Typtext eindeutig; jede importierte Familie muss eine Geräteart haben. Gerätearten und Regeln werden als ein versioniertes Konfigurationsaggregat gespeichert. Keine zusätzliche Gerätearttabelle ist für diesen Umfang nötig; Validatoren erzwingen referenzielle Integrität. Referenzierte Gerätearten können nicht kommentarlos entfernt werden.

Startwerte: je Feld ProjectDevice vor Geräteart vor leer. Anzeigename: Auswahlkenner, sonst Geräteartname, sonst Familie/Typ. Quellleistung bleibt Quelle; eine Übernahme geschieht nur als sichtbare Planungsentscheidung. Fehlender GZF wird sichtbar mit 1 vorbelegt, ohne zusätzliche Bestätigung. Geräteart- Änderungen schreiben keine vorhandenen Objekt-Overrides oder Rows um.

5. Konkretes Persistenzschema

Bestehende UUID-/Projekt-FKs und Eigentumsprüfungen werden beibehalten. JSON bezeichnet validierten JSON-Text in SQLite, nicht ExcelJS-Objekte.

Tabelle Zielspalten / Constraints
external_model_configurations (ersetzt CSV-Tabelle) id TEXT PK, project_id TEXT NOT NULL UNIQUE FK projects, configuration JSON NOT NULL. Enthält obiges vollständiges Aggregat; keine eigene Versionszählung.
external_model_sources id, project_id UNIQUE, name, source_type = revit_xlsx. Genau eine implizite Quelle je Projekt.
external_import_batches Letzter Batch vollständig mit IDs, Importart, Zeit, Dateiname, SHA-256, Objektzahl, applied_project_revision, configuration_snapshot JSON, original_bytes BLOB, document JSON; ältere Batches nur als Metadaten Datum, Dateiname, SHA-256 und Objektzahl.
external_room_mappings Vorhandene Felder einschließlich normalisiertem Quellraumschlüssel, room_id, default_distribution_board_id; UNIQUE (source_id, normalized_source_room_key) bleibt.
external_model_objects Bestehende interne IDs/Links; neu worksharing_id TEXT NOT NULL, UNIQUE (source_id, worksharing_id); ifc_guid TEXT NULL, ohne Unique; device_type_id TEXT NOT NULL als validierter Verweis in das Konfigurationsaggregat.
Objektzustand accepted_source_values JSON mit rohen typisierten Werten für Raum, Familie/Typ, Marker, Menge, Bemerkung und alle Rückgabefelder; planning_values JSON mit Anzeigename, Kategorie, Anschlussart, effektiver Menge, Einzelleistung W, nullable GZF/cosPhi/Kostengruppe/Bemerkung; overridden_fields JSON; bisherige Batch-/Raum-/Board-/ProjectDevice-/Row-Verweise und presence_status bleiben.
external_export_batches (neu) id TEXT PK, project_id FK, project_revision INTEGER, import_batch_id TEXT, exported_at_iso TEXT, file_name TEXT, sha256 TEXT, configuration_snapshot/hash, scope TEXT, object_count INTEGER. Append-only Audit-Store.

import_batch_id des Exportnachweises ist absichtlich eine historische UUID ohne löschenden FK: Undo eines Imports oder Snapshot-Restore darf den Nachweis nicht entfernen. Exportnachweise liegen außerhalb rücksetzbarer Fachsnapshots und werden beim Projektduplikat nicht als dort erfolgte Exporte ausgegeben. Sie bleiben beim Originalprojekt erhalten; diese Abgrenzung wird in R1 dokumentiert. Nur der letzte Importbatch gehört mit Bytes und Matrix zu Snapshot/Transfer; ältere Batches werden dort nur als Metadaten erhalten.

Indices: bisherige Projekt-/Presence-, Board- und Row-Indices behalten; zusätzlich (project_id, device_type_id), external_room_mapping_id, linked_project_device_id, Export (project_id, exported_at_iso). Cross-Project-Links und Geräteart-Verweise prüft jeder Command in der Transaktion; bloße Existenz eines UUID-FK genügt nicht.

Effektiver Verteiler: ein gemeinsamer Resolver verwendet bei verknüpften Objekten die Row/Circuit-Verteilung, sonst die Objektabweichung, sonst die Raumvorgabe. distributionBoardId = null bedeutet Raumvorgabe verwenden; bei fehlender Vorgabe ist das Objekt ohne Verteiler. Eine Änderung des Raum-Standardverteilers betrifft nur unzugeordnete Objekte; verknüpfte Objekte folgen immer der Row-Verteilung und blockieren diese Änderung nicht.

Planungswerte bleiben von Quellwerten getrennt. Nach Row-Zuordnung sind Objekt-Planungswerte eingefrorene Startwerte; Anzeige, Abweichung und Export verwenden die Row. Beim Lösen werden aktuelle Row-Werte einschließlich Einheitenkonvertierung in die Objektplanung übernommen und als explizite Overrides markiert. Effektive Objektmenge wird nicht durch die Row-Gesamtmenge ersetzt. Die Row und ihr manueller Anteil bleiben erhalten.

6. Commands und Transaktionsgrenze

Alle öffentlichen Fach-Writes verlangen expectedRevision, Anmeldung und X-Leistungsbilanz-Request: 1. expectedRevision gehört wie bisher zum Ausführungsumschlag. Jede Transition enthält vollständige erwartete/Ziel- Snapshots der betroffenen Datensätze, keine ungesicherten Teilpatches.

Command Payload-Skizze und Gegenrichtung
external-model-configuration.update v1 { expected, target } einschließlich Layout, Mapping, Gerätearten und Regeln. Inverse tauscht den vollständigen Fachinhalt; keine eigene Konfigurationsversion.
external-import.apply-initial v2 { expectedConfiguration, targetConfiguration, expected, target }. Quelle, Batch, Mapping, Objekte und neue Regeln zusammen; Inverse stellt leeren externen und vorherigen Konfigurationsinhalt wieder her. Keine Rows.
external-import.apply-follow-up v1 { configuration: transition, batch: transition, roomMappings: transitions, objects: transitions, rows: quantityTransitions, decisions }; Server erzeugt deterministischen Diff und alle UUIDs. Inverse tauscht alle betroffenen Zustände.
external-model-object.update-planning v1 { objects: transitions }; nur ungebundene Objekte; geänderte Felder in Overrides. Einzel-/Sammelbearbeitung identischer Regeln.
external-model-object.update-distribution-board v1 { objects: transitions }; explizite Objektabweichung, Projekt-/Row-Konsistenz.
external-model-room-mapping.update v1 { mappings: transitions }; interner Raum/Standardverteiler; betroffene Objekt-/Row-Konsistenz mitprüfen.
external-model-object.update-project-device-link v1 { objects: transitions, confirmedPlanningFields }; keine Vorlagenänderung; neue Startwerte nur für ausdrücklich bestätigte Felder. Gebundene Objekte werden über ihre Row bearbeitet.
external-object.update-row-assignment v2 { rows: transitions, objects: transitions, confirmedConflictObjectIds }; Linkwechsel, materialisierte Mengen, beim Lösen aktuelle Row-Planungswerte; vollständige Inverse.
external-object.assign-to-new-row v2 Bestehender vollständiger Row-/Objekt-/Reserveplan mit neuen Objektverträgen; history-only Inverse entfernt nur exakt unveränderte Erzeugnisse.
external-object.assign-to-new-circuit v2 Bestehender Circuit-/Protection-/Row-/Objektplan; BMK einmal planen und festschreiben, gleiche UUIDs bei Redo.
external-model-object.delete-missing v1 { objects: transitionsToNull, rows: quantityTransitions }; ausschließlich ausdrücklich bestätigte weiterhin fehlende Objekte, kein Row-/Circuit-Löschen; Inverse stellt IDs, Links und Mengen wieder her.

Bestehende project-device.insert, Room-/Floor-Commands bleiben eigenständige Undo-Schritte. Familien-/Geräteartentscheidungen im Wizard sind lokale Entwürfe und werden erst mit dem Import atomar persistiert. Nach separater Kataloganlage aktualisiert der Wizard die Projektrevision und plant neu, ohne lokale Entscheidungen zu verlieren.

Die Konfiguration hat keine eigene Versionszählung. Vorschau und Apply binden sich an expectedRevision; weil auch Undo/Redo neue, strikt steigende Projektrevisionen erzeugen, wird ein veralteter Plan eindeutig ungültig. Importbatches speichern eine vollständige Konfigurationskopie. Prüfen: Änderung → Undo → anderer Zweig darf niemals denselben Plan wieder gültig machen.

XLSX wird vor der synchronen SQLite-Transaktion in einer serverinternen Vorbereitung geparst. Apply überträgt Bytes erneut; Hash, Matrix und Entscheidungen werden erneut validiert. Im Store werden Revision, Konfigurationsinhalt, erwartete Objekte, Links und vollständiger vorbereiteter Plan atomar geprüft. Vorbereitete Daten sind keine vom Client behauptete Validierung: Generic-Command-Requests dürfen Importcommands nicht an dieser serverseitigen Vorbereitung vorbeischleusen. Undo/Redo lesen und parsen keine Excel-Datei; sie wenden ausschließlich die gespeicherten Vorher-/Nachher-Zustände an. Keine asynchronen Callbacks in better-sqlite3-Transaktionen.

Row-/Circuit-/Gruppen-Löschcommands erfassen verknüpfte Objekte vollständig. Nach der Warnung X Revit-Objekte werden wieder unzugeordnet lösen sie die Links im selben Command; ihre Inverse stellt sie exakt wieder her. Sperren bleiben nur für das Löschen referenzierter Verteiler und Räume und gelten auch in Unterbaum- und History-only-Pfaden.

7. Migration, Snapshot 10, History und Transfer

Neue additive Migration nach 0013_users (voraussichtlich 0014, Nummer beim Beginn von R3 erneut prüfen). Bestehende SQL-/Metadateien unverändert.

  1. Vor R3-Anwendung API-Schreibzugriffe stoppen und npm run db:backup ausführen; verifiziertes Backup samt Wiederherstellungsmöglichkeit sichern. R0 verändert keine DB und benötigt daher kein Migrationsbackup.
  2. Vorhandene externe CSV-Entwicklungsdaten dürfen gemäß Auftrag verworfen werden. Zuerst je verknüpfter Row quantity = manual_quantity setzen; sonst bliebe nach Entfernen der externen Objekte eine Phantomlast. Rows, Circuits, manuelle Anteile, UUIDs und BMKs bleiben bestehen.
  3. Externe Objekte → Mappings → Batches → Quellen → CSV-Konfiguration in FK-sicherer Reihenfolge entfernen. Tabellen gezielt neu aufbauen, wo SQLite NOT-NULL-/Unique-Änderungen dies erfordern. Neue Zieltabellen und Indices erstellen. Keine leeren Worksharing-IDs als Backfill erfinden.
  4. Generiertes SQL und Drizzle-Metadaten prüfen; saubere und bestehende Test-DBs migrieren; FK-/Integritätsprüfung und Mengenabgleich ausführen. Der Reset ist eine dokumentierte einmalige Entwicklungsmigration, kein stiller Laufzeit-Import.
  5. Alte Revisionsdaten nicht umschreiben, keine CSV-History heimlich überspringen. An der Ausführungsgrenze alte CSV-Konfigurationscommands, Initial-/Zuordnungscommands v1 einschließlich ihrer History-Inversen und Restores mit CSV-Inhalt vor jedem Write ablehnen.

Fehlermeldung für History: „Dieser Verlaufsschritt verwendet die frühere CSV-/IfcGUID-Anbindung und kann mit der Excel-Anbindung nicht ausgeführt werden.“ Der History-Status sollte den blockierten obersten Schritt samt Grund zeigen; keine automatisch geleerten Stacks und keine Änderung bei Ablehnung. Frühere allgemeine Commands können nach dem Reset zusätzlich an ihren exakten Vorbedingungen scheitern; das bleibt eine sichere, sichtbare Ablehnung.

Snapshot v10 enthält aktive Excel-Konfiguration, Gerätearten/Regeln, Quelle, den letzten Batch mit Originalbytes/Matrix, ältere Batches nur als Metadaten sowie Raum-Mappings, Objekte und Links. Upgrade v1–9: bestehende nicht-externe Upgrader erhalten. Nur wenn externalCsvConfiguration fehlt/null ist und der externe Zustand leer ist, verlustfrei auf v10 heben. Auch eine gespeicherte CSV-Konfiguration allein zählt als nicht leerer CSV-Zustand und wird nicht still verworfen. Snapshot-Checksumme am gespeicherten Original vor Upgrade prüfen.

Fehlermeldung: „Dieser Projektstand enthält Daten der früheren CSV-/IfcGUID-Anbindung. Eine automatische Übernahme in die Excel-Anbindung ist nicht möglich. Bitte verwenden Sie einen Projektstand ohne CSV-Daten.“

Der aktuelle portable Transfer ist bereits Format 2 (Grobbilanzen), nicht Format 1 wie im alten Audit. Envelope 2 und dessen Format-1-Lesepfad bleiben; enthaltenes Projektzustandsschema wird 10. Duplizieren remappt Projekt-, Konfigurations-, Geräteart-, Regel-, Quellen-, Batch-, Mapping-, Objekt-UUIDs und alle internen Links, auch in Konfigurationssnapshots der Batches. Worksharing-IDs, optionale IfcGUIDs und Originalbytes bleiben unverändert. Grobbilanzen und globale Office-/Auth-Daten behalten ihre bisherige Abgrenzung. Exportnachweise werden nicht als neue Projektexporte dupliziert.

8. Read-Modelle, Oberfläche und Rückgabe

Vorgeschlagene API-Basis /api/projects/:projectId/revit: configuration (GET/PUT), profile/preview (POST, zustandslos), initial-import/plan|apply, follow-up-import/plan|apply (POST), status und objects (GET), return-workbook (POST mit Export-Audit). Der bestehende listenbezogene External-Objects-GET bleibt erhalten. Objektmutationen verwenden den vorhandenen Project-Command-Endpunkt mit neuen typisierten Verträgen. CSV-Endpunkte werden entfernt, keine Aliasse.

Export verwendet expectedRevision für einen konsistent gelesenen Stand; die Datei-Erzeugung erfolgt außerhalb des kurzen Read-Snapshots. Danach separater append-only Audit-Write, ohne Projektrevision oder Undo-Schritt. Bei Auditfehler kein Erfolg/download; ein Eintrag belegt Dateierzeugung, nicht einen tatsächlich abgeschlossenen Browserdownload.

Die Revit-Seite lädt einmal eine kompakte Objektliste. Filterung und Sortierung laufen im Client; die Tabelle wird virtualisiert und verwendet keine Server- Pagination. Filter-/Sortierzustand, UUID-Auswahl und Sammelaktionen sind unabhängig vom DOM. „Alle gefilterten“ wird vor einer Mutation zu einer expliziten ID-Auswahl an der aktuellen Revision aufgelöst. Große Auswahlmengen werden nicht in getrennte Undo-Schritte aufgeteilt. Kein vollständiges Batch-Blob im DTO.

Einstellungen verwenden Musterdatei-Erkennung mit editierbaren Positionen, Feld-Dropdowns/freier Eingabe und Kommentar-Typ-/Einheitenanzeige. Regeln entstehen im Wizard und sind auf der Seite einklappbar nachbearbeitbar. Fehlende Raumangaben bleiben zulässig, Board-Zuordnung ist auch ohne Raum möglich. ProjectDevice-Zuordnung bleibt optional.

Rechter Editor-Drawer: nur vorhandene, ungebundene konfliktfreie Objekte des effektiven Verteilers. Gruppierung nach internem Raum, Auswahlkenner, Geräteart-ID, Kategorie und identischen Planungswerten; unterschiedliche ProjectDevice-Links bleiben ebenfalls getrennt, da eine Row nur einen Link haben kann. Effektive Einzelmengen sind kein Gleichheitsfeld: Einfach- und Mehrfachsteckdosen sollen gemeinsam gruppierbar sein. Anzeige enthält Mengensumme und Objektanzahl. Fachlich heterogene Auswahl darf nicht willkürlich auf eine einzelne Row zusammenfallen; Konfliktanzeige verlangt eine kompatible Auswahl. Row-Indikator öffnet Objekte und explizites Lösen.

Eine Funktion getRevitBoardName(board) liefert ausschließlich board.name. Gemeinsam: Name + unverändertes equipmentIdentifier, ohne Separator. Getrennt: Name und BMK in eigene Parameter. Ohne Circuit bleiben beide Stromkreiswerte leer, auch wenn ein Planungsverteiler bekannt ist.

Exportprojektion und Abweichungsanzeige teilen dieselbe reine Funktion: Row-Anzeigename/-Leistung bei Link, sonst Objektplanung; Objektleistung in W = effektive Menge × Einzelleistung (Row-kW vorher × 1000), ohne GZF. Spannung vom Circuit, sonst Projektstandard passend zur Kategorie. Strom aus Objektleistung, U, cosPhi und Phasenart; Drehstrom mit Faktor √3, auf 0,01 A. Fehlende/ungültige Werte ergeben leer plus Hinweis. Nullleistung bleibt bei gültigem Nenner numerisch 0. Kein still angenommenes cosPhi. Abweichungsvergleich normalisiert Zahlpräzision, Leere und skalare Typen gegen den zuletzt importierten, nicht den zuletzt exportierten Stand.

Umfang: alle im letzten Batch vorhandenen Objekte / abweichende / explizite Auswahl. Fehlende Objekte haben keine aktuelle Originalzeile und werden nicht künstlich wieder eingefügt. Alle Spalten bleiben, nicht ausgegebene Parameter behalten importierte Werte. Fehlende optionale Spalten für Bezeichnung, Leistung, Spannung und Strom werden mit Hinweis übersprungen. Nur fehlende Stromkreisspalten des gewählten Modus blockieren. Dateiname gemäß Auftrag mit bereinigtem Projektnamen und Tagesdatum.

Folgeimport matcht ausschließlich Worksharing-ID. Ein neuer Batch speichert immer den vollständigen letzten Quellstand. Unveränderte Objekte werden nicht allein zum Fortschreiben von lastSeenImportBatchId neu geschrieben; aktuelle Sichtbarkeit/Quellwerte kommen aus Batch/Matrix. Akzeptierte Planungsgrundlage und letzte importierte Beobachtung sind getrennt. Raum-/Familien-/Marker-/Mengenänderungen brauchen Entscheidungen. Bei unvereinbarer Row-Zuordnung blockiert die Übernahme bis zum ausdrücklichen Lösen/Umordnen, statt Rows automatisch zu erzeugen. Übernommene Mengen ändern alle betroffenen Row-Summen im selben Importcommand. Fehlend setzt nur den Status, erhält vorerst Link und Menge. Rückgabefeld-Abweichungen sind Hinweise, keine Übernahmeentscheidungen. Ein völlig unveränderter Folgeimport erzeugt einen nachvollziehbaren Batch, aber keine unnötigen Objekt-/Row-Updates.

9. Pakete, Verifikation und Risiken

R0 liefert nur diesen Bericht und einen eigenen Commit. R1–R10 starten erst nach Freigabe; keine Fortschreibung der alten 14.0–14.6-Liste.

Paket Arbeit und entscheidende Abnahme
R1 Neue Excel-Anforderungen und R0–R10-Plan; alte Dokumente archivieren/auf Verweise kürzen; AGENTS, Architektur, History-Doku, Phase-14-Abschnitt, LLM-Kontext und alle Links nachziehen. Referenzdatei gezielt ignorieren.
R2 XLSX-Adapter und lokaler Referenzprüfer mit Pfadargument. Synthetischer Roundtrip für Kommentare, Blattname, Spaltenbreiten, Typen, Header-/Startpositionen, unbekannte Spalten, Auswahl und Summenausschluss. Aus der lokalen Musterdatei entsteht eine Rückgabedatei mit geänderten Werten. Danach Nutzerabnahme in Linear; R3 bleibt bis zum Erfolg gesperrt. Bei Fehlschlag vor R3 OOXML-Direktänderung als Alternative vorlegen. Keine DB-Änderung.
R3 Neue Konfiguration/Identität, additive Migration, Snapshot 10, Transfer und History-Ablehnungen; Backend-CSV entfernen. Parser-Vorbereitung von synchroner Transaktion trennen.
R4 Revit-Seite, Navigation, Einstellungen; Projektseitenmodal und dessen CSV-Frontend-Verträge entfernen.
R5 Erstimport mit atomaren Regeln, Geräten, Raum-/Board- und Objektentscheidungen; ProjectDevice-Vorbelegung nach Priorität; ein Import-Undo-Schritt.
R6 Kompakte Objekt-Reads, clientseitige Filter/Sortierung, Virtualisierung, Sammel-Commands und Overrides.
R7 Gruppierung, Drag-and-drop, Row-Indikatoren und Lösen inklusive aktueller Row-Werte; drei Drop-Ziele, atomare Objektlösung beim Row-/Circuit-/Gruppen-Löschen und Reload/Undo/Redo.
R8 Drei Exportumfänge, gemeinsame Abweichungsprojektion, typisierte Rückgabe, append-only Nachweis und Linear-Strukturabnahme.
R9 Kontrollierter Folgeimport, fehlende Objekte, explizites Löschen, mengenwirksame Entscheidungen und atomare Inverse.
R10 Vollständige synthetische Ende-zu-Ende-Kette einschließlich Neustart, Snapshot/Restore und Duplikat; mehrere Tausend Objekte; Doku auf ausgelieferten Stand.

Die temporäre Grenze zwischen R3 und R4 wird ausdrücklich behandelt: Buildfähige, nicht aktive Kompatibilitätstypen für das alte Modal dürfen bis R4 bestehen, aber kein aktiver CSV-Backendpfad. Veraltete Projektaktion bis zur neuen Seite deaktivieren/entfernen, keinen funktionslosen Upload anbieten. Die Dokumentation darf Zwischenstände nicht als fertigen Workflow ausweisen.

Pflicht je R1–R10: fokussierte Tests, npm test, npm run build:api, npm run build:web, npm run typecheck:scripts, npx tsc --noEmit -p tsconfig.next.json, je ein knapper imperativer Commit. R0: 31 vorhandene Tests aus sechs Dateien erfolgreich ausgeführt: external-model-foundation, external-initial-import-plan, external-initial-import-project-command.repository, external-object-row-assignment-project-command.repository, external-circuit-list-objects, external-csv-configuration-project-command.repository (je .test.ts). Diese decken vorhandene Commit-/Rollback-, Undo-/Redo-, Snapshot-/Transfer- Grundlagen ab, nicht die neue Excel-Funktion. Der erste Start scheiterte an Sandbox-spawn EPERM; derselbe Lauf außerhalb der Sandbox bestand. Vollständige Builds/Tests sind für diesen reinen R0-Bericht nicht ausgeführt.

Zusätzlich erforderliche neue Prüfungen:

  • Migration mit externen Row-Anteilen; keine Phantomlast und unveränderte BMKs.
  • v1–9 ohne CSV verlustfrei, mit CSV klare Ablehnung; alte Command-Inversen und alte Restore-Payloads ebenfalls ohne Teilwrites ablehnen.
  • Config-Änderung/Undo/Neuzweig invalidiert alte Pläne über expectedRevision; Apply mit anderem Dateiinhalt, fehlenden Entscheidungen oder fremden UUIDs rollt vollständig zurück. Später Historyfehler rollt auch Regeln, Links und Mengen zurück.
  • Gebundene Row ändern → Export → Lösen → Undo/Redo behält fachliche Werte.
  • Mehrfachsteckdosen: unterschiedliche effektive Mengen, identische Einzelwerte, richtige Gruppierung und objektweise Rückgabeleistung.
  • Row-/Circuit-/Gruppen-Löschen löst externe Links im Command und stellt sie per Undo wieder her. Raum-/Verteilerlöschen mit Referenzen blockiert.
  • Export-Audit scheitert: keine fachliche Revision; SHA-256 entspricht exakt den gelieferten Bytes. Snapshot/Restore entfernt keine Exportnachweise.
  • 5.000/10.000 synthetische Objekte: Parserzeit, Peak-Speicher, Payloadgröße, Command-/Snapshot-Dauer und UI-Reaktionszeit messen; nur sichtbare Zeilen im DOM, stabile Auswahl über virtuelle Bereiche.

Wesentliche Restrisiken: Linear-Kommentarbindung ist nur anhand des Exports beobachtet; ExcelJS-Releasepflege und Roundtrip sind in R2 zu belegen. Große Originaldateien vervielfachen sich in History/Snapshots; Limits und Messungen müssen reale Speichergrößen berücksichtigen. Die CSV-Entwicklungsbereinigung ist absichtlich verlustbehaftet, aber auf den externen Zustand begrenzt und nur nach verifiziertem Backup zulässig. Fehlende Zielparameter im Muster verlangen einen neuen vollständigen Linear-Export, keine geratenen GUID-Kommentare.

Freigabepunkt: R0 wurde am 29.09.2026 mit den in R1 dokumentierten Korrekturen freigegeben. R2 besitzt einen neuen verbindlichen Freigabepunkt: Vor Beginn von R3 muss der Nutzer die in R2 erzeugte Rückgabedatei erfolgreich in Linear getestet haben.