Paperless Contract Companion (TypeScript + React)
Begleitservice zur Verwaltung von Vertragsmetadaten (Laufzeiten, Kündigungsfristen, Preise) als Ergänzung zu einer bestehenden paperless-ngx Instanz. Dokumente verbleiben in paperless, der Service liefert zusätzliche Struktur, Fristüberwachung, Web-GUI und optionale Mail-Benachrichtigungen.
Features
- REST-API (Express) zum Anlegen, Aktualisieren und Löschen von Verträgen.
- Speicherung der Metadaten in SQLite (via
better-sqlite3). - Periodischer Scheduler prüft anstehende Kündigungsfristen und schreibt diese ins Log bzw. versendet auf Wunsch E-Mails.
- Paperless-Integration ruft zugehörige Dokument-Metadaten über API-Token ab.
- JWT-basierte Authentifizierung mit Login-Endpunkt (optional aktivierbar).
- Moderne React-UI (Vite + MUI) mit Dashboard, Tabellen, Kalender und Settings.
- Einstellbare Integrationen direkt im Browser (Paperless, Mail, ntfy, Scheduler).
- Komfortable Paperless-Suche beim Verknüpfen von Dokumenten.
- Optionaler ntfy-Push für Fristenmeldungen.
- iCal-Feed zum Abonnieren der Kündigungsfristen.
- Test-Buttons für Mail- und ntfy-Konfiguration direkt in der Oberfläche.
- Läuft als Docker-Container, konfigurierbar über Umgebungsvariablen oder
.env(beim Kopieren auf den Zielhost).
Projektstruktur
backend/
src/
index.ts # Express-Server und Routing
config.ts # Umgebungsvariablen & Defaults
db.ts # SQLite-Initialisierung
contractsStore.ts # CRUD-Logik auf DB-Ebene
scheduler.ts # Fristenmonitor
paperlessClient.ts # HTTP-Client für paperless-ngx
notifications.ts # SMTP-Integration (optional)
validators.ts # Zod-Schemas für Payloads
frontend/
src/ # React App (Dashboard, Login, Verträge, Kalender, Settings)
Frontend (Vite + React)
Die Web-Oberfläche liegt im Ordner frontend/ und kommuniziert ausschließlich über die gesicherte REST-API.
cd frontend
npm install
npm run dev # Lokale Entwicklung (http://localhost:5173)
npm run build # Produktionsbuild in frontend/dist
Build & Run (Docker)
docker compose up --build
Die API lauscht per Default auf Port 8000, extern über Compose auf 8080. Die SQLite-Datenbank wird im Volume contracts-data unter /app/data/contracts.db persistiert. Das Frontend ist über http://localhost:8081 (laut Compose) erreichbar.
Wichtige Umgebungsvariablen
| Variable | Standard | Beschreibung |
|---|---|---|
PORT |
8000 |
HTTP-Port des Dienstes. |
LOG_LEVEL |
info |
debug, info, warn, error. |
DATABASE_PATH |
/app/data/contracts.db |
Pfad zur SQLite-Datei (Volume nicht vergessen). |
PAPERLESS_BASE_URL |
(leer) | Basis-URL der paperless-ngx API (z.B. http://paperless:8000). |
PAPERLESS_EXTERNAL_URL |
(leer) | Optionale externe URL für Direkt-Link aus der Web-Oberfläche (z.B. https://paperless.example.com). |
PAPERLESS_TOKEN |
(leer) | Personal Token aus paperless-ngx (read-only genügt). |
SCHEDULER_INTERVAL_MINUTES |
60 |
Prüffrequenz für Fristen (mind. 5). |
ALERT_DAYS_BEFORE |
30 |
Wie viele Tage vor Deadline gewarnt wird. |
AUTH_USERNAME / AUTH_PASSWORD |
(leer) | Aktiviert das Login (JWT) – beide Werte müssen gesetzt werden. |
AUTH_JWT_SECRET |
(leer) | Geheimnis zum Signieren der Tokens (Pflicht, wenn Auth aktiv). |
AUTH_TOKEN_EXPIRES_IN_HOURS |
12 |
Lebensdauer der JWTs. |
NTFY_SERVER_URL / NTFY_TOPIC |
(leer) | ntfy-Server & Topic für Push-Benachrichtigungen. |
NTFY_TOKEN / NTFY_PRIORITY |
(leer) | Optionaler Bearer-Token & Priorität für ntfy. |
MAIL_* |
(leer) | Optional: SMTP-Einstellungen für Benachrichtigungs-E-Mails. |
ICAL_SECRET |
(leer) | Optional vordefiniertes Token für den iCal-Feed (ansonsten automatisch). |
Mail-Setup (optional): MAIL_SERVER, MAIL_PORT, MAIL_USERNAME, MAIL_PASSWORD, MAIL_USE_TLS, MAIL_FROM, MAIL_TO.
Tipp: Bei gesetzter Authentifizierung muss sich die Web-UI einmalig per Login anmelden; Tokens werden im LocalStorage gespeichert.
API Übersicht
GET /healthz– einfacher Gesundheitscheck.GET /auth/status– zeigt, ob Authentifizierung aktiviert ist.POST /auth/login– Login mit Benutzername/Passwort, liefert JWT.GET /contracts?skip=0&limit=100– Liste aller Verträge (max. 500 pro Anfrage).POST /contracts– Neuen Vertrag anlegen.GET /contracts/:id– Einzelnen Vertrag abrufen.PUT /contracts/:id– Vertrag aktualisieren (Felder optional/teilweise).DELETE /contracts/:id– Vertrag löschen.GET /contracts/:id/paperless-document– Zugehöriges paperless-Dokument abrufen (wenn verknüpft).GET /reports/upcoming?days=N– Anstehende Kündigungsdeadlines innerhalb der nächstenNTage (Default =ALERT_DAYS_BEFORE).
Beispiel-JSON für Create/Update:
{
"title": "KFZ-Versicherung 2024",
"paperlessDocumentId": 123,
"provider": "Versicherung AG",
"category": "Automotive",
"contractStartDate": "2024-01-01",
"contractEndDate": "2025-12-31",
"terminationNoticeDays": 30,
"renewalPeriodMonths": 12,
"autoRenew": true,
"price": 54.99,
"currency": "EUR",
"tags": ["kfz", "privat"],
"notes": "SFR prüfen im Herbst."
}
Lokale Entwicklung – Backend
Hinweis: Im aktuellen Arbeitsverzeichnis wurden noch keine Node-Module installiert (
npm install). Auf dem Zielhost bitte einmal ausführen, damitpackage-lock.jsonentsteht und der Build reproduzierbar wird.
npm install
npm run dev # Hot-Reload via tsx
# oder
npm run build && npm start
Die API ist anschließend unter http://localhost:8000 erreichbar. Für Tests ohne paperless-Verbindung kann PAPERLESS_* weggelassen werden.
Integration mit paperless-ngx
- Companion-Service und paperless-Container sollten im gleichen Docker-Netz laufen, damit
http://paperless:8000erreichbar ist. - Token in paperless-ngx erstellen (
Einstellungen → Tokens) und alsPAPERLESS_TOKENsetzen. - Contract-IDs können mit Custom Fields/Tags in paperless verknüpft werden; die Companion-API hält zusätzliche Metadaten und erinnert an Fristen.
- Nutze
PAPERLESS_EXTERNAL_URL, wenn die API intern erreichbar ist, die Benutzer im Browser aber eine andere URL (z. B. Reverse-Proxy mit TLS) verwenden sollen. - Einstellungen (Paperless, Mail, ntfy, Scheduler) lassen sich komfortabel unter „Einstellungen“ in der Weboberfläche pflegen.
- Aktiviere Push-Benachrichtigungen via ntfy oder abonniere den iCal-Feed unter
https://<host>/api/calendar/feed.ics?token=<...>(Token im Settings-Dialog sichtbar).
Weiterführende Ideen
- Webhook/Chat-Integration (z.B. Matrix, Slack).
- ICS/CalDAV-Export der Deadlines.
- Intelligente Importer, die paperless-Tags automatisch auswerten.
- Multi-User-Unterstützung inkl. Rollen und Audit-Logs.
- Optionaler Reverse-Proxy mit TLS-Termination und Single-Sign-On.