Ein schlankes, in sich geschlossenes Mini-CRM, das folgende Kern-Workflows abdeckt:
- Anmeldung (Login/Logout) per Session-Cookie
- Verwaltung von **Firmen** (Anlegen, Anzeigen, Bearbeiten, Löschen, Liste mit Suche)
- Verwaltung von **Kontaktpersonen** (Anlegen, Anzeigen, Bearbeiten, Löschen, Zuordnung zu Firma)
- Übersichts-Dashboard mit Anzahl Firmen, Kontakten und letzten Änderungen
Single-Tenant, eine Org, eine SQLite-Datei. Keine Rollen, keine Multi-User-Berechtigungen jenseits Login ja/nein.
## 2. Personas
- **Admin/Nutzer** (1 Person pro Org): meldet sich an, verwaltet Daten.
- **Entwickler**: betreibt die App lokal und in Coolify.
## 3. Funktionale Anforderungen (Must-Have)
| ID | Anforderung | Akzeptanzkriterium |
|----|-------------|---------------------|
| F-1 | Login-Formular | GET `/login` zeigt Formular; POST mit gültigen Credentials setzt Session-Cookie und leitet auf `/` weiter; ungültige Credentials → 401 + Fehlermeldung. |
| F-2 | Logout | POST `/logout` löscht Session und leitet auf `/login` weiter. |
| F-3 | Auth-Schutz | Alle Seiten außer `/login` und `/api/health` erfordern eine aktive Session; ohne Session → 302 → `/login`. |
| F-4 | Dashboard | GET `/` zeigt Anzahl Companies, Anzahl Contacts, letzte 5 Änderungen (Companies + Contacts). |
| F-5 | Companies-Liste | GET `/companies` zeigt Tabelle mit Name, Stadt, Land, Anzahl Contacts; Volltextsuche über Name/Stadt filtert. |
| F-6 | Company anlegen | GET `/companies/new` zeigt Formular; POST erstellt Datensatz, Redirect auf Detail. |
| F-7 | Company-Detail | GET `/companies/{id}` zeigt Stammdaten + Liste der zugeordneten Contacts + Link „Contact hinzufügen". |
| F-8 | Company bearbeiten | GET `/companies/{id}/edit` zeigt vorausgefülltes Formular; PATCH speichert, Redirect auf Detail. |
| F-9 | Company löschen | POST `/companies/{id}/delete` löscht inkl. zugeordneter Contacts (cascade). |
| F-10 | Contact anlegen | GET `/contacts/new?company_id={id}` zeigt Formular; POST erstellt Datensatz mit FK auf Company. |
| F-11 | Contact-Detail | GET `/contacts/{id}` zeigt alle Felder + Link zur Firma. |
| F-12 | Contact bearbeiten | GET `/contacts/{id}/edit` zeigt Formular; PATCH speichert. |
| F-14 | API parallel zu HTML | Für jede HTML-Aktion gibt es einen äquivalenten JSON-API-Endpoint (siehe API-Spec unten), damit Tests Headless durchlaufen können. |
| F-16 | Demo-Seed | Beim ersten Start wird automatisch 1 Admin-User (`admin`/`admin`), 2 Beispiel-Firmen und 3 Beispiel-Kontakte angelegt, falls DB leer. |
## 4. Datenmodell
```
User
id INTEGER PK
username TEXT UNIQUE NOT NULL
password_hash TEXT NOT NULL
created_at TIMESTAMP DEFAULT now
Company
id INTEGER PK
name TEXT NOT NULL
street TEXT
zip TEXT
city TEXT
country TEXT DEFAULT 'DE'
email TEXT
phone TEXT
website TEXT
notes TEXT
created_at TIMESTAMP DEFAULT now
updated_at TIMESTAMP DEFAULT now
Contact
id INTEGER PK
company_id INTEGER FK -> Company.id ON DELETE CASCADE
first_name TEXT NOT NULL
last_name TEXT NOT NULL
email TEXT
phone TEXT
position TEXT
notes TEXT
created_at TIMESTAMP DEFAULT now
updated_at TIMESTAMP DEFAULT now
```
## 5. API-Spec (für Headless-Tests)
| Methode | Pfad | Body / Params | Erfolg | Fehler |