Infrastruktur-Referenz
Übersicht
┌─────────────────────────────────────────────────────────┐
│ Prilog Platform │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌───────────────┐ │
│ │ Backend-API │ │ Web-Client │ │ Portal │ │
│ │ (Fastify) │ │ (React/Vite)│ │ (Next.js) │ │
│ └──────┬───────┘ └──────────────┘ └───────────────┘ │
│ │ │
│ ┌──────┴───────┐ ┌──────────────┐ ┌───────────────┐ │
│ │ PostgreSQL │ │ Redis │ │ S3 Storage │ │
│ │ (Datenbank) │ │ (Cache/PubSub)│ │ (Dateien) │ │
│ └──────────────┘ └──────────────┘ └───────────────┘ │
└─────────────────────────────────────────────────────────┘Externe Dienste
| Dienst | Anbieter | Zweck |
|---|---|---|
| PostgreSQL | Hetzner (Prod), Docker (Dev) | Datenbank für alle Prilog-Daten |
| Redis | Hetzner (Prod), Docker (Dev) | Cache, Event-Bus Pub/Sub, Agent-Registry, JWT-Blacklist |
| S3 Object Storage | Hetzner (Prod), MinIO (Dev) | Dateiablage, Store-Artefakte |
| Stripe | Stripe.com | Zahlungen, Subscriptions, Modul-Billing, Developer-Auszahlungen |
| DNS | Bunny.net | DNS-Verwaltung für *.prilog.chat und *.prilog.team |
| Cloud Server | Hetzner Cloud | Kundenserver (Synapse + Matrix) |
| Tailscale | Tailscale.com | VPN-Tunnel zu Kundenservern |
| MailPace / SendGrid | Transaktions-E-Mails |
S3 Object Storage
Wie es funktioniert
Der Code spricht reines S3-Protokoll über @aws-sdk/client-s3. Es ist kein Vendor-Lock-in — jeder S3-kompatibler Dienst funktioniert.
Umgebungen
| Umgebung | Backend | Endpoint | Konfiguration |
|---|---|---|---|
| Lokal (Dev) | MinIO | http://localhost:9000 | docker-compose.dev.yml in prilog-infra |
| Produktion | Hetzner Object Storage | https://fsn1.your-objectstorage.com | Env-Vars auf dem Server |
| Alternativ | AWS S3, Backblaze B2, Cloudflare R2 | Jeweiliger Endpoint | Env-Vars anpassen |
Env-Variablen
S3_ENDPOINT=http://localhost:9000 # MinIO lokal
S3_REGION=eu-central-1 # Standard
S3_BUCKET=prilog-files # Bucket-Name
S3_ACCESS_KEY_ID=prilog-dev # MinIO User (Dev)
S3_SECRET_ACCESS_KEY=prilog-dev-secret # MinIO Passwort (Dev)Bucket-Struktur
prilog-files/
├── spaces/{spaceId}/{folderId}/{uuid}-{filename} ← Projekt-Modul Dateien
└── store/modules/{moduleId}/{version}/{filename} ← Store-ArtefakteMinIO lokal starten
cd prilog-infra
docker compose -f docker-compose.dev.yml up -dMinIO Console: http://localhost:9001 (User: prilog-dev, Passwort: prilog-dev-secret)
S3-Anbieter wechseln
Um den S3-Anbieter zu wechseln, reicht es die 5 Env-Vars anzupassen. Kein Code muss geändert werden. Der forcePathStyle: true Parameter im S3-Client sorgt für Kompatibilität mit allen S3-Clones.
PostgreSQL
Lokal
cd prilog-infra
docker compose -f docker-compose.dev.yml up -dDATABASE_URL=postgresql://prilog:prilog-dev-password@localhost:5432/prilogMigrationen
cd prilog-backend-api
# Neue Migration erstellen (braucht laufende DB)
npx prisma migrate dev --name beschreibung
# Migrationen deployen
npx prisma migrate deploy
# Prisma Client neu generieren (nach Schema-Änderungen)
npx prisma generateAktuelle Tabellen (Modul-Architektur)
| Tabelle | Zweck |
|---|---|
module_registrations | Zentrale Modul-Registry |
tenant_module_installations | Installation pro Tenant (Lifecycle) |
module_events | Event-Bus Persistenz |
module_configs | Key-Value Konfiguration |
module_usage_events | Billing-Tracking |
developer_accounts | Store-Entwickler |
store_submissions | Einreichungs-Pipeline |
store_ratings | Modul-Bewertungen |
cron_job_runs | Cron-Job Tracking |
Redis
Lokal
cd prilog-infra
docker compose -f docker-compose.dev.yml up -dREDIS_URL=redis://localhost:6379Verwendung
| Feature | Redis-Keys |
|---|---|
| Event-Bus | prilog:events:{tenantId} (Pub/Sub Channel) |
| Modul-Cache | prilog:mod:{moduleId}:{tenantId}:{key} |
| Modul-Metriken | prilog:mod:metrics:{moduleId}:durations, :errors, :total |
| Performance-Violations | prilog:mod:violations:{moduleId}:{type} |
| Agent-Registry | agent:{orderId}:meta, :metrics, :modules |
| JWT-Blacklist | Via jwt-blacklist.service.ts |
3 separate Redis-Clients (verhindert Blocking bei Pub/Sub):
redis— Haupt-Client (get/set)redisSub— SubscriberredisPub— Publisher
Lokale Entwicklungsumgebung
Alles starten
# 1. Infrastruktur (PostgreSQL, Redis, MinIO)
cd prilog-infra
docker compose -f docker-compose.dev.yml up -d
# 2. Backend-API
cd prilog-backend-api
cp .env.example .env # Env-Vars anpassen
npx prisma migrate deploy
npx prisma generate
npm run dev
# 3. Web-Client
cd prilog-web-client
npm run dev
# 4. Portal
cd prilog-portal
npm run dev
# 5. Admin
cd prilog-admin
npm run devPorts
| Service | Port |
|---|---|
| Backend-API | 3001 |
| Web-Client | 5173 |
| Portal | 3003 |
| Admin | 3004 (oder 3000) |
| PostgreSQL | 5432 |
| Redis | 6379 |
| MinIO API | 9000 |
| MinIO Console | 9001 |
Umgebungsvariablen (Backend-API)
Definiert in src/config/env.ts mit Zod-Validierung.
Pflicht
| Variable | Beschreibung |
|---|---|
DATABASE_URL | PostgreSQL Connection String |
JWT_SECRET | JWT-Signierung (min. 32 Zeichen) |
BUNNY_API_KEY | Bunny.net DNS API Key |
BUNNY_ZONE_ID_CHAT | Bunny Zone für *.prilog.chat |
BUNNY_ZONE_ID_TEAM | Bunny Zone für *.prilog.team |
TAILSCALE_AUTH_KEY | Tailscale Auth Key |
TAILSCALE_API_KEY | Tailscale API Key |
HETZNER_API_TOKEN | Hetzner Cloud API Token |
ADMIN_PASSWORD | Admin-Dashboard Passwort (min. 8 Zeichen) |
Optional
| Variable | Default | Beschreibung |
|---|---|---|
NODE_ENV | development | development, production, test |
PORT | 3001 | Server-Port |
JWT_EXPIRES_IN | 24h | Token-Gültigkeit |
STRIPE_SECRET_KEY | — | Stripe API Key (Billing) |
STRIPE_WEBHOOK_SECRET | — | Stripe Webhook Signierung |
MAILPACE_API_KEY | — | MailPace E-Mail-Versand |
SENDGRID_API_KEY | — | SendGrid E-Mail-Versand |
EMAIL_FROM | noreply@prilog.chat | Absender-Adresse |
MATRIX_CONNECTOR_SHARED_SECRET | — | Shared Secret für Matrix-Connector |
WEBHOOK_SECRET | (Default) | Webhook-Signierung |
S3_ENDPOINT | — | S3-Endpoint (MinIO/Hetzner) |
S3_REGION | eu-central-1 | S3-Region |
S3_BUCKET | prilog-files | S3-Bucket |
S3_ACCESS_KEY_ID | — | S3-Zugang |
S3_SECRET_ACCESS_KEY | — | S3-Secret |
FRONTEND_URL | https://www.prilog.chat | Marketing-Website URL |
ONBOARDING_URL | https://onboarding.prilog.chat | Bestell-Wizard URL |
PORTAL_URL | https://portal.prilog.chat | Kunden-Portal URL |
PWA & Service Worker
Der Web-Client ist als Progressive Web App installierbar — Nutzer koennen Prilog ueber "Zum Startbildschirm hinzufuegen" wie eine native App nutzen.
Technologie
- vite-plugin-pwa (v1.2.0) mit Workbox
generateSW - Manifest (
manifest.webmanifest) mit Icons, Standalone-Display, Portrait-Orientation - Service Worker wird beim Build generiert (
dist/sw.js)
Caching-Strategie
| Request-Typ | Strategie | Details |
|---|---|---|
| Statische Assets (JS, CSS, Bilder, Fonts) | Precache | 89 Dateien beim Install gecacht, versioniert per Content-Hash |
Matrix Media (/_matrix/client/v1/media/*) | CacheFirst | 7 Tage, max. 200 Eintraege. mxc-IDs sind immutable — sicher zu cachen |
Matrix Sync/API (/_matrix/*) | NetworkOnly | Nie cachen — Sync-State muss immer live sein |
Backend API (/api/*) | NetworkOnly | Nie cachen — verhindert 401-Fehler nach Token-Erneuerung |
Navigation (index.html) | NetworkFirst | Frisch vom Server, Fallback auf Cache wenn offline. Denylist: /_matrix, /api |
Auto-Update
Der Service Worker prueft alle 60 Sekunden auf neue Versionen (registration.update()). Wenn eine neue Version erkannt wird:
- Neuer SW wird im Hintergrund installiert
skipWaiting+clientsClaimaktivieren ihn sofortonNeedRefreshruftupdateSW(true)→ automatischer Tab-Reload- Alte Caches werden via
cleanupOutdatedCaches()aufgeraeumt
Kein Nutzer-Klick noetig — das Update passiert unsichtbar. Besonders wichtig fuer PWA-Standalone-Sessions auf Mobilgeraeten, die tagelang offen bleiben.
Historie
Der Service Worker war zeitweise deaktiviert (selfDestroying: true) weil eine fruehere Konfiguration API-Responses gecacht hatte. Nach Token-Erneuerung kamen alte 401-Responses aus dem Cache zurueck. Die Loesung: explizite NetworkOnly-Regeln fuer alle API- und Matrix-Requests. Seit 2026-04-27 ist der Service Worker wieder aktiv.