Proposal: cable-sizing module (on-demand DIN VDE 0298-4 cross-section calculator) #1

Open
Grovy311 wants to merge 10 commits from Grovy311/leistungsbilanz-ts:feature/cable-sizing-module into main
Showing only changes of commit 52cc8b20e0 - Show all commits

View file

@ -76,14 +76,50 @@ cell, nothing crashes, no data is affected, and the rest of the app
(including manual cable-field editing) is completely unaffected - the
module's actual logic and persistence never depend on this column key.
## How a suggestion is applied
## Feature overview
The module never writes to `circuits` directly. The modal's "Empfehlung
übernehmen" button calls the **existing, unmodified** frontend helper:
- **Calculate a recommendation**: laying method, insulation, conductor
material, ambient temperature, grouping, cos phi and max voltage drop -
same VDE 0298-4 reference-method model as the sibling Kabelliste tool
(see Verification status below).
- **Breaker-aware sizing**: if the circuit already has a protection device
(`circuit.protectionDevice`), the cross-section is selected against
`designCurrentA = max(operatingCurrentA, protectionDevice.ratedCurrentA)`,
not the load current alone - the standard `In <= Iz` rule (a breaker only
trips at its own rated current, so a cable sized for the actual load
alone could overheat under sustained current below that threshold). If no
cross-section can cover an oversized breaker, that is reported as the
limiting factor by name, not a generic capacity error.
- **Maximum length for the voltage-drop limit**: each cross-section option
also reports the longest single run that still meets the requested
`maxVoltageDropPercent` at the given load - the inverse of the
voltage-drop check, shown for the recommended cross-section.
- **Practical minimum for socket circuits**: `single_phase`-category
circuits are raised to at least 2.5 mm² if the calculation alone would
recommend less - see the dedicated note under Verification status. Never
lowers a calculation that already needs more.
- **Manual entry, always available**: the modal has a plain text Kabeltyp/
Querschnitt field. Running a calculation pre-fills it as a suggestion,
but the field is the single source of truth for what gets applied, and
stays freely editable - satisfying
`docs/spec/06-future-sizing-and-calculations.md`'s explicit requirement
that "users must remain able to manually override suggestions" without
requiring a calculation to have been run first. A non-blocking warning
appears if the typed value is not a standard cross-section, is smaller
than the last calculation, or is below the practical minimum above -
informational only, never forced, matching the same spec doc's "shown as
a warning or status indicator, not as an automatic forced change."
## How a suggestion or manual entry is applied
The module never writes to `circuits` directly. The modal's "Übernehmen"
button calls the **existing, unmodified** frontend helper with whatever is
currently in the Kabeltyp/Querschnitt fields, calculated or hand-typed:
```ts
updateCircuitById(projectId, expectedRevision, circuitId, {
cableCrossSection: "4 mm²",
cableType: "NYM-J 3x2.5",
cableLength: 30,
});
```
@ -94,10 +130,8 @@ cell edits. This means:
- optimistic concurrency (`expectedRevision`) is respected automatically
- the change appears in the project's revision history and is undoable/
redoable exactly like a manual edit
- manually typing a value into the `cableCrossSection` cell keeps working
unchanged - the module only adds a small calculator trigger next to the
cell, per `docs/spec/06-future-sizing-and-calculations.md`'s explicit
requirement that "users must remain able to manually override suggestions"
- nothing is ever written automatically - calculating only fills the modal's
own fields, applying is always an explicit, separate click
## API contract
@ -119,6 +153,8 @@ cell edits. This means:
"maxVoltageDropPercent": 3,
"harmonicNeutralLoad": "none", // "none" | "15to33Percent" | "over33Percent", three-phase only
"existingProtectionRatedCurrentA": 16, // optional, from circuit.protectionDevice
"circuitCategory": "single_phase", // optional, from the circuit's section.category -
// enables the practical-minimum convention below
"context": { "projectId": "...", "circuitId": "...", "equipmentIdentifier": "-1F1.1" }
}
```
@ -149,6 +185,15 @@ recommended cross-section's corrected capacity) is a **simplified** `In <=
Iz` check only - it is not a full IEC 60364-4-43 overload (`I2 <= 1.45 x
Iz`) or short-circuit withstand check.
`PRACTICAL_MINIMUM_CROSS_SECTION_MM2` (2.5 mm² for `single_phase`) is
**not** a verified norm value at all - it is a named planning convention,
sourced directly from this project's own
`docs/spec/06-future-sizing-and-calculations.md` ("Standard Single-Phase
Circuits ... usually use ... cable cross-section: 2.5 mm²"), applied as a
floor on top of the calculated recommendation. It intentionally only
covers the one category and one convention that document already states;
it is not a general substitute for norm-compliant calculation.
## Relationship to the project's own future-sizing spec
`docs/spec/06-future-sizing-and-calculations.md` separately describes simple
@ -177,8 +222,22 @@ app for now", per the intent of this proposal.
## Local testing
Deployed and manually exercised on an internal test host at
`http://192.168.0.133:3220` (a fork of this repository's `main` branch, not
pushed anywhere). `npm test`, `npm run build:api`, `npm run build:web` and
`npm run typecheck:scripts` all pass with this module included; see the
accompanying diff/branch for the exact commit.
Deployed and manually exercised end-to-end on an internal test host at
`http://192.168.0.133:3220` (own docker deployment, own subnet/ports to
avoid clashing with ~50 other containers on that host - see the two
commits marked "Local-only" in this branch, which are not part of this
proposal and should not be carried over if it is ever proposed upstream).
Exercised against seeded real project/circuit data created through the
actual command API (not direct DB writes), including a deliberately long
(85 m) circuit to trigger the voltage-drop-critical path.
`npm test`, `npm run build:api`, `npm run build:web` and
`npm run typecheck:scripts` all pass with this module included at every
commit in this branch.
This branch (`feature/cable-sizing-module`) is pushed to a mirror of this
repository under this homelab's own Forgejo instance, not to
`git.jappel.io` - no write access to the upstream repository was available
or used. See the branch's commit history for the incremental history of
this module, including fixes made during manual testing (trigger column,
icon rendering, breaker-aware sizing).