Files
leistungsbilanz-ts/docs/spec/09-distribution-board-components-and-protection-groups.md
T

823 lines
28 KiB
Markdown

# 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
- `Circuit` remains the outgoing-circuit aggregate.
- `CircuitDeviceRow` remains 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.
- `CircuitSection` remains the migration starting point for a protected circuit
group.
- Grid projection remains separate from persisted domain structure.
### Change
- A `CircuitSection` gains 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
- `rcdAssignment` as 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
```text
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:
- `lighting`
- `single_phase`
- `three_phase`
Each new distribution board creates exactly:
1. `Beleuchtung 1`
2. `1-phasig 1`
3. `3-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_switch`
- `surge_protective_device`
- `group_upstream_protection`
- `group_residual_current_protection`
- `auxiliary`
Initial placement zones:
- `header`
- `group`
- `footer`
New distribution boards create exactly:
- `-Q0`, name `Hauptschalter`, role `main_switch`
- `-FA`, name `Überspannungsableiter`, role
`surge_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:
- `D02`
- `NH000`
- `NH00`
- `NH0`
- `NH1`
- `NH2`
- `NH3`
- `LS`
- `FI`
- `FI_LS`
- `AFDD`
`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 `gG` or `gR`
- LS:
- trip characteristic `B`, `C`, `D` or `Z`
- FI:
- RCD type `A`, `AC`, `B` or `B+`
- rated residual current in milliampere
- FI/LS:
- trip characteristic `B`, `C`, `D` or `Z`
- RCD type `A`, `AC`, `B` or `B+`
- rated residual current in milliampere
- AFDD:
- trip characteristic `B`, `C`, `D` or `Z`
- no RCD type
- no rated residual current
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:
```text
-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:
1. finds the highest existing outgoing-circuit suffix in the target group
2. assigns that suffix plus one
3. moves the complete circuit, its one-to-one protection device and all device
rows
4. 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 `.0` group-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:
1. header:
- `-Q0 Hauptschalter`
- `-FA Überspannungsableiter`
2. groups:
- group heading
- optional upstream protection row
- optional group RCD row
- circuit rows and their optional expanded device rows
3. 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:
```text
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 `0024` adds 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.insert` with 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.insert` schema version 3 carries stable UUIDs for three
initial groups, main switch `-Q0` and 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.insert` and
`distribution-board-component.delete` persist 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.update` exchanges one complete expected
component/protection snapshot for one complete target snapshot
- name, BMK, protection configuration and `sortOrder` can 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.update` and
`circuit-group.delete` persist 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.reorder` requires every group in the circuit list with its
exact expected and target `sortOrder`
- 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.renumber` persists 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-group` atomically 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-subtree` requires the exact previously confirmed
snapshot and re-captures the full current subtree before deletion
- `circuit-group.restore-subtree` restores 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. Group management and circuit-protection editing 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
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