Audit Linear Excel integration
This commit is contained in:
parent
cf022b250f
commit
ae318a51ac
1 changed files with 521 additions and 0 deletions
521
docs/spec/revit-excel-r0-audit.md
Normal file
521
docs/spec/revit-excel-r0-audit.md
Normal file
|
|
@ -0,0 +1,521 @@
|
|||
# R0 – Audit der Linear-Excel-Anbindung
|
||||
|
||||
Stand: 29.09.2026. Geprüfter Code: `cf022b2`.
|
||||
|
||||
**Status: R0 abgeschlossen, Freigabe für R1–R10 ausstehend.** 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.
|
||||
|
||||
## 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 | 2 Gruppen nichtleerer doppelter Werte |
|
||||
| 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.
|
||||
|
||||
Nicht nachgewiesen: erfolgreicher Rückimport in Linear, dessen genaue
|
||||
Auswertung der Kommentar-/VML-Metadaten und der ExcelJS-Roundtrip. R2 prüft
|
||||
die Struktur, R8/R10 benötigen zusätzlich einen realen Linear-Abnahmelauf.
|
||||
|
||||
## 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](https://github.com/exceljs/exceljs),
|
||||
[offizielle Paketdokumentation](https://www.npmjs.com/package/exceljs).
|
||||
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`, passender OOXML-Inhalt und ZIP-Signatur; kein
|
||||
`.xlsm`, verschlüsseltes Archiv, VBA, ActiveX oder externe Workbook-Links;
|
||||
- maximal 10 MiB Upload, 100 MiB tatsächlich entpackte Daten, 2.000 ZIP-
|
||||
Einträge, 50.000 Zeilen, 256 Spalten und 2 Millionen materialisierte Zellen;
|
||||
- genau ein Arbeitsblatt; keine Formelausführung, kein Nachladen von URLs;
|
||||
- ZIP-Vorprüfung vor ExcelJS: Verzeichniseinträge, doppelte Pfade,
|
||||
Kompressionsverfahren und tatsächliche entpackte Bytezahl prüfen.
|
||||
Zentralverzeichnisangaben allein schützen nicht vor manipulierten Archiven.
|
||||
Begrenzte Dekompression mit Node-Bordmitteln, keine zweite direkte Library;
|
||||
- Parser in begrenztem Worker mit Zeit-/Speichergrenze; Abbruch ohne DB-
|
||||
Schreibvorgang. API-Body-Limit auf Uploadgrenze einschließlich Base64-
|
||||
Overhead abstimmen, statt global beliebige Requestgrößen zuzulassen.
|
||||
|
||||
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.
|
||||
|
||||
Fehlende ID bei sonstigen Objektdaten blockiert; Leer-/eindeutige Summenzeilen
|
||||
werden ignoriert. Nicht passende nichtleere IDs blockieren ebenfalls.
|
||||
Worksharing-ID bleibt als Quelltext erhalten, Matching ist exakt; ungültige
|
||||
Leerzeichen/uneindeutige Schreibweisen 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:
|
||||
|
||||
```ts
|
||||
{
|
||||
schemaVersion: 1,
|
||||
layout: {
|
||||
headerRow: 1, firstDataRow: 3, firstDataColumn: 1,
|
||||
idColumn: "Worksharing-ID"
|
||||
},
|
||||
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.
|
||||
`layout.idColumn` und `columns.worksharingId` werden gemeinsam gesetzt und
|
||||
müssen übereinstimmen. 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 bleibt vor Zuordnung leer; verlangt der Row-Vertrag einen Wert,
|
||||
wird `1` sichtbar vorgeschlagen und ausdrücklich bestätigt. 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_version INTEGER NOT NULL CHECK > 0`, `configuration JSON NOT NULL`. Enthält obiges vollständiges Aggregat. |
|
||||
| `external_model_sources` | `id`, `project_id UNIQUE`, `name`, `source_type = revit_xlsx`. Genau eine implizite Quelle je Projekt. |
|
||||
| `external_import_batches` | Bestehende IDs, Importart, Zeit, Dateiname, SHA-256, `applied_project_revision`, `configuration_version`, `configuration_snapshot JSON`, `original_bytes BLOB`, `document JSON`; Matrix jetzt typisiert und transportneutral. Unveränderlich innerhalb des aktiven Zustands; Undo/Restore darf ganze Batches entfernen/wiederherstellen. |
|
||||
| `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_version INTEGER`, `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. Importbatches selbst gehören vollständig zu Snapshot/Transfer.
|
||||
|
||||
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. Room-/Board-
|
||||
Sammeländerungen prüfen alle betroffenen Row-Links und lehnen inkonsistente
|
||||
Umbuchungen ab, bis diese ausdrücklich gelöst/verschoben sind.
|
||||
|
||||
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 Fachinhalt; Versionsgeneration siehe unten. |
|
||||
| `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.
|
||||
|
||||
Konfigurationsgeneration: `configurationVersion` erhält bei jedem
|
||||
Konfigurationswechsel einschließlich Undo/Redo/Restore die neu entstehende
|
||||
Projektrevision. Sie ist damit strikt steigend, aber nicht lückenlos.
|
||||
Historienbefehle vergleichen den erwarteten Fachinhalt und die aktuelle
|
||||
Projektversion; die administrative Generation wird serverseitig neu erzeugt.
|
||||
Die Inverse restauriert alle Fachwerte exakt, nicht einen alten Zählerstand.
|
||||
Importbatches behalten ihre ursprüngliche Generation und ihren Snapshot.
|
||||
Ein Restore/Projekttransfer erhält diese Herkunft; die aktive Konfiguration
|
||||
wird an die Revision des Zielprojekts gebunden. Prüfen: Änderung → Undo →
|
||||
anderer Zweig darf niemals denselben Vorschau-Token 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/-generation, 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 benutzen
|
||||
denselben Prüfdienst für persistierte Bytes vor der Transaktion. Keine
|
||||
asynchronen Callbacks in `better-sqlite3`-Transaktionen.
|
||||
|
||||
Allgemeine Row-/Circuit-/Gruppen-/Board-/Raum-/ProjectDevice-Löschungen
|
||||
erhalten Guards, solange externe Referenzen betroffen sind. Nutzer lösen die
|
||||
Referenzen zuvor ausdrücklich über die passenden Commands. Guards gelten
|
||||
auch in Unterbaum- und History-only-Pfaden. Dadurch werden vorhandene
|
||||
Commands nicht unbemerkt zu unvollständigen externen Löschcommands.
|
||||
|
||||
## 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,
|
||||
alle Batches mit Originalbytes/Matrix, 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 zeigt Status, Aktionen und eine paginierte Objekttabelle
|
||||
(Vorschlag: 100 Zeilen pro Seite). Filter-/Sortierzustand, UUID-Auswahl und
|
||||
Sammelaktionen sind unabhängig vom DOM. „Alle gefilterten“ verwendet eine
|
||||
explizit aufgelöste Auswahl zur bekannten Revision; keine Mutation anhand
|
||||
eines inzwischen veränderten Filters. 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 benötigte Zielspalten bzw.
|
||||
Linear-Bindungen blockieren die betreffende Exportkonfiguration mit Hinweis
|
||||
auf einen neuen vollständigen Linear-Export. 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; ZIP-/Formelgrenzen. 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 | Objekt-Reads, Paging/Filter, Sammel-Commands und Overrides; verwandte Lösch-/Referenzguards vollständig absichern. |
|
||||
| R7 | Gruppierung, Drag-and-drop, Row-Indikatoren und Lösen inklusive aktueller Row-Werte; drei Drop-Ziele 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; 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.
|
||||
- Löschen über alle Unterbaum-/History-Pfade kann externe FKs nicht still
|
||||
nullen. Fremde Verteilungen/Räume/Kategorien und Gerätearten blockieren.
|
||||
- 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; höchstens eine
|
||||
paginierte Seite im DOM, stabile Auswahl über Seitenwechsel.
|
||||
|
||||
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:** Der Nutzerauftrag verlangt wörtlich
|
||||
„R0. Audit (danach stoppen und Freigabe abwarten)“.
|
||||
Mit Freigabe dieses Vorschlags beginnt R1; R0 selbst autorisiert keine
|
||||
Installation, Migration oder Implementierung von R1–R10.
|
||||
Loading…
Add table
Add a link
Reference in a new issue