# 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.