Commit graph

94 commits

Author SHA1 Message Date
Grovy311
c56cfb30ad Add login-required user management (admin/user roles, Config->Benutzer)
No self-signup: admins create every account in Config -> Benutzer with a
typed start password; a forced password change gates first use. Session-
cookie auth protects all /api/* routes; /api/users additionally requires
the admin role. See docs/authentication.md.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-28 19:51:47 +02:00
dce31ee143 Add optional room areas 2026-09-27 20:00:03 +02:00
573487666c Integrate rough estimate balance 2026-09-27 12:37:59 +02:00
868f48e7ac Integrate project building structure 2026-09-27 10:45:10 +02:00
4643c8d11a Integrate print view and document branding 2026-09-27 10:32:07 +02:00
2e223be8b4 Integrate project overview filters and icon actions
Document filter combinations, reset and browser persistence. Keep the search hint applicable before board information fields are introduced.

Validation: 20 focused tests, 431 total tests, API/web builds, scripts and Next typechecks, and diff checks passed. GUI retest skipped as authorized based on the colleague's prior testing.
2026-09-26 21:16:48 +02:00
Grovy311
37a70b6b36 Add the rough power balance module for early design phases
In LPH 2/3 there are no circuits yet, but the office needs a power
balance by DIN 276 cost group, as in the Excel template "Leistungsbilanz -
KG400": each trade enters consumers by piece or by area (W/m²) with GLF
and cos phi; the balance sums AV and SV per cost group, adds a reserve and
derives the maximum current.

The module is separate from the circuit structure: own tables
(migration 0010), own folder src/estimate-balance and an import-free
shared calculation used by API and UI. Writes go through project commands
(estimate-balance.insert/.update/.delete with complete documents), so
revision checks and Undo/Redo apply; it is not part of project snapshots
or transfer yet. A comparison endpoint sums the device rows of all circuit
lists by cost group (longest prefix) against the estimate.

The UI adds a sidebar entry, a list of Stände (template KG 400, empty or
copy) and a spreadsheet-like editor with autosave, AMEV picker for the
GLF, totals, reserve, maximum current, comparison table and print layout.
The tests reproduce the template example exactly (143.24 kW, 148.48 kVA,
157.56 kW / 163.33 kVA with 10 % reserve, 235.75 A). See
docs/estimate-balance.md and issue #7.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 17:39:28 +02:00
Grovy311
80dbc73230 Merge fix/client-id-insecure-context for client-side ids 2026-09-26 14:22:35 +02:00
Grovy311
68b9ee850b Search board info fields and confirm project device deletion
The distribution-board search also matches board number and location as
soon as the boards carry them (distribution-board info card of
feature/print-view); the fields are optional in the filter, so the branch
works with and without them. Deleting a project device now asks for
confirmation like the other delete actions, since the row action is a
small trash icon.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 13:16:22 +02:00
Grovy311
837b29c7c5 Add icon actions and collapsible filters to the project overview
The overview now uses the same icon buttons as the circuit list editor:
row actions are icon-only IconButtons (Pencil, Link2, Library, Trash2),
card-header and panel actions show icon plus text, and the circuit-list
link uses the new IconLink. The version history uses Undo2/Redo2, a
chevron toggle and a RotateCcw restore action. Page-header buttons stay
Bootstrap buttons with a lucide icon so the upcoming "Seitenansicht"
button of feature/print-view merges without conflicts and matches them.

The Verteilungen and Projektgeräte cards get a PM-style filter bar:
search plus MultiSelectDropdown (checkbox list with "Alle", closes on
outside click and Escape) and "Zurücksetzen" while a filter is active.
Only the bar collapses; the state is kept per card in localStorage and a
collapsed active filter shows "Filter aktiv". The header row shows
"x von y", and an empty-state row explains when filters hide everything.
The filter logic is a pure module (overview-filters.ts) with node tests;
selections that are no longer offered (deleted floor) are ignored.

IconButton now imports React explicitly like the other components that
are rendered in node tests with the classic JSX runtime.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 13:01:31 +02:00
Grovy311
cd89c4a499 Add buildings above floors and a building structure page
Projects with several buildings could not be structured: floors and rooms
hung directly off the project. Floors can now belong to a building
(migration 0009: table buildings, nullable floors.building_id). Rooms and
distribution boards keep their floor; their building follows from it.
Existing floors stay without a building.

Buildings use the location-structure command store with
project-building.insert/.update/.delete, inverses and persistent Undo/Redo;
deleting a building with assigned floors is rejected. Floor commands carry
buildingId since command version 2. Version 1 floor commands from existing
history predate buildings and are upgraded with buildingId = null before
they are executed and persisted, so forward and inverse keep one version.

Project snapshot schema 7 stores buildings and floor.buildingId; versions
1-6 are upgraded without buildings. Restore and portable transfer include
buildings, and the transfer remaps building ids.

Buildings, floors and rooms move from the project overview to their own
page /projects/:id/struktur with three columns (Gebäude -> Etagen -> Räume)
that filter each other, and a sidebar entry. Floor selects in the board and
room dialogs are grouped by building. Unchanged dialogs close without a
command. Details in docs/building-structure.md; see issue #6.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 12:52:34 +02:00
Grovy311
79fcb75ffb Create client ids without crypto.randomUUID
crypto.randomUUID() is only defined in secure contexts (HTTPS or
localhost). Opened over plain HTTP from another machine in the LAN, the
circuit list editor failed with "crypto.randomUUID is not a function"
whenever it created a circuit, device row, circuit group or distribution
board component, including typing into the -frei- row.

createClientId() uses crypto.randomUUID() where available and otherwise
builds an RFC 4122 version 4 UUID from crypto.getRandomValues(), which
works in every context. AGENTS.md notes the rule.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 12:01:43 +02:00
Grovy311
7692699ee2 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-26 10:39:18 +02:00
Grovy311
4779e4a1a7 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-26 10:38:59 +02:00
b45dc5002d Fix code-review findings across domain, persistence, server and frontend
Full-codebase review turned up five real correctness/security bugs and
a dozen smaller inconsistencies; all are fixed here with matching test
coverage:

- BMK uniqueness silently allowed German-umlaut duplicates ("Ä1" vs
  "ä1") because the DB's normalized index only folds ASCII case. Added
  a shared Unicode-aware pre-check used by every circuit/component
  insert and rename path (one of which had no pre-check at all).
- CircuitDeviceRow.simultaneityFactor had no upper bound at the row
  level (command model and snapshot/restore schema), unlike every
  sibling entity, letting a bad value silently corrupt power totals.
- Grid cell editing silently misread German thousands-separator input
  ("1.500" parsed as 1.5); "." is now rejected outright with a clear
  message instead of guessing.
- The editor's shared command runner (runCommand/applyHistory) had no
  re-entrancy guard, so a double click/drop could fire the same
  command twice and race a BMK collision or revision conflict. Added a
  synchronous ref guard plus isSaving on the buttons that lacked it.
- GET .../next-identifier leaked circuit-numbering state for sections
  in other projects (no ownership check, 400 instead of 404). Moved
  under /projects/:projectId and scoped it.

Also: added the missing circuits.section_id / circuit_device_rows.
circuit_id indexes (migration 0006), gave FormModal a focus trap /
Escape-to-close / focus restore and rebuilt ProjectSettingsModal on
top of it instead of duplicated markup, removed dead code (3 orphaned
domain model files, an unused persistence helper, a wrapper only used
by its own test), pointed the project page at GET /projects/:id
instead of listing+filtering client-side, closed the gap between the
documented 18 MB CSV limit and the ~17.17 MiB actually enforced, added
missing upper bounds on several free-text fields, filled in nine
missing German labels in the revision timeline, replaced a
key-order-fragile JSON.stringify equality check with a real field
comparison, made an implicit sort-order assumption in three
renumbering helpers explicit, cleared the sidebar's target selection
when it no longer resolves after a tree reload, and fixed
updateGlobalDevice to check-then-write instead of write-then-check.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-06 21:31:16 +02:00
74bea1a3c9 Add Revit circuit list object feed 2026-08-02 18:59:01 +02:00
ab2449419b Add Revit initial import wizard 2026-08-02 17:52:21 +02:00
a9d6301753 Add Revit CSV project dialog 2026-08-02 16:59:18 +02:00
44b6fde940 Add public building project setting 2026-07-31 17:41:30 +02:00
1eed19ef6b Add editable project floors and rooms 2026-07-31 14:46:06 +02:00
5fb81bab04 Support decimal commas and cell units 2026-07-31 14:33:47 +02:00
734a2bcfc4 Create clean release database baseline 2026-07-31 14:07:26 +02:00
5bee3cb103 Add distribution board copy and delete controls 2026-07-31 12:03:52 +02:00
86f1d42e60 Expose distribution board copy and delete API 2026-07-31 11:59:31 +02:00
54874f9fcb Render circuit protection values 2026-07-31 09:56:49 +02:00
2964205a27 Show circuit protection in saved layouts 2026-07-31 09:45:58 +02:00
2d97fafce9 Restore circuit drag placement 2026-07-31 08:33:41 +02:00
ab989cc637 Delete populated circuit groups safely 2026-07-31 08:01:55 +02:00
93ec294759 Move circuits between groups 2026-07-31 07:58:42 +02:00
be9c6f0d52 Renumber circuit groups explicitly 2026-07-31 07:53:07 +02:00
0cb280ddb2 Reorder circuit groups 2026-07-31 07:47:45 +02:00
8898117ed4 Configure circuit protection 2026-07-31 07:45:48 +02:00
0c92fbd09e Manage circuit groups 2026-07-31 07:32:46 +02:00
756e307bd8 Manage distribution board components 2026-07-31 07:29:25 +02:00
31589875b5 Render protected circuit structure 2026-07-31 07:22:26 +02:00
ac21d6eb5d WIP multiple sections 2026-07-30 20:27:17 +02:00
99bdf6491b Persist populated group deletion 2026-07-30 20:10:10 +02:00
3399fcd88b Persist circuit group moves 2026-07-30 20:03:11 +02:00
07925b2fd9 Persist circuit group renumbering 2026-07-30 19:56:59 +02:00
e702712bd8 Add circuit group reordering 2026-07-30 19:49:27 +02:00
1250f9a6af Add circuit group commands 2026-07-30 19:46:55 +02:00
69b020339e Add component update commands 2026-07-30 19:42:09 +02:00
604604f056 Add component structure commands 2026-07-30 19:38:48 +02:00
9ea081179d Add distribution power summaries 2026-07-29 19:02:18 +02:00
dcb303284c Describe snapshot source revisions 2026-07-29 11:52:26 +02:00
602ae6da0b Compact circuit grid columns 2026-07-29 11:12:24 +02:00
1b2ca84258 Preserve focus inside grid editors 2026-07-29 11:02:30 +02:00
096ba8aa1c Standardize phase type labels 2026-07-29 10:46:00 +02:00
084103bf54 Derive device voltages from project settings 2026-07-29 09:53:58 +02:00
b1a11397b3 Add configurable distribution supply types 2026-07-29 09:31:20 +02:00