15 KiB
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 lesen.
Inhalt
- Bestehende Installation übernehmen
- Voraussetzungen
- Neuinstallation
- Konfiguration
- Berechtigungen
- Betrieb und Datensicherung
- Abnahme und Fehlerbehebung
- 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.
- 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 verwenden.
git clone https://git.jfritzsche.de/jf/taskmanager.git
cd taskmanager
git switch feature/security-rbac
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:
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.
docker compose -p taskmanager build
docker compose -p taskmanager up -d --wait db
docker compose -p taskmanager run --rm migrate
docker compose -p taskmanager run --rm --no-deps migrate npm run prisma:seed
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.
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.
Betrieb und Datensicherung
Dienste
db: persistentes PostgreSQL-Volumepostgres_data.migrate: Schema-, Rollen- und Anhangsmigration; beendet sich bei Erfolg mit Exitcode 0. Bei Fehler startetappnicht.app: Next.js, UID/GID 1001, schreibgeschütztes Root-Dateisystem, privatesuploads-Volume; Port nur am Host-Loopback.worker: genau eine Instanz für Erinnerungen, Wiederholungen, Zustellung und Bereinigung. Gleiches privates Upload-Volume wieappundmigrate.
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:
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. 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:
- Migration Exitcode 0,
db,app,workerhealthy; HTTPS und richtige externe URL. - Anzahl Benutzer/Aufgaben/Kommentare/Dateien mit dem Backup vergleichen; alte Beauftragungsdaten und Anhänge stichprobenartig prüfen.
- Bestehender Administrator und Bearbeiter können sich nach erneuter Anmeldung anmelden. Rollen und Gruppenzugriff prüfen.
- Fremde Aufgaben/Dateien sind ohne Berechtigung gesperrt; Rechteentzug greift sofort.
- Aufgabe erstellen, bearbeiten, zuweisen, erledigen, archivieren und wiederherstellen; Kommentar sowie Upload/Download prüfen.
/uploads/...liefert keine Altdateien; Proxy bedient das Verzeichnis ebenfalls nicht statisch.- 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.
Entwicklung und Tests
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:
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. API: API_DOCUMENTATION.md. Oberfläche und Abnahme: UX-ABNAHME.md. Technischer Prüfstand: IMPLEMENTATION.md.