Document Linear Excel integration

This commit is contained in:
Julian Appel 2026-09-29 22:28:16 +02:00
parent ae318a51ac
commit d4803a18d2
16 changed files with 932 additions and 2316 deletions

184
AGENTS.md
View file

@ -320,29 +320,21 @@ supported versions contain circuit-group identity, distribution-board components
separate circuit/component protection records. Portable duplicate imports
remap component ids and protection-owner references together with the existing
project graph.
Project-wide Revit CSV configuration uses
`external-csv-configuration.update`. Its complete expected/target snapshot is
persisted through the shared project-command transaction, so create, update,
delete, Undo and Redo are revision-safe. Snapshot schema 5-9, restore and portable
project duplication preserve the configuration; duplication remaps its internal
id and project link.
The project page exposes the Revit CSV modal. It edits the complete
transport/column/family-rule configuration through the revision-safe endpoint,
requests a stateless preview and then shows the Phase 14.2 initial-import
decisions. Preview responses include all mapped objects, while the UI renders
only the first 25. No preview or plan creates external objects, rows, revisions
or server-side drafts.
Phase 14.2 migration `0003` provides one implicit Revit CSV source per project,
immutable import batches with original bytes plus the classified cell matrix,
normalized source-room mappings and external objects unique by
`(sourceId, ifcGuid)`. Source values, planning values and overrides are separate.
The general external-model repository is read-only; runtime writes belong only
to typed command adapters. Snapshot/restore and portable project transfer schema versions 5-9
capture the complete external state and remap every internal UUID and link while
preserving IFCGUIDs, source values, original bytes and the classified matrix.
Import batches additionally store the monotonic project CSV configuration
version introduced by additive migration `0004`; it is distinct from the CSV
configuration JSON schema version.
The current runtime still contains the legacy Revit-CSV/IfcGUID foundation:
project configuration, preview, confirmed initial import, external objects and
the three row-assignment commands. It remains the audited starting point, not
the Phase-14 target. Do not extend its CSV transport or IFCGUID identity model.
The approved cutover is Linear XLSX with exact case-sensitive Worksharing-ID
identity. See `docs/spec/revit-excel-integration-requirements.md` and
`docs/spec/revit-excel-phase-14-plan.md`.
During R1/R2 no database or runtime schema changes are made. R3 will replace
the legacy configuration and transport additively, reject non-empty legacy CSV
snapshot/history state with a German error, and introduce snapshot schema 10.
The target configuration has no independent version counter; `expectedRevision`
invalidates stale plans, and each import batch stores a configuration copy.
Only the newest import batch retains workbook bytes and the full matrix; older
batches retain date, filename, SHA-256 and object count.
Phase 14.3 migration `0005` adds `CircuitDeviceRow.manualQuantity`, backfills
existing rows from `quantity` and keeps `quantity` as the materialized total.
Normal manual row inserts and quantity edits update both values together.
@ -363,37 +355,12 @@ protection and its external object links. Its history-only inverse requires the
complete unchanged circuit snapshot and exact link set. Redo never recalculates
the BMK. All three external assignment stores share
`external-object-assignment.persistence.ts` for compatibility and link safety.
The read-only
The current read-only
`GET /api/projects/:projectId/circuit-lists/:circuitListId/external-objects`
projection resolves the board through the owned CircuitList and returns only
that board's compact external objects, unassigned first. It exposes no original
CSV bytes or command payloads and returns an empty list before optional import.
Confirmed initial state is written only through
`external-import.apply-initial`. The command rechecks configuration version,
original-byte SHA-256, parsed matrix, complete IFCGUID/source values, explicit
planning overrides and internal project links in the shared transaction. It
never creates or links a CircuitDeviceRow. Its exact inverse removes the whole
unchanged external state, and Redo restores the same UUIDs and bytes.
`POST /api/projects/:projectId/external-csv/initial-import/plan` is a stateless
read path for the first wizard stage. It rejects projects with an existing
external source and returns source-room groups, exact room-number suggestions,
exact family/type groups, projected object values, issue counts and the current
floor/room/board/ProjectDevice catalogs. It creates no draft, revision or
domain row. The wide modal renders these groups and catalogs as explicit
decisions and identifies exact, ambiguous and new room matches. Missing rooms
and ProjectDevices are created through the reused project forms with mapped
Revit values as visible defaults. Each catalog creation remains its own project
command; the wizard adds and selects the result without discarding its plan.
The dedicated
`POST /api/projects/:projectId/external-csv/initial-import/apply` endpoint
retransmits and replans the file against the expected hash, configuration
version and project revision. It requires one explicit decision per source-room
and exact family/type group, blocks unclassified families, creates all stable
external UUIDs server-side and invokes `external-import.apply-initial`.
Room/default-board and optional ProjectDevice links are supported; CSV circuit
values remain source-only and every `circuitDeviceRowId` remains null. The UI
blocks unclassified families, requires a final confirmation and applies the
whole import as one persistent Undo/Redo step.
projection resolves the board through the owned CircuitList and returns compact
legacy external objects. The target Revit page will load one compact project
list and filter/sort it client-side in a virtualized table, without server
pagination or batch blobs in the DTO.
The central revision boundary creates an automatic logical snapshot after each
25 new revisions and retains only the newest 12 automatic snapshots per
project. Named snapshots are never removed by this retention policy.
@ -575,70 +542,58 @@ Required operations:
Uploads are PNG/JPEG/SVG up to 2 MB with a content signature check; the logo
is served with `nosniff` and a restrictive CSP.
## Revit / CSV External Model Work
## Revit / Linear Excel External Model Work
Status: further Revit work (editor assignment UI, follow-up import, return
export) is deferred and will be tackled later. When it resumes, the exchange
stays CSV-based and uses the CSV export/import of the Linear plugin in Revit.
The internal Revit/CAD steering committee prefers this over manipulating the
model directly through Dynamo. Do not start Dynamo, Revit API or JSON
transport work. The Linear CSV layout is not yet known: check a sample export
against the existing project CSV configuration before changing the parser.
Earlier Dynamo considerations are archived in
`docs/archive/revit-dynamo-leistungsbilanz-integration-konzept.md`; the
removed diagnostic scripts remain reachable through the git tag
`archive/dynamo-vorueberlegungen`.
Phase 14 is active and follows
`docs/spec/revit-excel-integration-requirements.md` plus
`docs/spec/revit-excel-phase-14-plan.md`. The old CSV requirements and phases
14.0–14.6 are superseded. Dynamo, Revit API and JSON transport remain excluded.
When explicitly working on Phase 14, use
`docs/spec/revit-csv-integration-requirements.md` as the detailed source of
truth together with the current architecture documents.
Critical target rules:
Critical rules:
- Exchange uses only `.xlsx` files produced and consumed by the Linear plugin.
- Revit integration remains optional. Import never creates a CircuitDeviceRow,
Circuit or equipment identifier.
- Worksharing-ID is the external key and is compared exactly and
case-sensitively. It stays separate from internal UUIDs and circuit BMKs.
IfcGUID is optional redundancy, never a key, and duplicate values are only a
warning.
- A row without Worksharing-ID is suspicious only when `Familie und Typ` is
populated. Show a warning and skip it; do not block. Other ID-less rows,
including the sample summary in column B, are skipped silently.
- Source, planning and override values remain separate. Existing ProjectDevices
remain canonical and are never silently changed.
- Multi-socket objects remain indivisible. Row quantity stays
`manualQuantity + sum(effectiveQuantity)`.
- The project configuration has no independent version counter. Preview and
apply use `expectedRevision`; import batches store a configuration copy.
- Apply retransmits and parses the workbook. Undo/Redo never reads Excel; they
apply only stored before/after states.
- Only the newest import batch retains original bytes and the full matrix;
older batches retain date, filename, SHA-256 and object count.
- The Revit object table loads one compact list, filters/sorts in the client and
renders it virtually; do not add server pagination.
- Linked objects always follow their row's distribution board. Changing a
room's default board affects only unassigned objects and is not blocked.
- Deleting a row, circuit or group warns that X Revit objects become unassigned,
detaches them in the same command and restores links on Undo. Only deletion
of referenced rooms and distribution boards is blocked.
- Missing optional return columns for designation, power, voltage or current
produce warnings and are skipped. Only missing circuit columns for the
selected combined/separate mode block export.
- Missing GZF defaults visibly to 1 without separate confirmation.
- R2 must generate a changed return workbook from the local sample. The user
tests it in Linear before R3. If Linear rejects it, propose direct OOXML
modification of the original workbook before starting R3.
- All confirmed writes use typed project commands with `expectedRevision`,
complete inverse data and the shared project-command transaction boundary.
- Do not add automatic circuit planning, Revit circuit adoption, multi-source
management, partial imports, PostgreSQL, background jobs or new permissions.
- Revit integration is optional. Do not make imported external data mandatory
for projects, rooms, project devices, circuits or device rows.
- Parse imports into staging first. Never write CSV rows directly into circuits
or device rows.
- Keep external object identity separate from internal UUIDs and circuit BMKs.
`IfcGUID` identifies the external Revit object and must never replace an
internal UUID or `equipmentIdentifier`.
- One imported Revit object may exist without a `CircuitDeviceRow`.
Import, room assignment, distribution-board assignment, classification and
ProjectDevice linking do not create a row.
- Create or change a `CircuitDeviceRow` only after an explicit user action in
the circuit-list editor.
- Several external objects may link to one `CircuitDeviceRow`, while every
external object remains individually traceable for follow-up imports and
object-specific export.
- Multi-socket Revit objects are indivisible. Their effective quantity may be
greater than one, but one external object must never be split across circuits.
- Existing ProjectDevices are canonical project templates and must not be
overwritten from Revit values. When creating a new ProjectDevice, mapped
Revit values may prefill the creation form.
- Store imported source values separately from local planning values and local
overrides. Imports never silently overwrite local values.
- Repeated imports match deterministically by project/source and `IfcGUID`.
New, changed, missing and conflicting objects require preview and explicit
user decisions.
- The first implementation assumes one complete Revit model export per project.
Do not add visible multi-source, linked-model or partial-import management.
- CSV configuration is project-scoped. Preserve title, header, blank, subtotal
and unknown rows and columns for the return export.
- Treat rows without `IfcGUID` as passthrough when they contain no object data.
Do not report Revit subtotal rows as missing-identity objects.
- Apply each confirmed import diff through a typed project command with
`expectedRevision`, complete inverse data and the shared project command
transaction boundary.
- External-model state must be added to logical project snapshots and portable
project transfer when it becomes part of the supported runtime.
- Keep CSV parsing/serialization in a transport adapter. Domain services must
not depend on CSV syntax, React, `better-sqlite3` or concrete repositories.
- Do not implement automatic circuit planning, Dynamo/API exchange,
PostgreSQL, background jobs or permissions as part of the initial CSV phase.
Before implementation, audit the current ProjectDevice, CircuitDeviceRow,
command, snapshot, transfer and editor drag-and-drop paths. Propose concrete
domain objects and commands before adding migrations.
The real sample `docs/spec/kbp-Stromkreis.xlsx` contains project data. It is
gitignored and must never be embedded in tests or committed. Use synthetic
workbooks for automated tests and accept the real file only as an explicit
local path in the reference checker.
## Cable Sizing Module
@ -733,9 +688,6 @@ for the early-phase power balance by DIN 276 cost group (see
## Current Deferred Work
- Revit/CSV/IFCGUID round-trip (deferred; later via Linear plugin CSV, never
Dynamo), except when Phase 14 is explicitly requested and
`docs/spec/revit-csv-integration-requirements.md` is being followed
- full electrical sizing
- multi-user/PostgreSQL operation
- supported production deployment