Technische Spezifikation
Stack, Architektur, Schnittstellen, Betrieb
Tech-Stack #
Die Auswahl ist bewusst klein und langweilig. Jede zusätzliche Technologie ist eine Sache mehr, die ein Nachfolger können muss.
| Bereich | Wahl | Anmerkung |
|---|---|---|
| Frontend | SvelteKit 5 (Runes Mode) | adapter-static, vorgerendert. Reaktivität über $state, $derived, $effect |
| CSS | TailwindCSS v4 | CSS-first konfiguriert: keine tailwind.config.js, kein @apply. Theme über @theme in app.css |
| UI-Komponenten | DaisyUI 5 | btn, card, badge, input, modal, tabs, collapse; zwei eigene Themes (hub-light, hub-dark) |
| Backend | FastAPI (Python 3.12+) | Pydantic v2 für Schemata, SQLAlchemy 2.x als ORM, asyncpg als Treiber |
| Datenbank | PostgreSQL 18 + pgvector | Zielbild; die Entwicklungs-Compose läuft auf postgres:16-alpine |
| Auth | JWT, selbst gebaut (Phase 1) | Auth0 Free ist für Phase 2 vorgesehen |
| Auslieferung | Docker Compose | nginx vor dem statischen Frontend, Uvicorn vor FastAPI |
| Pfad | Inhalt |
|---|---|
frontend/src/routes/(marketing)/ | Öffentliche Seiten — Landing, Login, Rechtliches, diese Dokumentation |
frontend/src/routes/(app)/ | Angemeldeter Bereich — Büro, Agenten, Konfigurationsstudio, Einstellungen |
frontend/src/lib/ | Komponenten, Zustandsmodule (*.svelte.ts), Kataloge, Hilfsfunktionen |
backend/app/routers/ | FastAPI-Router — ein Modul je Themenbereich |
backend/app/models/ | SQLAlchemy-Modelle |
backend/app/data/ | Fachkataloge: Rollen, Fähigkeiten, Werkzeuge, Vorlagen, Systemvorgabe |
backend/app/dienste/ | Fachdienste: Bildgenerator, Stilerkennung, OpenRouter, C2PA, Stufe |
docs/architektur/ | Architekturentscheidungen |
Aufbau des Systems #
/api/ geht an FastAPI, alles andere ist eine vorgerenderte Datei. Externe Dienste erreicht ausschließlich das Backend — deshalb liegt dort auch jeder Schlüssel.Die Trennung ist strikt: Das Frontend wird als statische Dateien ausgeliefert (adapter-static, fallback: 200.html). Es gibt keinen Node-Prozess in der Produktion. Der Fallback trägt die Routen, die später mandantenspezifisch werden und deshalb nicht vorgerendert werden können.
server {
listen 80;
root /usr/share/nginx/html;
index index.html;
location / {
try_files $uri $uri/ /200.html;
}
location /api/ {
proxy_pass http://hub-backend:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}Datenmodell #
| Modell | Zweck | Bemerkenswerte Felder |
|---|---|---|
Tenant | Der Mandant — zugleich die Datengrenze | tarifstufe, credits_verbraucht |
User | Anmeldung und Profil | email, password_hash, tenant_id |
Agent | Ein Omni auf einem Arbeitsplatz | type_key, avatar, status, level, xp, desk_x/desk_y, room, model_override, credit_budget, config (JSONB) |
Team | Gruppe von Agenten | farbe, beschreibung, team_tools |
Entity | Gegenstände und Möbel im Grundriss | bauart, Position |
Task | Auftrag an einen Agenten | Zustand, Ergebnis, Token-Verbrauch |
Activity | Audit-Log jeder Agenten-Aktion | Zeitpunkt, Agent, Art |
Aus demselben Grund wird auch die Stufe nicht abgeleitet gespeichert: Sie ergibt sich aus den verbrauchten Token, und die Formel steht an genau einer Stelle. Agent.level ist eine Bequemlichkeitsspalte für Sortierungen, keine Wahrheit.
Schnittstellen #
Alle Endpunkte liegen unter dem Präfix /api. Authentifiziert wird mit einem JWT im Authorization-Header. Listen antworten seitenweise (Page[…]) und sind immer mandantengefiltert — die Filterung geschieht serverseitig und ist kein Parameter, den der Aufrufer weglassen könnte.
# 1) Anmelden — liefert einen JWT
curl -X POST https://os.agentenwerk.ai/api/auth/login \
-H 'Content-Type: application/json' \
-d '{"email": "demo@agentenwerk.ai", "password": "..."}'
# {"access_token": "eyJhbGciOi...", "token_type": "bearer"}
# 2) Eigene Agenten auflisten
curl https://os.agentenwerk.ai/api/agents \
-H "Authorization: Bearer $TOKEN"| Methode & Pfad | Zweck |
|---|---|
GET /api/health | Lebendigkeit — antwortet ohne Datenbank |
GET /api/health/ready | Bereitschaft — prüft Postgres mit SELECT 1 |
POST /api/auth/register | Konto anlegen |
POST /api/auth/login | Anmelden, JWT erhalten |
GET /api/auth/me | Angemeldetes Profil |
GET /api/tenant | Eigenen Mandanten lesen (Tarif, Verbrauch) |
GET /api/agents | Agenten auflisten (seitenweise, mandantengefiltert) |
GET /api/agents/skills | Fähigkeitenkatalog — 31 Fähigkeiten in 6 Kategorien |
GET /api/agents/tools | Werkzeugkatalog samt Verbindungsstatus je Mandant |
GET /api/agents/rollen | Rollen-Katalog und Ausprägungen |
GET /api/agents/templates | Die fünf Starter-Vorlagen |
GET /api/agents/llm-models | Werkzeugfähige Sprachmodelle aus dem OpenRouter-Katalog |
GET /api/agents/avatar-modelle | Bildmodelle je Stilkategorie (FAL.ai) |
GET/PUT /api/agents/{id}/persoenlichkeit | Rolle, Auftreten, Ergänzung |
GET/PATCH /api/agents/{id}/faehigkeiten | Fähigkeiten und Werkzeuge |
GET /api/agents/{id}/synergien | Passende Gespanne im eigenen Büro |
GET/PATCH /api/agents/{id}/modell | Modellwahl und Kostenrahmen |
POST /api/agents/{id}/avatar/generate | Avatar erzeugen (mehrere Vorschläge) |
POST /api/agents/{id}/avatar/generate/stream | Dasselbe als Ereignisstrom — Vorschläge treffen einzeln ein |
POST /api/agents/{id}/avatar/select | Vorschlag übernehmen |
POST /api/agents/{id}/test | Probelauf gegen das gewählte Modell |
POST /api/agents/einstellen | Agenten anlegen und auf einen Arbeitsplatz setzen |
POST /api/setup/blueprint/kmu-buero | Die Blaupause anlegen — 5 Teams, 20 Agenten |
GET /api/avatare/{datei}/nachweis | C2PA-Herkunftsnachweis eines erzeugten Bildes |
LLM- und Bild-Integration #
agentenwerkOS bindet keine Modellanbieter einzeln an. Sprachmodelle laufen über OpenRouter, Bildmodelle über FAL.ai. Beide sind Vermittler, und das ist der Punkt: Ein fest verdrahteter Anbieter ist eine Wette darauf, dass sein bestes Modell in zwölf Monaten noch das beste ist.
| Dienst | Rolle | Auswahl |
|---|---|---|
| OpenRouter | Sprachmodelle für alle Agenten | Tagesaktueller Katalog, gefiltert auf werkzeugfähige Modelle. Rollen bringen einen Vorschlag mit (überwiegend Claude Sonnet 4.5 und Haiku 4.5), der gegen die Liste geprüft wird |
| FAL.ai | Bildgenerierung für Avatare | Katalog wird abgerufen und um für Porträts unbrauchbare Einträge bereinigt; je Stilkategorie eine Modell-Union plus Reserveliste |
Der Modellvorschlag einer Rolle ist ein Vorschlag und keine Festlegung. Ist das vorgeschlagene Modell nicht mehr verfügbar, wählt die Oberfläche das nächstbeste und sagt es. Eine fest verdrahtete Modell-ID, die nach vier Monaten ins Leere zeigt, wäre der wahrscheinlichste stille Ausfall des ganzen Systems.
- Kostenschätzung vor der Aufgabe. Das Register „Modell" zeigt den Preis je 1 000 Token für das gewählte Modell.
- Budget je Agent.
credit_budgetbegrenzt, was ein einzelner Agent verbrauchen darf. - Rückfall bei Ausfall. Antwortet die Stilerkennung nicht, greift die Schlüsselwortsuche, danach der Standardstil — der Vorgang bricht nie ab.
- Offenlegung. Der Einsatz von FAL.ai ist in Impressum und Datenschutzerklärung benannt.
Deployment #
Der Betrieb läuft über Docker Compose auf crewmesh.tech. Drei Dienste, feste Containernamen — die Namen sind nicht kosmetisch: nginx.conf leitet /api/ an den Host hub-backend weiter, und ohne die festen Namen endet jeder API-Aufruf in einem 502.
| Dienst | Container | Port | Inhalt |
|---|---|---|---|
frontend | hub-frontend | 3000:80 | nginx mit den vorgerenderten Dateien |
backend | hub-backend | 8000:8000 | FastAPI unter Uvicorn |
db | hub-db | 5432:5432 | PostgreSQL mit Volume pgdata und pg_isready-Healthcheck |
# Alles zusammen — Datenbank, Backend, Frontend
cd docker && docker compose up --build
# Frontend: http://localhost:3000
# API-Doku: http://localhost:8000/api/docs
# Nur das Frontend, mit Hot Reload:
cd frontend && npm install && npm run dev # http://localhost:3000
# Bauen und prüfen, was ausgeliefert würde:
npm run build && npm run previewSicherheit & Compliance im Code #
| Zusage | Umsetzung |
|---|---|
| Kein API-Schlüssel im Browser | Alle Anbieterschlüssel liegen in der Backend-Konfiguration; das Frontend kennt nur /api/… |
| System-Prompt nicht änderbar | Zusammenbau ausschließlich serverseitig; Agent hat kein Feld dafür; Ergänzung auf 2 000 Zeichen begrenzt |
| KI-Kennzeichnung nicht abschaltbar | Eine einzige Komponente ohne Eigenschaft zum Ausblenden; Systemhinweis im Layout statt auf den Einzelseiten |
| Erzeugte Bilder maschinenlesbar markiert | Signiertes C2PA-Manifest im Bild; Nachweis über einen eigenen Endpunkt abrufbar |
| Mandantentrennung | Jede Abfrage ist auf den Mandanten der Sitzung gefiltert; Row Level Security auf Datenbankebene |
| Missbrauch melden | Fester Prompt-Block plus Audit-Log-Eintrag je Agenten-Aktion |
| Katalogverweise stimmen | Fähigkeiten, Werkzeuge und Synergien werden beim Import geprüft — ein Tippfehler bricht den Start, nicht die Oberfläche |
Der Textfilter, der typische Modell-Sprachmuster entfernt, ist ausdrücklich kein Ersatz für die Kennzeichnung — im Gegenteil: Er macht KI-Text menschlicher und die Kennzeichnung damit wichtiger, nicht unwichtiger.