Developer ReferenceArchitecture

Architecture

StudioBrain is a schema-driven digital asset management and narrative intelligence platform for game development. This page covers the system architecture from service topology through the entity system to the frontend layout engine.

Core Principle: Markdown is Source of Truth

Every entity in StudioBrain lives in a markdown file with YAML frontmatter. The database is a cache and index layer that is fully rebuildable from files. All writes flow through the markdown sync layer, which updates both the file on disk and the database record atomically.

User's Markdown Files (YAML frontmatter + content)
    |
    v
Backend (parse, validate, cache in DB)
    |
    +---> Database (SQLite local / PostgreSQL cloud)
    |
    +---> AI Service (RAG indexing, context building, generation)

This means:

  • Users can edit files directly in any text editor and changes sync into the app.
  • The database can be deleted and rebuilt from files at any time.
  • Git version control works naturally on the markdown files.
  • No vendor lock-in: your content is always plain text.

Three-Service Stack

StudioBrain runs as three independent services that communicate over HTTP/WebSocket.

ServiceTechnologyDefault PortPurpose
FrontendNext.js 15, React 19, TypeScript, Tailwind 43100Web UI, client-side rendering, API orchestration
BackendFastAPI, SQLAlchemy 2.0, Python 3.128201Entity CRUD, auth, file sync, billing, plugins
AI ServiceFastAPI, PyTorch, multi-provider orchestration8202RAG, content generation, image generation, embeddings

Request Flow

Entity operations (CRUD, sync, search) route through the backend:

Frontend --> Backend API (port 8201) --> Database + Filesystem

AI operations (chat, image gen, analysis) route directly to the AI service:

Frontend --> AI Service (port 8202) --> External APIs (OpenAI, Anthropic, etc.)

Complex AI generation loads context from the backend first:

Frontend --> Backend (load entity context, rules, templates)
         --> AI Service (generate with context) --> External APIs

Authentication

  • JWT with httpOnly cookies: The backend issues JWTs containing tenant_id, user_id, and role. No PII is stored in the token.
  • API key auth: The AI service accepts API keys passed per-request. Users can bring their own keys (BYOK) or use admin fallback keys.
  • Web auth routes: /api/auth/web/login, /api/auth/web/session, /api/auth/web/select-tenant handle cookie-based browser sessions.

Deployment Topology

Production Layout

StudioBrain runs across two compute hosts and four dedicated database LXCs:

Proxmox LXC 138 (10.15.0.137) -- App Services
  +-- Docker: studiobrain-caddy    (HTTPS termination, port 443)
  +-- Docker: studiobrain-frontend (internal port 3100)
  +-- Docker: studiobrain-backend  (port 8201)
  +-- NFS mount: /data/content --> NAS

BRAINZ (10.15.0.20) -- AI Service + GPU
  +-- Docker: studiobrain-ai       (port 8202, GPU access)
  +-- NFS mount: /data/content --> NAS (same content)

Database Services

Four dedicated LXCs enforce security zone separation. PII never co-locates with content.

ServiceLXC IPEnginePurpose
Auth DB10.15.0.138PostgreSQL 17.8Users, tenants, billing, OAuth tokens
Content DB10.15.0.139PostgreSQL 17.8 + RLSEntities, assets, templates, plugins
Vector Store10.15.0.140Qdrant v1.13.6Embeddings, collection-per-tenant
Cache/PubSub10.15.0.141Redis 8.0.2Sessions, rate limits, presence, real-time events

Security zones:

  • Zone 1 (Restricted): Auth DB accepts connections only from the app backend. The AI service is blocked.
  • Zone 2 (Standard): Content DB, Qdrant, and Redis accept connections from both the backend and the AI service (read-only for AI).

Desktop Mode

For local/offline use, StudioBrain runs as a Tauri 2.0 desktop app. The backend runs as a Python sidecar with SQLite for storage and ChromaDB for local vector search. No cloud services are required.

Multi-Tenancy

Every database table includes a tenant_id column. When running on PostgreSQL, Row-Level Security (RLS) policies enforce tenant isolation at the database level. On SQLite (desktop mode), tenant filtering happens in the application layer.

