Seitenansicht mit PDF-Export, Verteiler-Infokarte und Logo-Upload #4

Closed
Grovy311 wants to merge 10 commits from Grovy311/leistungsbilanz-ts:feature/print-view into main

10 commits

Author SHA1 Message Date
Grovy311
bf58296ba5 Add print cover fields and office profile
- Project settings gain siteAddress, workStage, projectLead and
  projectEditor (project.update-settings schema version 3, migration 0009);
  versions 2 and 1 stay executable and keep the current cover values.
  Snapshot schema 6 carries the fields; older versions upgrade with null.
- Global office profile (office name/address) next to the document logo:
  table document_branding_settings, PUT /api/document-branding/office,
  editable from the print view toolbar.
- Cover page reads all fields; empty values show the "[ergänzen]" marker.
  The Planstände editor column shows the project editor.
- Shared logo constants moved to a dependency-free module so the Next.js
  bundler can import them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 20:42:53 +02:00
Grovy311
94688d7a8c Add print view, board info card and document logo upload
- Seitenansicht (/projects/:projectId/print): tabular cover page, board
  overview with supply structure and power sums, one plan per board with a
  repeating title block; PDF via the browser print dialog with named @page
  rules (A4 portrait cover, A4/A3 landscape plans, page x of y).
- Distribution-board info card (board number, location, fed-from, remark)
  in the board edit dialog, persisted through the additively extended
  distribution-board.update command (migration 0008, snapshot schema 6,
  legacy subtree commands normalized).
- Global document logo upload (PNG/JPEG/SVG, max 2 MB) outside project
  revisions and snapshots.
- fed-from stays free text; the overview hierarchy and cumulated sums are
  preliminary until the feed link is modeled.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 19:31:36 +02:00
Grovy311
2742b26b87 docs: cover breaker-aware sizing, max length, socket minimum, manual entry 2026-09-25 19:31:36 +02:00
Grovy311
287da1c0e7 cable-sizing: max length, socket minimum, manual-entry warning, SVG icon
- Cross-section rows now include maxLengthForVoltageDropM, the inverse of
  the voltage-drop formula: the longest single run that stays within the
  requested max voltage drop at the given load/cosPhi/phase. Shown as a KPI
  and in the ok-summary alert.
- Added PRACTICAL_MINIMUM_CROSS_SECTION_MM2 (2.5 mm² for single_phase
  circuits) - a planning convention already named in this projects own
  docs/spec/06-future-sizing-and-calculations.md, not a thermal/
  voltage-drop requirement. Only ever raises a calculated recommendation,
  never lowers one that already needs more. circuitCategory is looked up
  from the circuits section and passed through from the editor.
- The manual cross-section field now warns (not blocks - manual override
  must stay possible per the same spec doc) when the typed value is not a
  standard cross-section, is smaller than the last calculation, or is
  below the practical minimum for single_phase circuits.
- Modal title now includes the circuit displayName next to the equipment
  identifier.
- Replaced the calculator emoji trigger icon with an inline SVG - the emoji
  did not render in at least one tested environment (missing font glyph),
  SVG has no such dependency.
2026-09-25 19:31:36 +02:00
Grovy311
68d2bad6e8 cable-sizing: size for the protective device, not just the load; manual entry; icon position
- calculateCableSizing now selects cross-section against
  designCurrentA = max(operatingCurrentA, existingProtectionRatedCurrentA)
  instead of the load current alone. A breaker only trips at its own rated
  current (In), so a cable sized for the actual load could overheat under
  sustained current below that threshold - the standard In <= Iz rule.
  Voltage-drop calculation still uses the real operating current, only the
  capacity check changed. Alerts and the ok-summary now name the breaker as
  the limiting factor when it is one.
- Added a manual cable type/cross-section entry in the modal itself:
  running a calculation pre-fills these fields as a suggestion, but they
  are the single field that actually gets applied, and stay editable -
  this restores the direct manual-entry capability the modal replaced when
  it took over the cableSummary/cableCrossSection cell click.
- Fixed calculator icon position from a trailing ::after (inconsistent
  position depending on cell text length, easy to miss on empty cells) to
  a fixed-position ::before, so it is always in the same place regardless
  of whether cable data is already filled in.
- No new display for the existing protection device - it already has its
  own Schutz column in this app.
2026-09-25 19:31:35 +02:00
Grovy311
05964fc15c docs: document the grid-column coupling and its failure mode 2026-09-25 19:31:35 +02:00
Grovy311
961c96f7a1 cable-sizing: trigger on both cable columns, calculator icon
Trigger now matches cableSummary OR cableCrossSection so it still
shows up regardless of which cable-related column a user has visible
(column visibility is a per-browser preference in this app, not fixed
- see docs/cable-sizing-module.md coupling note). Icon changed to a
calculator glyph.
2026-09-25 19:31:35 +02:00
Grovy311
b6e50539ad cable-sizing: fix trigger column and add visible affordance
The trigger was wired to the cableCrossSection column, which is not in
the default visible column set - the actually visible "Kabel" column
is cableSummary (a computed cableType/cableCrossSection/cableLength
join). Editing cableSummary already maps to the remark field rather
than the underlying cable data (see buildCircuitEditPatch), so this
column was effectively a read-only display already; retargeting the
trigger there loses no existing manual-edit capability. Also adds
.cell-cable-sizing-trigger styling (mirrors .cell-protection-trigger)
so the trigger is visually discoverable, which the initial version was
missing entirely.
2026-09-25 19:31:35 +02:00
Grovy311
fa9eaec2c5 cable-sizing: return 400 instead of 500 for an unknown context circuitId/projectId
context.circuitId/projectId are caller-supplied audit-log metadata, not
used in the calculation itself. A stale or unknown id (e.g. a circuit
deleted between page load and this request) violated the foreign key
and fell through to the generic 500 handler; catch it and report it as
a normal validation error instead.
2026-09-25 19:31:35 +02:00
Grovy311
8b8526b8df Add proposed cable-sizing module
Isolated module (mirrors src/external-model/ dependency direction) that
adds an on-demand, DIN VDE 0298-4 referenced cable cross-section
calculator: a click-on-a-circuit input mask for laying method,
insulation, ambient temperature, grouping and voltage-drop limit that
suggests a cross-section for the circuit cableCrossSection/cableLength
fields. Applying a suggestion goes through the existing circuit.update
command (expectedRevision, undo/redo) unchanged - nothing here writes
to circuits directly or touches the revision/command system. See
docs/cable-sizing-module.md for the full rationale, API contract,
verification status and maintenance plan. Proposal, not yet reviewed
by the project owner - see the docs file.

423 existing + 11 new tests pass, build:api/build:web/typecheck:scripts
clean.
2026-09-25 19:31:35 +02:00