Live App →

Purpose

Studio is the Backend-for-Frontend (BFF) middleware for the entire Sentinel AI platform. The Sentinel browser app calls only Studio — never the capability backends directly. Studio owns:

  • Authentication — JWT issuance, refresh, and validation (HS256 via python-jose)
  • Session management — Redis-backed sessions with connection pooling
  • RBAC — role-based access decisions before requests reach downstreams
  • Rate limiting — per-route quotas for auth-sensitive endpoints
  • Service discovery — resolves downstream URLs from a YAML registry, injects per-stage Basic Auth from AWS SSM
  • Transparent proxying — wildcard or explicit-route forwarding to capability backends with response-envelope normalisation

If you’re calling the platform from outside the browser, Studio is your single entry point.


Architecture

graph TB
    subgraph Clients["Clients"]
        Browser["Sentinel Frontend<br/>Next.js 16"]
        ServerSide["Server-side / scripts<br/>via Bearer JWT"]
    end

    subgraph Studio["Studio BFF — FastAPI 0.115"]
        Auth["Auth router<br/>/api/v1/auth/*"]
        Health["Health<br/>/health · /api/v1/health"]
        Discovery["Discovery<br/>/api/v1/discovery/*"]
        Dashboard["Dashboard aggregator<br/>/api/v1/dashboard"]
        Proxy["Proxy router<br/>YAML-driven service registry"]
    end

    subgraph Stores["Stores"]
        PG["PostgreSQL<br/>auth · RBAC · audit"]
        Redis["Redis<br/>sessions · rate-limit"]
        SSM["AWS SSM Parameter Store<br/>service credentials"]
    end

    subgraph Downstreams["Downstream services"]
        Nexus["Nexus<br/>Document AI"]
        Zen["Zen<br/>RAG chat"]
        Agents["Agents<br/>Orchestration"]
        Ingestion["Ingestion / KB"]
    end

    Browser --> Auth
    Browser --> Proxy
    ServerSide --> Auth
    ServerSide --> Proxy

    Auth --> PG
    Auth --> Redis
    Proxy --> SSM
    Proxy --> Nexus
    Proxy --> Zen
    Proxy --> Agents
    Proxy --> Ingestion

    classDef primary fill:#dbeafe,stroke:#3b82f6,color:#1e293b
    classDef secondary fill:#e0e7ff,stroke:#6366f1,color:#1e293b
    classDef success fill:#d1fae5,stroke:#10b981,color:#1e293b
    classDef neutral fill:#f1f5f9,stroke:#64748b,color:#1e293b
    class Browser,ServerSide primary
    class Auth,Health,Discovery,Dashboard,Proxy secondary
    class PG,Redis,SSM neutral
    class Nexus,Zen,Agents,Ingestion success

API surface

All routes are mounted under the API prefix (/api/v1 by default).

Method Path Purpose Notes
POST /auth/login Email/password → JWT pair Rate-limited
POST /auth/register Create new account Rate-limited
POST /auth/refresh Exchange refresh for new access token Bearer = refresh token
POST /auth/logout Invalidate session Bearer = access token
GET /health Container liveness Used by Docker healthcheck
GET /api/v1/health App liveness with deps probe Public
GET /api/v1/dashboard Aggregated platform metrics Composes from multiple downstreams
GET /api/v1/discovery/services/{svc}/health Per-service health via discovery  
ANY /api/v1/nexus/* Proxy → Nexus (32 explicit routes) Explicit registration required
ANY /api/v1/zen/* Proxy → Zen Wildcard — any new path works
ANY /api/v1/agents/* Proxy → Agents Wildcard
ANY /api/v1/ingestion/* Proxy → Ingestion / Knowledge Base Wildcard

The full OpenAPI schema is served at /docs (FastAPI Swagger UI) when ENVIRONMENT is dev. For the canonical request/response schemas as used by the frontend, see the API reference.

Response envelope

Every Studio response wraps the downstream payload in a standard envelope so the frontend can pattern-match a single shape:

{
  "success": true,
  "message": "Operation completed",
  "error": null,
  "result": { /* T  actual payload */ }
}

The frontend’s api-client.ts automatically unwraps result so callers receive T directly. The V2 progress polling endpoint is the documented exception — it returns raw JSON without the envelope.


Dependencies

Upstream (callers)

  • Sentinel frontend at sentinel.centricitywealth.tech — the only browser client. Server actions on the Next.js side authenticate via Studio.

Downstream (services Studio calls)

