125 lines
5.1 KiB
Markdown
125 lines
5.1 KiB
Markdown
# Circuit List Editor Architecture
|
|
|
|
## Purpose
|
|
|
|
The circuit-list editor is a circuit-first planning workspace for distribution-board design. It is optimized for spreadsheet-like editing while preserving electrical domain boundaries: circuit-level data stays on circuits, and load rows stay inside circuits.
|
|
|
|
## Frontend Grid Modules
|
|
|
|
- `circuit-tree-editor.tsx` owns React state, API commands, undo/redo and drag-and-drop orchestration.
|
|
- `circuit-grid-model.ts` owns column metadata, circuit/device cell ownership, value projection, formatting, numeric parsing and block sort values.
|
|
- `circuit-grid-projection.ts` owns block-preserving filtering/sorting and the normalized visible row projection.
|
|
- `circuit-grid-insertion.ts` resolves insertion intent and insertion sort positions.
|
|
- `circuit-grid-safety.ts` resolves delete intent, BMK conflicts and cross-section move confirmation requirements.
|
|
|
|
The pure grid modules have no React state and are covered by focused unit tests. This keeps circuit/device ownership rules testable while the editor UI is split incrementally.
|
|
|
|
## Domain Model Overview
|
|
|
|
- `CircuitSection`
|
|
- Represents a protected circuit group in one of the categories lighting,
|
|
single-phase or three-phase.
|
|
- Owns category, positive group number, generated prefix, display name and
|
|
ordering.
|
|
- `Circuit`
|
|
- Core electrical unit in the list.
|
|
- Owns circuit-level identifiers and technical data:
|
|
- `equipmentIdentifier` (BMK)
|
|
- one explicit one-to-one protection device
|
|
- cable data
|
|
- reserve state
|
|
- voltage and optional control requirement for future sizing
|
|
- circuit-level remark/status
|
|
- `CircuitDeviceRow`
|
|
- Load/device line inside a circuit.
|
|
- Owns row-level load and context values:
|
|
- `quantity`
|
|
- `powerPerUnit`
|
|
- `simultaneityFactor`
|
|
- `cosPhi`
|
|
- room snapshots
|
|
- category/cost group and related row attributes
|
|
- canonical `phaseType` values `single_phase` or `three_phase`; the
|
|
frontend always presents these as `1-phasig` or `3-phasig` and edits
|
|
them through a selection control
|
|
- `ProjectDevice`
|
|
- Reusable device template entity at project level.
|
|
- Can be linked to `CircuitDeviceRow` entries, with copied display values on insert.
|
|
- `DistributionBoardComponent`
|
|
- Represents fixed header components, optional group protection and manually
|
|
named auxiliary footer devices with their own unique BMK.
|
|
- Group protection may own a separate one-to-one protection configuration.
|
|
## Why A Circuit Is Not One Row
|
|
|
|
A circuit can contain zero, one, or many device rows. Treating a circuit as a single row breaks:
|
|
|
|
- BMK ownership (belongs to circuit, not each device row)
|
|
- circuit-level protection/cable fields
|
|
- grouped calculations and circuit move/reorder semantics
|
|
|
|
The tree model keeps circuit identity stable while allowing row-level load composition.
|
|
|
|
## Rendering Model: Single vs Multi Device
|
|
|
|
- Single-device circuit:
|
|
- Rendered as compact combined row (`circuitCompact`) for fast editing.
|
|
- Multi-device circuit:
|
|
- Rendered as one circuit summary row (`circuitSummary`) plus indented `deviceRow` entries.
|
|
|
|
This keeps visual density high without losing ownership boundaries.
|
|
|
|
## Reserve / Empty Circuits
|
|
|
|
Circuits with no device rows are rendered as reserve rows (`reserveCircuit`).
|
|
Section-level `-frei-` placeholder rows represent insertion targets for creating a new circuit in that section.
|
|
|
|
## BMK Ownership (`equipmentIdentifier`)
|
|
|
|
`equipmentIdentifier` / BMK is circuit-owned (`Circuit.equipmentIdentifier`).
|
|
|
|
- Device rows do not have their own BMK.
|
|
- Existing identifiers stay stable on sort, insert and delete. Explicit
|
|
renumbering may change them, and a user-initiated complete-circuit move to
|
|
another same-category group assigns the next target-group identifier.
|
|
- Renumbering is explicit, not implicit on move/sort/delete.
|
|
|
|
## Data Ownership Split: Circuit vs Device Row
|
|
|
|
Circuit-level fields on `Circuit`:
|
|
|
|
- protection type/rating/characteristic
|
|
- cable type/cross-section/length
|
|
- RCD/terminal/status
|
|
|
|
Device-level load fields on `CircuitDeviceRow`:
|
|
|
|
- quantity, power per unit, simultaneity, cosPhi
|
|
- row naming/categorization and room snapshots
|
|
|
|
This split matches execution-design workflows where many loads share one protective path.
|
|
|
|
## Calculated Totals
|
|
|
|
- `rowTotalPower` is calculated per `CircuitDeviceRow`.
|
|
- `circuitTotalPower` is calculated as sum of all row totals in one circuit.
|
|
|
|
Totals are exposed by the tree response and shown in computed read-only cells.
|
|
|
|
## Frontend Route
|
|
|
|
Primary circuit-first editor route:
|
|
|
|
- `/projects/:projectId/circuit-lists/:circuitListId/tree-edit`
|
|
|
|
Old `/projects/:projectId/circuit-lists` bookmarks redirect to the project
|
|
page. A future print view will provide a dedicated read-only presentation.
|
|
|
|
## Future Persistence Direction
|
|
|
|
Persistent Undo/Redo, project revisions and logical snapshots are implemented
|
|
through project-scoped commands and the shared transaction boundary. Database
|
|
backups remain separate from user-visible project snapshots. External-model
|
|
exchange and PostgreSQL readiness are specified in
|
|
[Project History and External Model Architecture](./project-history-and-external-model-architecture.md)
|
|
and remain future work.
|