Skip to content

Platform Service

The platform is the single public API — every SDK call, WebUI click, and OpenAI-compatible request enters here. It authenticates the caller, then either answers directly (login, Stripe checkout, chain queries, the diagnostics console, docs) or proxies the request to the right backend with the user's identity attached. Port 8100.

It's essentially stateless — auth is JWT, and its Postgres database holds a single table (stripe_events, for webhook idempotency). Everything else lives in the services it fronts.

Auth

Every token is a JWT (HS256, JWT_SECRET) with a sub (username) and roleuser, provider, or admin; admin passes every role check. The platform mints them (create_token):

  • Users get one at signup — the faucet triggers the platform's admin-only POST /v1/auth/onboard; an admin can also call it directly.
  • Providers get theirs as a JWT join key issued when their node registers (by kuberay, same secret), so the one token works as auth everywhere — SDK, web UI, API.
  • Admin is a shortcut: the raw ADMIN_TOKEN used as a bearer is accepted directly as {role: admin} — no JWT — for service-to-service and first run.

On each request the platform verifies the token, sets X-User-Id / X-User-Role, and forwards downstream — the backends trust those rather than re-verifying, so end-user login is centralized here. User tokens are additionally checked against the faucet's revocation flag (cached 60s, fail-open) since JWTs live 30 days; a revoked user gets 401.

What it answers directly

  • Auth (/v1/auth) — me, onboard (create user + grant credits), join-key CRUD (proxied to kuberay).
  • OpenAI-compatible API (/v1/models, /v1/chat/completions, /v1/completions) — a drop-in for the OpenAI SDK that routes to a user's hosted endpoints (/{username}/{name}/v1/… on Ray Serve).
  • Payments (/v1/credits/checkout, /v1/credits/webhook) — Stripe checkout for credit packs; the webhook mints paid credits to the buyer, idempotent via stripe_events.
  • Chain (/v1/chain) — read the on-chain token-economy ledger: events, a tx by hash, a user's history, raw RPC.
  • Diagnostics (/v1/diagnostics, admin) — the operator's log + health console (a read layer over the cluster's logging/metrics backends).
  • Docs (/llms.txt) — public SDK docs with this deployment's own URLs + current SDK version substituted in.

What it proxies (auth → forward with user context)

Prefix → Service For
/v1/jobs/*, /v1/jobs/train, /v1/resources job gateway (:8200) run/manage jobs + training, cluster resources
/v1/endpoints/* job gateway deploy / start / stop / delete model endpoints
/v1/admin/*, /v1/operator/* job gateway GPU pricing, revenue splits, cluster status (admin)
/v1/accounting/* metering (:8300) usage summaries + reports
/v1/credits/* credit service (:8400) balance, transactions, transfer, packs
/v1/storage/* S3 per-user files — every user is boxed into a users/{username}/ prefix

Storage isolation is enforced here: a user can only touch their own prefix. Full endpoint reference, error codes, and config: STORAGE.md.

Configuration

Variable Default Description
PLATFORM_PORT 8100 Service port
PLATFORM_DATABASE_URL — (required) Postgres (holds only stripe_events; DB auto-created)
JWT_SECRET dev-secret-change-me JWT signing key
ADMIN_TOKEN — (required) Bootstrap admin token (no-JWT admin access)
GATEWAY_URL http://localhost:8200 Job gateway (jobs, endpoints, admin, operator)
CREDIT_SERVICE_URL / METERING_URL service defaults Credits + usage proxies
KUBERAY_URL http://localhost:8800 Join-key proxy
FAUCET_URL http://faucet:8500 Revocation check on each request
S3_ENDPOINT / S3_ACCESS_KEY / S3_SECRET_KEY / S3_BUCKET MinIO defaults User file storage
STRIPE_SECRET_KEY / STRIPE_WEBHOOK_SECRET Stripe checkout + webhook; key alone suffices — the webhook auto-provisions on boot (see docs/guides/4-stripe.md). Also settable at runtime via /v1/admin/stripe
CORS_ORIGINS * Allowed origins
RATE_LIMIT_PER_MINUTE 6000 Per-IP rate limit

Running & testing

# Unit tests need a Postgres (test compose exposes one on host port 5433):
docker compose -f docker-compose.test.yml --profile credit up postgres -d
pytest tests/platform_service/ -v --ignore=tests/platform_service/test_docker.py

Coverage: test_auth / test_routers_auth (JWT, roles, onboard, join-key proxy), a test_routers_* per proxy (jobs, serve, credits, accounting, operator, training, storage) checking each forwards the right user context, test_routers_storage (per-user prefix isolation), test_openai_compat (OpenAI mapping), test_routers_stripe (checkout + webhook), test_routers_chain* (chain queries), test_diagnostics (health console), test_rate_limit, test_docker (deployed). Interactive API docs at /docs.