Server-Konfiguration
Du konfigurierst den tibi-server über eine config.yml plus Umgebungsvariablen. Env schlägt Datei. Die Wahrheit steht in internal/config/server.go (Struct-Tags).
config.yml (Datei) < Umgebungsvariable (gewinnt immer) \ / v v Server.Server (Speicher)Datei und Env-Regeln
Abschnitt betitelt „Datei und Env-Regeln“- Fehlt die Datei, startet der Server mit Notwerten: Port
8080, Prefixtibi, Stacktraces an. API_PORToderPORTsind Pflicht: Port<= 0beendet den Start per Panic.- Namen mit Bindestrich werden in Env zu Unterstrich + Großschrift:
bge-m3→EMBEDDING_BGE_M3_*. - Listen in Env sind Komma-getrennt:
LLM_PROVIDERS=openai,lokal.
Die Bereiche im Überblick
Abschnitt betitelt „Die Bereiche im Überblick“Bereich (config.yml) |
Wichtigste Schlüssel | Env-Override |
|---|---|---|
db |
dial, prefix, logging |
DB_DIAL (Fallback MGO_DIAL), DB_PREFIX, DB_LOGGING |
api |
port, jwtSecret, upload.maxBodySize, upload.allowedMimeTypes (nur Datei), Token-Lifetimes |
API_PORT/PORT, API_JWTSECRET, API_UPLOAD_MAX_BODY_SIZE, API_ACCESS_TOKEN_LIFETIME, API_REFRESH_TOKEN_LIFETIME, API_SECURE_COOKIES |
mail |
host, username, password |
MAIL_HOST |
security |
allowAbsolutePaths, allowUpperPaths |
SECURITY_ALLOWABSOLUTEPATHS, SECURITY_ALLOWUPPERPATHS |
response.error |
stack, message |
RESPONSE_ERROR_STACK, RESPONSE_ERROR_MESSAGE |
audit |
enabled, defaultTTL, defaultLimit, maxLimit |
AUDIT_ENABLED, AUDIT_DEFAULT_TTL, AUDIT_DEFAULT_LIMIT, AUDIT_MAX_LIMIT |
ratelimit |
enabled, loginInitialDelay, loginMaxDelay, loginResetAfter |
RATELIMIT_* (gleiche Namen) |
hook |
cache.*, ratelimit.* |
HOOK_CACHE_*, HOOK_RATELIMIT_* |
mcp |
enabled, route, maxResultItems, allowAdminActions |
MCP_ENABLED, MCP_ROUTE, MCP_MAX_RESULT_ITEMS, MCP_ALLOW_ADMIN_ACTIONS |
sentry |
dsn, environment, serverName, enableTracing, debug |
keine — nur Datei |
cors |
allowOrigins, allowCredentials, … |
keine — wirksam ist die Projekt-/Collection-Ebene (siehe Sicherheit) |
search.inMemory |
enabled, maxMemoryMB (Kill-Switch + Budget für In-Memory-N-Gram-Indizes) |
keine — nur Datei |
llm / embedding |
Provider-Listen | dynamisch, siehe unten |
Datenbank, API, Mail
Abschnitt betitelt „Datenbank, API, Mail“db: dial: mongodb://mongo prefix: meinprojektapi: port: 8080 jwtSecret: mindestens-32-zufallszeichenmail: host: maildev:25environment: DB_DIAL: mongodb://mongo DB_PREFIX: ${TIBI_PREFIX} MAIL_HOST: maildev:25 SECURITY_ALLOWABSOLUTEPATHS: "true" SECURITY_ALLOWUPPERPATHS: "true" RESPONSE_ERROR_STACK: "true"Der Starter nutzt mongodb://mongo (Compose-Netz). Lokal ohne Compose heißt der Dial mongodb://localhost:27017. Der Prefix trennt Projekte in einer MongoDB.
Defaults, die du kennen musst:
secureCookies: Standardtrue. Nur für reines HTTP-Lokalsetup auffalsesetzen.accessTokenLifetime: Standard60m.refreshTokenLifetime: Standard10h. Format ist Go-Duration (30m,24h).- Ungültige Duration fällt still auf den Default zurück (Log-Warnung).
LLM und Embedding per Env
Abschnitt betitelt „LLM und Embedding per Env“Provider musst du nicht in die Datei schreiben. Diese Muster gelten:
LLM_PROVIDERS=openai,lokal-llmLLM_OPENAI_APIKEY=sk-...LLM_OPENAI_TYPE=openai # Vorgabe, wenn leerLLM_OPENAI_BASEURL=https://api.openai.com/v1 # Vorgabe für Typ openaiLLM_OPENAI_DEFAULTMODEL=gpt-4oLLM_OPENAI_MODELS=gpt-4o,gpt-4o-miniEMBEDDING_PROVIDERS=bge-m3EMBEDDING_BGE_M3_TYPE=nativeEMBEDDING_BGE_M3_MODELPATH=/models/bge-m3EMBEDDING_BGE_M3_DIMENSIONS=1024EMBEDDING_BGE_M3_DOCUMENTPREFIX="search_document: "EMBEDDING_BGE_M3_QUERYPREFIX="search_query: "Gruppen gehen über EMBEDDING_GROUPS=main plus EMBEDDING_GROUP_MAIN_MEMBERS=..., ..._POLICY=..., ..._TIMEOUT_TOTAL=....
Upload-Allowlist und Embedding-Gruppen im Detail
Abschnitt betitelt „Upload-Allowlist und Embedding-Gruppen im Detail“upload.allowedMimeTypes begrenzt, welche MIME-Typen der Server bei Datei-Feldern annimmt.
Kaskade (erste nicht-leere Liste gewinnt): Collection (upload.allowedMimeTypes) → Projekt (upload.allowedMimeTypes) → Server (api.upload.allowedMimeTypes).
Leer heißt: alles erlaubt. Es gibt dafür kein Env-Override — nur api.upload.maxBodySize hat eins (API_UPLOAD_MAX_BODY_SIZE).
api: upload: maxBodySize: 50MB allowedMimeTypes: ["image/jpeg", "image/png", "image/webp", "application/pdf"]Eine Embedding-Gruppe fasst mehrere Provider zu einer Failover-Einheit zusammen (Suche: onSingleQuery, Index-Schreiben: onBulkWrite, Prüfen: health).
Alle Gruppen-Schlüssel hängen an EMBEDDING_GROUP_<NAME>_ — <NAME> groß, Bindestrich zu Unterstrich (main → EMBEDDING_GROUP_MAIN_…).
Env (Suffix an EMBEDDING_GROUP_<NAME>_) |
Wirkung | Gültige Werte |
|---|---|---|
MEMBERS |
Komma-getrennte Provider-Namen der Gruppe | z. B. bge-m3,openai-embed |
DESCRIPTION |
Freitext | beliebig |
POLICY |
Strategie für einzelne Suchanfragen | prefer-in-order, fastest-wins, round-robin, lowest-latency, weighted |
PREFERRED_ORDER |
Bevorzugte Reihenfolge | Komma-Liste von Provider-Namen |
TIMEOUT_PER_ATTEMPT / TIMEOUT_TOTAL |
Timeout je Versuch / gesamt (Gesamt >= Versuch, sonst Fehler) |
Go-Duration (120s, 30s) |
AUTO_FAILBACK |
Nach Ausfall automatisch zurück | true/false |
RACE_DELAY / RACE_MAX_FANOUT |
Verzögerung / max. parallele Teilnehmer beim Rennen | nur mit POLICY=fastest-wins sinnvoll |
WEIGHTS |
Relative Gewichte je Mitglied | nur mit POLICY=weighted sinnvoll |
LATENCY_WINDOW |
Fenster für Latenz-Tracking | Zahl (100) |
RETRY_ATTEMPTS / RETRY_BACKOFF / RETRY_BACKOFF_MAX |
Wiederholungen und Abstände | Zahl / Go-Duration |
HEDGE_AFTER_SLOW |
Hedge-Anfrage nach dieser Dauer | Go-Duration |
DISTRIBUTION |
Verteilung beim Bulk-Schreiben | round-robin, lowest-latency, weighted |
MAX_CONCURRENT_TOTAL / MAX_CONCURRENT_PER_ENDPOINT |
Parallele Bulk-Schreibvorgänge | Zahl |
BULK_TIMEOUT_PER_ATTEMPT / BULK_TIMEOUT_TOTAL |
Timeouts beim Bulk-Schreiben | Go-Duration |
CHECK_INTERVAL / CHECK_TIMEOUT |
Healthcheck-Abstand / -Timeout | Go-Duration |
UNHEALTHY_AFTER_FAILURES / HEALTHY_AFTER_SUCCESSES |
Fehlschläge bis ungesund / Erfolge bis gesund | Zahl |
COOLDOWN_AFTER_UNHEALTHY |
Pause nach Ausfall | Go-Duration |
EMBEDDING_GROUPS=mainEMBEDDING_GROUP_MAIN_MEMBERS=bge-m3,openai-embedEMBEDDING_GROUP_MAIN_POLICY=prefer-in-orderEMBEDDING_GROUP_MAIN_TIMEOUT_TOTAL=30sWas eine Gruppe beim Start und im Betrieb tut
Abschnitt betitelt „Was eine Gruppe beim Start und im Betrieb tut“Die vollständige Fassung steht in tibi-server/docs/02-configuration.md; hier die Betreiber-Kurzfassung:
- Prüfung beim Start. Referenz ist das erste Mitglied aus
PREFERRED_ORDER, das antwortet (zwei Versuche). Jedes weitere Mitglied muss dieselben Vektoren liefern: Kosinus ≥ 0.999, zweimal identisch (deterministische Inferenz), gleiche Sparse-Form (beide mit oder beide ohne Sparse-Vektoren) und — wenn eine Gold-Datei verankert ist — auch dagegen passen. Abweichende Mitglieder sindquarantined; ohne ein einziges verifiziertes Mitglied ist die Gruppeoffline. Der Server startet trotzdem. - Rückkehr. Mit
CHECK_INTERVAL > 0prüft der Health-Loop Quarantänisierte neu gegen die aktuelle Referenz und nimmt sie zurück, sobald sie wieder passen — auch eineofflineGruppe kommt so zurück. OhneCHECK_INTERVALhalf bisher nur ein Neustart. NachCOOLDOWN_AFTER_UNHEALTHYöffnet außerdem die nächste Anfrage das Mitglied wieder halb (nur ein Versuch gleichzeitig). - Fehlkonfiguration (unbekanntes Mitglied, Tippfehler in
PREFERRED_ORDER, doppelter Gruppen- oder Mitgliedsname, Namensgleichheit mit einem Provider, abweichende Modell-Identität) macht die Gruppeofflineplus Warnzeile im Log — nie den ganzen Server. - Timeouts. Der bevorzugte Member läuft in das Gruppen-
TIMEOUT_PER_ATTEMPT; ein Ausweich-Member bekommtmax(Provider-Timeout, Gruppen-Timeout), damit ein kurzes Gruppen-Timeout einen kalten lokalen Fallback nicht abschneidet — beim Bulk-Schreiben genauso. BeiPOLICY=fastest-winsoderHEDGE_AFTER_SLOWimmerTIMEOUT_TOTALsetzen. Sind alle Sicherungen offen, antwortet die Gruppe sofort mit Fehler, statt die Gegenstellen zu bombardieren. - Dense-only-Endpoints bleiben kompatibel: fehlen Sparse-Vektoren, obwohl
SPARSEaktiv ist, liefert der Provider weiter dense-only Treffer (Hybrid-Suche fällt auf dense zurück) und schreibt einmalig eine Warnung;SPARSE=falseschaltet sie stumm. Innerhalb einer Gruppe lehnt die Prüfung ein Mitglied mit abweichender Sparse-Form ab, damit ein Failover nie still Sparse-Vektoren verliert. - Während die Gruppe weg ist, bleiben Dokumente liegen: Der Batch-Weg meldet sie dem Aufrufer als offen, einzelne Schreibvorgänge lassen den Such-Eintrag stehen. Nachziehen per nächstem Schreibvorgang,
regenerate-searchoderautoRegenerate; Suchanfragen brechen mit einer Meldung ab, die die Gruppe beim Namen nennt.
Provider-Env zum Vergleich (Provider <NAME> → EMBEDDING_<NAME>_…, ebenfalls Bindestrich zu Unterstrich):
APIKEY, TYPE, MODEL, MODELPATH, DIMENSIONS, BASEURL, DOCUMENTPREFIX, QUERYPREFIX, REVISION, TIMEOUTPERATTEMPT, SLOWTHRESHOLD, SPARSE —
z. B. EMBEDDING_BGE_M3_MODELPATH, EMBEDDING_BGE_M3_DIMENSIONS.
Unbekannte POLICY/DISTRIBUTION oder ungültige Durations lassen die Gruppe mit Fehler im Log scheitern; unpassende WEIGHTS/RACE_*-Kombis geben nur eine Warnung und werden ignoriert.
Provider- und Gruppen-Env gelten auch mit Bindestrich im Namen (EMBEDDING_BGE-M3_TYPE): der Server übernimmt solche Alt-Schlüssel beim Start auf die Unterstrich-Form und schreibt eine Hinweiszeile ins Log.
Wo die Gold-Dateien für die Mitglieds-Prüfung liegen, setzt du global: embedding.goldenPath bzw. EMBEDDING_GOLDEN_PATH (Vorgabe testdata/embedding-golden relativ zum Arbeitsverzeichnis); erzeugen mit go run ./cmd/embed-probe-golden. Ohne verankerte Gold-Datei protokolliert die Gruppe das beim Start und prüft nur gegen die Referenz.
Für IDE/Validierung liegt der Abschnitt als JSON-Schema in tibi-types/schemas/config/embedding.schema.json (Beispiel: tibi-types/examples/server/embedding.yml).
Suche: In-Memory-Indizes (search.inMemory)
Abschnitt betitelt „Suche: In-Memory-Indizes (search.inMemory)“Die optionalen In-Memory-Indizes für ngram-Suchen sind global aus. Der Schalter ist bewusst zweistufig: ohne diese Server-Freigabe wird kein Index gebaut, egal was ein Projekt in seiner YAML einträgt.
search: inMemory: enabled: false # Kill-Switch (Default: false) maxMemoryMB: 1024 # Budget-Cap je Index (Default: 1024)- Projektseitig aktiviert man den Index pro Suchblock mit
ngram.inMemory.enabled: true(Details und Messwerte: Suche). maxMemoryMBist eine Obergrenze pro Index, kein gemeinsam geteilter Pool; zusätzlich bricht der Loader ab, wenn der Prozess-RSS während des Ladens die Grenze (mit 30 % Sicherheitsmarge) reißt. Nach einem Abbruch bleibt der Index leer, die Suche läuft dauerhaft über MongoDB.- Änderungen an
enabled/maxMemoryMBwirken erst nach einem Projekt-Reload (POST /_/:project/_/admin/reloadbzw. Serverneustart). - Snapshot- und Backup-Restore verwerfen und laden alle In-Memory-Zustände (N-Gram-Indizes, Vektor-Indizes, Combined-Cache) neu — bis der Neuaufbau fertig ist, laufen die betroffenen Suchen über MongoDB.
Admin-Tokens
Abschnitt betitelt „Admin-Tokens“Server-Admin-Tokens stehen unter api.adminTokens. Jedes Token hat token, label und permissions:
api: adminTokens: - token: ersetze-mich-durch-zufall label: backup-job permissions: ["project.backup", "project.reload"]- Syntax:
domain.action(project.read,user.create,server.shutdown). - Kurzform:
projectmeintproject.*.*matcht genau ein Segment (namespace.*.articles.read). - Gültige Domänen:
user,project(plusreload,backup,regenerate-search,snapshot),team,org,audit.read,llm.chat,namespace…. - Header:
X-Admin-Token: …oderAuthorization: Bearer ….
Abnahme über den Version-Endpunkt
Abschnitt betitelt „Abnahme über den Version-Endpunkt“- Server starten und warten, bis das Config-Dump im Log steht.
- Version abfragen — antwortet sie, stimmen Port und Prefix:
Version prüfen curl http://localhost:8080/api/v1/version# {"version":"0.0.0"} - Bei Fehlern zuerst
DB_DIAL,DB_PREFIXundAPI_PORTprüfen (Tabelle oben).
Weiter: Betrieb und Beobachtung zeigt Profile und Metriken. Sicherheit erklärt Token-Arten und Ratelimit.
Verifiziert am d272041 2026-10-17 (tibi-server); Starter-Compose am e3f92eb 2026-10-14 (tibi-svelte-starter); Go-Version aus go.mod. Upload-Kaskade aus internal/controller/collection.go (resolveAllowedMimeTypes), Provider-/Gruppen-Env und goldenPath aus internal/config/server.go, Gruppen-Regeln aus internal/config/embedding_group.go, Prüfung/Quarantäne/Rückkehr/Timeouts aus internal/embedding/{registry,probe,group}.go, Pending-Verhalten aus internal/utils/search.go.