The editor built the circuit-group subtree snapshot without
manualQuantity, while the server compares it with an exact capture that
includes the column. Deleting any group that contained a device row was
therefore rejected with "Circuit-group subtree changed before deletion."
The new integration test builds the snapshot from the real circuit-tree
read model, as the editor does, and deletes the group for a manual row
and for a row with a Revit quantity share.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
tsx runs tests without type checking and tsconfig.json covers only src,
so 71 type errors had accumulated unnoticed. tsconfig.tests.json now
checks every test and helper, and npm run typecheck includes it.
Fixtures gain the fields the DTOs have grown since they were written
(manualQuantity, circuit apparent power/cos phi, downstream board loads,
section totals, building, cover and board info fields). Repository
lookups that return "row ?? null" now declare the null in their type,
which their callers already handle.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- log only the error name for rejected 4xx requests (JSON.parse messages
can quote the request body, e.g. a password)
- refuse LB_DATABASE_PATH in production; it is test-only
- fix two stale file references in the skill texts
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- make quick/check/mutation from cj/security-baseline (Makefile unchanged,
settings in baseline.mk), pre-commit, gitleaks, Semgrep rules, ESLint
security rules, Forgejo workflow
- tests/security: generic baseline tests plus app config and role tests
against createApp() with an in-memory database
- extract createApp() from src/server/index.ts; LB_DATABASE_PATH for tests
- fix gaps found by the tests: reject unknown fields on project create,
answer malformed JSON with 400 instead of 500, set nosniff on the API
- npm audit fix (next 16.4.1 and others, no high/critical left)
- clear ESLint errors, safeFileName without control-character regex
- per-project ownership stays an open, documented gap (idorGap -> TODO)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Also document that Sec-Fetch-Site is only sent over HTTPS, so plain-HTTP
LAN access relies on SameSite=Lax alone.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Renumber the users migration to 0013_users so it follows the upstream
0012_good_gateway (logical board feeds); AGENTS.md deferred-work list keeps
both the new feed items and the auth items.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Security: per-username login throttling, constant-time unknown-user check,
Sec-Fetch-Site CSRF guard for writes, session rotation on login and
password change, absolute session lifetime, sessions ended on reset and
deactivation, last-admin protection, input length caps, ASCII usernames,
clickjacking headers. Covered by tests/authentication.test.ts.
Filter panel: toggle, fields and count share one row to save space.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Square icon-only theme toggle sits next to the Abmelden button in a shared
row, collapsing to just the toggle when the sidebar is collapsed - same
arrangement as pm-app's Sidebar.tsx.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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>
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.
Preserve the ID fallback and compact editor controls. Add dialog keyboard focus, Tab containment and Escape handling; document navigation and picker behavior.
Validation: 418 tests, API/web builds, scripts and Next typechecks, isolated AMEV dialog checks and diff checks passed. Full GUI retest waived by the user based on the colleague's prior testing; the keyboard follow-up was checked in isolation.
The printed page kept the dark app background in the page margins, the
consumer column wrapped while the empty remark column took the space, an
empty "bearbeitet von" label was printed, and numbers were printed as
typed (11200). Print margins are white now, the consumer column is wider,
empty editors are omitted and numbers print with thousands separators
(11.200) like the template.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The dark theme sets color-scheme: dark on the root element; Chrome then
paints the page margins of printed pages dark, even with a white
background. The print view forces the light scheme and a white root
background while printing.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Versorgung field suggests ELT and MSR (plus values already used in
the balance) through a datalist and still accepts free text. The circuit
number column is not needed in early design phases; it is removed from
the data model, the regenerated migration 0010, the editor and the
print. All cells are centered except "Verbraucher / Flächen", group
titles and total labels.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The print of the rough power balance was plain grey. It now follows the
kbp design of the print view: a title block with office logo, stand,
project, number, owner, address, work stage, date, editor and office;
header row in kbp blue, cost-group rows tinted with a lilac rule, bold
subtotals, the total including reserve as a blue band, colored
deviations in the comparison, Arial, exact print colors, and a footer
with project, stand and "Seite x von y" on every page.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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>
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>
The "Seitenansicht" link in the project header had text only, while the
other header buttons show an icon plus text.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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>