fix(compose): user-files dauerhaft speichern und Betriebshandbuch nachziehen
- docker-compose.yml und docker-compose.prod.yml mounten /app/user-files im Dienst api auf ein neues benanntes Volume user-files (Eigentuemerschaft uid 1001 folgt aus dem Image, kein Bind-Mount) - docker-compose.dev.yml bleibt unveraendert (Compose fuehrt Mount-Listen ueber das Ziel zusammen) - Betriebshandbuch Kapitel 6: Speicher als dauerhaft beschrieben, Mount-Zeile woertlich zum Kopieren, Hinweis dass /opt/tessera/docker-compose.yml auf dem Server separat gepflegt werden muss (Deploy erreicht sie nicht) - Betriebshandbuch Kapitel 7: Fehlerzeile zu verschwundenen Avataren/Exporten an den reparierten Repository-Stand angepasst WINDOWS #17 bleibt offen, bis die Serverdatei manuell ergaenzt ist. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FYZcd3SSmo14QTqWx2KKzU
This commit is contained in:
@@ -53,6 +53,8 @@ services:
|
|||||||
# it falls back to it.
|
# it falls back to it.
|
||||||
TESSERA_ENCRYPTION_KEY: "${TESSERA_ENCRYPTION_KEY:-${CALENDAR_ENCRYPTION_KEY:?set TESSERA_ENCRYPTION_KEY in .env, generate one with openssl rand -hex 32}}"
|
TESSERA_ENCRYPTION_KEY: "${TESSERA_ENCRYPTION_KEY:-${CALENDAR_ENCRYPTION_KEY:?set TESSERA_ENCRYPTION_KEY in .env, generate one with openssl rand -hex 32}}"
|
||||||
CALENDAR_ENCRYPTION_KEY: "${CALENDAR_ENCRYPTION_KEY:-}"
|
CALENDAR_ENCRYPTION_KEY: "${CALENDAR_ENCRYPTION_KEY:-}"
|
||||||
|
volumes:
|
||||||
|
- user-files:/app/user-files
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3001/health"]
|
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3001/health"]
|
||||||
interval: 10s
|
interval: 10s
|
||||||
@@ -88,3 +90,4 @@ networks:
|
|||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
pgdata:
|
pgdata:
|
||||||
|
user-files:
|
||||||
|
|||||||
@@ -57,6 +57,8 @@ services:
|
|||||||
# it falls back to it.
|
# it falls back to it.
|
||||||
TESSERA_ENCRYPTION_KEY: "${TESSERA_ENCRYPTION_KEY:-${CALENDAR_ENCRYPTION_KEY:?set TESSERA_ENCRYPTION_KEY in .env, generate one with openssl rand -hex 32}}"
|
TESSERA_ENCRYPTION_KEY: "${TESSERA_ENCRYPTION_KEY:-${CALENDAR_ENCRYPTION_KEY:?set TESSERA_ENCRYPTION_KEY in .env, generate one with openssl rand -hex 32}}"
|
||||||
CALENDAR_ENCRYPTION_KEY: "${CALENDAR_ENCRYPTION_KEY:-}"
|
CALENDAR_ENCRYPTION_KEY: "${CALENDAR_ENCRYPTION_KEY:-}"
|
||||||
|
volumes:
|
||||||
|
- user-files:/app/user-files
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3001/health"]
|
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3001/health"]
|
||||||
interval: 10s
|
interval: 10s
|
||||||
@@ -91,3 +93,4 @@ networks:
|
|||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
pgdata:
|
pgdata:
|
||||||
|
user-files:
|
||||||
|
|||||||
+30
-14
@@ -270,24 +270,40 @@ Restores stattfinden.
|
|||||||
|
|
||||||
- **PostgreSQL-Daten**: liegen im benannten Docker-Volume `pgdata`
|
- **PostgreSQL-Daten**: liegen im benannten Docker-Volume `pgdata`
|
||||||
(`docker-compose.prod.yml`, Mount `pgdata:/var/lib/postgresql/data` im
|
(`docker-compose.prod.yml`, Mount `pgdata:/var/lib/postgresql/data` im
|
||||||
`db`-Container). Dieses Volume ist der einzige daürhafte Datenspeicher, der über
|
`db`-Container). `pgdata` ist eines von zwei dauerhaften Docker-Volumes (siehe
|
||||||
ein `docker volume`-Backup zusätzlich gesichert werden könnte.
|
nächster Punkt) und kann zusätzlich über ein `docker volume`-Backup gesichert
|
||||||
|
werden.
|
||||||
- **Verschlüsselungsschlüssel** `TESSERA_ENCRYPTION_KEY`: liegt nur in `.env` auf
|
- **Verschlüsselungsschlüssel** `TESSERA_ENCRYPTION_KEY`: liegt nur in `.env` auf
|
||||||
dem Host, **nicht** im Datenbank-Dump. Getrennt sichern (siehe Kapitel 2/3) – ohne
|
dem Host, **nicht** im Datenbank-Dump. Getrennt sichern (siehe Kapitel 2/3) – ohne
|
||||||
ihn sind alle per `pg_dump` gesicherten verschlüsselten Zugangsdaten wertlos.
|
ihn sind alle per `pg_dump` gesicherten verschlüsselten Zugangsdaten wertlos.
|
||||||
- **Hochgeladene Dateien** (Avatare unter `user-files/avatars/`, generierte
|
- **Hochgeladene Dateien** (Avatare unter `user-files/avatars/`, generierte
|
||||||
DKV-Exporte unter `user-files/`, siehe `apps/api/src/user/user.controller.ts` und
|
DKV-Exporte unter `user-files/`, siehe `apps/api/src/user/user.controller.ts` und
|
||||||
`apps/api/src/dkv/dkv-export.service.ts`): Diese Dateien landen im Verzeichnis
|
`apps/api/src/dkv/dkv-export.service.ts`): Diese Dateien liegen im benannten
|
||||||
`user-files/` **innerhalb** des `api`-Containers. Weder `docker-compose.yml` noch
|
Docker-Volume `user-files`, gemountet auf `/app/user-files` im Dienst `api`. Der
|
||||||
`docker-compose.prod.yml` mounten dafür ein Docker-Volume oder ein Host-Verzeichnis
|
Mount ist in `docker-compose.yml` und `docker-compose.prod.yml` eingetragen:
|
||||||
– der Ordner existiert ausschließlich in der beschreibbaren Container-Schicht.
|
|
||||||
**Das bedeutet: Bei jedem `--force-recreate` von `api` gehen Avatare und DKV-Exporte
|
```yaml
|
||||||
verloren**, sofern auf dem Server nicht zusätzlich (außerhalb des Repo-Standes)
|
# beim Dienst api:
|
||||||
ein Bind-Mount ergänzt wurde. Vor einem Redeploy prüfen, ob auf dem Server ein
|
- user-files:/app/user-files
|
||||||
solcher Mount existiert (`docker inspect tessera-api-1` → `Mounts`); falls
|
# im Top-Level-Block volumes:
|
||||||
nicht, gelten Avatare/Exporte als nicht persistent und sollten bei Bedarf vorher
|
user-files:
|
||||||
manuell aus dem Container kopiert werden (`docker compose cp api:/app/user-files
|
```
|
||||||
./user-files-backup`).
|
|
||||||
|
Damit überstehen Avatare und DKV-Exporte ein `--force-recreate` von `api`. Wie bei
|
||||||
|
`pgdata` zeigt `docker volume ls` das Volume mit vorangestelltem Projektnamen an
|
||||||
|
(`<projekt>_user-files`). Gesichert werden die Dateien weiterhin mit
|
||||||
|
`docker compose cp api:/app/user-files ./user-files-backup`, alternativ über eine
|
||||||
|
Sicherung des Docker-Volumes selbst (wie bei `pgdata`).
|
||||||
|
|
||||||
|
**Wichtig für den Betrieb auf einem bestehenden Server:** `/opt/tessera/docker-compose.yml`
|
||||||
|
ist keine Arbeitskopie dieses Repositorys – die Datei wurde dort von Hand
|
||||||
|
bearbeitet und weicht ab. Ein Deploy holt ausschließlich Images und fasst diese
|
||||||
|
Datei nicht an. Diese Compose-Änderung erreicht eine bereits laufende Installation
|
||||||
|
deshalb **nicht von selbst**. Wer die Reparatur dort haben will, trägt dieselben
|
||||||
|
zwei Zeilen selbst in `/opt/tessera/docker-compose.yml` ein (vorher sichern) und
|
||||||
|
erstellt die Container einmal neu. Bis dahin gilt für die laufende Installation
|
||||||
|
weiterhin der alte, verlustbehaftete Zustand – prüfbar mit `docker inspect
|
||||||
|
tessera-api-1` und einem Blick auf `Mounts`.
|
||||||
|
|
||||||
## 7. Protokolle und Fehlersuche
|
## 7. Protokolle und Fehlersuche
|
||||||
|
|
||||||
@@ -313,7 +329,7 @@ protokolliert die durchgelaufenen Prisma-Migrationen sowie zuletzt
|
|||||||
| Neue Version scheint nicht anzukommen, obwohl `pull` gelaufen ist | Klassische `up -d`-Falle ohne `--force-recreate` (siehe Kapitel 4) | `StartedAt` des Containers gegen `Created` des Images vergleichen, ggf. `--force-recreate` nachholen. |
|
| Neue Version scheint nicht anzukommen, obwohl `pull` gelaufen ist | Klassische `up -d`-Falle ohne `--force-recreate` (siehe Kapitel 4) | `StartedAt` des Containers gegen `Created` des Images vergleichen, ggf. `--force-recreate` nachholen. |
|
||||||
| Initialer Admin-Login funktioniert nicht nach Änderung von `TESSERA_ADMIN_PASSWORD` | Seed läuft nur, wenn der Benutzername noch **nicht** existiert; bestehende Accounts werden nicht überschrieben | Passwort über die Anwendung selbst (bzw. direkt in der Datenbank) ändern, nicht über die `.env`-Variable. |
|
| Initialer Admin-Login funktioniert nicht nach Änderung von `TESSERA_ADMIN_PASSWORD` | Seed läuft nur, wenn der Benutzername noch **nicht** existiert; bestehende Accounts werden nicht überschrieben | Passwort über die Anwendung selbst (bzw. direkt in der Datenbank) ändern, nicht über die `.env`-Variable. |
|
||||||
| Mails werden nicht versendet | `TESSERA_SMTP_HOST` leer (Prod-Default) | SMTP-Variablen vollständig setzen und Container neu erstellen. |
|
| Mails werden nicht versendet | `TESSERA_SMTP_HOST` leer (Prod-Default) | SMTP-Variablen vollständig setzen und Container neu erstellen. |
|
||||||
| Avatare/DKV-Exporte nach einem Deploy verschwunden | `user-files/` ist nicht als Volume gemountet, siehe Kapitel 6 | Vor `--force-recreate` sichern, langfristig einen Bind-Mount für `user-files/` ergänzen. |
|
| Avatare/DKV-Exporte nach einem Deploy verschwunden | Die verwendete Compose-Datei mountet `user-files/` nicht als Volume – im Repository-Stand seit dieser Version behoben, betrifft nur eine Installation mit abweichender Compose-Datei | Die zwei Zeilen aus Kapitel 6 in die verwendete Compose-Datei eintragen (auf dem Server: `/opt/tessera/docker-compose.yml`, vorher sichern) und `api` neu erstellen. |
|
||||||
|
|
||||||
## 8. Abgrenzung zur CI/CD-Pipeline
|
## 8. Abgrenzung zur CI/CD-Pipeline
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user