Resolved from config/services.yaml and overridden per stage via deployment/config/{dev,prod}.yml injected by CloudFormation.

Service Pattern Auth Notes
Nexus Explicit routes Basic Auth (SSM) 32 registered routes; new endpoints need code change
Zen Wildcard proxy Basic Auth (SSM) New paths auto-available
Agentic Wildcard proxy Basic Auth (SSM) Routed through Zen wildcard for some paths
Knowledge base Wildcard proxy Basic Auth (SSM) Document ingestion + search

Stores

  • PostgreSQL — users, RBAC, audit log. Async via SQLAlchemy 2.0 + asyncpg. Migrations via Alembic; idempotent upgrade-on-boot when RUN_MIGRATIONS=true.
  • Redis — sessions, rate-limit counters. Pool of 10 connections, 5 retries.
  • AWS SSM Parameter Store — Basic Auth credentials for downstream services at /<stage-prefix>/service-user and /<stage-prefix>/service-password.

Configuration

All values come from the per-environment .env file. This page lists variable NAMES only — secrets are never echoed in documentation.

Group Variables
Server APP_PORT, APP_HOST, ENVIRONMENT, LOG_LEVEL, LOG_DIR, RUN_MIGRATIONS
Database DATABASE_URL, POSTGRES_POOL_SIZE, POSTGRES_MAX_OVERFLOW
Redis REDIS_HOST, REDIS_PORT, REDIS_MAX_CONNECTIONS
Auth JWT_SECRET_KEY, JWT_ALGORITHM, JWT_AUDIENCE, JWT_ACCESS_TOKEN_EXPIRE_SECONDS, JWT_REFRESH_TOKEN_EXPIRE_SECONDS
Network CORS_ALLOW_ORIGINS, SECURITY_HSTS_MAX_AGE
Rate limits RATE_LIMIT_LOGIN_ATTEMPTS, RATE_LIMIT_LOGIN_WINDOW, RATE_LIMIT_REGISTER_ATTEMPTS, RATE_LIMIT_REGISTER_WINDOW
Service registry SERVICE_CONFIG_PATH, SERVICE_HEALTH_CHECK_ENABLED, SERVICE_HEALTH_CHECK_INTERVAL

The full layered .env model (workspace .env for shared infra, <repo>/.env.dev for local dev, <repo>/.env for runtime) is documented in Environments.


Deployment

Aspect Detail
Container Multi-stage Dockerfile: stage 1 sources ghcr.io/astral-sh/uv:0.5.14, stage 2 is python:3.13.3-slim
User Non-root studio:studio (uid 1000)
Port 8000 (override via APP_PORT)
Health probe Docker HEALTHCHECK — 30s interval, 10s timeout, 3 retries
Migrations alembic upgrade head runs on container boot when RUN_MIGRATIONS=true (idempotent)
Stage config deployment/config/{dev,prod}.yml injected by CloudFormation
Branch model Per workspace policydev push deploys dev, main push deploys prod, both via Jenkins webhook

Promotion flow

sequenceDiagram
    participant Dev as Engineer
    participant GH as GitHub
    participant J as Jenkins
    participant ECS as ECS Fargate

    Dev->>GH: git push origin dev
    GH->>J: webhook
    J->>J: lint · test · build image
    J->>ECS: deploy to dev cluster
    Note right of ECS: Alembic auto-runs<br/>RUN_MIGRATIONS=true

    Dev->>GH: PR dev → main
    GH->>J: webhook on merge
    J->>ECS: deploy to prod cluster

Observability

  • Structured logging via loguru with 10 MB error-file rotation and 10-day retention, plus structlog for per-request field instrumentation.
  • Health endpoints (/health, /api/v1/health) report status of PostgreSQL, Redis, and downstream connectivity.
  • OpenTelemetry tracing is available behind an optional dependency group (fastapi, sqlalchemy, redis, httpx instrumentations); OTLP export endpoint set via OTel env vars when enabled.
  • Per-downstream discovery/api/v1/discovery/services/{svc}/health is used by the frontend to surface backend status on the dashboard.

Owners

Centricity Wealth — primary contact kamna@centricity.co.in. Workspace maintainer (commits, deploys): Rishabh Arya (rishabh.arya@centricity.co.in).



Open questions (for the maintainer)

  • SSM credential rotation cadence for downstream Basic Auth?
  • Redis posture in prod — single node or replica/cluster?
  • Per-route rate limits beyond auth, or do downstreams handle their own?
  • Audit-log retention period and compliance scope?

These will be filled in as the maintainer confirms — see v2 service coverage plan.