Create clean release database baseline

This commit is contained in:
2026-07-31 14:07:26 +02:00
parent 5bee3cb103
commit 734a2bcfc4
129 changed files with 2121 additions and 30607 deletions
-3
View File
@@ -20,9 +20,6 @@ ausdrücklich getrennt und dürfen nicht als bereits implementiert verstanden we
- [Entwicklungs- und Contributor-Workflow](development-workflow.md)
- [Deployment und Betrieb](deployment.md)
- [Lokale Circuit-First-Datenbankmigration](local-db-circuit-first-migration.md)
- [Retained Legacy-Datenmigration](circuit-list-editor-migration.md)
ausschließlich für Upgrades alter Datenbanken
## Zukunftsarchitektur
-8
View File
@@ -225,8 +225,6 @@ returns HTTP `409` with `PROJECT_HISTORY_OPERATION_UNAVAILABLE`.
`{ "distributionBoard": { ... }, "revision": { ... }, "history": { ... } }`
- persistent Undo removes only the unchanged and still-empty generated
structure; Redo restores the same ids
- stored command schema versions 1 and 2 remain executable with their four
legacy sections and without generated components
- stale revisions return `409 PROJECT_REVISION_CONFLICT`
- `PUT /projects/:projectId/distribution-boards/:distributionBoardId`
- body:
@@ -358,12 +356,6 @@ available only as the corresponding versioned commands through
structure POST, move, reorder, renumber, identifier-restore, Circuit DELETE or
CircuitDeviceRow DELETE routes.
## Removed Legacy Endpoints
The former `/consumers` read/write endpoints were removed after every retained
consumer had a verified Circuit-First migration mapping. Database upgrade tooling
reads retained legacy rows directly; application features must use the Circuit-First
endpoints above.
## Linked Project Device Review
-5
View File
@@ -49,11 +49,6 @@ The pure grid modules have no React state and are covered by focused unit tests.
- Represents fixed header components, optional group protection and manually
named auxiliary footer devices with their own unique BMK.
- Group protection may own a separate one-to-one protection configuration.
- Retained legacy migration source
- Old `consumers` rows, mappings and reports are available only to explicit
database upgrade tooling.
- They are not application-domain entities and have no UI or API.
## Why A Circuit Is Not One Row
A circuit can contain zero, one, or many device rows. Treating a circuit as a single row breaks:
@@ -23,4 +23,3 @@
- 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.
- Legacy consumer UI and server endpoints are removed; retained source rows and migration mappings remain available only for upgrade traceability.
-90
View File
@@ -1,90 +0,0 @@
# Circuit List Editor Migration
## Status
Upgrade-only. New installations already use the Circuit-First schema and do not
run this workflow.
## Goal
Migrate legacy row-first consumers into the circuit-first model without deleting legacy data.
## Legacy Mapping
Legacy `Consumer` rows map into:
- `Circuit` for shared circuit identity and circuit-level technical fields
- `CircuitDeviceRow` for per-device load rows
Multiple legacy consumers can map into one circuit when they share normalized circuit identity.
For one circuit list, all new circuits, device rows, trace mappings and the migration report are committed in one SQLite transaction. A failed run therefore leaves none of those prepared migration writes behind.
## Grouping Strategy (`circuitNumber`)
Migration groups legacy rows by normalized `circuitNumber`:
- valid/normalizable values become one target circuit per normalized value
- duplicates are grouped under that circuit (multiple `CircuitDeviceRow`s)
- missing/invalid values trigger generated identifiers and may fall back to `unassigned` section
## Default Section Backfill
Before migration, default sections are created/backfilled per circuit list.
This guarantees a valid target section space, including `unassigned` when no section can be inferred.
## Migration Commands
Run in this order for local database workflows:
1. Backup:
- `npm run db:backup`
2. Migrate schema:
- `npm run db:migrate`
3. Verify circuit schema:
- `npm run db:verify:circuit-schema`
4. Backfill missing sections:
- `npm run db:backfill:sections`
5. Migrate legacy consumers:
- `npm run db:migrate:legacy-consumers`
The migration command finishes with a cutover verification across the complete
database. It exits with an error while any legacy consumer lacks a migration
mapping, including consumers that cannot be migrated because they have no circuit
list assignment. The legacy multi-list UI was removed only after this check passed;
old `/projects/:projectId/circuit-lists` bookmarks redirect to the project page.
## Validation Checks
After migration, verify:
- tree endpoint returns sections/circuits/rows
- grouped duplicate circuit numbers are reported
- generated identifiers are reported where expected
- migrated rows include `legacyConsumerId` traceability
- no duplicate BMKs exist inside one circuit list
## If Tree Endpoint Returns Empty Sections
Likely causes:
- circuit-first tables missing (migration not run)
- sections not backfilled yet
- migrated dataset genuinely empty for selected list
Actions:
1. Run schema migration and verification commands.
2. Run section backfill command.
3. Run legacy-consumer migration command.
4. Retry tree endpoint.
## Legacy Data Retention
Do not delete legacy consumers yet.
- legacy read/write endpoints have been removed from the application server
- migration trace tables reference old/new mapping
- retained rows allow upgrade verification and audit of the completed mapping
- a future automatic cleanup migration must migrate and verify old databases
before dropping these source and trace tables
+22 -31
View File
@@ -9,10 +9,8 @@ Der unterstützte Editor ist Circuit-First:
Ein Stromkreis ist nicht dasselbe wie eine Gerätezeile. BMK, Schutz- und Kabeldaten
gehören zum Stromkreis; Last-, Raum- und Kategoriedaten gehören zur Gerätezeile.
Die frühere Consumer-Oberfläche und ihre API sind entfernt. Die Tabelle
`consumers` sowie Mappings und Reports bleiben ausschließlich erhalten, damit
ältere Datenbanken über den expliziten Upgrade-Befehl migriert und geprüft werden
können.
Die frühere Consumer-Oberfläche, ihre API, Tabellen und Upgrade-Werkzeuge sind
entfernt. Neue Funktionen bauen ausschließlich auf dem Circuit-First-Modell auf.
## Laufzeit
@@ -130,8 +128,8 @@ Datenbank-Backups gespeichert. `POST /api/projects/:projectId/snapshots`
erzeugt bei passender erwarteter Revision transaktional einen vollständigen,
schema-versionierten Projektzustand mit SHA-256-Prüfwert. Enthalten sind
Projekteinstellungen, Verteiler, Stromkreislisten, Bereiche, Stromkreise und
Gerätezeilen sowie Projektgeräte, Geschosse und Räume. Globale Geräte,
Legacy-Consumer und Migrationsberichte sind nicht Teil des Projekt-Snapshots.
Gerätezeilen sowie Projektgeräte, Geschosse und Räume. Globale Geräte sind nicht
Teil des Projekt-Snapshots.
Create/List verändern weder Projektrevision noch Undo-/Redo-Stapel.
`kind` unterscheidet benannte und automatische Stände. Die zentrale
Revisionspersistenz erzeugt nach jeweils 25 weiteren Projektänderungen
@@ -144,9 +142,7 @@ Prüfsumme, erwartete Revision und den unmittelbar zuvor gelesenen
Projektzustand. Der Restore ersetzt alle unterstützten Projektdaten in einer
Transaktion und schreibt dabei eine neue Revision mit Quelle `restore` sowie
ein vollständiges inverses Kommando. Undo und Redo können deshalb auch einen
Restore nach einem Neustart exakt zurücknehmen oder wiederholen. Kompatible
Upgrade-only-Verknüpfungen und Migrationsnachweise bleiben erhalten, obwohl sie
nicht Bestandteil des logischen Snapshots sind.
Restore nach einem Neustart exakt zurücknehmen oder wiederholen.
Die Projektseite bindet diese APIs in einem einklappbaren Bereich
„Versionen und Sicherungspunkte“ ein. Dort können Benutzer Sicherungspunkte
benennen, jeden aufgeführten benannten oder automatischen Stand nach
@@ -246,8 +242,7 @@ Store leitet das inverse Kommando aus dem gespeicherten Projekt ab und schreibt
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-Versionen vor dieser Erweiterung bleiben les- und
ausführbar; fehlende Metadaten werden dabei als `null` behandelt.
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,
@@ -264,8 +259,8 @@ rückgängig machbare Projektrevision. 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. Upgrade-only-
Consumer-Verweise werden nicht in die Kopie übernommen; fachliche Verknüpfungen
innerhalb des unterstützten Laufzeitmodells bleiben erhalten. Die
Fachliche Verknüpfungen innerhalb des unterstützten Laufzeitmodells bleiben
erhalten. Die
Projektübersicht verwendet dafür den separaten Collection-Endpunkt
`POST /api/projects/import`, der ausschließlich eine neue Kopie anlegt und
deshalb weder eine bestehende Projekt-ID noch `expectedRevision` annimmt. Das
@@ -283,8 +278,6 @@ Controller-Schreibweg ist entfernt. Verteilungen besitzen eine optionale
Etagenreferenz sowie eine Netzart aus dem Projektkatalog. Anlage und
nachträgliche Bearbeitung prüfen die Projektzugehörigkeit der Etage und die
Freigabe der Netzart in den Projekteinstellungen.
Gespeicherte Anlage-Commands der Schemas 1 und 2 bleiben mit ihren vier
Legacy-Abschnitten und ohne nachträglich erfundene Komponenten ausführbar.
Bereits befüllte Verteilungen werden über
`distribution-board.insert-subtree` und `distribution-board.delete-subtree`
als vollständiger Unterbaum kopiert beziehungsweise gelöscht. Der Snapshot
@@ -462,32 +455,30 @@ Kopieren in ein Projekt erzeugt ein eigenständiges Projektgerät.
- SQLite ist die aktuell unterstützte Datenbank.
- Fremdschlüssel werden für jeden Datenbankkontext aktiviert.
- `npm run db:migrate` wendet Drizzle-Migrationen an.
- `npm run db:migrate` richtet mit der einzelnen Migration `0000` das komplette
aktuelle Schema einer leeren Datenbank ein.
- `npm run db:verify:circuit-schema` prüft erforderliche und entfernte Spalten.
- `npm run db:backup` erzeugt ein konsistentes und verifiziertes Online-Backup.
- `npm run typecheck:scripts` prüft alle TypeScript-Wartungs- und
Upgrade-Skripte mit ihren Anwendungspfaden, ohne Code zu erzeugen.
- Angewendete Migrationen werden niemals nachträglich verändert.
- `db:migrate:legacy-consumers` ist Upgrade-Werkzeug, kein Anwendungspfad.
Der fachliche Migrationsdienst kennt nur schmale Reader-/Store-Ports unter
`src/domain/ports`; konkrete SQLite-Repositories werden ausschließlich im
CLI-Skript zusammengesetzt.
- `npm run typecheck:scripts` prüft die TypeScript-Wartungsskripte, ohne Code zu
erzeugen.
- Die Baseline ersetzt alle vorigen Entwicklungsmigrationen. Datenbanken,
Snapshots und persistierte Commands aus Vor-Baseline-Ständen werden bewusst
nicht unterstützt. Ab der ersten veröffentlichten Version sind angewendete
Migrationen unveränderlich und Änderungen erfolgen additiv.
- Allgemeine Circuit-, Gerätezeilen-, CircuitList- und DistributionBoard-
Repositories stellen im Anwendungspfad nur noch benötigte Leseabfragen bereit.
Fachliche Schreibvorgänge liegen in den typisierten Command-Repositories;
Upgrade-Schreibvorgänge bleiben in expliziten Migrationsadaptern.
Fachliche Schreibvorgänge liegen in den typisierten Command-Repositories.
- Die vollständige Verteilungs-Testfixture liegt unter
`tests/support/distribution-board-fixture.ts` und ist kein exportierter
Produktions-Schreibweg.
- Migration `0024` bildet die additive relationale Grundlage für geschützte
Stromkreisgruppen und Verteilerkomponenten. Die drei bestehenden
Stromkreisabschnitte erhalten Kategorie und Gruppennummer 1. Separate
1:1-Tabellen halten künftig Stromkreis- und Komponenten-Schutzgeräte; die
bisherigen flachen Schutzfelder bleiben in dieser Übergangsphase unverändert.
- Die Baseline bildet die relationale Grundlage für geschützte Stromkreisgruppen
und Verteilerkomponenten. Separate
1:1-Tabellen halten Stromkreis- und Komponenten-Schutzgeräte. Die früheren
flachen Stromkreis-Schutzfelder sind aus der Baseline entfernt.
Ein triggergeführtes Register erzwingt bereits eine normalisierte,
stromkreislistenweite BMK-Eindeutigkeit über Stromkreise und
Verteilerkomponenten. Snapshot- und Transfer-Integration verwenden
Snapshot-Schema 7. Persistente Insert/Delete/Update-Commands für
Snapshot-Schema 1 der Baseline. 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 an und bearbeitet veränderliche Gruppen- und
+9 -8
View File
@@ -96,18 +96,19 @@ erneut direkte Schreibmethoden erhalten.
## Migrationen
1. Bestehende lokale Datenbank sichern: `npm run db:backup`.
2. Schema unter `src/db/schema/` ändern.
3. `npm run db:generate` ausführen.
4. Das generierte SQL vollständig prüfen; es darf nur die beabsichtigte Änderung
1. Schema unter `src/db/schema/` ändern.
2. `npm run db:generate` ausführen.
3. Das generierte SQL vollständig prüfen; es darf nur die beabsichtigte Änderung
enthalten.
5. Upgrade-/Erhaltungstest ergänzen, wenn Spalten oder Beziehungen geändert
4. Upgrade-/Erhaltungstest ergänzen, wenn Spalten oder Beziehungen geändert
werden.
6. `npm test`, `npm run db:migrate` und
5. `npm test`, `npm run db:migrate` und
`npm run db:verify:circuit-schema` ausführen.
Bereits angewendete SQL-Migrationen dürfen nicht geändert oder neu sortiert
werden. Korrekturen erfolgen immer über eine neue Migration.
`0000` ist die saubere Baseline für leere Neuinstallationen. Vor-Baseline-
Entwicklungsdatenbanken werden nicht aktualisiert. Nach Veröffentlichung der
ersten Version dürfen angewendete SQL-Migrationen nicht geändert oder neu
sortiert werden; Korrekturen erfolgen dann immer über eine neue Migration.
## Pull-Request-Handoff
-137
View File
@@ -1,137 +0,0 @@
# Local DB Migration: Circuit-First Schema
This project uses SQLite at `data/leistungsbilanz.db` and Drizzle migrations in `src/db/migrations`.
This document is an upgrade runbook for databases created before the Circuit-First
cutover. A clean installation only needs the normal `db:migrate` and schema
verification steps documented in the main README.
## Safe command order
1. Backup local DB (required before schema/data migration)
```bash
npm run db:backup
```
The command uses SQLite's online backup API, so committed WAL changes are included
even while the application is running. It opens the resulting standalone database
and requires both `PRAGMA integrity_check` and `PRAGMA foreign_key_check` to pass.
Database backups are operational recovery files and remain separate from the future
user-visible project version history.
2. Apply pending schema migrations (includes `0008_circuit_first_model`, the additive
`0009_project_device_circuit_fields` transition and the post-cutover
`0011_project_device_canonical_fields` cleanup)
```bash
npm run db:migrate
```
3. Verify circuit-first tables exist
```bash
npm run db:verify:circuit-schema
```
4. Backfill default sections for existing `circuit_lists`
```bash
npm run db:backfill:sections
```
5. Run legacy consumer -> circuit/device-row migration explicitly
```bash
npm run db:migrate:legacy-consumers
```
## Verification SQL
Run these against `data/leistungsbilanz.db`:
```sql
SELECT name
FROM sqlite_master
WHERE type = 'table'
AND name IN (
'circuit_sections',
'circuits',
'circuit_device_rows',
'legacy_consumer_circuit_migrations',
'legacy_consumer_migration_reports'
)
ORDER BY name;
```
The verification command also checks the circuit-first project-device columns added by migration `0009`.
```sql
SELECT circuit_list_id, key, prefix, sort_order
FROM circuit_sections
ORDER BY circuit_list_id, sort_order;
```
```sql
SELECT circuit_list_id, COUNT(*) AS circuits
FROM circuits
GROUP BY circuit_list_id;
```
```sql
SELECT c.circuit_list_id, COUNT(r.id) AS device_rows
FROM circuits c
LEFT JOIN circuit_device_rows r ON r.circuit_id = c.id
GROUP BY c.circuit_list_id;
```
## API verification
After the steps above:
`GET /api/projects/:projectId/circuit-lists/:circuitListId/tree`
Expected response shape:
```json
{
"circuitListId": "string",
"sections": [
{
"id": "string",
"key": "lighting|single_phase|three_phase|unassigned|...",
"displayName": "string",
"prefix": "-1F|-2F|-3F|-UF|...",
"sortOrder": 10,
"circuits": [
{
"id": "string",
"equipmentIdentifier": "-2F1",
"displayName": "string",
"sortOrder": 10,
"isReserve": false,
"circuitTotalPower": 1.23,
"deviceRows": [
{
"id": "string",
"displayName": "string",
"quantity": 1,
"powerPerUnit": 0.3,
"simultaneityFactor": 1,
"rowTotalPower": 0.3
}
]
}
]
}
]
}
```
If migrations were not applied, endpoint may return an empty fallback with a warning.
## Visual verification
Manual device rows and multi-device circuits can be created directly in the
circuit-list editor. The former development scripts for direct database writes
were removed because they bypassed project revisions and persistent undo/redo.
@@ -93,8 +93,6 @@ Implemented named-snapshot foundation:
- restore records a new `restore` revision containing both the selected target
state and the complete pre-restore inverse; undo/redo therefore remains
available after application restarts
- compatible upgrade-only Consumer links, mappings and reports are preserved
separately and are never imported into the logical snapshot payload
- arbitrary restore payloads are rejected by the generic user-command
endpoint; only server-stored snapshots can initiate a forward restore
- the project page provides an initially collapsed snapshot/timeline panel,
+7 -6
View File
@@ -342,9 +342,8 @@ Implemented foundation:
- circuit-device-row transaction tests cover both successful commits and forced SQLite rollbacks
- project-device row synchronization has real multi-row SQLite commit and rollback coverage
- BMK swaps and section reorder have real SQLite commit and rollback coverage
- the legacy consumer migration service depends only on narrow domain ports;
all concrete repositories are composed at the script entry point
- legacy circuit, row, mapping and report writes have real late-failure rollback coverage
- the former Consumer migration service, mappings and reports were removed with
the pre-release database cutover
- circuit and device-row persistence value mapping is separated from the general repositories
- obsolete direct Circuit, CircuitDeviceRow, CircuitList, DistributionBoard and
Project repository writes are removed; integration fixtures live under
@@ -362,8 +361,9 @@ Implemented foundation:
direct global SQLite access
- TypeScript maintenance and upgrade scripts have a dedicated no-emit
typecheck, including all referenced application modules
- the legacy consumer UI and application read/write endpoints are removed after verified data cutover
- retained legacy rows are accessible only through explicit database upgrade tooling
- the former Consumer UI, API, tables and upgrade tooling are removed
- migration `0000` is the clean baseline for new installations; pre-baseline
development databases are intentionally unsupported
- project devices no longer persist duplicate legacy power, phase, cosPhi or remark fields
## Phase 12: Project Revisions and Persistent Undo / Redo
@@ -618,7 +618,8 @@ Implemented handoff:
- README is a concise setup and project entry point without prototype status lists
- `docs/README.md` separates current, operational, future, specification and archived material
- current runtime, module boundaries and upgrade-only legacy data are documented explicitly
- current runtime and module boundaries are documented without unsupported
upgrade-only data paths
- contributor workflow covers clean databases, safe demo data, migrations, tests and commits
- development Compose is clearly separated from the currently unsupported production deployment
- `AGENTS.md` points LLM-assisted work to supported code paths and deferred architecture