taskmanager/README.md
Weapie e7d8d1a856
Some checks are pending
check / publish (push) Blocked by required conditions
check / verify (push) Has started running
Release 1.0.1
2026-10-08 15:41:59 +02:00

213 lines
15 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Aufgabenplaner – Installation, Produktivbetrieb und Upgrade
Aufgabenverwaltung mit Next.js, PostgreSQL, privaten Anhängen und RBAC aus Benutzern, Gruppen, Rollen und einzelnen Berechtigungen. Die Oberfläche nutzt shadcn/Radix und Lucide; Aufgaben sind als Liste, Kanban oder Monatsagenda verfügbar.
**Eine bestehende Installation wird aktualisiert, nicht neu initialisiert.** Benutzer, Passwort-Hashes, Aufgaben, Status, Zuweisungen, Beauftragungsdaten, Kommentare und Anhänge werden übernommen. Die neue Version darf erst nach erfolgreicher Migration und Abnahme öffentlich erreichbar sein. Für den Umstieg einer produktiven Altinstallation zuerst die vollständige [Upgrade-Anleitung](UPGRADE.md) lesen.
## Inhalt
- [Produktions-Compose für Dokploy/Traefik](PRODUCTION.md)
- [Fertige Docker-Images, Versionen und Registry-Deployment](REGISTRY.md)
- [Bestehende Installation übernehmen](UPGRADE.md)
- [Voraussetzungen](#voraussetzungen)
- [Neuinstallation](#neuinstallation)
- [Konfiguration](#konfiguration)
- [Berechtigungen](#berechtigungen)
- [Betrieb und Datensicherung](#betrieb-und-datensicherung)
- [Abnahme und Fehlerbehebung](#abnahme-und-fehlerbehebung)
- [Entwicklung und Tests](#entwicklung-und-tests)
## Funktionen
Aufgaben mit Suche, Filtern, Prioritäten, Tags, Projekten, Standorten, Checklisten, Kommentaren, Unteraufgaben, Abhängigkeiten und Wiederholungen. Zuweisung an Personen oder Teampool, Archiv/Wiederherstellung, Stapelaktionen, Vorlagen und gespeicherte Ansichten. CSV-/XLSX-Import mit Vorschau, CSV-/XLSX-/ICS-Export, widerrufbare Kalenderlinks, API-Tokens, signierte Webhooks, Audit und Erinnerungen. Benutzer und Gruppen lassen sich verwalten; Löschungen erfordern Bestätigung und unterliegen serverseitigen Schutzregeln.
## Voraussetzungen
- Linux-Server mit Docker Engine und Docker Compose v2; ausreichend Speicher für PostgreSQL, Anhänge, Builds und mindestens eine vollständige Sicherung. Kapazität mit dem eigenen Datenbestand prüfen.
- PostgreSQL 16 (im Compose enthalten). **Kein gleichzeitiger PostgreSQL-Major-Versionswechsel beim Anwendungsupgrade.**
- Öffentlich erreichbare HTTPS-Domain und Reverse Proxy. Beispiel: [deploy/nginx.conf.example](deploy/nginx.conf.example).
- Repository-Zugriff und administrativer Zugriff auf die eigenen Docker-Volumes/Backups.
- Für lokale Entwicklung: Node.js 22+, npm und PostgreSQL 16. Docker nutzt Node 22.
Die folgenden Serverbefehle verwenden Bash. Alle Befehle im Checkout ausführen. `.env`, Backups und Produktivdaten gehören nicht ins Git. Das öffentliche TLS-Zertifikat und die Proxy-Konfiguration sind betreiberspezifisch.
## Neuinstallation
**Nur für eine leere Installation. Bei vorhandenen Daten stattdessen [UPGRADE.md](UPGRADE.md) verwenden.**
```bash
git clone https://git.jfritzsche.de/jf/taskmanager.git
cd taskmanager
git switch main
cp .env.example .env
chmod 600 .env
openssl rand -hex 32 # als NEXTAUTH_SECRET eintragen
openssl rand -hex 24 # als Datenbankpasswort verwenden
```
`.env` bearbeiten, mindestens:
```dotenv
POSTGRES_PASSWORD=HIER_ZUFAELLIGES_DATENBANKPASSWORT
DATABASE_URL=postgresql://taskmanager:HIER_ZUFAELLIGES_DATENBANKPASSWORT@db:5432/taskmanager
NEXTAUTH_URL=https://aufgaben.example.org
NEXTAUTH_SECRET=HIER_ZUFAELLIGES_SECRET_MIT_MINDESTENS_32_ZEICHEN
ALLOW_LOCAL_HTTP=false
APP_TIMEZONE=Europe/Berlin
ARCHIVE_RETENTION_DAYS=0
BOOTSTRAP_EMAIL=admin@example.org
BOOTSTRAP_PASSWORD=HIER_EINMALPASSWORT_MIT_MINDESTENS_12_ZEICHEN
```
Passwörter in `DATABASE_URL` müssen URL-kodiert sein; die oben generierten Hexwerte benötigen keine Sonderbehandlung. `POSTGRES_PASSWORD` ist der unveränderte Passwortwert. Variablen mit `$` in `.env` passend einfach quotieren, um Compose-Interpolation zu verhindern.
```bash
docker compose -p taskmanager build
docker compose -p taskmanager up -d --wait db
docker compose -p taskmanager run --rm migrate
```
Der Migrationsdienst führt auch die Seeds aus: RBAC über `migrate-access.ts`, danach Administrator-Bootstrap über `prisma/seed.ts`. Bootstrap-Werte danach aus `.env` entfernen. Seed legt ausschließlich bei fehlendem Administrator einen neuen an; keine Standardzugänge. Das Startpasswort muss bei der ersten Anmeldung geändert werden.
```bash
docker compose -p taskmanager up -d --wait app worker
curl --fail http://127.0.0.1:3000/api/health
```
Proxy auf `127.0.0.1:3000` richten, Domain/Zertifikate einrichten, `/uploads/` sperren, HTTPS erzwingen. Wenn der Proxy selbst in Docker läuft, sein Netz und Upstream ausdrücklich anpassen: dessen `127.0.0.1` ist nicht der Host. Erst nach der Abnahme unten freigeben.
## Konfiguration
| Variable | Bedeutung / Produktionswert |
| --- | --- |
| `DATABASE_URL` | PostgreSQL-Verbindung; in Compose `db:5432`, außerhalb die tatsächliche Adresse. |
| `POSTGRES_PASSWORD` | Passwort des Compose-DB-Benutzers `taskmanager`. Bei vorhandenem Volume muss es zum tatsächlich gesetzten DB-Passwort passen. Eine Änderung der Variable allein ändert das DB-Passwort nicht. |
| `POSTGRES_DB` | Optional, Standard `taskmanager`; auch DATABASE_URL anpassen. |
| `NEXTAUTH_URL` | Externe HTTPS-Adresse, keine interne Containeradresse. |
| `NEXTAUTH_SECRET` | Zufällig, mindestens 32 Zeichen; sichern. Wechsel meldet Sitzungen ab. |
| `APP_TIMEZONE` | Gültige Zeitzone, Standard `Europe/Berlin`. |
| `UPLOAD_DIR` | Compose setzt `/app/private-uploads`. Bei Betrieb ohne Docker absoluten privaten Pfad verwenden. |
| `LEGACY_UPLOAD_DIR` | Nur Migration. Compose verwendet dasselbe private Volume als Wurzel der übernommenen alten Upload-Verzeichnisstruktur. Ohne Compose explizit auf das alte `public/uploads` setzen. |
| `GROUP_UPLOAD_QUOTA_MB` | Upload-Quota pro Gruppe; Standard 1024 MB. An Bestandsvolumen anpassen. |
| `TRUST_PROXY` | Nur `true`, wenn der vertrauenswürdige Proxy `x-real-ip` ersetzt und direkter externer Zugriff ausgeschlossen ist. |
| `ALLOW_LOCAL_HTTP` | Produktion `false`; nur lokale Tests dürfen Loopback-HTTP freischalten. |
| `ARCHIVE_RETENTION_DAYS` | `0` bewahrt Archive unbegrenzt. Ab 30 werden archivierte erledigte Aufgaben nach Frist endgültig gelöscht. |
| `SMTP_URL`, `MAIL_FROM` | Gemeinsam setzen, um Einladung, Passwort-Reset und Benachrichtigungen zu aktivieren. Ohne SMTP Konten mit Einmalpasswort anlegen. |
| `OIDC_ISSUER`, `OIDC_CLIENT_ID`, `OIDC_CLIENT_SECRET` | Optional gemeinsam konfigurieren. Callback: `https://DOMAIN/api/auth/callback/oidc`. |
| `OIDC_REQUIRED_ACR` | Optional erwarteter ACR-Wert; MFA zusätzlich im Identity Provider erzwingen. |
| `WEBHOOK_ALLOWED_HOSTS` | Kommagetrennte exakte öffentliche HTTPS-Hosts; keine Wildcards. |
| `BOOTSTRAP_EMAIL`, `BOOTSTRAP_PASSWORD` | Ausschließlich einmalig bei Neuinstallation. Passwort 12 Zeichen bis 72 UTF-8-Bytes. |
| `TASKMANAGER_ENV_FILE` | Optional anderer Pfad statt `.env` für die Container. Für Compose-Variablen zusätzlich `--env-file PFAD` verwenden. |
Die alte `Role`-Spalte bleibt als Migrationsinformation erhalten; sie steuert keine Berechtigungen mehr. OIDC-Konten werden ausdrücklich über den Provider-Subject verknüpft, nicht automatisch über gleiche E-Mail-Adressen. Danach ist ihre lokale Passwortanmeldung gesperrt.
## Berechtigungen
- **ASSIGNED:** Zugriff auf dem Benutzer zugewiesene Aufgaben.
- **GROUP:** Zugriff auf Aufgaben der jeweiligen Gruppe; direkte Gruppenrollen benötigen eine aktive Mitgliedschaft.
- **GLOBAL:** Zugriff unabhängig von der Gruppe. Verwaltungsrechte sind ausschließlich global zulässig.
Rollen bündeln Permissions; Benutzer erhalten sie direkt oder über Gruppen. Fehlende Rechte werden serverseitig abgewiesen, auch bei Dateien und Exporten. Systemadministrator wird ausschließlich direkt vergeben; mindestens ein aktiver Administrator muss erhalten bleiben. Benutzerpflege verleiht nicht automatisch Rechteverwaltung.
Für den Teampool einer Gruppe „Teampool lesen und übernehmen“ mit GROUP und „Bearbeiter“ mit ASSIGNED zuweisen. Koordinatoren erhalten für die Bearbeitung eigener Aufgaben zusätzlich „Bearbeiter“. Gruppen mit bestehenden Aufgaben lassen sich nicht löschen; Aufgaben vorher umordnen oder die Gruppe deaktivieren.
Die genaue Zuordnung alter Rollen und die erforderliche organisatorische Nachprüfung stehen in [UPGRADE.md](UPGRADE.md).
## Betrieb und Datensicherung
### Dienste
- `db`: persistentes PostgreSQL-Volume `postgres_data`.
- `migrate`: Schema-, Rollen- und Anhangsmigration; beendet sich bei Erfolg mit Exitcode 0. Bei Fehler startet `app` nicht.
- `app`: Next.js, UID/GID 1001, schreibgeschütztes Root-Dateisystem, privates `uploads`-Volume; Port nur am Host-Loopback.
- `worker`: genau **eine** Instanz für Erinnerungen, Wiederholungen, Zustellung und Bereinigung. Gleiches privates Upload-Volume wie `app` und `migrate`.
```bash
docker compose -p taskmanager ps -a
docker compose -p taskmanager logs --tail=100 migrate app worker
```
`/api/health` prüft die DB-Verbindung. Worker-Heartbeat prüft, ob Durchläufe stattfinden. `unhealthy` extern alarmieren: Docker startet allein aufgrund dieses Status nicht neu. Auf freien Speicher, PostgreSQL-Backups, Zustellfehler und Backup-Alter überwachen. Genau eine Migration gleichzeitig ausführen; bei Updates App und Worker vorher stoppen.
### Konsistentes Backup (Bash)
Projektname an die tatsächliche Installation anpassen; vorab `docker compose ... ps` kontrollieren. Der kurze Stopp verhindert auseinanderlaufende Datenbank-/Dateisicherungen. Folgender Ablauf setzt normalerweise laufende App und Worker voraus:
```bash
mkdir -p backups
BACKUP_DIR="$(pwd)/backups/$(date -u +%Y%m%dT%H%M%SZ)"
mkdir -m 700 "$BACKUP_DIR"
docker compose -p taskmanager stop -t 60 app worker
# Bei JEDEM Fehler hier angehalten lassen, Fehler prüfen und Dienste bewusst wieder starten.
docker compose -p taskmanager exec -T db sh -c 'pg_dump -U "$POSTGRES_USER" -d "$POSTGRES_DB" -Fc' > "$BACKUP_DIR/database.dump"
docker compose -p taskmanager run --rm --no-deps --user 0:0 \
-v "$BACKUP_DIR:/backup" worker tar -czf /backup/uploads.tar.gz -C /app/private-uploads .
cp .env "$BACKUP_DIR/environment.env"
(cd "$BACKUP_DIR" && sha256sum database.dump uploads.tar.gz environment.env > SHA256SUMS)
docker compose -p taskmanager start app worker
```
Jeden Exitcode prüfen, insbesondere vor Neustart; Skripte mit `set -euo pipefail` ausführen. PowerShell-Alternative: `scripts/backup.ps1 -Project taskmanager -EnvFile .env`; diese startet vorher laufende Dienste auch bei Fehlern wieder. `.env` zusätzlich geschützt sichern. Backups verschlüsselt außerhalb des Servers lagern, Zugriffsrechte begrenzen und regelmäßig in einer separaten Instanz wiederherstellen. SHA-256 prüft Integrität, ersetzt keine Verschlüsselung.
### Updates und Wiederherstellung
Den getesteten Commit festhalten, Images bauen, Wartungsfenster aktivieren, konsistentes Backup erstellen, Dienste stoppen, `docker compose ... run --rm migrate`, anschließend `up -d --wait app worker`. **Niemals `prisma migrate reset`, `db push --accept-data-loss` oder `docker compose down -v` auf Bestandsdaten verwenden.**
Restore und Rollback stehen mit konkreten Befehlen in [UPGRADE.md](UPGRADE.md). Schemaänderungen werden nicht durch Start eines älteren Images rückgängig gemacht. Nach Freigabe entstandene Änderungen beim Rollback gesondert berücksichtigen.
## Abnahme und Fehlerbehebung
Vor Freigabe prüfen:
1. Migration Exitcode 0, `db`, `app`, `worker` healthy; HTTPS und richtige externe URL.
2. Anzahl Benutzer/Aufgaben/Kommentare/Dateien mit dem Backup vergleichen; alte Beauftragungsdaten und Anhänge stichprobenartig prüfen.
3. Bestehender Administrator und Bearbeiter können sich nach erneuter Anmeldung anmelden. Rollen und Gruppenzugriff prüfen.
4. Fremde Aufgaben/Dateien sind ohne Berechtigung gesperrt; Rechteentzug greift sofort.
5. Aufgabe erstellen, bearbeiten, zuweisen, erledigen, archivieren und wiederherstellen; Kommentar sowie Upload/Download prüfen.
6. `/uploads/...` liefert keine Altdateien; Proxy bedient das Verzeichnis ebenfalls nicht statisch.
7. SMTP, OIDC/MFA und Webhooks bei Verwendung mit echten Zielsystemen separat prüfen. Restore erfolgreich üben.
| Problem | Vorgehen |
| --- | --- |
| `P3005` / vorhandene DB ohne Migrationshistorie | Baseline nur nach Schemaabgleich, siehe Upgrade-Anleitung. Nicht zurücksetzen. |
| Doppelte normalisierte E-Mails | Beide Konten erhalten und eindeutige echte Adressen festlegen; kein automatisches Zusammenführen. Danach Migration erneut starten. |
| `ENOENT`, Größen-/Inhaltsprüfung eines Anhangs | Volume/Verzeichnisstruktur und Originalbackup prüfen. Fehlende Bytes können nicht rekonstruiert werden. Keine File-Zeilen löschen, um die Prüfung zu umgehen. |
| `EACCES` | Eigentümer/Rechte des privaten Volumes für UID/GID 1001 prüfen. Nicht pauschal 777 vergeben. |
| Leere Daten nach Umstieg | Projekt-/Volume-Namen und DATABASE_URL vergleichen; häufig wurde ein neues leeres Volume eingebunden. Nicht seeden, bevor die Quelle geklärt ist. |
| Login-Schleife / Cookie fehlt | NEXTAUTH_URL, HTTPS und Proxy prüfen; nach Migration alte Sitzung abmelden. |
| Worker unhealthy | Logs, DB-Erreichbarkeit, Platz, Konfiguration und Heartbeat prüfen. |
## Grenzen
Anhänge: PDF/JPEG/PNG/DOCX/XLSX, maximal 10 MB, tatsächlicher Inhalt wird geprüft. Nicht erkannte oder früher fälschlich akzeptierte Bestandsdateien bleiben erhalten und stoppen die Übernahme bis zur Klärung. Nicht referenzierte Altdateien bleiben im privaten Volume und werden nicht als Aufgabenanhang erfunden.
CSV/XLSX: 100 Zeilen/100 KB, keine Formeln; Batch: 50 Aufgaben mit möglichen Teilerfolgen; Export: 5000 Aufgaben. Kalenderseite ist eine Monatsagenda. Keine Offline-Datenkopien und keine native lokale MFA. E-Mail/Webhooks können nach einem Absturz doppelt zugestellt werden; Empfänger müssen deduplizieren. Audit ist kein externes manipulationssicheres Archiv. Malware-Scanning, TLS, externe Sicherung und Monitoring sind Betreiberaufgaben. Aktuelle Abhängigkeitsbefunde: [SECURITY.md](SECURITY.md).
## Entwicklung und Tests
```bash
npm ci
npx prisma generate
npx prisma migrate deploy
npx tsx scripts/migrate-access.ts
npx tsx scripts/migrate-uploads.ts
npm run dev
# separat:
npm run worker
```
Bei einer leeren Entwicklungsdatenbank einmalig Bootstrap-Werte setzen und `npm run prisma:seed` ausführen. Für Checks:
```bash
npm run typecheck
npm run lint
npm test
npm run build
```
Integration und Playwright nur gegen dedizierte `taskmanager_review`-DB, niemals Produktion: `npm run test:integration`, `npx playwright install chromium`, `npx playwright test`. Playwright nutzt Port 3107. Bei Proxy `NO_PROXY=localhost,127.0.0.1` setzen.
Der reproduzierbare Altversions-Upgrade-Test verwendet ausschließlich eine **leere** Datenbank `taskmanager_upgrade_test`: `DATABASE_URL=... npx tsx --test tests/upgrade.test.ts`. Er legt das ursprüngliche Schema und Bestandsdaten an, prüft alle alten Aufgabenfelder, Konten, Kommentare, Anhangsbytes, Rollen und Wiederholbarkeit. Er lässt die Testdatenbank zur Kontrolle stehen; ein weiterer Lauf benötigt erneut eine leere Testdatenbank.
Lokale Vorführung: [TESTBETRIEB.md](TESTBETRIEB.md). API: [API_DOCUMENTATION.md](API_DOCUMENTATION.md). Oberfläche und Abnahme: [UX-ABNAHME.md](UX-ABNAHME.md). Technischer Prüfstand: [IMPLEMENTATION.md](IMPLEMENTATION.md).