forked from jappel/leistungsbilanz-ts
Merge remote-tracking branch 'origin/main' into feature/cable-sizing
This commit is contained in:
commit
598003554a
136 changed files with 27182 additions and 1669 deletions
|
|
@ -12,6 +12,12 @@ ausdrücklich getrennt und dürfen nicht als bereits implementiert verstanden we
|
|||
fachliches Modell und Grid-Aufteilung
|
||||
- [Editor-Interaktionen](circuit-list-editor-interactions.md) – Tastatur,
|
||||
Drag-and-drop, Sortierung, Filterung und Undo/Redo
|
||||
- [Seitenansicht und PDF-Export](print-view.md) – Deckblatt,
|
||||
Verteilerübersicht, Verteilerpläne, Büro-Logo
|
||||
- [Gebäudestruktur](building-structure.md) – Gebäude → Etagen → Räume,
|
||||
Befehle, Snapshot-Schema 7, eigene Seite
|
||||
- [Grobe Leistungsbilanz](estimate-balance.md) – LPH 2/3 nach Kostengruppen,
|
||||
Rechnung, Vergleich mit der detaillierten Bilanz
|
||||
- [Editor-API](circuit-list-editor-api.md) – unterstützte Circuit-First-Endpunkte
|
||||
- [Bekannte Einschränkungen](circuit-list-editor-known-limitations.md) –
|
||||
bewusst noch nicht implementierte oder begrenzte Funktionen
|
||||
|
|
@ -27,7 +33,8 @@ ausdrücklich getrennt und dürfen nicht als bereits implementiert verstanden we
|
|||
|
||||
- [Projektversionen und externer Modellaustausch](project-history-and-external-model-architecture.md)
|
||||
- [LLM-Kontext für die Revit-Anforderungsplanung](revit-requirements-llm-context.md)
|
||||
- [Revit-CSV-Anforderungen](spec/revit-csv-integration-requirements.md)
|
||||
- [Revit-CSV-Anforderungen](spec/revit-csv-integration-requirements.md) –
|
||||
zurückgestellt; später über den CSV-Export/-Import des Linear-Plugins
|
||||
- [Phase-14-Audit und Implementierungsplan](spec/revit-csv-phase-14-audit-and-plan.md)
|
||||
- [Zukünftige Dimensionierung](spec/06-future-sizing-and-calculations.md)
|
||||
- [Roadmap und Phasen](spec/07-implementation-phases-todo.md)
|
||||
|
|
@ -50,3 +57,6 @@ Limitierungen und Roadmap.
|
|||
|
||||
- [Frühe Codex-Promptvorlagen](archive/initial-codex-prompts.md) – historischer
|
||||
Arbeitsstand, keine aktuelle Implementierungsanweisung
|
||||
- [Revit-/Dynamo-Anbindung](archive/revit-dynamo-leistungsbilanz-integration-konzept.md) –
|
||||
nicht weiterverfolgte Vorüberlegung zur direkten Dynamo-/API-Anbindung;
|
||||
Diagnoseskripte über den Git-Tag `archive/dynamo-vorueberlegungen`
|
||||
|
|
|
|||
1152
docs/archive/revit-dynamo-leistungsbilanz-integration-konzept.md
Normal file
1152
docs/archive/revit-dynamo-leistungsbilanz-integration-konzept.md
Normal file
File diff suppressed because it is too large
Load diff
83
docs/building-structure.md
Normal file
83
docs/building-structure.md
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
# Gebäudestruktur (Gebäude → Etagen → Räume)
|
||||
|
||||
Projekte mit mehreren Gebäuden werden über eine eigene Ebene **Gebäude**
|
||||
gegliedert. Etagen können einem Gebäude zugeordnet sein, Räume und Verteilungen
|
||||
hängen wie bisher an der Etage. Das Gebäude eines Raums oder einer Verteilung
|
||||
ergibt sich also aus der Etage; eine zweite, konkurrierende Zuordnung gibt es
|
||||
nicht. Abgestimmt in Issue #6: Das Modell ist so bestätigt, und Gebäude mit
|
||||
zugeordneten Etagen lassen sich nicht löschen.
|
||||
|
||||
## Datenmodell
|
||||
|
||||
| Tabelle | Feld | Bedeutung |
|
||||
|---|---|---|
|
||||
| `buildings` | `id`, `project_id` (FK, cascade), `name`, `sort_order` | Gebäude eines Projekts |
|
||||
| `floors` | `building_id` (nullable FK → `buildings`, `ON DELETE set null`) | optionales übergeordnetes Gebäude |
|
||||
|
||||
Migration `0009_buildings`. Bestehende Etagen behalten `building_id = null` und
|
||||
erscheinen in der Oberfläche als „Ohne Gebäude“. Es gibt keine Zwangsmigration
|
||||
und kein automatisch angelegtes Standardgebäude. Vor dem Anwenden der Migration
|
||||
auf eine bestehende Datenbank ist wie bei jeder Schemamigration eine separate
|
||||
Datenbanksicherung anzulegen.
|
||||
|
||||
## Befehle, Undo/Redo
|
||||
|
||||
Alle Änderungen laufen über die bestehende Orts-Struktur
|
||||
(`ProjectLocationStructureProjectCommandRepository`) mit Revision, Inverse und
|
||||
persistentem Undo/Redo:
|
||||
|
||||
- `project-building.insert` / `project-building.delete` mit vollständigem
|
||||
Gebäude-Snapshot (Schema-Version 1)
|
||||
- `project-building.update`: ändert nur den Namen
|
||||
- Löschen eines Gebäudes wird abgelehnt, solange Etagen zugeordnet sind
|
||||
(„Das Gebäude kann nicht gelöscht werden, solange Etagen zugeordnet sind.“)
|
||||
- Etagenbefehle `project-floor.insert/.update/.delete` haben seit
|
||||
Schema-Version **2** das Feld `buildingId`. `project-floor.update` darf Name
|
||||
und/oder Gebäude ändern, nicht aber `sortOrder`. Ein referenziertes Gebäude
|
||||
muss zum Projekt gehören.
|
||||
- Version-1-Etagenbefehle aus bestehender Historie bleiben ausführbar. Sie
|
||||
stammen aus der Zeit vor den Gebäuden und werden vor der Ausführung mit
|
||||
`buildingId = null` auf Version 2 gehoben; auch die daraus neu gespeicherten
|
||||
Vorwärts- und Inversbefehle sind Version 2. Das ist bei linearer Historie
|
||||
exakt: Wird ein Gebäude später zugeordnet, liegt dieser neuere Befehl im
|
||||
Undo-Stapel vor dem alten Befehl und wird zuerst zurückgenommen.
|
||||
- Raumbefehle bleiben unverändert (Version 1).
|
||||
|
||||
## Snapshots und Transfer
|
||||
|
||||
Projekt-Snapshot-Schema **7** enthält `buildings` und `floors[].buildingId`.
|
||||
Alle älteren unterstützten Versionen (1–6) werden beim Einlesen mit leerer
|
||||
Gebäudeliste und `buildingId = null` hochgestuft; gespeicherte Sicherungspunkte
|
||||
bleiben wiederherstellbar. Die Relationen werden geprüft (Gebäude gehört zum
|
||||
Projekt, `buildingId` verweist auf ein Gebäude des Snapshots). Restore löscht
|
||||
und schreibt Gebäude zusammen mit den Etagen; der Projekt-Transfer vergibt neue
|
||||
Gebäude-IDs und stellt die Etagenverweise um.
|
||||
|
||||
## API
|
||||
|
||||
- `GET /api/projects/:projectId/buildings` – Gebäude sortiert nach
|
||||
`sortOrder`, Name
|
||||
- `POST /api/projects/:projectId/buildings` – `{ "name": "Haus A", "expectedRevision": 3 }`
|
||||
- `PUT /api/projects/:projectId/buildings/:buildingId` – `{ "name": "Haus B", "expectedRevision": 4 }`
|
||||
- `DELETE /api/projects/:projectId/buildings/:buildingId` – `{ "expectedRevision": 5 }`
|
||||
- `POST/PUT /api/projects/:projectId/floors[/:floorId]` akzeptieren zusätzlich
|
||||
optional `buildingId` (`string | null`). Fehlt das Feld, bleibt beim Bearbeiten
|
||||
das bisherige Gebäude erhalten; ältere Clients funktionieren unverändert.
|
||||
|
||||
## Oberfläche
|
||||
|
||||
Gebäude, Etagen und Räume werden auf der eigenen Seite
|
||||
`/projects/:projectId/struktur` („Gebäudestruktur“) gepflegt, erreichbar über
|
||||
die Seitenleiste und die Kennzahlen der Projektübersicht. Drei Spalten
|
||||
Gebäude → Etagen → Räume filtern sich gegenseitig: Klick auf ein Gebäude zeigt
|
||||
nur dessen Etagen, Klick auf eine Etage nur deren Räume, „Alle“ hebt den Filter
|
||||
auf. Hinzufügen, Bearbeiten und Löschen laufen über Icon-Buttons wie in der
|
||||
Stromkreisliste.
|
||||
|
||||
## Offen
|
||||
|
||||
- Revit: Eine Übernahme des Gebäudes aus Revit ist derzeit nicht geplant. Die
|
||||
Revit-Arbeit ist insgesamt zurückgestellt und läuft später über die
|
||||
Linear-CSV; das Modell steht einer späteren CSV-Zuordnung nicht im Weg.
|
||||
- Sortierung von Gebäuden per Drag-and-drop ist noch nicht umgesetzt; neue
|
||||
Gebäude werden hinten angehängt.
|
||||
|
|
@ -59,6 +59,14 @@ this value for optimistic concurrency checks.
|
|||
- clients cannot submit arbitrary `project.restore-state` payloads through
|
||||
the generic command endpoint
|
||||
|
||||
Grobbilanzen sind bewusst kein Teil dieser logischen Snapshots. Der portable
|
||||
Projektexport unter `GET /projects/:projectId/export` verwendet dagegen
|
||||
Transferformat 2 und enthält alle Grobbilanzen. Die beiden Importwege
|
||||
`POST /projects/:projectId/import` und `POST /projects/import` prüfen ihre
|
||||
Prüfsumme; Ersetzen übernimmt die Grobbilanzen atomar und mit Undo/Redo,
|
||||
Duplizieren vergibt neue IDs. Transferformat 1 bleibt ohne Grobbilanzen
|
||||
importierbar.
|
||||
|
||||
The public dispatcher supports the Circuit and CircuitDeviceRow commands
|
||||
`circuit.update`, `circuit.insert`, `circuit.delete`,
|
||||
`circuit-device-row.update`, `circuit-device-row.insert`,
|
||||
|
|
@ -74,8 +82,9 @@ Protected-board structure uses
|
|||
persisted inverse of a delete. The dispatcher also supports the documented
|
||||
project-device, project settings, distribution-board and project-location
|
||||
commands. The generic editor commands listed here use schema version `1`.
|
||||
`project.update-settings` uses version `2` and still accepts supported baseline
|
||||
version `1` commands without changing the newer building classification.
|
||||
`project.update-settings` uses version `3` (including the print cover fields)
|
||||
and still accepts version `2` and supported baseline version `1` commands
|
||||
without changing the newer cover fields or building classification.
|
||||
Pre-baseline formats remain unsupported. Unsupported types or schema versions
|
||||
are rejected. Insert commands contain the complete entity or circuit block
|
||||
with stable ids; delete commands include the expected parent identity. Circuit
|
||||
|
|
@ -173,6 +182,9 @@ synchronizes linked circuit rows implicitly.
|
|||
- `PUT /projects/:projectId`
|
||||
- request:
|
||||
`{ "expectedRevision": 12, "isPublicBuilding": true, "singlePhaseVoltageV": 230, "threePhaseVoltageV": 400, "enabledDistributionBoardSupplyTypes": ["AV", "MSR", "SiBe"], ...projectMetadata }`
|
||||
- optional print cover fields `siteAddress` (max. 500), `workStage` (max.
|
||||
100), `projectLead` and `projectEditor` (max. 200 each); omitted fields keep
|
||||
their value, empty strings are stored as `null`
|
||||
- executes `project.update-settings` as one atomic revision
|
||||
- response:
|
||||
`{ "project": { ... }, "revision": { ... }, "history": { ... } }`
|
||||
|
|
@ -210,6 +222,12 @@ A stale `expectedRevision` returns HTTP `409` with
|
|||
`PROJECT_REVISION_CONFLICT`. Undo or redo without an eligible stack entry
|
||||
returns HTTP `409` with `PROJECT_HISTORY_OPERATION_UNAVAILABLE`.
|
||||
|
||||
## Estimate Balance (Grobe Leistungsbilanz)
|
||||
|
||||
Separate module under `/projects/:projectId/estimate-balances`; complete
|
||||
documents are written through `estimate-balance.insert/.update/.delete` project
|
||||
commands. Endpoints, payloads and calculation rules: `docs/estimate-balance.md`.
|
||||
|
||||
## Circuit-First Endpoints
|
||||
|
||||
### Distribution Board Setup
|
||||
|
|
@ -230,9 +248,13 @@ returns HTTP `409` with `PROJECT_HISTORY_OPERATION_UNAVAILABLE`.
|
|||
- stale revisions return `409 PROJECT_REVISION_CONFLICT`
|
||||
- `PUT /projects/:projectId/distribution-boards/:distributionBoardId`
|
||||
- body:
|
||||
`{ "floorId": null, "supplyType": "AV", "expectedRevision": 13 }`
|
||||
- executes `distribution-board.update`; floor and supply type are restored
|
||||
together by persistent Undo/Redo
|
||||
`{ "floorId": null, "supplyType": "AV", "simultaneityFactor": 1, "expectedRevision": 13 }`
|
||||
- optional info-card fields: `boardNumber` (max. 50), `location`,
|
||||
`fedFrom` (max. 200 each) and `remark` (max. 2000); strings are trimmed
|
||||
and an empty string is stored as `null`
|
||||
- executes `distribution-board.update`; all submitted values, including the
|
||||
submitted info fields, are restored together by persistent Undo/Redo
|
||||
- `fedFrom` is free text until the logical feed link is modeled
|
||||
- `POST /projects/:projectId/distribution-boards/:distributionBoardId/copy`
|
||||
- body: `{ "name": "UV-02 Kopie", "expectedRevision": 14 }`
|
||||
- duplicates the complete distribution-board subtree with new owning UUIDs
|
||||
|
|
@ -249,15 +271,27 @@ returns HTTP `409` with `PROJECT_HISTORY_OPERATION_UNAVAILABLE`.
|
|||
`distribution-board.delete-subtree`. Persistent Undo/Redo restores or
|
||||
removes the same complete subtree, including protection devices.
|
||||
|
||||
### Project Floors and Rooms
|
||||
### Project Buildings, Floors and Rooms
|
||||
|
||||
- `GET /projects/:projectId/buildings`
|
||||
- `POST /projects/:projectId/buildings`
|
||||
- body: `{ "name": "Haus A", "expectedRevision": 12 }`
|
||||
- executes `project-building.insert` with a stable building id
|
||||
- response: `{ "building": { ... }, "revision": { ... }, "history": { ... } }`
|
||||
- `PUT /projects/:projectId/buildings/:buildingId`
|
||||
- body: `{ "name": "Haus B", "expectedRevision": 13 }` (name only)
|
||||
- `DELETE /projects/:projectId/buildings/:buildingId`
|
||||
- body: `{ "expectedRevision": 14 }`
|
||||
- rejects buildings with assigned floors
|
||||
- `POST /projects/:projectId/floors`
|
||||
- body: `{ "name": "EG", "expectedRevision": 13 }`
|
||||
- executes `project-floor.insert` with a stable floor id
|
||||
- body: `{ "name": "EG", "buildingId": "building_1", "expectedRevision": 13 }`
|
||||
(`buildingId` optional, `null` = no building)
|
||||
- executes `project-floor.insert` (command version 2) with a stable floor id
|
||||
- response: `{ "floor": { ... }, "revision": { ... }, "history": { ... } }`
|
||||
- `PUT /projects/:projectId/floors/:floorId`
|
||||
- body: `{ "name": "1. OG", "expectedRevision": 14 }`
|
||||
- executes an exact persistent floor update
|
||||
- body: `{ "name": "1. OG", "buildingId": null, "expectedRevision": 14 }`
|
||||
- executes an exact persistent floor update of name and/or building; a
|
||||
missing `buildingId` keeps the current building
|
||||
- `DELETE /projects/:projectId/floors/:floorId`
|
||||
- body: `{ "expectedRevision": 15 }`
|
||||
- rejects floors with assigned rooms or distribution boards
|
||||
|
|
@ -447,3 +481,27 @@ Full request example and calculation rules: `docs/cable-sizing-module.md`.
|
|||
Parser errors expose stable codes such as `header-not-found`,
|
||||
`ambiguous-header`, `invalid-ifc-guid` and `duplicate-ifc-guid`. The confirmed
|
||||
import uploads and parses the file again and verifies its hash.
|
||||
|
||||
## Document Branding (print view)
|
||||
|
||||
Office-wide branding for the print view. These endpoints are mounted at
|
||||
`/api/document-branding`, outside `/api/projects`, because the data is global
|
||||
and intentionally not part of project revisions, snapshots or transfer.
|
||||
|
||||
- `GET /document-branding`
|
||||
- returns `{ "logo": { "mimeType", "fileName", "sizeBytes", "updatedAtIso" } | null, "office": { "officeName", "officeAddress" } }`
|
||||
- `GET /document-branding/logo`
|
||||
- returns the stored image bytes with its media type, or `404` without logo
|
||||
- responses carry `X-Content-Type-Options: nosniff` and a restrictive
|
||||
Content-Security-Policy so an SVG logo cannot execute scripts
|
||||
- `PUT /document-branding/logo`
|
||||
- request: `{ "fileName": "logo.png", "mimeType": "image/png", "contentBase64": "..." }`
|
||||
- accepted types: `image/png`, `image/jpeg`, `image/svg+xml`; at most 2 MB
|
||||
after decoding; the content signature must match the declared type
|
||||
- replaces an existing logo; returns the logo metadata
|
||||
- `DELETE /document-branding/logo`
|
||||
- removes the logo; returns `204`
|
||||
- `PUT /document-branding/office`
|
||||
- request: `{ "officeName": "…" | null, "officeAddress": "…" | null }`
|
||||
(at most 200 / 500 characters; empty text is stored as not set)
|
||||
- returns `{ "office": { "officeName", "officeAddress" } }`
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
# Circuit List Editor Interactions
|
||||
|
||||
The back-arrow link beside the page title returns to the project's distribution
|
||||
board overview without changing circuit-list data.
|
||||
|
||||
## Editing Model
|
||||
|
||||
Inline cells are static text by default. A cell enters edit mode by:
|
||||
|
|
@ -44,6 +47,7 @@ Selection, keyboard movement, and editability checks run against this normalized
|
|||
- arrow keys: move selected cell in grid when not editing
|
||||
- type-to-edit: printable keys open edit mode and replace current display value with typed character
|
||||
- `Ctrl+Plus` / `Ctrl+Shift+Plus`: insert below the selected circuit or device context
|
||||
- `Alt+ArrowDown` on a GZF cell (selected or editing): open the AMEV simultaneity-factor table
|
||||
- `Delete`: delete the selected circuit or device context after confirmation
|
||||
|
||||
For insertion, a circuit-level cell creates a reserve circuit directly after the selected circuit. A device-level cell creates a manual device row directly after the selected device. On the virtual `-frei-` row, or without a valid row selection, the shortcut creates a circuit at the end of the active section. Insertions use command history and never renumber existing equipment identifiers.
|
||||
|
|
@ -52,6 +56,23 @@ For deletion, a circuit-level cell targets the complete circuit and a device-lev
|
|||
|
||||
Creating or deleting a device row updates the row and the circuit reserve state in one SQLite transaction.
|
||||
|
||||
## AMEV Simultaneity Factor
|
||||
|
||||
The selected GZF cell shows a small table-icon button; it and `Alt+ArrowDown` open
|
||||
the shared `GzfPickerModal` (AMEV Planungshilfe, Tabelle 3), which the project
|
||||
device dialog uses as well. "Übernehmen" commits the mean value of the chosen
|
||||
consumer group through the same path as a typed edit (`commitEdit` with an
|
||||
explicit target cell), so it is one undoable command and works on device rows,
|
||||
compact circuits, reserve circuits and the `-frei-` row. A running inline edit
|
||||
of the cell is discarded when the picker opens. The button only appears on the
|
||||
selected cell; the grid keeps its static-text cells.
|
||||
|
||||
The dialog takes keyboard focus, keeps Tab/Shift+Tab within its actions and
|
||||
closes on Escape without writing a value. Closing returns focus to the grid;
|
||||
only "Übernehmen" saves the selected mean value. Opening the picker is disabled
|
||||
while a write or history operation is running. Its cell button stays outside
|
||||
the Tab order; `Alt+ArrowDown` provides keyboard access from the selected cell.
|
||||
|
||||
## Equipment Identifier Validation
|
||||
|
||||
Equipment identifiers are compared case-insensitively after trimming whitespace. A conflicting edit is highlighted before submission and cannot be committed. Existing conflicts are highlighted in the grid. Validation errors remain dismissible above the editor instead of replacing the complete workspace.
|
||||
|
|
@ -127,11 +148,30 @@ Cross-section device moves show confirmation-required feedback before drop. The
|
|||
|
||||
## Filtering and Sorting
|
||||
|
||||
- Clicking a column label changes sorting; the funnel icon next to it opens
|
||||
the value filter. An active filter is highlighted and shows the number of
|
||||
selected values. Both controls retain German accessible names and tooltips.
|
||||
- Header labels wrap between words; trailing units such as `[kW]` appear on
|
||||
a separate line.
|
||||
- Per-column filtering works on normalized displayed values.
|
||||
- Sorting is view-level first and treats circuits as blocks.
|
||||
- Multi-device circuits are not split during sort.
|
||||
- Sorting alone does not persist order.
|
||||
|
||||
## Action Buttons
|
||||
|
||||
The editor toolbar uses icons with visible German labels. Group headers and
|
||||
circuit/device rows use compact icon buttons with German accessible names and
|
||||
tooltips. Group protection buttons additionally show `VS` or `FI` to distinguish
|
||||
their roles. Dividers separate related actions; destructive actions use the
|
||||
danger style. Circuit deletion uses a trash icon, while device-row deletion
|
||||
uses a crossed-out list icon.
|
||||
|
||||
The shared `src/frontend/components/icon-button.tsx` component preserves
|
||||
disabled states and expanded states for toggles. Row and group action buttons
|
||||
retain `tabIndex={-1}` so the spreadsheet's existing cell navigation remains
|
||||
unchanged. The existing command handlers and deletion confirmations are reused.
|
||||
|
||||
## Apply Sorted Order
|
||||
|
||||
`Apply sorted order` persists current sorted block order to backend by section.
|
||||
|
|
@ -161,6 +201,11 @@ across multiple sections is atomic and occupies one history step. Explicit
|
|||
renumbering uses a collision-safe persistent project command and one
|
||||
project-history step.
|
||||
|
||||
The editor creates client-side UUIDs through `createClientId` in
|
||||
`src/frontend/utils/client-id.ts`. It uses `crypto.randomUUID()` when available
|
||||
and otherwise generates a UUID v4 with `crypto.getRandomValues()`, so insertion
|
||||
also works over plain HTTP from another machine in the LAN.
|
||||
|
||||
Covered operations include:
|
||||
|
||||
- insert/delete circuit
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@
|
|||
- Named and automatic logical project snapshots can be listed and restored
|
||||
through the project page with persistent Undo/Redo. Automatic snapshots are
|
||||
created every 25 revisions and only their newest 12 entries are retained.
|
||||
- Further Revit work is deferred; it will later use the CSV export/import of
|
||||
the Linear plugin in Revit, not Dynamo.
|
||||
- The Revit/CSV foundation and confirmed initial import are implemented.
|
||||
Existing-row assignment, move and detach plus creation of an external-only
|
||||
row in an existing or newly created circuit have atomic persistent commands.
|
||||
|
|
@ -31,3 +33,12 @@
|
|||
- Protection and cable values are planner-owned manual selections. The later
|
||||
sizing/warning engine does not yet validate them against load, length or
|
||||
voltage-drop rules.
|
||||
- Distribution-board `fedFrom` is free text. The print overview derives its
|
||||
supply structure and "Σ inkl. unterlagert" only from exact text matches with
|
||||
board numbers/names and adds values without an upstream simultaneity factor
|
||||
(see `docs/print-view.md`).
|
||||
- The print view uses a kbp corporate design derived from logo and
|
||||
presentation material. Snapshots do not record an editor, so the cover's
|
||||
Planstände list shows the project's current editor for every entry. On screen, long
|
||||
board plans are not split into pages; pagination happens in the browser print
|
||||
dialog.
|
||||
|
|
|
|||
|
|
@ -27,9 +27,18 @@ Next.js App Router ── /api/* Rewrite ──▶ Express API :3000
|
|||
data/leistungsbilanz.db (SQLite)
|
||||
```
|
||||
|
||||
Im Docker-Entwicklungssetup laufen Frontend und API in getrennten Containern. Das
|
||||
Frontend leitet `/api/*` über `API_INTERNAL_URL` an die API weiter. Die Datenbank
|
||||
liegt über einen Host-Mount außerhalb des Containers.
|
||||
In beiden Docker-Stacks laufen Frontend und API in getrennten Containern.
|
||||
`compose.yaml` startet den gebauten Stand, `compose.dev.yaml` die Entwicklung
|
||||
mit Hot Reload. Das Frontend leitet `/api/*` über `API_INTERNAL_URL` an die API
|
||||
weiter; beim gebauten Stand wird das Ziel zur Build-Zeit festgelegt. Die
|
||||
Datenbank liegt über einen Host-Mount außerhalb des Containers.
|
||||
|
||||
Neue IDs für Stromkreise, Gerätezeilen, Gruppen und Verteilerkomponenten erzeugt
|
||||
der Editor über `src/frontend/utils/client-id.ts` (`createClientId`). Die
|
||||
Hilfsfunktion nutzt `crypto.randomUUID()`, sofern verfügbar, andernfalls
|
||||
`crypto.getRandomValues()` mit UUID-v4-Format. Damit funktioniert das Anlegen
|
||||
auch beim HTTP-Zugriff im LAN ohne sicheren Browserkontext. Die IDs entstehen
|
||||
vor dem Command und bleiben über Undo/Redo unverändert.
|
||||
|
||||
## Wichtige Einstiegspunkte
|
||||
|
||||
|
|
@ -232,8 +241,9 @@ und Historienstapel teilen dieselbe Transaktion. Create, Import aus der globalen
|
|||
Gerätebibliothek und Delete laufen über dieselbe Command-Grenze; ihre Antworten
|
||||
liefern Gerät und aktualisierten Historienstand an die Projektseite zurück.
|
||||
`project.update-settings` versioniert Projektname, interne und externe
|
||||
Projektnummer, Bauherr, Beschreibung, die Kennzeichnung als öffentliches
|
||||
Gebäude, beide Standardspannungen sowie die im Projekt freigeschalteten
|
||||
Projektnummer, Bauherr, Beschreibung, die Deckblattangaben (Anschrift,
|
||||
Leistungsphase, Projektleitung, Bearbeitung; Schema-Version 3, Migration
|
||||
`0008`), die Kennzeichnung als öffentliches Gebäude, beide Standardspannungen sowie die im Projekt freigeschalteten
|
||||
Verteiler-Netzarten als eine atomare Änderung. Die Gebäudekennzeichnung ist
|
||||
der spätere Eingang für die Auswahl halogenfreier Kabel und Leitungen. Der
|
||||
Systemkatalog besteht aus `AV`, `SV`, `EV`, `USV`, `MSR` und `SiBe`; mindestens
|
||||
|
|
@ -245,22 +255,55 @@ Werte, Revision und Historienstapel gemeinsam. `PUT /api/projects/:projectId`
|
|||
verlangt deshalb `expectedRevision`, liefert Projekt plus aktualisierten
|
||||
Historienstand und besitzt keinen separaten direkten Settings-Schreibweg mehr.
|
||||
Kommando- und Snapshot-Payloads müssen dem aktuellen Baseline-Schema entsprechen.
|
||||
Die Projektseite zeigt Verteilungen, Etagen und Räume als kompakte
|
||||
Bestandsübersichten; ihre versionierten Erstellwege öffnen beschriftete Modals
|
||||
statt dauerhafter Eingabezeilen. Projektgeräte werden als durchsuchbare,
|
||||
Die Projektseite zeigt Verteilungen als kompakte Bestandsübersicht; ihre
|
||||
versionierten Erstellwege öffnen beschriftete Modals statt dauerhafter
|
||||
Eingabezeilen. Gebäude, Etagen und Räume werden auf der eigenen Seite
|
||||
„Gebäudestruktur“ (`/projects/:projectId/struktur`) gepflegt; Etagen können
|
||||
einem Gebäude zugeordnet sein (`docs/building-structure.md`). Projektgeräte werden als durchsuchbare,
|
||||
fünfspaltige Übersicht dargestellt. Manuelle Anlage, Übernahme aus der globalen
|
||||
Bibliothek und vollständige Bearbeitung erfolgen in einem gemeinsamen Modal.
|
||||
Die anschließende Vorschau verknüpfter Stromkreiszeilen bleibt davon getrennt,
|
||||
damit Änderungen weiterhin niemals still synchronisiert werden.
|
||||
`GET /api/projects/:projectId/export` verpackt denselben vollständigen
|
||||
Projektzustand in ein portables, format- und schema-versioniertes JSON-Dokument
|
||||
mit SHA-256-Prüfsumme. `POST /api/projects/:projectId/import` prüft Format,
|
||||
Snapshot-Relationen und Prüfsumme vor jedem Schreibzugriff. Der Modus `replace`
|
||||
läuft über `project.restore-state` und ist dadurch eine atomare, dauerhaft
|
||||
rückgängig machbare Projektrevision. Der Modus `duplicate` ordnet Projekt-,
|
||||
Die Karten Verteilungen und Projektgeräte besitzen je eine einklappbare
|
||||
Filterleiste im Stil der PM-App (Suche, Mehrfachauswahl für Etage/Netzart bzw.
|
||||
Kategorie/Phasenzahl/Kostengruppe, „Zurücksetzen“, Anzeige „x von y“); die
|
||||
Filterlogik liegt rein in `src/frontend/utils/overview-filters.ts`, der
|
||||
Einklappzustand je Karte in `localStorage`. Aktionen verwenden wie der Editor
|
||||
`IconButton`/`IconLink`.
|
||||
Die allgemeinen Anwendungskarten verwenden in `src/app/globals.css` einen
|
||||
gleichmäßigen Rahmen, 16-px-Rundungen und einen Schatten mit eigener
|
||||
Dark-Mode-Abstimmung. Bootstrap-Karten mit `shadow-sm` nutzen denselben
|
||||
Schatten; der Stromkreis-Grid bleibt eine eigenständige Komponente.
|
||||
Die Verteilersuche berücksichtigt Name, Verteilernummer, Örtlichkeit und
|
||||
Etagenname; die Gerätesuche
|
||||
Name, Anzeigename, Kategorie einschließlich deutscher Bezeichnung, Anschlussart
|
||||
und Kostengruppe. Der Gerätefilter „Anschluss“ wählt zwischen 1- und 3-phasig.
|
||||
Mehrere Werte innerhalb eines Filters gelten alternativ, verschiedene Filter
|
||||
und die Suche gemeinsam. Eine leere Auswahl bedeutet „Alle“; fehlende
|
||||
Zuordnungen sind über „Ohne Etage“, „Nicht festgelegt“ beziehungsweise
|
||||
„Ohne Kostengruppe“ auswählbar. Nicht mehr angebotene Auswahlwerte werden bei
|
||||
der Filterung ignoriert. „Zurücksetzen“ leert die Filter der jeweiligen Karte.
|
||||
Beim Einklappen bleiben aktive Filter wirksam und durch „Filter aktiv“ sichtbar.
|
||||
Nur der Einklappzustand wird je Kartentyp im Browser gespeichert; Suchbegriffe
|
||||
und Filterauswahl werden nicht dauerhaft gespeichert. Die Filter ändern keine
|
||||
Projektdaten und erzeugen keine Revisionen. Das Löschen eines Projektgeräts
|
||||
erfordert eine Bestätigung mit dessen Namen und verwendet weiterhin den
|
||||
bestehenden persistenten Projektbefehl.
|
||||
|
||||
`GET /api/projects/:projectId/export` verpackt den vollständigen portablen
|
||||
Projektzustand in ein format- und schema-versioniertes JSON-Dokument mit
|
||||
SHA-256-Prüfsumme. Transferformat 2 enthält zusätzlich alle Grobbilanzen,
|
||||
ohne sie in das logische Snapshot-Schema aufzunehmen; Format 1 bleibt ohne
|
||||
Grobbilanzen importierbar. `POST /api/projects/:projectId/import` prüft Format,
|
||||
Snapshot-Relationen, Grobbilanzen und Prüfsumme vor jedem Schreibzugriff. Der
|
||||
Modus `replace` läuft über `project.restore-state` Version 2 und ersetzt den
|
||||
Projektzustand und die Grobbilanzen atomar und dauerhaft rückgängig machbar.
|
||||
Normale Snapshot-Restores verwenden weiterhin Version 1 und lassen
|
||||
Grobbilanzen unverändert. Der Modus `duplicate` ordnet Projekt-,
|
||||
Struktur-, Gruppen-, Verteilerkomponenten-, Raum-, Stromkreis- und
|
||||
Gerätezeilen-UUIDs sowie Schutzgeräte-Referenzen vollständig neu zu und legt
|
||||
die Kopie mit Revision `0` in einer Transaktion an. Fachliche Verknüpfungen
|
||||
Gerätezeilen-UUIDs sowie Schutzgeräte-Referenzen und die IDs aller Grobbilanzen
|
||||
vollständig neu zu und legt die Kopie mit Revision `0` in einer Transaktion an.
|
||||
Fachliche Verknüpfungen
|
||||
innerhalb des unterstützten Laufzeitmodells bleiben
|
||||
erhalten. Die
|
||||
Projektübersicht verwendet dafür den separaten Collection-Endpunkt
|
||||
|
|
@ -416,7 +459,16 @@ wieder her.
|
|||
verteilerweiten Gleichzeitigkeitsfaktor gemeinsam und stellt alle Werte über
|
||||
dauerhaftes Undo/Redo wieder her. Der Faktor liegt zwischen `0` und `1` und
|
||||
ist für bestehende sowie neu angelegte Verteilungen standardmäßig `1`.
|
||||
Snapshot-Schema 5 enthält zusätzlich den manuellen Mengenanteil jeder
|
||||
Derselbe Befehl versioniert die Felder der Verteiler-Infokarte
|
||||
(`boardNumber`, `location`, `fedFrom`, `remark`, Migration `0007`). Die
|
||||
Infokarte liegt im Bearbeiten-Dialog der Verteilung; die Werte sind lokale
|
||||
Planungswerte und sollen später über den Revit-Abgleich nur nach Vorschau und
|
||||
ausdrücklicher Bestätigung vorbelegt werden. `fedFrom` ist vorerst Freitext.
|
||||
Snapshot-Schema 7 enthält zusätzlich die Gebäude und die Gebäudezuordnung
|
||||
der Etagen; ältere Versionen werden ohne Gebäude hochgestuft.
|
||||
Snapshot-Schema 6 enthält diese Felder und die Deckblattangaben des
|
||||
Projekts; ältere Versionen werden mit `null`
|
||||
hochgestuft. Snapshot-Schema 5 enthält zusätzlich den manuellen Mengenanteil jeder
|
||||
Gerätezeile. Version 4 wird mit `manualQuantity = quantity` hochgestuft und
|
||||
enthält bereits den vollständigen externen Modellzustand
|
||||
aus Quelle, Batches, Raum-Mappings und Objekten. Es enthält außerdem die
|
||||
|
|
@ -498,7 +550,7 @@ Revision und Undo/Redo. Details, Rechenweg und Prüfnachweis der Tabellen:
|
|||
`toLowerCase()` gegen das vollständige Register der Stromkreisliste und wird
|
||||
von jedem Anlage-/Umbenennungspfad für Stromkreise und Verteilerkomponenten
|
||||
aufgerufen, auch dort, wo zuvor kein Vorab-Check existierte. Snapshot- und
|
||||
Transfer-Integration verwenden aktuell Snapshot-Schema 5. Persistente
|
||||
Transfer-Integration verwenden aktuell Snapshot-Schema 6. Persistente
|
||||
Insert/Delete/Update-Commands für veränderliche Verteilerkomponenten,
|
||||
Gruppen einschließlich befüllter Unterbäume sowie vollständige
|
||||
Gruppensortierung sind integriert. Der Editor zeigt die geschützte Struktur
|
||||
|
|
@ -517,6 +569,10 @@ bei einem späteren Wechsel trotzdem einen eigenen PostgreSQL-Adapter.
|
|||
|
||||
## Revit-CSV-Grundlage
|
||||
|
||||
**Zurückgestellt:** Die weitere Revit-Arbeit wird später angegangen, dann
|
||||
über den CSV-Export/-Import des Linear-Plugins in Revit statt über Dynamo.
|
||||
Details: [Revit-CSV-Anforderungen, Abschnitt 1](spec/revit-csv-integration-requirements.md).
|
||||
|
||||
Der reine Adapter unter `src/external-model/csv` validiert die projektweite
|
||||
Transport- und Mappingkonfiguration und parst UTF-8-CSV verlustarm in eine
|
||||
klassifizierte Zellmatrix. Er erkennt Metadaten, Header, Passthrough-, Objekt-
|
||||
|
|
@ -526,7 +582,7 @@ einschließlich BOM, CRLF und Quotierung bytegleich zurück. Der lokale Befehl
|
|||
|
||||
`external_csv_configurations` enthält höchstens eine versionierte Konfiguration
|
||||
je Projekt. `external-csv-configuration.update` schreibt Anlage, Änderung oder
|
||||
Entfernung zusammen mit Revision und persistentem Undo/Redo. Snapshot-Schema 5,
|
||||
Entfernung zusammen mit Revision und persistentem Undo/Redo. Snapshot-Schema 6,
|
||||
Restore und portabler Projekttransfer enthalten diesen Zustand; beim Duplizieren
|
||||
werden Konfigurations-UUID und Projektlink remapped.
|
||||
|
||||
|
|
|
|||
|
|
@ -16,9 +16,10 @@ und macOS keine inotify-Events durchreichen; das kostet dauerhaft CPU, auch
|
|||
ohne Benutzeraktivität. Dieser Stack gehört deshalb nur auf einen
|
||||
Entwicklungsrechner.
|
||||
|
||||
Beides enthält weder TLS, Authentifizierung, Reverse Proxy, Prozesshärtung noch
|
||||
ein zentral betriebenes Datenbanksystem. Der Stack darf deshalb nicht öffentlich
|
||||
erreichbar gemacht werden.
|
||||
Beide Stacks enthalten weder TLS, Authentifizierung, einen vorgeschalteten
|
||||
Reverse Proxy noch ein zentral betriebenes Datenbanksystem. Die oben genannten
|
||||
Container-Schutzmaßnahmen ersetzen diese Funktionen nicht. Der Stack darf
|
||||
deshalb nicht öffentlich erreichbar gemacht werden.
|
||||
|
||||
## Topologie
|
||||
|
||||
|
|
@ -34,6 +35,11 @@ erreicht, kann jedes Projekt lesen und ändern. Erreichbar ist sie nur aus dem
|
|||
Compose-Netz, praktisch also über den Next.js-Rewrite. Im Entwicklungs-Stack
|
||||
hängen beide Ports am Loopback und sind nicht aus dem LAN erreichbar.
|
||||
|
||||
Beim HTTP-Zugriff auf den Server-Stack aus dem LAN erzeugt der Editor neue
|
||||
UUIDs über `createClientId`, mit `crypto.getRandomValues()` als Ersatz für das
|
||||
dort nicht verfügbare `crypto.randomUUID()`. HTTPS ist für diese
|
||||
ID-Erzeugung nicht erforderlich.
|
||||
|
||||
### Speichergrenzen
|
||||
|
||||
Jeder Dienst hat ein `mem_limit`. Im Server-Stack ist zusätzlich
|
||||
|
|
@ -140,14 +146,17 @@ Vor einer produktiven Installation werden mindestens benötigt:
|
|||
- Entscheidung, ob SQLite für einen einzelnen Prozess genügt oder PostgreSQL für
|
||||
Mehrbenutzerbetrieb erforderlich ist
|
||||
|
||||
Bis diese Punkte umgesetzt und getestet sind, besteht die „Installation“ aus dem
|
||||
lokalen Entwicklungsstart in der README.
|
||||
Der in der README beschriebene Server-Stack ermöglicht bereits den Betrieb des
|
||||
gebauten Stands in einer geschützten Umgebung. Ein vollständig unterstütztes
|
||||
Produktionssetup bleibt bis zur Umsetzung und Prüfung dieser Punkte offen.
|
||||
|
||||
## Backup und Wiederherstellung
|
||||
|
||||
`npm run db:backup` erzeugt unter `data/backups/` ein konsistentes SQLite-Backup,
|
||||
öffnet es unabhängig und prüft Integrität sowie Fremdschlüssel. Diese
|
||||
Dateisicherungen sind von zukünftigen logischen Projektversionen getrennt.
|
||||
Dateisicherungen sind von den bereits vorhandenen benannten und automatischen
|
||||
logischen Projektsicherungen getrennt. Projektsicherungen werden über die
|
||||
Projektseite wiederhergestellt und unterstützen persistentes Undo/Redo.
|
||||
|
||||
Eine produktive Restore-Anweisung wird erst zusammen mit einem unterstützten
|
||||
Produktionsbetrieb veröffentlicht. Lokale Wiederherstellung darf nur bei
|
||||
|
|
|
|||
|
|
@ -13,6 +13,11 @@ Ein sauberer Clone enthält keine SQLite-Datenbank. Beim ersten Start werden
|
|||
`data/leistungsbilanz.db`, alle Tabellen und Migrationseinträge automatisch
|
||||
angelegt. Das Frontend ist unter <http://localhost:3001> erreichbar.
|
||||
|
||||
Dieser Standard-Stack verwendet gebauten Anwendungscode. Für die Entwicklung
|
||||
mit Quellcode-Mounts und Hot Reload stattdessen
|
||||
`docker compose -f compose.dev.yaml up --build --detach` verwenden; die Dienste
|
||||
sind dabei nur über die Loopback-Ports des Entwicklungsrechners erreichbar.
|
||||
|
||||
Für direkte Node.js-Entwicklung:
|
||||
|
||||
```powershell
|
||||
|
|
@ -86,7 +91,8 @@ Bei Docker- oder Laufzeitänderungen zusätzlich:
|
|||
```powershell
|
||||
docker compose up --build --detach
|
||||
docker compose ps
|
||||
Invoke-WebRequest http://localhost:3000/health
|
||||
Invoke-WebRequest http://localhost:3001/health
|
||||
Invoke-WebRequest http://localhost:3001/web-health
|
||||
```
|
||||
|
||||
Bei sichtbaren Editoränderungen ist außerdem ein kurzer GUI-Test erforderlich.
|
||||
|
|
|
|||
119
docs/estimate-balance.md
Normal file
119
docs/estimate-balance.md
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
# Grobe Leistungsbilanz (LPH 2/3)
|
||||
|
||||
Eigenes Modul für die Leistungsbilanz der Vor- und Entwurfsplanung, gegliedert
|
||||
nach Kostengruppen (DIN 276, KG 400). Es gibt dort noch keine Verteilungen und
|
||||
Stromkreise: Jedes Gewerk trägt unter seiner Kostengruppe Verbraucher als
|
||||
Stückzahl mit Einzelleistung oder als Fläche mit W/m² ein. Aufbau und Rechnung
|
||||
folgen der bisherigen Excel-Vorlage „Leistungsbilanz – KG400“. Abstimmung:
|
||||
Issue #7.
|
||||
|
||||
Das Modul ist **nicht** mit der Stromkreisstruktur verknüpft. Es liest die
|
||||
Gerätezeilen nur für den Vergleich „geschätzt ↔ detailliert“ und schreibt
|
||||
nichts in Stromkreislisten, Verteilungen oder Projektgeräte.
|
||||
|
||||
## Aufbau
|
||||
|
||||
```
|
||||
src/shared/estimate-balance/estimate-balance.ts Datenform, Rechnung, Vergleich (rein, ohne Imports)
|
||||
src/estimate-balance/domain/estimate-balance-command.model.ts Snapshot-Schema (Zod), Befehle
|
||||
src/estimate-balance/domain/estimate-balance-project-command.store.ts Store-Port
|
||||
src/estimate-balance/api/estimate-balance-request.schemas.ts Request-Schemas
|
||||
src/db/schema/estimate-balances.ts Tabellen (Migration 0010)
|
||||
src/db/repositories/estimate-balance*.ts Lesen, Schreiben, Befehls-Store
|
||||
src/server/controllers/estimate-balance.controller.ts API
|
||||
src/app/projects/[projectId]/grobbilanz/ Übersicht der Stände und Editor
|
||||
src/frontend/estimate-balance/ Editor-Komponenten und Helfer
|
||||
```
|
||||
|
||||
Die gemeinsame Datei unter `src/shared/estimate-balance` hat keine Imports, weil
|
||||
das Frontend sie direkt nutzt (Turbopack löst die `.js`-Suffixe der API nicht auf).
|
||||
|
||||
## Datenmodell
|
||||
|
||||
| Tabelle | Inhalt |
|
||||
|---|---|
|
||||
| `estimate_balances` | ein **Stand** je Projekt (z. B. Vorplanung, Entwurfsplanung): Name, LPH, Datum, Reserve AV/SV in %, Sortierung |
|
||||
| `estimate_groups` | Kostengruppe (`"410"` … `"480"`, `""` für „Allgemein“), Titel, „bearbeitet von“, Sortierung |
|
||||
| `estimate_rows` | Versorgung (Auswahl ELT/MSR oder Freitext), Verbraucher/Fläche, Anzahl bzw. Fläche, Einheit (`piece` = St., `area` = m²), Anschluss (fest/Steckdose), Einzelleistung in W bzw. W/m², GLF, cos φ, SV ja/nein, Anmerkung |
|
||||
|
||||
Neue Stände entstehen aus der Vorlage KG 400 (410 Sanitär, 420 Wärme, 430 Luft,
|
||||
434 Kälte, 440 Starkstrom, 450 Schwachstrom, 460 Förder, 470 Nutzungsspezifisch,
|
||||
480 GA, Allgemein; Reserve AV 10 %), leer oder als Kopie eines bestehenden
|
||||
Stands mit neuen IDs. Stände bleiben bearbeitbar; ein zusätzlicher Status oder
|
||||
eine Bearbeitungssperre ist derzeit nicht vorgesehen.
|
||||
|
||||
## Rechnung
|
||||
|
||||
- Zeile: P = Anzahl bzw. Fläche × Einzelleistung × GLF, S = P / cos φ.
|
||||
- **AV** enthält alle Verbraucher (Normalversorgung). **SV** listet zusätzlich
|
||||
die Zeilen mit „SV = ja“, die auch aus der Sicherheitsstromversorgung versorgt
|
||||
werden müssen. Das ist die Lesart der Vorlage; die Regel liegt in
|
||||
`calculateEstimateRow` und lässt sich dort zentral ändern.
|
||||
- Summen je Kostengruppe, Gesamtsumme, Reserve in % (AV und SV getrennt),
|
||||
Leistung inklusive Reserve und Maximalstrom I = S / (√3 · U) mit der
|
||||
Drehstromspannung aus den Projekteinstellungen.
|
||||
- Anzeige wie in der Tabellenkalkulation gerundet (`roundEstimateValue`,
|
||||
40,175 → 40,18). Der Test `tests/estimate-balance.test.ts` rechnet das
|
||||
Beispiel der Vorlage vollständig nach (143,24 kW, 148,48 kVA, mit 10 %
|
||||
Reserve 157,56 kW / 163,33 kVA, 235,75 A).
|
||||
|
||||
## Vergleich geschätzt ↔ detailliert
|
||||
|
||||
`GET …/comparison` summiert alle Gerätezeilen aller Stromkreislisten des
|
||||
Projekts (Anzahl × Leistung je Stück × Geräte-GZF, wie der Stromkreisbaum) und
|
||||
ordnet sie über das Feld **Kostengruppe** der Gerätezeile zu. Maßgeblich ist das
|
||||
längste passende Präfix: `434` → Gruppe 434, `431` → Gruppe 430, `444` → 440.
|
||||
Zeilen ohne passende Kostengruppe erscheinen als „nicht zugeordnet“. Der
|
||||
Verteiler-GZF wird auf keiner Seite angewendet; ein fehlendes cos φ zählt als 1.
|
||||
Verglichen wird die AV-Leistung (kW) mit Differenz absolut und in %.
|
||||
|
||||
## Befehle, Undo/Redo
|
||||
|
||||
Alle Änderungen laufen über den bestehenden Projekt-Befehlsmechanismus mit
|
||||
Revision, Inverse und persistentem Undo/Redo:
|
||||
|
||||
- `estimate-balance.insert` / `estimate-balance.delete` mit dem vollständigen
|
||||
Stand (Gruppen und Zeilen)
|
||||
- `estimate-balance.update` mit vollständigem `expected`/`target`-Dokument; der
|
||||
Store prüft, dass der gespeicherte Stand genau `expected` entspricht, und
|
||||
ersetzt ihn atomar. Die Inverse ist das vertauschte Paar.
|
||||
|
||||
Der Editor speichert das ganze Dokument verzögert (Autosave); jeder
|
||||
Speichervorgang ist ein Undo-Schritt. Unveränderte Dokumente erzeugen keine
|
||||
Revision (`{ unchanged: true }`).
|
||||
|
||||
## Projekttransfer und bewusste Abgrenzung
|
||||
|
||||
- Das reguläre SQLite-Datenbank-Backup sichert die Grobbilanz-Tabellen zusammen
|
||||
mit allen übrigen Anwendungsdaten.
|
||||
- Benannte und automatische Projektsnapshots enthalten keine Grobbilanzen; das
|
||||
Snapshot-Schema bleibt Version 7. Snapshot-Restore und dessen Undo/Redo lassen
|
||||
vorhandene Grobbilanzen unverändert.
|
||||
- Der portable Projektexport enthält alle Grobbilanzen ab Transferformat 2.
|
||||
Ersetzen übernimmt sie atomar und rückgängig machbar; Duplizieren vergibt neue
|
||||
IDs für Bilanz, Gruppen und Zeilen. Alte Transferdateien in Version 1 bleiben
|
||||
importierbar und enthalten definitionsgemäß keine Grobbilanzen.
|
||||
- Keine Rechte je Gewerk; „bearbeitet von“ ist ein Freitext je Kostengruppe.
|
||||
- Kostengruppen der Gerätezeilen sind nicht normiert; der Vergleich arbeitet
|
||||
mit Präfixen.
|
||||
- Der erste Vergleich zeigt die geschätzte und detaillierte AV-Wirkleistung in
|
||||
kW. SV- und kVA-Vergleiche können später ergänzt werden.
|
||||
- Eine Stromkreisnummer gehört nicht zur Grobbilanz, weil sie eine frühe
|
||||
Abschätzung ohne Stromkreisplanung ist.
|
||||
|
||||
## API
|
||||
|
||||
- `GET /api/projects/:projectId/estimate-balances`
|
||||
- `POST /api/projects/:projectId/estimate-balances` –
|
||||
`{ "expectedRevision": 7, "name": "Entwurfsplanung", "workStage": "LPH 3", "dateIso": "2026-09-26", "template": "kg400" }`
|
||||
(`template`: `kg400` | `empty` | `copy` mit `copyFromBalanceId`)
|
||||
- `GET /api/projects/:projectId/estimate-balances/:balanceId`
|
||||
- `PUT /api/projects/:projectId/estimate-balances/:balanceId` –
|
||||
`{ "expectedRevision": 8, "balance": { …vollständiges Dokument… } }`
|
||||
- `DELETE /api/projects/:projectId/estimate-balances/:balanceId` – `{ "expectedRevision": 9 }`
|
||||
- `GET /api/projects/:projectId/estimate-balances/:balanceId/comparison`
|
||||
|
||||
Validierung: Name 1–200 Zeichen, getrimmte Texte, Anzahl/Fläche und
|
||||
Einzelleistung ≥ 0, GLF 0–1, cos φ > 0 bis 1, Reserve 0–100 %, Datum
|
||||
`YYYY-MM-DD`, eindeutige Gruppen- und Zeilen-IDs, unbekannte Felder werden
|
||||
abgelehnt.
|
||||
127
docs/print-view.md
Normal file
127
docs/print-view.md
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
# Seitenansicht und PDF-Export
|
||||
|
||||
Die Seitenansicht ist rein lesend und verändert keine Projektdaten.
|
||||
Die Aktionen für Büroangaben und Logo speichern dagegen globale Einstellungen.
|
||||
Projekt- und Verteilerangaben werden in den jeweiligen Bearbeitungsdialogen
|
||||
über Projektbefehle mit Undo/Redo gepflegt.
|
||||
|
||||
Beim Laden werden die Projektrevisionen aller Stromkreislisten und ein
|
||||
abschließend erneut gelesener Projektstand verglichen. Ändert sich das Projekt
|
||||
währenddessen, wird statt eines gemischten Datenstands eine Aufforderung zum
|
||||
Neuladen angezeigt. Eine bereits geladene Seitenansicht aktualisiert sich nicht
|
||||
automatisch bei späteren Änderungen in einem anderen Tab.
|
||||
|
||||
## Aufruf
|
||||
|
||||
- Projektseite → Button **Seitenansicht** öffnet
|
||||
`/projects/:projectId/print` in einem neuen Tab.
|
||||
- **Als PDF speichern / Drucken** nutzt den Druckdialog des Browsers
|
||||
(Ziel „Als PDF speichern“). Der Dokumenttitel `Leistungsbilanz – <Projekt>`
|
||||
wird als Dateiname vorgeschlagen.
|
||||
- **Planformat** schaltet die Verteilerpläne zwischen A4 quer und A3 quer um.
|
||||
Deckblatt bleibt A4 hoch.
|
||||
- **Büroangaben** pflegt Büroname und Büroanschrift (Planverfasser, für alle
|
||||
Projekte).
|
||||
- **Logo hinterlegen / ersetzen / entfernen** verwaltet das Büro-Logo.
|
||||
|
||||
## Seiten
|
||||
|
||||
1. **Deckblatt (A4 hoch)** – tabellarisch: Projekt, Planverfasser, Dokument,
|
||||
Planstände (aus benannten Sicherungspunkten) und Inhalt. Leere Angaben
|
||||
erscheinen als orangefarbenes „[ergänzen]“.
|
||||
2. **Verteilerübersicht (quer)** – Versorgungsstruktur und Tabelle je
|
||||
Verteiler mit Stromkreisanzahl, P<sub>inst</sub> (Anzahl × Leistung je
|
||||
Stück), P<sub>Geräte</sub> (mit Geräte-GZF), Verteiler-GZF,
|
||||
P<sub>gl</sub>, I<sub>B</sub> und „Σ inkl. unterlagert“.
|
||||
3. **Verteilerpläne (quer, je Verteiler)** – Titelleiste mit
|
||||
Verteilernummer, Bezeichnung, Örtlichkeit, Netzart, „Gespeist von“ und
|
||||
P<sub>gl</sub>; darunter Kopfkomponenten, Gruppen, Stromkreise
|
||||
(mehrzeilige mit Sammelzeile und eingerückten Gerätezeilen),
|
||||
Gruppensummen und Verteilersumme. Fehlende Kabelangaben sind als „offen“
|
||||
markiert. Die Titelleiste steht im Tabellenkopf und wiederholt sich beim
|
||||
Drucken auf Folgeseiten.
|
||||
|
||||
Seitenformat, Ränder und „Seite x von y“ kommen beim Drucken aus benannten
|
||||
`@page`-Regeln (`lb-portrait`, `lb-landscape`), die die Seite zur Laufzeit
|
||||
einfügt. Die Bildschirmansicht zeigt Blätter in Papiergröße; die exakte
|
||||
Seitenaufteilung langer Verteilerpläne entsteht erst beim Drucken.
|
||||
|
||||
## Vorläufige Punkte
|
||||
|
||||
- **Einspeisung / Hierarchie:** `fedFrom` ist Freitext. Die Übersicht ordnet
|
||||
einen Verteiler nur dann unter, wenn der Text eindeutig der Nummer oder
|
||||
Bezeichnung eines anderen Verteilers entspricht (ohne Beachtung von
|
||||
Groß-/Kleinschreibung und äußeren Leerzeichen). Mehrdeutige Treffer bleiben
|
||||
ohne Zuordnung; „Σ inkl. unterlagert“ ist
|
||||
eine einfache Summe ohne übergeordneten GZF. Die fachliche Verknüpfung
|
||||
(Verteiler und/oder speisender Stromkreis) und die Summierungslogik sind
|
||||
offen.
|
||||
- **I<sub>B</sub>** ist ein symmetrischer Drehstromwert
|
||||
S / (√3 · U<sub>3~</sub>) mit S aus P / cos φ je Gerätezeile
|
||||
(fehlendes cos φ = 1) und Verteiler-GZF.
|
||||
- **Corporate Design:** Farben (`--pd-*` in
|
||||
`src/frontend/print/print-document.css`) und Schrift (Arial) sind aus Logo
|
||||
und kbp-Präsentationsmaterial abgeleitet und werden durch die offizielle
|
||||
CD-Vorgabe ersetzt, falls diese abweicht.
|
||||
- **Planstände:** Die Spalte „Bearbeitung“ zeigt für jeden Planstand die
|
||||
aktuelle Bearbeitung aus den Projekteinstellungen, weil Sicherungspunkte
|
||||
(noch) keinen Bearbeiter speichern.
|
||||
|
||||
## Datenquellen des Deckblatts
|
||||
|
||||
| Feld | Quelle |
|
||||
|---|---|
|
||||
| Bauvorhaben, Bauherr, Projektnummern, Beschreibung | Projekteinstellungen |
|
||||
| Anschrift Bauvorhaben, Leistungsphase, Projektleitung, Bearbeitung | Projekteinstellungen → Abschnitt „Deckblatt“ (`siteAddress`, `workStage`, `projectLead`, `projectEditor`) |
|
||||
| Büro, Anschrift Büro | Seitenansicht → „Büroangaben“ (global) |
|
||||
| Stand, Datenstand, Anzahl Verteiler, Inhalt | automatisch |
|
||||
| Planstände | benannte Sicherungspunkte |
|
||||
|
||||
Die vier Projektfelder laufen über `project.update-settings` (Schema-Version
|
||||
3, Migration `0008`) und sind Teil von Snapshot-Schema 6 und Projektexport.
|
||||
Im `PUT /api/projects/:projectId` sind sie optional; fehlende Felder behalten
|
||||
ihren Wert.
|
||||
|
||||
## Büroangaben
|
||||
|
||||
- Tabelle `document_branding_settings` (Schlüssel/Wert, Migration `0008`),
|
||||
global wie das Logo.
|
||||
- `GET /api/document-branding` liefert zusätzlich
|
||||
`office: { officeName, officeAddress }`.
|
||||
- `PUT /api/document-branding/office` mit `{ "officeName", "officeAddress" }`
|
||||
(max. 200 / 500 Zeichen, leerer Text = nicht gesetzt).
|
||||
|
||||
## Logo
|
||||
|
||||
- Globale Büro-Einstellung, nicht Teil von Projekten, Revisionen, Snapshots
|
||||
oder Projektexport.
|
||||
- Tabelle `document_branding_assets` (Migration `0007`).
|
||||
- `GET /api/document-branding` → `{ logo: { mimeType, fileName, sizeBytes, updatedAtIso } | null }`
|
||||
- `GET /api/document-branding/logo` → Bilddaten (`404` ohne Logo), mit
|
||||
`X-Content-Type-Options: nosniff` und restriktiver CSP.
|
||||
- `PUT /api/document-branding/logo` mit
|
||||
`{ "fileName", "mimeType": "image/png" | "image/jpeg" | "image/svg+xml", "contentBase64" }`,
|
||||
maximal 2 MB; der Dateiinhalt wird gegen das Format geprüft.
|
||||
- `DELETE /api/document-branding/logo` → `204`.
|
||||
|
||||
## Code
|
||||
|
||||
- `src/app/projects/[projectId]/print/page.tsx` – Datenladen, Werkzeugleiste,
|
||||
`@page`-Regeln
|
||||
- `src/frontend/print/print-document-model.ts` – reine Berechnungen und
|
||||
Formatierung (Tests: `tests/print-document-model.test.ts`)
|
||||
- `src/frontend/print/print-document.tsx` – Blätter und Tabellen
|
||||
- `src/frontend/print/print-document.css` – Layout, auf `.print-view`
|
||||
begrenzt
|
||||
- `src/frontend/components/distribution-board-info-card.tsx` – Infokarte im
|
||||
Bearbeiten-Dialog der Verteilung
|
||||
|
||||
## Bestehende Datenbanken
|
||||
|
||||
Vor dem Anwenden der additiven Migrationen `0007` und `0008` eine verifizierte
|
||||
Datenbanksicherung mit `npm run db:backup` erstellen. Die neuen Projekt- und
|
||||
Verteilerfelder bleiben bei bestehenden Datensätzen zunächst leer (`null`).
|
||||
Snapshot-Schema 6 enthält beide Feldgruppen; die unterstützten Versionen 1–5
|
||||
werden beim Lesen hochgestuft. Restore und Projektkopie erhalten die neuen
|
||||
Angaben. Globale Büroangaben und Logo gehören zur Datenbanksicherung, nicht
|
||||
zum logischen Projektsnapshot oder Projekttransfer.
|
||||
|
|
@ -113,6 +113,10 @@ Implemented automatic-snapshot policy:
|
|||
|
||||
## Revit / CSV / IFCGUID Round-Trip Direction
|
||||
|
||||
**Deferred:** further Revit work will be tackled later, then through the
|
||||
CSV export/import of the Linear plugin in Revit instead of Dynamo. Details:
|
||||
[Revit-CSV requirements, section 1](spec/revit-csv-integration-requirements.md).
|
||||
|
||||
External model exchange should use explicit staging and link entities instead of writing imported rows directly into circuits.
|
||||
|
||||
Conceptual entities:
|
||||
|
|
@ -275,6 +279,10 @@ Completed foundation:
|
|||
- `project-floor.insert` and `project-room.insert` persist complete location
|
||||
records with stable ids; their inverses reject changed or referenced records
|
||||
so Undo never clears room assignments or device-row links implicitly
|
||||
- `project-building.insert/.update/.delete` persist complete building records;
|
||||
deleting a building with assigned floors is rejected. Floor commands carry
|
||||
`buildingId` since command version 2; version 1 floor commands from older
|
||||
history are upgraded with `buildingId = null` before execution
|
||||
- the floor and room POST routes require the current expected revision and the
|
||||
project page tracks the returned history state
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,9 @@
|
|||
# Kontext für die Revit-Anforderungsplanung
|
||||
|
||||
**Zurückgestellt:** Die weitere Revit-Arbeit wird später angegangen, dann
|
||||
über den CSV-Export/-Import des Linear-Plugins in Revit statt über Dynamo.
|
||||
Details: [Revit-CSV-Anforderungen, Abschnitt 1](spec/revit-csv-integration-requirements.md).
|
||||
|
||||
## Zweck dieser Datei
|
||||
|
||||
Diese Datei ist eine kompakte Übergabe an ein anderes LLM. Sie soll dabei
|
||||
|
|
|
|||
|
|
@ -532,6 +532,10 @@ Acceptance criteria:
|
|||
|
||||
## Phase 14: External Model Round-Trip
|
||||
|
||||
**Zurückgestellt:** Die weitere Revit-Arbeit wird später angegangen, dann
|
||||
über den CSV-Export/-Import des Linear-Plugins in Revit statt über Dynamo.
|
||||
Details: [Revit-CSV-Anforderungen, Abschnitt 1](revit-csv-integration-requirements.md).
|
||||
|
||||
Status: Phase 14.2 (persistente externe Objekte und bestätigter Erstimport) ist
|
||||
implementiert. Editor-Zuordnung, Rückexport und Folgeimport folgen. Siehe
|
||||
[Phase-14-Audit und Implementierungsplan](revit-csv-phase-14-audit-and-plan.md)
|
||||
|
|
@ -540,7 +544,7 @@ und die verbindlichen
|
|||
|
||||
Goal:
|
||||
|
||||
Exchange model objects and planning parameters with Revit or comparable tools through CSV or another agreed format.
|
||||
Exchange model objects and planning parameters with Revit through CSV (Linear plugin export/import).
|
||||
|
||||
Tasks:
|
||||
|
||||
|
|
|
|||
|
|
@ -143,4 +143,5 @@ The pre-release cleanup established the following compatibility boundary:
|
|||
|
||||
The Revit/CSV/IFCGUID round-trip follows the distribution-board component
|
||||
foundation as a separate jointly planned phase and must not be inferred from
|
||||
these tasks.
|
||||
these tasks. It is currently deferred and will later use the CSV
|
||||
export/import of the Linear plugin in Revit, not Dynamo.
|
||||
|
|
|
|||
|
|
@ -2,6 +2,19 @@
|
|||
|
||||
## 1. Status und Verbindlichkeit
|
||||
|
||||
> **Zurückgestellt (September 2026).** Die weitere Revit-Arbeit
|
||||
> (Editor-Oberfläche zur Objektzuordnung, Folgeimport, Rückexport) wird später
|
||||
> angegangen. Wenn sie wieder aufgenommen wird, bleibt der Austausch
|
||||
> CSV-basiert: Export und Import laufen über das Linear-Plugin in Revit. Das
|
||||
> entspricht der Vorgabe des internen Revit/CAD-Lenkungskreises, weil dabei
|
||||
> nicht direkt per Dynamo im Modell gearbeitet wird. Eine Dynamo- oder
|
||||
> API-Anbindung ist nicht vorgesehen; die früheren Vorüberlegungen liegen unter
|
||||
> [docs/archive](../archive/revit-dynamo-leistungsbilanz-integration-konzept.md).
|
||||
> Der Aufbau der Linear-CSV ist noch offen. Vor der Wiederaufnahme wird ein
|
||||
> Musterexport gegen die bestehende projektweite CSV-Konfiguration und den
|
||||
> Parser geprüft; erst danach wird entschieden, was anzupassen ist. Die bereits
|
||||
> umgesetzten Schritte bleiben unverändert nutzbar.
|
||||
|
||||
Dieses Dokument ist die verbindliche fachliche und technische Arbeitsgrundlage für **Phase 14: External Model Round-Trip**.
|
||||
|
||||
Es unterscheidet ausdrücklich zwischen:
|
||||
|
|
@ -1338,7 +1351,7 @@ Diese Punkte blockieren die Erstellung dieser Spezifikation nicht.
|
|||
- automatische raumbezogene Stromkreisvorschläge;
|
||||
- projektübergreifend wiederverwendbare Mappingprofile;
|
||||
- Teilmodelle und mehrere externe Quellen;
|
||||
- Dynamo/API/JSON-Transportadapter;
|
||||
- Dynamo/API/JSON-Transportadapter (nicht vorgesehen, siehe Abschnitt 1);
|
||||
- Rollen und Berechtigungen;
|
||||
- Hintergrundjobs;
|
||||
- PostgreSQL.
|
||||
|
|
|
|||
|
|
@ -2,6 +2,10 @@
|
|||
|
||||
## Status
|
||||
|
||||
**Zurückgestellt:** Die weitere Revit-Arbeit wird später angegangen, dann
|
||||
über den CSV-Export/-Import des Linear-Plugins in Revit statt über Dynamo.
|
||||
Details: [Revit-CSV-Anforderungen, Abschnitt 1](revit-csv-integration-requirements.md).
|
||||
|
||||
Phase 14.0 ist abgeschlossen und freigegeben. Dieses Dokument beschreibt den
|
||||
gegen den aktuellen Code geprüften Zielzuschnitt. Phase 14.1 ist abgeschlossen.
|
||||
Phase 14.2 hat mit den externen Domänenverträgen, Identitätsregeln und dem
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue