# GerbilManager — TrueNAS Custom Application # ============================================== # Vor dem ersten Start: # 1. Kopiere deploy/truenas/.env.example -> deploy/truenas/.env und setze die Werte. # 2. Lege die Dataset-Pfade auf der NAS an (pgdata, photos, backups). # 3. docker compose -f deploy/truenas/compose.yaml up -d # # Zugriff: http://:${PORT:-80} # API-Doku: http://:${PORT:-80}/scalar services: # --- PostgreSQL-Datenbank --- db: image: postgres:17-alpine restart: unless-stopped environment: POSTGRES_PASSWORD: "${POSTGRES_PASSWORD}" POSTGRES_DB: gerbilmanager POSTGRES_USER: postgres volumes: - pgdata:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U postgres -d gerbilmanager"] interval: 10s timeout: 5s retries: 5 start_period: 30s # --- .NET API (GerbilManagerWebAPI) --- api: image: "${REGISTRY:-truenas:13000/gulum}/gerbilmanager-api:${TAG:-latest}" build: context: ../.. dockerfile: GerbilManagerWebAPI/Dockerfile restart: unless-stopped environment: ASPNETCORE_ENVIRONMENT: Production # Verbindung zur Postgres-DB im selben Compose-Netz ConnectionStrings__gerbilmanager: "Host=db;Port=5432;Database=gerbilmanager;Username=postgres;Password=${POSTGRES_PASSWORD}" # Speicherort der hochgeladenen Fotos (NAS-Dataset gemounted unter /data/photos) Photos__RootPath: /data/photos # AR-3: Data Protection Key-Ring (persistiert Gmail-App-Passwort-Verschlüsselung über Redeployments) DataProtection__KeyRingPath: /data/keys # AR-4: KI-Funktionen (Verkaufstext + Posteingang-Entwurf, Sektion AI; beliebiger OpenAI-kompatibler Anbieter) # Anbieter-Optionen und Schlüssel-Beispiele: docs/ai-provider.md # Leer lassen = KI deaktiviert (503 AiKeyMissing statt Fehler) AI__BaseUrl: "${AI__BaseUrl:-}" AI__ApiKey: "${AI__ApiKey:-}" AI__Model: "${AI__Model:-gemini-2.0-flash}" volumes: - photos:/data/photos - keys:/data/keys depends_on: db: condition: service_healthy healthcheck: test: ["CMD-SHELL", "wget -qO- http://localhost:8080/health || exit 1"] interval: 30s timeout: 10s retries: 3 start_period: 90s # --- nginx Frontend (React SPA + API-Proxy) --- frontend: image: "${REGISTRY:-truenas:13000/gulum}/gerbilmanager-frontend:${TAG:-latest}" build: context: ../.. dockerfile: gerbil-manager-web/Dockerfile restart: unless-stopped ports: - "${PORT:-80}:80" depends_on: api: condition: service_healthy # --- Backup-Sidecar (taeglicher pg_dump + Foto-Archiv + Rotation) --- backup: image: postgres:17-alpine restart: unless-stopped environment: PGPASSWORD: "${POSTGRES_PASSWORD}" POSTGRES_HOST: db POSTGRES_USER: postgres POSTGRES_DB: gerbilmanager BACKUP_KEEP_DAYS: "${BACKUP_KEEP_DAYS:-7}" volumes: - photos:/data/photos:ro - backups:/backups - ./scripts:/scripts:ro depends_on: db: condition: service_healthy entrypoint: ["/bin/sh", "/scripts/entrypoint.sh"] volumes: # NAS-Datasets als Bind-Mounts (Pfade in .env konfigurieren). # TrueNAS: Dataset-Pfad z.B. /mnt/SSD/gerbil/pgdata pgdata: driver: local driver_opts: type: none o: bind device: "${PGDATA_PATH:-/mnt/gerbil/pgdata}" photos: driver: local driver_opts: type: none o: bind device: "${PHOTOS_PATH:-/mnt/gerbil/photos}" # AR-3: Data Protection key ring — persistiert Gmail-App-Passwort-Verschlüsselung. # Muss ein persistentes NAS-Dataset sein (nicht dasselbe wie photos). keys: driver: local driver_opts: type: none o: bind device: "${KEYS_PATH:-/mnt/gerbil/keys}" backups: driver: local driver_opts: type: none o: bind device: "${BACKUPS_PATH:-/mnt/gerbil/backups}"