# FEDEO Central Services Eigenständiger Stack für zentrale FEDEO-Dienste. Neben Push können Selfhost-Instanzen darüber freigeschaltete und verbrauchsabhängig erfasste KI- und Banking-Dienste verwenden. Die Instanzen authentifizieren sich mit einem rotierbaren HMAC-Schlüssel, der im Admin-Dashboard gepflegt wird. ## Bestandteile - `apps/api`: Fastify API für Admin-Dashboard und Selfhost-Instanzen - `apps/admin`: Nuxt Admin Dashboard mit Nuxt UI - `packages/db`: Drizzle Schema und Migrationen für PostgreSQL - `docker-compose.yml`: lokaler Stack aus Postgres, API und Admin Provider-Schlüssel wie `OPENAI_API_KEY` und die GoCardless-Zugangsdaten liegen ausschließlich in diesem zentralen Stack. Selfhost-Instanzen erhalten nur Instanz-ID und Instanzschlüssel. ## Entwicklung ```bash cd push-server cp .env.example .env npm install npm run db:migrate npm run dev:api npm run dev:admin ``` Für den dauerhaften Betrieb: ```bash cp .env.example .env # .env mit sicheren Zugangsdaten und Provider-Schlüsseln befüllen docker compose up -d --build ``` Der API-Container wendet Datenbankmigrationen vor jedem Start automatisch an. PostgreSQL-Daten liegen im Volume `push_postgres_data`. Für ein öffentliches Deployment müssen API und Admin hinter einem TLS-Reverse-Proxy betrieben und `PUBLIC_API_BASE_URL` auf die öffentliche API-Adresse gesetzt werden. Standardports: - API: `http://localhost:4020` - Admin: `http://localhost:3000` lokal oder `http://localhost:3020` über Docker Compose - Postgres: `localhost:5442` ## Admin-Zugang Das Dashboard nutzt den Wert aus `ADMIN_TOKEN`. Der Token wird im Browser nur lokal gespeichert und als `Authorization: Bearer ...` an die API gesendet. ## Instanz-Authentifizierung Instanzaufrufe verwenden HMAC-SHA256: ```text X-Fedeo-Instance-Id: inst_... X-Fedeo-Timestamp: 2026-05-22T10:00:00.000Z X-Fedeo-Signature: ``` Signiert wird: ```text METHOD PATH TIMESTAMP SHA256(BODY) INSTANCE_ID ``` Beispiel: ```ts import { createHash, createHmac } from "node:crypto"; const body = JSON.stringify(payload); const timestamp = new Date().toISOString(); const bodyHash = createHash("sha256").update(body).digest("hex"); const canonical = ["POST", "/v1/push", timestamp, bodyHash, instanceId].join("\n"); const signature = createHmac("sha256", clientSecret).update(canonical).digest("hex"); ``` ## Wichtige API-Endpunkte - `GET /v1/public-config` - `POST /v1/instances/heartbeat` - `POST /v1/devices` - `DELETE /v1/devices/:centralDeviceId` - `POST /v1/push` - `GET /v1/push/:deliveryJobId` - `POST /v1/services/ai/chat-completions` - `GET /v1/services/banking/institutions` - `POST /v1/services/banking/requisitions` - `GET /v1/services/banking/requisitions/:id` - `GET /v1/services/banking/accounts/:id` - `GET /v1/services/banking/accounts/:id/balances` - `GET /v1/services/banking/accounts/:id/transactions` Admin: - `GET /admin/summary` - `GET /admin/instances` - `POST /admin/instances` - `PATCH /admin/instances/:id` - `POST /admin/instances/:id/rotate-secret` - `GET /admin/instances/:id/devices` - `GET /admin/instances/:id/jobs` - `GET /admin/instances/:id/services` - `PUT /admin/instances/:id/services/:service` - `GET /admin/instances/:id/usage` - `GET /admin/usage/summary` ## Freischaltung und Abrechnung Die Dienste `ai` und `banking` sind für neue Instanzen standardmäßig gesperrt. Im Instanzdetail des Admin-Dashboards werden sie einzeln aktiviert. Pro Dienst können ein Monatslimit und ein Preis in Mikro-Euro je Einheit gepflegt werden. - KI wird anhand der von OpenAI gemeldeten Gesamt-Token erfasst. - Banking wird je erfolgreichem Provider-Aufruf erfasst. - Fehlgeschlagene Aufrufe werden technisch protokolliert, aber mit `0` Einheiten und `0` Kosten verbucht. - Usage Events enthalten technische Metadaten, aber keine Prompts, Bankumsätze oder sonstigen fachlichen Nutzdaten. ## Apple Push Notification service Für iOS müssen diese Werte gesetzt sein: ```env IOS_BUNDLE_ID=software.federspiel.fedeo APNS_TEAM_ID=... APNS_KEY_ID=... APNS_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----" APNS_PRODUCTION=false ``` Solange APNs nicht vollständig konfiguriert ist, nimmt die API Push-Aufträge an, markiert iOS-Zustellversuche aber mit `apns_not_configured`. ## Aktueller Umfang Implementiert: - Instanzverwaltung im Admin-Dashboard - rotierbare Instanzschlüssel mit verschlüsselter Speicherung - HMAC-authentifizierte Instanzbefehle - Geräte-Registry für `web`, `ios` und `android` - Zustelljobs mit Idempotenzschlüssel - APNs-Zustellung für iOS - technische Status- und Fehlererfassung - dienstbezogene Freischaltungen und Monatslimits - unveränderliche Usage Events samt Kostenwert - zentraler OpenAI- und GoCardless-Zugang Vorbereitet, aber noch nicht vollständig implementiert: - Web Push Zustellung - FCM Zustellung - asynchrone Queue/Worker-Verarbeitung - produktive Rate-Limits pro Instanz - Rechnungsstellung beziehungsweise Export an ein Buchhaltungssystem