28 KiB
Distribution Board Components and Protection Groups
Status
This document defines the agreed target behavior for distribution-board components, protected circuit groups and circuit protection devices. Phase A and the relational Phase-B1 foundation are implemented; later sections remain requirements and are not proof of runtime or editor support.
Full rule-based protection and cable sizing is deliberately deferred. This phase establishes the structure and manually selected technical values that a later calculation and warning engine will evaluate.
Goals
- represent the circuit list as the basis of a tabular single-line diagram
- list incoming, group-level and auxiliary distribution-board components with stable equipment identifiers
- support multiple independently protected groups for lighting, single-phase and three-phase outgoing circuits
- give every newly created outgoing circuit one explicit protection device
- preserve the existing distinction between a circuit and its device rows
- keep every structural change atomic, revisioned and persistently undoable
- prepare stable target fields for the later Revit round-trip
Non-Goals
- norm-compliant protection or cable sizing
- automatic creation of additional groups based on the incoming rating
- automatic phase balancing
- manufacturer-specific product catalogs
- automatic equipment-identifier generation for auxiliary components
- channel-level relationships between actors and controlled circuits
- PostgreSQL or multi-user operation
Existing Model Audit
Keep
Circuitremains the outgoing-circuit aggregate.CircuitDeviceRowremains a load assigned to a circuit and never receives its own protection device or equipment identifier.- Circuit-level load, cable and control fields remain circuit-owned.
- Existing stable UUIDs, project revisions, snapshots and persistent Undo/Redo remain authoritative.
CircuitSectionremains the migration starting point for a protected circuit group.- Grid projection remains separate from persisted domain structure.
Change
- A
CircuitSectiongains an explicit category and group number and represents one protected circuit group. - Circuit protection changes from loosely related flat strings to an explicit one-to-one protection-device model.
- Distribution-board components become independent BMK-bearing list entries.
- Equipment-identifier uniqueness covers circuits and all distribution-board components in the complete circuit list.
- Moving a circuit to another group of the same category atomically assigns the next identifier of the target group.
- New distribution boards create three default groups rather than treating the optional unassigned compatibility section as a normal fourth group.
Remove Eventually
- hard-coded assumptions that each category has exactly one section
- numbering that only understands
prefix + integer - free-text protection-device combinations that cannot be validated
rcdAssignmentas a substitute for an explicit group relationship
Removal happens only after migrated state, snapshots, commands and the editor use the replacement model.
Target Domain Structure
Project
└── DistributionBoard
└── CircuitList
├── fixed header components
│ ├── Main switch
│ └── Surge protective device
├── CircuitGroup 1..n
│ ├── optional upstream protection component
│ ├── optional group RCD component
│ └── Circuit 0..n
│ ├── ProtectionDevice exactly 1
│ └── CircuitDeviceRow 0..n
└── auxiliary components 0..n
The hierarchy defines ownership and electrical grouping. It does not require every level to be visually indented in the table.
Circuit Groups
CircuitSection evolves into the circuit-group entity. A group has:
- stable UUID
- circuit-list ownership
- category
- positive group number
- display name
- sort order
- optional upstream protection component
- optional group RCD component
- zero or more outgoing circuits
Supported categories:
lightingsingle_phasethree_phase
Each new distribution board creates exactly:
Beleuchtung 11-phasig 13-phasig 1
Additional groups are created manually. A new group receives the highest existing group number in its category plus one. Gaps are not filled automatically.
A group may have at most one upstream protection component and at most one group RCD. Both are optional. Every circuit in the group remains downstream of those group components until it is moved to another group.
Distribution-Board Components
Every distribution-board component has:
- stable UUID
- circuit-list ownership
- unique equipment identifier
- name
- role
- placement
- sort order within its placement
Initial roles:
main_switchsurge_protective_devicegroup_upstream_protectiongroup_residual_current_protectionauxiliary
Initial placement zones:
headergroupfooter
New distribution boards create exactly:
-Q0, nameHauptschalter, rolemain_switch-FA, nameÜberspannungsableiter, rolesurge_protective_device
These fixed components appear at the top and may initially have no further technical product data.
Auxiliary components initially require only:
- manually entered equipment identifier
- name
- sort order
Examples include KNX switching actuators, blind actuators, phase-monitoring modules, DALI gateways, relays and other installed board equipment. They appear after all circuit groups and can be reordered by drag-and-drop. Automatic BMK suggestions and channel-to-circuit relationships are deferred.
Circuit Protection
Every newly created outgoing circuit owns exactly one protection device.
CircuitDeviceRow does not own a protection device.
The circuit and its protection device are projected as one circuit row. The circuit equipment identifier is also the displayed identifier of its protection device and must not be stored twice.
Supported protection-device types:
D02NH000NH00NH0NH1NH2NH3LSFIFI_LSAFDD
D01 and NH4 are intentionally excluded.
Protection-Device Fields
All protection devices have:
- type
- rated current in ampere
Type-dependent fields:
- D02 and NH:
- fuse utilization category
gGorgR
- fuse utilization category
- LS:
- trip characteristic
B,C,DorZ
- trip characteristic
- FI:
- RCD type
A,AC,BorB+ - rated residual current in milliampere
- RCD type
- FI/LS:
- trip characteristic
B,C,DorZ - RCD type
A,AC,BorB+ - rated residual current in milliampere
- trip characteristic
- AFDD:
- trip characteristic
B,C,DorZ - no RCD type
- no rated residual current
- trip characteristic
Poles are intentionally not stored. The circuit-group category supplies the required phase context for the current scope.
Allowed Ratings
D02
20, 25, 32, 35, 40, 50, 63 A
NH000 and NH00
6, 10, 16, 20, 25, 32, 35, 40, 50, 63, 80, 100, 125, 160 A
NH0
6, 10, 16, 20, 25, 32, 35, 40, 50, 63, 80, 100, 125, 160, 200, 224, 250 A
NH1
16, 20, 25, 32, 35, 40, 50, 63, 80, 100, 125, 160, 200, 224, 250 A
NH2
25, 32, 35, 40, 50, 63, 80, 100, 125, 160, 200, 224, 250, 300, 315, 355, 400 A
NH3
50, 63, 80, 100, 125, 160, 200, 224, 250, 315, 355, 400, 500, 630, 800 A
LS, FI/LS and AFDD
6, 10, 13, 16, 20, 25, 32, 40, 50, 63, 80, 100, 125 A
FI/RCD
Rated currents:
16, 25, 40, 63, 80, 100, 125 A
Rated residual currents:
10, 30, 100, 300, 500 mA
The device type determines which values and characteristics are valid. UI, request validation and domain validation use one shared catalog rather than duplicated free-text rules.
All supported devices that provide overcurrent protection may be selected as a group upstream protection device. A standalone FI belongs in the separate optional group-RCD role.
Default Protection Devices
New circuits receive:
- lighting:
- LS
- 10 A
- characteristic B
- single-phase:
- FI/LS
- 16 A
- characteristic B
- RCD type A
- 30 mA
- three-phase:
- FI/LS
- 16 A
- characteristic B
- RCD type A
- 30 mA
A newly added group RCD defaults to:
- FI
- 40 A
- RCD type A
- 30 mA
An upstream protection component has no automatic default and is created only when the planner requests it.
Equipment-Identifier Rules
The leading hyphen is part of every generated identifier.
Group 1 examples:
-1F1.0 upstream protection, lighting
-1Q1.0 group RCD, lighting
-1F1.1 first lighting circuit
-2F1.0 upstream protection, single-phase
-2Q1.0 group RCD, single-phase
-2F1.1 first single-phase circuit
-3F1.0 upstream protection, three-phase
-3Q1.0 group RCD, three-phase
-3F1.1 first three-phase circuit
Category numbers:
- lighting:
1 - single-phase:
2 - three-phase:
3
Function letters:
- overcurrent protection and outgoing circuit:
F - group RCD:
Q
The group number follows the function letter. .0 is reserved for the group
component. Outgoing-circuit suffixes start at .1.
Equipment identifiers must be unique across all circuits and components of the complete circuit list, including header and footer components.
Manual BMK edits must validate that same shared uniqueness boundary.
Reorder, Move and Renumber Behavior
Reorder Within One Group
Changing circuit order changes only sortOrder. It never changes an equipment
identifier.
Move to Another Group
A circuit may move only to another group of the same category.
The move:
- finds the highest existing outgoing-circuit suffix in the target group
- assigns that suffix plus one
- moves the complete circuit, its one-to-one protection device and all device rows
- commits old and new group, position and identifier atomically
Gaps are not filled. Undo restores the original group, sort position and equipment identifier. Redo reapplies the same previously determined target identifier rather than calculating another one.
This automatic identifier change is specific to a cross-group move initiated by the user. A reorder inside one group never renumbers.
Reorder Groups
Changing group display order changes only group sortOrder. Group numbers and
all equipment identifiers remain unchanged.
Explicitly Renumber Groups
Group renumbering is a separate explicit action. It:
- changes group numbers according to the requested mapping
- preserves every outgoing circuit suffix
- updates optional
.0group-component identifiers - updates every affected circuit identifier
- resolves swaps through collision-safe temporary identifiers
- commits the complete mapping as one project revision
Undo restores the exact previous group numbers and identifiers.
Delete Behavior
A group may be deleted even when populated, but only after an explicit warning that summarizes:
- optional upstream protection
- optional group RCD
- number of circuits
- number of circuit device rows
Confirmation deletes the complete group subtree atomically. The inverse command stores the complete stable snapshots needed to restore all UUIDs, fields, links, protection devices, group relationships, identifiers and sort positions.
A stale or partially changed subtree must not be silently deleted or restored.
UI Projection
The circuit-list editor projects three fixed zones:
- header:
-Q0 Hauptschalter-FA Überspannungsableiter
- groups:
- group heading
- optional upstream protection row
- optional group RCD row
- circuit rows and their optional expanded device rows
- footer:
- auxiliary distribution-board components
Group indentation is optional presentation. Group ownership must remain clear through headings, separators or a dedicated group indication.
The grid remains a custom spreadsheet component:
- static text by default
- edit mode only when invoked
- group and auxiliary-component drag handles
- clear valid and invalid drop indicators
- German user-facing labels
Protection editing must show only fields valid for the selected device type. Changing the type resets or explicitly confirms removal of fields that the new type cannot use.
History and Command Boundary
New project-scoped writes must use typed persistent commands and the existing shared project-command transaction boundary.
Required logical operations:
- insert/update/delete auxiliary component
- reorder auxiliary components
- insert/update/delete group protection component
- insert/delete group
- reorder groups
- explicitly renumber groups
- move circuit between same-category groups with deterministic BMK assignment
- update circuit protection device
Creating a distribution board includes its fixed components, three default
groups, circuit list and all stable UUIDs in one distribution-board.insert
command.
Every command must:
- require
expectedRevision - validate complete project/list/group ownership
- validate shared BMK uniqueness inside the write transaction
- contain deterministic forward and inverse data
- commit the domain mutation, revision and history transition atomically
- remain undoable and redoable after application restart
Snapshot and Transfer Compatibility
The supported logical project snapshot and portable JSON transfer must include:
- group category and group number
- fixed, group and auxiliary components
- circuit protection-device state
- all new component relationships and sort positions
Introducing the model requires a snapshot-schema version increase and explicit upgraders for supported older payloads.
Database migration rules:
- preserve all existing stable UUIDs
- preserve existing circuit equipment identifiers during schema migration
- map the existing lighting, single-phase and three-phase sections to group 1 of the respective category
- preserve an existing unassigned section only when required by existing data; it is not created for a new distribution board
- preserve existing flat circuit protection values when creating the new one-to-one protection state
- do not silently replace an existing protection selection with a new default
- allow legacy identifiers to remain until an explicit, collision-safe conversion or renumber action is approved
New defaults apply to newly created circuits and boards, not as an implicit rewrite of existing planning data.
Historical persisted commands and snapshots that remain in the supported compatibility window must still deserialize and execute after the migration.
Later Sizing and Warning Engine
The selected protection device is the planner-owned value. Later sizing logic will calculate a recommendation separately.
Target behavior:
stored selection
-> calculation and validation
-> valid: no warning
-> invalid: colored warning plus recommended protection
-> user explicitly accepts or rejects the recommendation
The same pattern applies later to cable cross-section and length. Suggestions never silently overwrite selected values.
Dimensioning rules and additional inputs are defined in a separate future specification supplied by the planner.
Delivery Phases
A. Catalog and Pure Domain Rules
Status: Complete.
- introduce typed component roles, categories and protection-device types
- centralize rating and characteristic catalogs
- validate device-specific field combinations
- define default circuit and group-RCD protection values
- test numbering parsing and formatting independently from persistence
Implemented foundation:
- shared circuit-group categories, German labels and category numbers
- one protection-device catalog with all agreed ratings and characteristics
- strict device-dependent validation for fuse, LS, FI, FI/LS and AFDD fields
- pure factories for circuit and group-RCD defaults
- pure nested BMK formatting, parsing and highest-number-plus-one rules
- no runtime database or editor integration before delivery phase B
Acceptance:
- every agreed valid combination is accepted
- invalid rating/type/field combinations are rejected
- defaults produce the exact agreed values
B. Persistence and Compatibility Model
Status: Complete.
- add group category and group number
- add distribution-board component persistence
- add one-to-one circuit protection persistence
- implement shared BMK uniqueness
- generate and inspect one additive migration
- add snapshot/transfer schema upgrade
- preserve existing identifiers and protection values
Implemented in B1:
- additive migration
0024adds group identity to circuit sections and maps the three established sections to group 1 without changing UUIDs - separate component and circuit/component protection tables preserve the one-to-one ownership boundaries
- a trigger-maintained circuit-list registry rejects normalized BMK collisions across circuits and distribution-board components
- the existing flat circuit protection fields remain untouched until their deterministic snapshot/runtime transition is implemented
- clean and populated pre-migration databases are covered by migration tests
- newly created legacy-compatible board structures receive the same initial group identity while their persisted command format remains unchanged
Implemented in B2:
- snapshot schema version 7 includes group identity, distribution-board components and both one-to-one protection collections
- capture, named and automatic snapshots, restore, Undo/Redo and portable JSON transfers preserve the complete new relational state
- duplicate imports remap component UUIDs and both protection-owner references together with the existing project structure
- versions 1 through 6 remain readable; version 6 maps the three established section keys to group 1 and leaves new collections empty
- older flat circuit protection values remain present and are not guessed into strict new protection configurations
- current snapshots reject invalid ownership, duplicate group numbers, cross-entity BMKs and invalid protection configurations before persistence
Acceptance:
- a current database migrates without data loss
- an empty database creates the complete schema
- old supported snapshots and transfers upgrade deterministically
- BMK collisions across circuits and components are rejected
C. Persistent Commands and Board Defaults
Status: Complete.
- extend
distribution-board.insertwith fixed components and three groups - implement component and group CRUD commands
- implement group and footer reordering
- add complete inverse snapshots and rollback tests
Implemented in C1:
distribution-board.insertschema version 3 carries stable UUIDs for three initial groups, main switch-Q0and surge protective device-FA- its inverse verifies and removes the unchanged complete structure; Redo restores the same UUIDs
- a late revision/history failure rolls back board, list, groups and components together
- stored schema versions 1 and 2 retain four legacy sections and receive no invented components
Implemented in C2a1:
distribution-board-component.insertanddistribution-board-component.deletepersist complete component snapshots with their optional one-to-one protection-device configuration- mutable group protection components validate their group ownership and protection-device combination before writing
- auxiliary components remain footer entries without protection-device data
- fixed header roles are excluded from these general CRUD commands
- deletion requires an exact unchanged snapshot; Undo/Redo restores the same component UUID and a late revision/history failure rolls back the complete write
Implemented in C2a2:
distribution-board-component.updateexchanges one complete expected component/protection snapshot for one complete target snapshot- name, BMK, protection configuration and
sortOrdercan change atomically - component id, list/group ownership, role and placement zone remain immutable through this general update command
- stale expected state and cross-entity BMK collisions are rejected; Undo/Redo restores the exact previous snapshot
Implemented in C2b1:
circuit-group.insert,circuit-group.updateandcircuit-group.deletepersist complete group snapshots with stable UUIDs- category, group number and prefix are validated as one consistent identity; general updates change only the display name
- deletion requires an exact unchanged and empty group; populated destructive deletion remains the separately confirmed Phase-D operation
- project/list ownership, stale state, Undo/Redo and late rollback are covered at the shared transaction boundary
Implemented in C2b2:
circuit-group.reorderrequires every group in the circuit list with its exact expected and targetsortOrder- sorting changes no group number, prefix or circuit equipment identifier
- incomplete or stale assignments are rejected before history is recorded
- the complete reorder is one project revision and one persistent Undo/Redo step; late failures roll back every position
Acceptance:
- new boards contain the agreed fixed structure
- every structural write survives reload and supports Undo/Redo
- forced late failures leave no partial components or groups
D. Group Numbering and Circuit Moves
Status: Complete.
- implement nested identifier generation
- support same-category cross-group circuit moves
- implement explicit collision-safe group renumbering
- implement confirmed populated-group deletion
Implemented in D1a:
- a pure renumber planner derives group prefixes, circuit BMKs and optional upstream-protection/RCD BMKs from category and target group number
- outgoing-circuit suffixes remain unchanged
- number swaps are allowed only when every conflicting group participates
- collisions with unchanged groups, no-op mappings and mismatched current BMKs are rejected before persistence
Implemented in D1b:
circuit-group.renumberpersists the complete expected/target plan as one project revision- group-number swaps use collision-safe temporary group identities and BMKs across both circuit and component tables
- every current circuit and group component must be included unchanged before execution starts
- Undo/Redo uses the exact inverse plan; late revision/history failures roll back every group, prefix and BMK
Implemented in D2a:
- a pure planner permits moves only between distinct groups of the same category
- it validates the source BMK and stores source/target group and sort position
- the target BMK uses the highest existing target-group circuit suffix plus one and never fills gaps
- the computed target BMK is part of the plan and is not recalculated for Redo
Implemented in D2b:
circuit.move-groupatomically changes only the circuit's group, BMK and sort position- the circuit UUID remains stable, so its device rows and one-to-one protection device remain connected without copying
- execution revalidates project/list ownership, both group identities and the complete expected circuit state
- Undo/Redo uses the stored inverse move and late failures restore source group, BMK and position
Implemented in D3a:
- one validated subtree snapshot combines the group, optional group components and their protection devices, complete circuits and their protection devices, and all circuit device rows
- linked-project-device and override metadata remain part of every row snapshot
- ownership and BMK uniqueness are checked across the complete subtree
- the snapshot derives the confirmation summary for upstream protection, RCD, circuit count and device-row count
Implemented in D3b:
circuit-group.delete-subtreerequires the exact previously confirmed snapshot and re-captures the full current subtree before deletioncircuit-group.restore-subtreerestores stable UUIDs in foreign-key-safe order, including both protection layers and row link/override metadata- deletion and restoration are exact persistent inverses for Undo/Redo
- stale confirmation state and late history failures leave no partial delete or restore
Acceptance:
- target identifiers use highest suffix plus one
- reordering never renumbers
- cross-category moves are rejected
- group renumbering preserves circuit suffixes
- delete, move and renumber Undo restore exact prior UUIDs and BMKs
E. Editor Projection and Editing
Status: In progress. The complete tree read model E1, pure structural projection E2a, grid rendering E2b and mutable component editing E3a are complete. Basic group management E3b1 is also complete. Circuit-protection editing and structural drag/renumber/delete workflows remain pending.
- render fixed header components
- render group components and circuit blocks
- render sortable auxiliary footer components
- add group management and destructive confirmations
- add type-dependent protection editing
- keep spreadsheet selection, keyboard and drag behavior coherent
Implemented in E1/E2a/E2b/E3a:
- the tree response exposes fixed header, group and auxiliary footer components plus both one-to-one protection layers
- a pure projection produces the stable order header, complete groups and footer without mixing zones
- each group keeps its heading, optional protection components, complete circuit blocks and free placeholder together
- empty groups remain visible and circuit device rows remain owned by their circuit block
- the editor renders fixed header, group protection and auxiliary footer components as read-only full-width rows
- structural component rows are excluded from spreadsheet cell navigation, insertion and deletion commands until their dedicated editing controls exist
- group headings offer at most one optional upstream protection device and one optional group RCD; the agreed group-RCD default is applied only when it is created
- mutable group protection and auxiliary footer components use labeled modals, type-dependent protection fields and persistent project commands
- fixed main-switch and surge-protection header components remain read-only
- users can create a group in any supported category; its number is the category's highest existing number plus one and its prefix is generated
- group editing changes only the display name; category, number, prefix and child BMKs remain stable
- an exactly empty group can be removed through the persistent group command; populated deletion stays disabled until the dedicated warning UI is present
Acceptance:
- the visible order is header, groups, footer
- users can create, configure, reorder and delete groups
- users can configure circuit and group protection without invalid fields
- device rows remain visually and technically subordinate to their circuit
F. Documentation and Full Verification
- update current architecture, API and interaction documentation
- update demo/sample data
- run focused domain and transaction tests
- run the complete required test, build and type-check suite
- perform the agreed GUI test checklist
Acceptance:
- documentation distinguishes implemented behavior from later sizing
- clean install and migrated database both work
- snapshots, JSON transfer and Undo/Redo cover all new state
Risks and Mitigations
- Mixed legacy and grouped BMKs: preserve old identifiers and provide an explicit conversion path.
- Cross-entity BMK collisions: enforce one transaction-level uniqueness boundary for the complete list.
- Partial destructive writes: persist complete subtree commands through the shared transaction wrapper.
- Bloated grid logic: add pure projection and ownership modules before React rendering changes.
- Invalid protection combinations: use one shared typed catalog for UI, API and domain validation.
- Silent planning changes: apply defaults only on creation and keep later recommendations explicit.
- Snapshot incompatibility: version payloads and test every supported upgrade path.
Open Implementation Decisions
These decisions may be resolved during the relevant delivery phase without changing the agreed domain behavior:
- exact relational implementation of the shared BMK ownership boundary
- presentation of group ownership through indentation, headings or a column
- filter behavior for structural component rows
- explicit UI for converting retained legacy identifiers to grouped numbering
- whether fixed header components become editable beyond name and BMK in this phase