docs: README, Schnellstart, Handbuch, Fahrplan und CHANGELOG

README mit Funktionsumfang, Bildergalerie, allen Umgebungsvariablen als
Tabelle und dem Betrieb inklusive Sicherung und Wiederherstellung.

Der Schnellstart führt in acht Schritten von git clone zur ersten
Anmeldung, jeder Schritt mit erwartetem Ergebnis. Er endet mit dem
Hinterlegen eines Passkeys statt beim ersten Kalenderkonto oder der
ersten Aufgabe — beides gibt es erst mit M3 und M2. Das ist in ROADMAP
und Handbuch so vermerkt, damit niemand danach sucht.

Handbuch mit Seiten zu Anmelden, Bereichen und Protokoll.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Florian Wilde
2026-09-10 14:29:51 +02:00
co-authored by Claude Opus 5
parent f91d015cc4
commit 56b5356708
9 changed files with 852 additions and 0 deletions
+155
View File
@@ -0,0 +1,155 @@
# Schnellstart
Von `git clone` bis zur ersten Anmeldung in höchstens zehn Minuten.
Jeder Befehl ist zum Kopieren, jeder Schritt nennt das erwartete Ergebnis.
## Voraussetzungen
| Werkzeug | Fassung | Prüfen mit |
| ------------------ | ---------------- | ------------------------ |
| Docker mit Compose | 25 oder neuer | `docker compose version` |
| Git | 2.40 oder neuer | `git --version` |
| Node.js | 22.12 oder neuer | `node -v` |
Node wird nur für die Entwicklung gebraucht. Für den reinen Betrieb genügen
Docker und Git.
## 1. Holen und Verzeichnis wechseln
```bash
git clone <REMOTE_URL> planer
cd planer
```
**Erwartet:** Das Verzeichnis `planer` enthält unter anderem `package.json`,
`docker-compose.yml` und `.env.example`.
## 2. Konfiguration anlegen
```bash
cp .env.example .env
```
Jetzt die Pflichtwerte setzen. Die Geheimnisse werden erzeugt, nicht erfunden:
```bash
# Signiert die Sitzungen. Ohne diesen Wert startet die Anwendung nicht.
openssl rand -base64 32
# Ein Passwort für die Datenbank.
openssl rand -hex 16
```
Unter Windows ohne OpenSSL geht auch:
```bash
node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"
```
Diese Werte in `.env` eintragen:
| Variable | Beispiel | Bedeutung |
| ------------------- | -------------------------------------------------------------------- | ------------------------------------------------------- |
| `INSTANZ` | `daheim` | `firma` oder `daheim` – bestimmt, was es überhaupt gibt |
| `APP_URL` | `http://localhost:3000` | Adresse ohne Schrägstrich am Ende |
| `AUTH_SECRET` | _(erzeugt)_ | Signatur der Sitzungen |
| `POSTGRES_PASSWORD` | _(erzeugt)_ | Passwort der Datenbank |
| `DATABASE_URL` | `postgresql://planer:<Passwort>@localhost:5432/planer?schema=public` | muss dasselbe Passwort enthalten |
| `WEBAUTHN_RP_ID` | `localhost` | nackte Domain, ohne Schema und Port |
| `WEBAUTHN_ORIGIN` | `http://localhost:3000` | exakt wie im Browser, mit Port |
| `ADMIN_EMAIL` | `du@example.de` | erstes Verwaltungskonto |
| `ADMIN_PASSWORT` | _(mindestens 12 Zeichen)_ | nur nötig, wenn du dich ohne OIDC anmelden willst |
> **Sind die Ports 5432 oder 3000 auf deinem Rechner belegt?**
> Dann `POSTGRES_PORT` beziehungsweise `APP_PORT` in `.env` auf einen freien
> Wert setzen. `DATABASE_URL`, `APP_URL` und `WEBAUTHN_ORIGIN` müssen denselben
> Port nennen.
**Erwartet:** `.env` liegt im Projektverzeichnis. Sie gehört niemals ins Git —
`.gitignore` sorgt dafür.
## 3. Starten
```bash
docker compose up -d --build
```
Beim ersten Mal dauert der Bau einige Minuten. Der Ablauf ist: Datenbank
starten, Migrationen einspielen, Anwendung starten.
**Erwartet:**
```bash
docker compose ps
```
zeigt `db` als `healthy` und `app` als `Up`. Der Dienst `migration` taucht
nicht mehr auf — er hat seine Arbeit getan und sich beendet.
## 4. Prüfen, ob alles läuft
```bash
curl http://localhost:3000/api/health
```
**Erwartet:**
```json
{ "status": "ok", "version": "0.1.0", "instanz": "daheim", "datenbank": "ok" }
```
Steht dort `"datenbank": "fehler"`, stimmt `DATABASE_URL` nicht mit
`POSTGRES_PASSWORD` überein.
## 5. Erste Bereiche und das Verwaltungskonto anlegen
```bash
docker compose run --rm migration node node_modules/prisma/build/index.js db seed
```
**Erwartet:** Die Ausgabe nennt die vier angelegten Bereiche (Firma, Gewerbe,
Privat, Homelab) und bestätigt das Verwaltungskonto.
## 6. Anmelden
Im Browser <http://localhost:3000> öffnen.
**Erwartet:** Die Anmeldeseite. Mit `ADMIN_EMAIL` und `ADMIN_PASSWORT`
anmelden — danach steht oben „Guten Tag" und darunter die vier Bereiche.
> Ist OIDC eingerichtet, erscheint zusätzlich ein Knopf mit dem Namen aus
> `OIDC_NAME`. Der Rückleit-URI, den du beim Anbieter hinterlegen musst,
> lautet `<APP_URL>/api/auth/callback/oidc`.
## 7. Einen Passkey hinterlegen
Auf **Einstellungen** gehen, unter _Passkeys_ einen Namen für das Gerät
eintragen (etwa „Arbeitsrechner") und auf **Anlegen** klicken. Das Gerät
fragt nach Fingerabdruck, Gesicht oder PIN.
**Erwartet:** Der Passkey steht in der Liste. Ab jetzt genügt zum Anmelden die
E-Mail-Adresse und **Mit Passkey anmelden**.
> Hinterlege am besten zwei Passkeys auf verschiedenen Geräten. Sonst sperrst
> du dich aus, wenn ein Gerät verlorengeht.
## 8. Aufräumen
Wenn `ADMIN_PASSWORT` nur zur Einrichtung gedient hat, kannst du es jetzt
zusammen mit `ADMIN_EMAIL` aus `.env` entfernen. Das Konto bleibt bestehen.
## Wie es weitergeht
- [Handbuch](handbuch/) – Anleitung für den Alltag
- [README](../README.md) – alle Umgebungsvariablen, Betrieb, Sicherung
- [ROADMAP](../ROADMAP.md) – was in den nächsten Meilensteinen kommt
## Wenn etwas klemmt
| Symptom | Ursache und Abhilfe |
| ------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| `INSTANZ fehlt in .env` beim Start | `INSTANZ` ist leer. Erlaubt sind nur `firma` und `daheim`. |
| `Die Konfiguration ist unvollständig` | Die Meldung nennt die fehlende Variable. Sie nennt nie den Wert. |
| `port is already allocated` | Ein anderer Dienst hält den Port. `APP_PORT` oder `POSTGRES_PORT` ändern. |
| Passkey lässt sich nicht anlegen | `WEBAUTHN_ORIGIN` muss exakt der Adresse im Browser entsprechen, inklusive Port. `WEBAUTHN_RP_ID` ist die nackte Domain, ohne `https://`. |
| Anmeldung schlägt immer fehl | Bewusst gibt es nur eine Meldung für alle Fälle. Prüfe im Protokoll der Anwendung: `docker compose logs app`. |
+36
View File
@@ -0,0 +1,36 @@
# Handbuch
Anleitung für den Alltag mit dem Planer. Eine Seite je Thema.
## Erste Schritte
1. **[Anmelden](anmelden.md)** – die drei Wege hinein, Passkeys einrichten,
was tun, wenn nichts mehr geht
2. **[Bereiche einrichten](bereiche.md)** – Farbe, Arbeitsfenster und
Tageskapazität festlegen
## Verwaltung
3. **[Protokoll](protokoll.md)** – nachsehen, wer wann was geändert hat
## Was noch kommt
Diese Seiten entstehen mit den nächsten Meilensteinen:
| Thema | Meilenstein |
| ------------------------------- | ----------- |
| Aufgaben erfassen, Inbox, Ideen | M2 |
| Projekte und Arbeitspakete | M2 |
| Kalenderkonten verbinden | M3 |
| Wochenplanung und Zeitblöcke | M4 |
| Benachrichtigungen | M5 |
| Integrationen | M6 |
| Schnellerfassung vom Handy, API | M7 |
| MCP | M8 |
Der [Fahrplan](../../ROADMAP.md) sagt, was in welchem Meilenstein steckt.
---
Zur Einrichtung einer neuen Instanz: [Schnellstart](../SCHNELLSTART.md).
Für Betrieb, Sicherung und alle Umgebungsvariablen: [README](../../README.md).
+83
View File
@@ -0,0 +1,83 @@
# Anmelden
Es gibt drei Wege in den Planer. Welche davon zu sehen sind, hängt davon ab,
was für deine Instanz eingerichtet wurde.
![Die Anmeldeseite](../bilder/anmelden-hell-schreibtisch.png)
| Weg | Wann sinnvoll |
| -------------------------------- | --------------------------------------------------------------------------------------------------- |
| **Unternehmensanmeldung** (OIDC) | In der Firma der Normalfall. Ein Klick, die Anmeldung übernimmt Entra ID beziehungsweise authentik. |
| **Passkey** | Der bequemste Weg am eigenen Gerät: Fingerabdruck, Gesicht oder Geräte-PIN, kein Passwort. |
| **E-Mail und Passwort** | Der Rückfallweg. Oft nur daheim freigeschaltet. |
## Mit Passkey anmelden
1. E-Mail-Adresse eintragen.
2. Auf **Mit Passkey anmelden** klicken.
3. Das Gerät fragt nach Fingerabdruck, Gesicht oder PIN.
Fertig — du landest auf der Startseite.
> **Warum erst die E-Mail-Adresse?** Damit der Planer weiß, welche Passkeys er
> anbieten soll. Er antwortet dabei für unbekannte Adressen genauso wie für
> bekannte, damit sich von außen nicht abfragen lässt, wer hier ein Konto hat.
## Einen Passkey einrichten
Das geht erst, wenn du angemeldet bist — also beim ersten Mal über OIDC oder
über E-Mail und Passwort.
1. Oben rechts auf **Einstellungen**.
2. Im Abschnitt _Passkeys_ einen Namen für das Gerät eintragen, etwa
„Arbeitsrechner" oder „Diensthandy".
3. Auf **Anlegen** klicken und die Abfrage des Geräts bestätigen.
![Passkeys in den Einstellungen](../bilder/einstellungen-hell-schreibtisch.png)
Der Passkey steht danach in der Liste, mit Anlegedatum und letzter Benutzung.
> **Lege zwei Passkeys an, auf zwei verschiedenen Geräten.** Sonst sperrst du
> dich aus, sobald ein Gerät verlorengeht oder zurückgesetzt wird.
Unter jedem Eintrag steht, ob der Passkey **geräteübergreifend** ist — dann
liegt er im Schlüsselbund von Apple, Google oder deinem Passwortmanager und ist
auf deinen anderen Geräten ebenfalls verfügbar. Steht dort **nur dieses
Gerät**, ist er an genau dieses Gerät gebunden.
## Einen Passkey entfernen
In den Einstellungen auf das Papierkorb-Symbol neben dem Eintrag. Der Passkey
ist sofort ungültig; auf dem Gerät selbst bleibt ein Rest zurück, den du dort
im Schlüsselbund löschen kannst.
## Abmelden
Oben rechts auf das Symbol mit dem Pfeil aus der Tür.
## Wenn es klemmt
| Was du siehst | Was dahintersteckt |
| -------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| „Anmeldung nicht möglich. Bitte Angaben prüfen." | Diese eine Meldung gilt für alle Fälle: falsches Passwort, unbekannte Adresse, gesperrtes Konto. Das ist Absicht — sonst ließe sich abfragen, wer hier ein Konto hat. |
| Es passiert nichts nach dem Klick auf **Mit Passkey anmelden** | Du hast den Systemdialog abgebrochen. Einfach noch einmal klicken. |
| „Dieses Gerät ist hier schon hinterlegt." | Für dieses Gerät gibt es bereits einen Passkey. Ein zweiter bringt nichts. |
| Der Passkey-Knopf tut gar nichts | Der Browser unterstützt WebAuthn nicht, oder die Seite läuft nicht über HTTPS. Passkeys brauchen eine sichere Verbindung — `localhost` ausgenommen. |
| Passkey lässt sich nicht anlegen | Meist stimmt die Konfiguration nicht: `WEBAUTHN_ORIGIN` muss exakt der Adresse im Browser entsprechen, inklusive Port. Siehe [README](../../README.md). |
## Ausgesperrt?
Wenn kein Weg mehr hineinführt, hilft nur jemand mit Zugriff auf den Server.
Dort lässt sich mit `ADMIN_EMAIL` und `ADMIN_PASSWORT` in der `.env` und einem
erneuten Seed-Lauf wieder ein Passwort setzen — siehe
[Schnellstart, Schritt 5](../SCHNELLSTART.md).
## Rollen
Unten in der Fußzeile und in den Einstellungen steht, welche Rolle du hast.
- **Benutzer** – sieht und plant die eigenen Sachen.
- **Verwaltung** – darf zusätzlich Bereiche ändern und das
[Protokoll](protokoll.md) einsehen.
Die Rolle vergibt die Verwaltung; sie lässt sich nicht selbst hochstufen.
+80
View File
@@ -0,0 +1,80 @@
# Bereiche einrichten
Ein **Bereich** ist ein Lebensbereich: Firma, Gewerbe, Privat, Homelab. Jede
Aufgabe und jeder Zeitblock gehört später zu genau einem davon.
Der Bereich bestimmt drei Dinge:
- **die Farbe**, an der du im Kalender sofort erkennst, worum es geht,
- **das Arbeitsfenster** — die Tageszeit, in der für diesen Bereich überhaupt
geplant wird,
- **die Tageskapazität** — wie viele Minuten je Wochentag höchstens
hineingehen.
![Die Bereichsseite](../bilder/bereiche-hell-schreibtisch.png)
> Bereiche ändern darf nur die **Verwaltung**. Als Benutzer siehst du sie,
> aber ohne die Formulare.
## Einen Bereich anlegen
1. Im Menü auf **Bereiche**.
2. Ganz unten unter _Neuen Bereich anlegen_ die Felder ausfüllen.
3. Auf **Bereich anlegen** klicken.
| Feld | Bedeutung |
| ---------------------------- | ----------------------------------------------------------------------------------------------- |
| **Name** | Zwei bis 40 Zeichen, muss eindeutig sein |
| **Farbe** | Wird zum Farbpunkt in Listen und später im Kalender |
| **Arbeitsfenster von / bis** | Zwischen diesen Uhrzeiten wird geplant. Muss nach dem Beginn enden |
| **Tageskapazität** | Minuten je Wochentag. 0 heißt: an diesem Tag gar nicht |
| **In Benutzung** | Abgehakt lassen. Ohne Haken bleibt der Bereich erhalten, taucht aber nicht mehr zur Auswahl auf |
| **Reihenfolge** | Kleinere Zahlen stehen weiter oben |
## Was eine sinnvolle Kapazität ist
Nicht die Zeit, die der Tag hergibt — die Zeit, die **wirklich für geplante
Arbeit** übrig bleibt, nach Besprechungen, Störungen und Pausen.
Ein brauchbarer Anfang:
| Bereich | Montag bis Donnerstag | Freitag | Wochenende |
| ------- | --------------------- | ------- | --------------- |
| Firma | 360 min (6 h) | 240 min | 0 |
| Gewerbe | 90 min | 60 min | Samstag 180 min |
| Privat | 60 min | 120 min | je 240 min |
| Homelab | 0 bis 60 min | 0 | Samstag 120 min |
Wenn am Ende der Woche regelmäßig etwas liegenbleibt, ist die Kapazität zu
hoch angesetzt, nicht der Tag zu kurz.
> Die Tageskapazität darf nie länger sein als das Arbeitsfenster. Ein Fenster
> von 08:00 bis 17:00 fasst höchstens 540 Minuten; trägst du mehr ein, weist
> das Formular es ab.
## Einen Bereich ändern
Auf **Bearbeiten** unter dem Bereich klicken, ändern, **Speichern**. Mit
**Schließen** verwirfst du, was du noch nicht gespeichert hast.
## Einen Bereich loswerden
Zwei Wege, und meistens ist der erste der richtige:
1. **Stilllegen** – den Haken bei _In Benutzung_ entfernen und speichern. Alles
Bisherige bleibt erhalten, der Bereich taucht nur nicht mehr zur Auswahl auf.
2. **Löschen** – der rote Knopf. Endgültig.
> Ab M2 hängen Aufgaben an Bereichen. Dann ist Stilllegen fast immer die
> richtige Wahl, weil beim Löschen auch die Zuordnung verlorenginge.
Jede Änderung landet im [Protokoll](protokoll.md).
## Typische Fehler
| Meldung | Was zu tun ist |
| --------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
| „Diesen Namen gibt es schon." | Namen sind eindeutig. Vielleicht existiert der Bereich stillgelegt schon. |
| „Das Arbeitsfenster muss nach seinem Beginn enden." | Von-Zeit liegt hinter der Bis-Zeit. Über Mitternacht hinweg geht nicht — dafür lieber zwei Bereiche. |
| „Keine Tageskapazität darf länger sein als das Arbeitsfenster." | Entweder die Kapazität senken oder das Fenster weiten. |
| „Dazu fehlt dir die Berechtigung." | Du bist als Benutzer angemeldet, nicht als Verwaltung. |
+57
View File
@@ -0,0 +1,57 @@
# Protokoll
Jede schreibende Aktion im Planer hinterlässt einen Eintrag: wer, wann, was,
und woran. Einträge lassen sich weder ändern noch löschen.
Die Seite steht nur der **Verwaltung** offen. Als Benutzer siehst du den
Menüpunkt gar nicht erst; wer die Adresse direkt aufruft, landet auf einem
Hinweis.
![Die Protokollseite](../bilder/protokoll-hell-schreibtisch.png)
## Was dort steht
| Spalte | Bedeutung |
| ------------- | --------------------------------------------------------------------- |
| **Zeitpunkt** | Datum und Uhrzeit in Europe/Berlin |
| **Wer** | Die E-Mail-Adresse zum Zeitpunkt der Aktion |
| **Was** | Die Aktion, in der Form `objekt.verb` |
| **Objekt** | Die Art des betroffenen Objekts, dahinter die fachlichen Einzelheiten |
Angezeigt werden die letzten 100 Einträge, die neuesten zuerst.
## Die Aktionen
| Aktion | Bedeutung |
| ------------------- | --------------------------------------------------- |
| `bereich.angelegt` | Ein neuer Bereich ist entstanden |
| `bereich.geaendert` | Name, Farbe, Fenster oder Kapazität wurden geändert |
| `bereich.geloescht` | Ein Bereich wurde entfernt |
| `passkey.angelegt` | Jemand hat ein Gerät hinterlegt |
| `passkey.entfernt` | Ein Gerät wurde entfernt |
Mit jedem Meilenstein kommen Aktionen hinzu.
## Was dort bewusst **nicht** steht
- Keine Passwörter, Hashes oder Tokens.
- Keine Termin-Betreffs und keine Mailinhalte.
- Keine Zugangsdaten der Kalenderkonten.
Das ist doppelt abgesichert: Solche Felder werden gar nicht erst übergeben,
und vor dem Speichern ersetzt der Planer zusätzlich jedes Feld, dessen Name
nach einem Geheimnis aussieht, durch `[entfernt]`. Wenn du dort `[entfernt]`
liest, hat dieser zweite Riegel gegriffen.
## Warum die E-Mail-Adresse und nicht nur die Kennung
Wird ein Benutzer gelöscht, verschwinden seine Passkeys und verknüpften
Konten — der Protokolleintrag bleibt. Die Verknüpfung zum Konto wird gelöst,
die Adresse bleibt als Nachweis stehen. Sonst wäre das Protokoll nach einer
Löschung wertlos.
## Aufbewahrung
Einträge werden nicht automatisch entfernt. Die Tabelle wächst langsam — ein
Eintrag je Änderung, nicht je Seitenaufruf. Sollte sie einmal stören, gehört
das Aufräumen in die Sicherungsroutine und nicht in die Anwendung.