JWT tokens carry tenant_id, which the TenantIsolationMiddleware extracts and passes to every database query via scope_query().

Entity System

Unified Entity Model

All entity types share a single database model (EntityBase) with a flexible fields JSON column. The entity type determines which fields are present, as defined by the corresponding template.

class EntityBase(Base):
    __tablename__ = "entities"
 
    id = Column(Integer, primary_key=True)
    entity_type = Column(String)       # "character", "location", "brand", etc.
    entity_id = Column(String)         # snake_case identifier
    name = Column(String)
    status = Column(String)
    fields = Column(JSON)              # Template-specific fields
    markdown_body = Column(Text)       # Markdown content below frontmatter
    tenant_id = Column(String)
    created_at = Column(DateTime)
    updated_at = Column(DateTime)

Template-Driven Fields

Templates define the schema for each entity type. They live at _Templates/Standard/{TYPE}_TEMPLATE.md and contain YAML frontmatter declaring all fields with their types and defaults.

The backend’s TemplateSchemaService parses these templates to:

  • Validate entity data on create/update
  • Generate TypeScript interfaces and Zod schemas for the frontend
  • Provide schema information to the AI service for structured outputs

Unified API Pattern

All entity types use the same API pattern:

GET    /api/entity/{type}              -- List entities of this type
GET    /api/entity/{type}/{id}         -- Get single entity
POST   /api/entity/{type}             -- Create entity
PUT    /api/entity/{type}/{id}         -- Update entity
DELETE /api/entity/{type}/{id}         -- Delete entity (soft, to recycle bin)
GET    /api/entity/{type}/schema       -- Get template schema
POST   /api/entity/{type}/smart-merge  -- AI-assisted merge
POST   /api/entity/{type}/import       -- Import from markdown
POST   /api/entity/{type}/compare      -- Compare two versions

The response shape is consistent across all entity types:

{
  "total": 42,
  "offset": 0,
  "limit": 50,
  "entities": [
    {
      "entity_type": "character",
      "entity_id": "rex_marshall",
      "name": "Rex Marshall",
      "status": "active",
      "fields": {
        "age": "34",
        "gender": "male",
        "faction": "independent",
        "personality_traits": ["resourceful", "paranoid", "loyal"]
      },
      "markdown_body": "# Rex Marshall\n\n## Background\n...",
      "primary_asset": "/Characters/rex_marshall/images/portrait.png"
    }
  ]
}

Entity Types

StudioBrain ships with 16 entity types. New types can be added by creating a template file — no code changes required.

TypeTemplateFile PrefixDescription
characterCHARACTER_TEMPLATE.mdCH_People, NPCs, players
locationLOCATION_TEMPLATE.mdLOC_Places, points of interest
districtDISTRICT_TEMPLATE.mdDST_City areas, zones
brandBRAND_TEMPLATE.mdBR_In-world companies, products
factionFACTION_TEMPLATE.mdFAC_Organizations, groups
itemITEM_TEMPLATE.mdITM_Game items, collectibles
jobJOB_TEMPLATE.mdJOB_Occupations, roles
questQUEST_TEMPLATE.mdQST_Missions, objectives
campaignCAMPAIGN_TEMPLATE.mdCMP_Story arcs, campaigns
eventEVENT_TEMPLATE.mdEVT_World events, incidents
dialogueDIALOGUE_TEMPLATE.mdDLG_Conversation trees
timelineTIMELINE_TEMPLATE.mdTL_Timeline entries
assemblyASSEMBLY_TEMPLATE.mdASM_Modular entity assemblies
style_bibleSTYLE_BIBLE_TEMPLATE.mdSTY_Visual style guides
universeUNIVERSE_TEMPLATE.mdUNI_World-building lore

Automatic Type Generation

Running npm run generate:types (or starting npm run dev) reads all templates and generates:

  • src/types/generated/entities.ts — TypeScript interfaces for each entity type
  • src/types/generated/schemas.ts — Zod validation schemas
  • src/types/generated/mappings.ts — Entity type constants and utilities

