Initialize clean CSR inventory repository
This commit is contained in:
113
docs/postgresql-migration.md
Normal file
113
docs/postgresql-migration.md
Normal file
@@ -0,0 +1,113 @@
|
||||
# SQLite → PostgreSQL mit Docker
|
||||
|
||||
Die Anwendung verwendet standardmäßig PostgreSQL. Es gibt keinen automatischen
|
||||
Rückfall auf SQLite. Die folgenden Befehle sind vorbereitet; sie wurden auf dem
|
||||
aktuellen Windows-Rechner ohne Docker nicht ausgeführt.
|
||||
|
||||
## Vorbereiten
|
||||
|
||||
Docker mit Compose muss verfügbar sein. Die Befehle im Projektverzeichnis ausführen.
|
||||
Die bisherige Anwendung während Export, Import und Prüfung stoppen, damit keine
|
||||
Änderungen nach dem Export verloren gehen. `db.sqlite3` und das Verzeichnis `media`
|
||||
behalten und zusätzlich extern sichern. Niemals `docker compose down -v` ausführen,
|
||||
wenn Volumes noch benötigte Daten enthalten.
|
||||
|
||||
`.env.example` nach `.env` kopieren und mindestens `SECRET_KEY`,
|
||||
`POSTGRES_PASSWORD`, Domain, erlaubte Hosts und CSRF-Origin ersetzen.
|
||||
`POSTGRES_HOST=db` beibehalten. Keine Zugangsdaten in Git ablegen.
|
||||
|
||||
```sh
|
||||
docker compose config --quiet
|
||||
docker compose --profile tools build web migration
|
||||
docker compose stop web traefik
|
||||
docker compose up -d --wait db
|
||||
```
|
||||
|
||||
Die Zieldatenbank muss leer sein. Vor dem Import den Webdienst noch **nicht**
|
||||
starten: Sein Startskript legt sonst bereits Seed-Daten an. Das Importkommando
|
||||
verweigert einen Import, sobald Benutzer, Gruppen oder Inventardaten vorhanden sind.
|
||||
Die zwei von Migration 0003 angelegten Standard-Gerätetypen werden als leere
|
||||
Ausgangsbasis erkannt und innerhalb der Importtransaktion durch die Exportdaten
|
||||
ersetzt. Ein vorhandenes PostgreSQL-System niemals zum Zweck des Imports leeren; stattdessen
|
||||
eine neue Datenbank bzw. ein separates Compose-Projekt verwenden.
|
||||
|
||||
## Exportieren, Schema anlegen, importieren
|
||||
|
||||
```sh
|
||||
docker compose run --rm migration scripts/export_sqlite.py /legacy/db.sqlite3 /transfer/sqlite-export.json
|
||||
docker compose run --rm migration manage.py migrate --noinput
|
||||
docker compose run --rm migration manage.py import_sqlite_export /transfer/sqlite-export.json
|
||||
```
|
||||
|
||||
Der Export liest SQLite über eine schreibgeschützte Verbindung, erstellt einen
|
||||
konsistenten temporären Snapshot und aktualisiert nur dessen Schema. Die originale
|
||||
SQLite-Datei bleibt unverändert. Existiert die Exportdatei bereits, wird sie nicht
|
||||
überschrieben; für einen weiteren Export einen neuen Dateinamen verwenden.
|
||||
|
||||
Der Export enthält Benutzer und Passwort-Hashes, Rollen, API-Schlüssel-Hashes,
|
||||
Geräte, Archivstatus, Zusatzfelder, Einstellungen, Nummernfolge und Historie.
|
||||
Content Types und Standardberechtigungen werden durch Migrationen angelegt und
|
||||
über natürliche Schlüssel zugeordnet. Sitzungen werden nicht übernommen; Benutzer
|
||||
müssen sich erneut anmelden. Der Import läuft transaktional und setzt die
|
||||
PostgreSQL-ID-Sequenzen durch Djangos `loaddata` zurück. Die Gerätenummernfolge
|
||||
wird mindestens auf die höchste vorhandene Gerätenummer gesetzt.
|
||||
|
||||
`backups/sqlite-export.json` enthält vertrauliche Daten und ist kein öffentliches
|
||||
Download-Artefakt. Der Export setzt auf Linux Dateirechte `0600`. Der offline
|
||||
gestartete Migrationscontainer läuft für den Zugriff auf das Backup-Verzeichnis
|
||||
als root; der Webcontainer läuft weiterhin als unprivilegierter `app`-Benutzer.
|
||||
|
||||
## Uploads übernehmen
|
||||
|
||||
Der Datenbankexport enthält Dateiverweise, nicht die Dateien selbst. Bei einem
|
||||
**neuen, leeren** `media_data`-Volume die bisherigen Uploads kopieren:
|
||||
|
||||
```sh
|
||||
docker compose run --rm --entrypoint sh migration -c 'cp -a /legacy/media/. /app/media/ && chown -R app:app /app/media'
|
||||
```
|
||||
|
||||
Ein bereits verwendetes Medienvolume zuerst sichern und seine Inhalte separat
|
||||
abgleichen; der Kopierbefehl darf nicht ungeprüft über vorhandene Dateien laufen.
|
||||
|
||||
## Prüfen und starten
|
||||
|
||||
```sh
|
||||
docker compose run --rm migration manage.py check
|
||||
docker compose run --rm migration manage.py makemigrations --check --dry-run
|
||||
docker compose run --rm -e DEBUG=true -e SECURE_SSL_REDIRECT=false migration manage.py test --noinput
|
||||
docker compose up -d --build web traefik
|
||||
docker compose ps
|
||||
```
|
||||
|
||||
Die Tests verwenden eine separate PostgreSQL-Testdatenbank. Danach Anmeldung,
|
||||
Geräteanzahl einschließlich Archiv, höchste Gerätenummer, Rollen, Historie und
|
||||
Upload-Verweise mit dem bisherigen System vergleichen. Ein PostgreSQL-Backup
|
||||
anlegen und testweise in eine separate leere Datenbank wiederherstellen:
|
||||
|
||||
```sh
|
||||
sh scripts/backup.sh
|
||||
```
|
||||
|
||||
Erst nach erfolgreicher Prüfung das alte System endgültig stilllegen. Für einen
|
||||
Rückwechsel den neuen Webdienst stoppen und die alte Anwendung mit ihrer
|
||||
unveränderten SQLite-Datei starten. Neue PostgreSQL-Änderungen werden nicht
|
||||
automatisch zurück nach SQLite übertragen.
|
||||
|
||||
## Lokaler Docker-Betrieb ohne HTTPS-Domain
|
||||
|
||||
Nach dem Import alternativ nur Datenbank und Webdienst starten:
|
||||
|
||||
```sh
|
||||
docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d --build db web
|
||||
```
|
||||
|
||||
Die Anwendung ist dann unter `http://localhost:8000` erreichbar. Der Port ist nur
|
||||
an localhost gebunden. Diese Entwicklungsüberschreibung nicht auf dem VPS nutzen.
|
||||
|
||||
## Bearbeitungsversionen
|
||||
|
||||
Geräte besitzen nun eine ganzzahlige `revision`. Browser-Formulare senden
|
||||
`expected_revision`; API-PATCH-Anfragen können ebenfalls dieses Feld verwenden.
|
||||
Bestehende API-Clients mit `expected_updated_at` bleiben kompatibel. Veraltete
|
||||
Versionen werden abgewiesen. Zeitstempel steigen auch bei geringer Auflösung der
|
||||
Systemuhr strikt an. Migration `0006` setzt bestehende Geräte auf Revision 1.
|
||||
Reference in New Issue
Block a user