WikifitaGitHub live67e8de5
projeto · infraestrutura/fitalabs-gateway-1p-jornada

FitaLabs Gateway — 1P Bundle + LiteLLM Proxy Journey

Documentation: FitaLabs Gateway — 1P Bundle + LiteLLM Proxy Journey

Baixar raw

FitaLabs Gateway — 1P Bundle + LiteLLM Proxy Journey

Complete documentation of the migration from custom gateway to LiteLLM Proxy Server and the hosting of the Claude Desktop 1P bundle on claude.unifita.app.

Final Architecture

Caddy (TLS)
├── claude.unifita.app  → SPA React 1P (bundle ion-dist + CDN chunks)
├── api.unifita.app     → LiteLLM Proxy (models, inference)
├── gateway.unifita.app → LiteLLM Admin UI (/ui)
├── docs.unifita.app    → Docusaurus (OpenAPI docs)
├── get.unifita.app     → DMG downloads
└── status/search/crawley → auxiliary services

Docker Compose:
├── caddy        — reverse proxy + TLS
├── gateway      — LiteLLM Proxy Server (FastAPI)
├── postgres     — proxy database (users, keys, spend)
├── redis        — prompt cache
├── searxng      — meta-search
├── crawl4ai     — web crawler
└── uptime-kuma  — monitoring

Models (4 Claude aliases + 4 provider-native)

ant_aliasmodel_iddisplay_name
claude-haiku-4-7[1m]deepseek-v4-flashHaiku Seek Flash
claude-sonnet-4-6[1m]mimo-v2.5Monnet v2.5
claude-opus-4-6[1m]mimo-v2.5-proMopus v2.5 Pro
claude-opus-4.7[1m]deepseek-v4-proDopus Pro

Provider-native: deepseek-v4-flash[1m], mimo-v2.5[1m], mimo-v2.5-pro[1m], deepseek-v4-pro[1m] Audio: tts-1, whisper-1

Gateway Evolution

Phase 1: Custom FastAPI (Jun 2026)

  • gateway.py — custom FastAPI app with manual Tier x Effort routing
  • router.py (304L) — routing table Haiku/Sonnet/Opus x Low/Med/High
  • handlers/messages.py — manual HTTP forwarding to MiMo/DeepSeek
  • services/forwarding.py, services/fallback.py — custom proxy code
  • MiMo provider registered via monkey-patch in ProviderConfigManager

Phase 2: LiteLLM Router as Library

  • litellm_router.py — singleton loading model_list from YAML
  • router.acompletion() replaces manual forwarding
  • Custom hooks registered in pipeline (hooks/pipeline.py)

Phase 3: LiteLLM Proxy Server (Jul 2026)

  • Critical discovery: CONFIG_FILE_PATH (not LITELLM_CONFIG_PATH) is the env var the proxy reads at startup
  • app = litellm.proxy.proxy_server.app — the proxy IS the gateway
  • Custom routes (voice WS, MCP, search, API handlers) added to the proxy app
  • PostgreSQL required for admin UI (login, key management, spend tracking)
  • Prisma: LiteLLM's default schema is PostgreSQL, not SQLite. libatomic1 required in Dockerfile
  • Migrations: prisma migrate deploy runs the litellm_proxy_extras migrations
  • Admin UI at /ui, login admin / admin (UI_USERNAME/UI_PASSWORD)

Phase 4: 1P Bundle (Jul 2026)

  • Bundle extracted from 1P Desktop via CDP → ~/.bezetacil/workdir/claude-desktop/ion-dist/
  • 47 files copied to webapp/claude/ (React 7.2MB + 35 chunks + CSS + fonts)
  • CDN fallback in Caddy: missing chunks downloaded on-demand from assets-proxy.anthropic.com
  • Caddy injects Authorization: Bearer sk-gateway-local in all API calls (no Service Worker)
  • SPA fallback: client-side routes (/login, /new, /onboarding) serve index.html
  • API routes (/api/*, /v1/*, /bootstrap, /account_profile, /edge-api/*, /accounts/*) proxied to gateway

1P Bundle Discoveries

Chunks and Code Splitting

  • The main bundle (index-BW29VlNm.js, 7.2MB) imports 35+ chunks via dynamic import()
  • Chunks follow Vite/Rollup pattern: vendor-react-B9b0-tId.js, c34d1f91f-DIhRpeoW.js, etc
  • Complete chunk list obtained from browser 404 errors
  • CDN URL: https://assets-proxy.anthropic.com/claude-ai/v2/assets/v1/

Authentication

  • SPA uses Google OAuth (accounts.google.com/gsi/status) as main provider
  • Magic link implemented: POST /api/auth/send_magic_link + GET /api/auth/verify_magic_link
  • Login methods: GET /api/auth/login_methods?email=...
  • SPA does PUT /api/account_profile to update onboarding settings

Onboarding

  • SPA checks has_finished_claudeai_onboarding and has_started_claudeai_onboarding on account
  • Mutations E() and be() do PUT on /api/account_profile with settings
  • invites array must exist (even empty) on account — e?.invites.some() crashes if undefined

Critical Endpoints Called by 1P SPA

  • GET /edge-api/bootstrap?statsig_hashing_algorithm=djb2&growthbook_format=sdk&include_system_prompts=false
  • GET /api/account_profile
  • PUT /api/account_profile — atualiza settings
  • POST /api/accounts/me/organizations/get_or_create_chat_organization
  • GET /api/auth/login_methods?email=...
  • POST /api/auth/send_magic_link
  • POST /api/event_logging/v2/batch
  • GET /api/updates — version check

Caddy Configuration

claude.unifita.app

file_server (root /var/www/claude)
reverse_proxy /api/* → gateway:4000 (with auth header injection)
reverse_proxy /v1/* → gateway:4000
SPA fallback: client-side routes → index.html (only Accept: text/html)
CDN fallback: handle_errors 404 → proxy assets-proxy.anthropic.com

gateway.unifita.app

redir / → /ui (admin panel)
/swagger → /docs (OpenAPI)

Docker

docker-compose.yml

  • PostgreSQL 16 Alpine with pg_isready healthcheck
  • prisma-cache volume for Prisma binaries
  • Bind mounts for dev: src/, litellm_config.yaml, data/
  • Env vars in .env (not in compose), following project convention

Dockerfile

FROM ghcr.io/astral-sh/uv:python3.13-bookworm-slim
RUN apt-get install -y ffmpeg curl libatomic1
RUN uv sync --frozen --no-dev
CMD ["uv", "run", "uvicorn", "gateway:app", "--host", "0.0.0.0", "--port", "4000"]

Lessons Learned

  1. LiteLLM Proxy, not Router: proxy_server.app is the gateway. Router is just a library.
  2. CONFIG_FILE_PATH: The env var the proxy actually reads. LITELLM_CONFIG_PATH is ignored.
  3. PostgreSQL required: Admin UI, key management, spend tracking all need Postgres.
  4. libatomic1: Required in Dockerfile for Prisma/Node binaries.
  5. Caddy auth injection > Service Worker: SW has caching issues. Caddy header_up is server-side and reliable.
  6. SPA fallback with Accept header: header Accept *text/html* avoids serving HTML for JS imports.
  7. CDN fallback with handle_errors 404: Chunks downloaded on-demand, no need for pre-download.

References