These are re-exported from src/types/index.ts for barrel-import usage:

import { Character, Location, District } from '@/types';
import { CharacterSchema } from '@/types';

Plugin System

StudioBrain supports plugins that extend the UI with custom panels rendered as sandboxed iframes. Plugins communicate with the host via a typed postMessage protocol.

Key plugin capabilities:

  • UI panels in entity sidebars, tabs, or footers
  • Component blocks placeable in the Layout Designer (plugin:{pluginId}:{panelId})
  • Backend routes registered via the plugin loader at startup
  • Event handlers subscribing to the backend event bus
  • Per-plugin data storage via /api/plugins/{plugin_id}/data/{record_type}
  • Settings (global and per-user) via /api/plugins/{plugin_id}/settings

See Plugin Development and Plugin Iframe Protocol for full details.

Layout System

The Layout Designer is a page composer that drives entity edit and view pages from JSON layout definitions stored at _Templates/Layouts/{entity_type}.json.

Layout Structure

interface EntityLayout {
  entity_type: string;
  sections: LayoutSection[];      // Field groups and component blocks
  tabs?: LayoutTab[];             // Configurable edit page tabs
  view_config?: LayoutViewConfig; // View page settings
}

Each section contains either form fields or a component block (mutually exclusive). Sections support column counts, collapse defaults, and custom titles.

Component Blocks

Nine built-in blocks are available in the Layout Designer palette:

Block IDCategoryDescription
entity-assetsmediaAsset browser with upload and primary image selection
entity-timelinedisplayInteractive timeline event panel
production-statusworkflowProduction pipeline status editor
markdown-contentdisplayRendered markdown body content
primary-imagemediaHero image display with fallback
entity-chatinteractionAI chat panel for conversational editing
entity-relationshipsdisplayAuto-discovered relationship links
entity-workflow-triggerworkflowComfyUI workflow trigger buttons
static-contentdisplayStatic text, headers, separators, info/warning boxes

Plugin blocks use the ID format plugin:{pluginId}:{panelId} and render inside sandboxed iframes.

Layout-Driven Views

Entity view pages can opt into layout-driven rendering by setting view_config.layout_driven: true. The LayoutDrivenEntityView component reads the layout, renders sections in read-only mode, and falls back to the original hand-coded view page if no layout is configured.

Configurable Tabs

Edit page tabs are resolved from the layout JSON via the useLayoutTabs hook:

  1. If the layout defines tabs, use those.
  2. Otherwise, fall back to 6 defaults: visual, yaml, markdown, preview, assets, generation.
  3. Plugin-registered tabs are merged in.

Key Files

AreaPath
Layout typessrc/types/layout.ts
Block registrysrc/lib/component-block-registry.ts
Plugin protocolsrc/lib/plugin-message-protocol.ts
Tab resolutionsrc/hooks/useLayoutTabs.ts
Layout loadingsrc/hooks/useEntityLayout.ts
Block renderersrc/components/ComponentBlockRenderer.tsx
Dynamic editorsrc/components/DynamicEntityEditor.tsx
View shellsrc/components/ViewPageShell.tsx
Layout-driven viewsrc/components/LayoutDrivenEntityView.tsx
Designer UIsrc/components/LayoutDesigner/
Backend validationbackend/services/layout_service.py

Theme System

StudioBrain uses a semantic surface system with 12 surfaces, each containing 7 coordinated CSS properties. Users can customize every value through the Settings UI, and all components — including plugins — must use semantic surface classes.

See Theme Customization for the full reference.

Product Tiers

TierStorageAI CreditsAccess
FreeLocal onlyBYO API keys + 100 BrainBits/moDesktop
Indie ($29/mo)Google Drive, 25GB cloud500 BrainBits/moDesktop + Web
Team ($45/user/mo)+ S3/Azure, 100GB cloud750/user pooledDesktop + Web + Mobile, SSO
EnterpriseUnlimitedUnlimitedAll + Dedicated instance

Feature gating is enforced by the FeatureGateMiddleware on the backend and useFeatureGate hooks on the frontend. The billing system uses Stripe with webhook-driven subscription lifecycle management.