SpecsModelExplore
Overview
IOModel Stack
Reverse ProxyIOModel StudioYjs Realtime ServerKeycloakPostgreSQLRedis
Why it's needed
Key configuration
Deployment
Roll out Studio
Expose via Ingress
SpecsModelExplore
IOModel Studio
OverviewStudio GuideLinks and Communications

IOModel Studio is the application itself — the Next.js web UI and the API that backs it. It is the component users actually interact with, and the hub that talks to every other service in the stack.

Role in the stack

Studio reads and writes to PostgreSQL, caches in Redis, authenticates users via Keycloak, and mints short-lived WebSocket tokens for the Yjs Realtime Server.

Why it’s needed

  • Product surface — serves the web UI and the REST/RPC API.
  • Orchestration — coordinates auth, persistence, caching, and realtime collaboration.
  • Stateless by design — holds no durable state locally, so it scales horizontally and restarts cleanly.

Key configuration

SettingPurpose
DATABASE_URLPostgreSQL connection string
REDIS_URLCache / coordination endpoint
AUTH_KEYCLOAK_ISSUEROIDC issuer for sign-in
AUTH_URLPublic origin of the deployment
COLLAB_JWT_SECRETSigns realtime WS tokens for the Yjs server

Deployment

Because Studio is stateless, the only real concern is wiring it to its dependencies and running database migrations before traffic arrives.

Migrate before serving

Always run database migrations before new Studio replicas accept traffic. Use order: start-first (Swarm) or readiness probes (Kubernetes) for zero-downtime rollouts.

A horizontally scalable Deployment behind a Service, with a one-shot migration Job:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: studio
  namespace: iomodel
spec:
  replicas: 2
  selector: { matchLabels: { app: studio } }
  template:
    metadata: { labels: { app: studio } }
    spec:
      containers:
        - name: studio
          image: iomodel/studio:latest
          ports: [{ containerPort: 3200 }]
          envFrom: [{ secretRef: { name: studio-env } }]
          readinessProbe:
            httpGet: { path: /api/health, port: 3200 }

Run migrations first

Apply the migration Job (or an init container) so the schema is ready before pods serve traffic.

Roll out Studio

Apply the Deployment and Service; scale replicas to match load.

Expose via Ingress

Route external / traffic to the studio service (see the Reverse Proxy guide).

apiVersion: apps/v1
kind: Deployment
metadata:
  name: studio
  namespace: iomodel
spec:
  replicas: 2
  selector: { matchLabels: { app: studio } }
  template:
    metadata: { labels: { app: studio } }
    spec:
      containers:
        - name: studio
          image: iomodel/studio:latest
          ports: [{ containerPort: 3200 }]
          envFrom: [{ secretRef: { name: studio-env } }]
          readinessProbe:
            httpGet: { path: /api/health, port: 3200 }