Studio — BFF Middleware
FastAPI gateway that owns auth, RBAC, session management, and proxies every API call from the Sentinel frontend to capability backends.
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-userand/<stage-prefix>/service-password.
Configuration
All values come from the per-environment
.envfile. 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 policy — dev 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
loguruwith 10 MB error-file rotation and 10-day retention, plusstructlogfor 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,httpxinstrumentations); OTLP export endpoint set via OTel env vars when enabled. - Per-downstream discovery —
/api/v1/discovery/services/{svc}/healthis 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).
Cross-links
- Platform overview — how Studio fits into the whole stack
- API reference — request/response schemas
- Authentication — JWT flow + token lifecycle
- Environments — variable layer reference
- CI/CD — branch model and deploy automation
- Sentinel frontend — the upstream caller
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.