Studio Backend¶
Generative AI Tools, Video Workbench, AI pipelines etc.
Directory Structure¶
The application follows a modular architecture where each feature is organized into its own directory with consistent file naming:
studio-backend/
├── src/
│ ├── [feature]/ # Each feature follows this pattern:
│ │ ├── [feature].router.ts # API route definitions
│ │ ├── [feature].controller.ts # HTTP request/response handling
│ │ ├── [feature].service.ts # Business logic
│ │ ├── [feature].validator.ts # Input validation (Zod schemas)
│ │ └── [feature].middleware.ts # Authentication/authorization
│ ├── models/ # MongoDB schema definitions
│ ├── shared/ # Common utilities, types, constants
│ ├── thirdPartyServices/ # External API integrations
│ ├── utilityServices/ # Standalone services for common operations
│ ├── [product]Templates/ # Email or Prompt templates etc.
│ └── [other-features]/ # Additional feature modules
├── tests/ # Test files mirroring src structure
├── dist/ # Compiled JavaScript output
└── config files # TypeScript, Biome, Vitest, etc.
Core Files: index.ts (app entry), router.ts (main router), mongoDBClient.ts, redisClient.ts, mailer.ts, errorLogger.ts
Architecture Overview¶
Router, Controllers, Validators, and Service Functions¶
The application follows a layered architecture pattern:
- Routers (
*.router.ts): Define API endpoints and route requests to controllers - Controllers (
*.controller.ts): Handle HTTP requests/responses and input validation - Validators (
*.validator.ts): Validate request data using Zod schemas - Services (
*.service.ts): Contain business logic and database operations - Middleware (
*.middleware.ts): Handle cross-cutting concerns like authentication and authorization
MongoDB Integration¶
The src/models/ directory contains MongoDB schema definitions for all data entities.
The application uses multiple mongoDB databases:
- Primary Database: Studio database for main application data
- Story Database: Rendarigo database for stories data (to be updated when storydesk is up)
- Connection Management:
mongoDBClient.tshandles connections to both databases - Collection Access: Provides methods for accessing collections in both databases
Webhooks¶
The webhook system (src/webhooks/) handles external service callbacks:
- Webhook Router: Defines webhook endpoints
- Webhook Middleware: Validates webhook signatures and authenticity
- Webhook Controller: Processes incoming webhook payloads
- Webhook Service: Contains webhook processing business logic
Activity Logging¶
The activity logging system tracks user-facing actions across projects (scene generation, shot edits, collaborator changes, etc.) and surfaces them in the frontend activity panel.
- Collection:
projectActivitiesin MongoDB - Service:
src/projectActivities/projectActivities.service.ts— fire-and-forget helpers (logActivity,logProjectLifecycleActivity) - Enum:
ProjectActivityActioninsrc/shared/sharedTypes.ts— single source of truth for all action types - Frontend: Mirrored enum +
ACTION_LABELSinstudio-frontend, displayed in a dropdown panel
Activity logging is a cross-cutting concern wired in the service layer (not controllers). When adding new user-facing features, activity logging must be added(also write tests). See src/projectActivities/README.md for the full checklist and conventions.
Test Library¶
The application uses Vitest as the testing framework:
- Configuration:
vitest.config.tswith TypeScript path aliases and experimentalfsModuleCache - Test Structure: Tests organized by module in
tests/directory - Global Setup:
tests/globalSetup.ts— starts a shared MongoMemoryServer instance (onemongodfor all test files) - Test Helpers:
tests/testHelpers.ts— connects to shared mongod, provides unique DB per file viagetDb() - Mockers: Reusable mock objects in
tests/mockers/ - Test Constants: Shared test constants in
tests/testConstants.ts
Performance: 527 tests run in ~7.5s locally thanks to:
- Shared MongoMemoryServer (one mongod process, unique DB name per file for full parallelism)
- fsModuleCache: true (experimental Vitest feature for faster module resolution)
- Fire-and-forget activity logging with flush() pattern (no sleeps in tests)
Running tests:
npm test # Run all tests
npx vitest # Run in watch mode
npx vitest --run # Run once (CI mode)
Lefthook Checks¶
Lefthook is configured for pre-commit and pre-push hooks (lefthook.yml):
pre-commit:
commands:
biome-format: # formats staged files, auto-stages fixes
biome-lint: # lints staged files, blocks commit on errors
no-console-log: # checks for console.log in staged files (opt-in)
pre-push:
commands:
build: # TypeScript compilation check
This ensures code quality by running:
- Formatting (priority 1): Biome auto-formats staged files and re-stages the fixes
- Linting (priority 2): Biome lints staged files — blocks commit if lint errors exist
- No Console Log: Prevents accidental
console.log(opt-in viaCHECK_CONSOLE_LOG=1) - Build (pre-push): TypeScript compilation verification before pushing
- Tests: Run in GitHub Actions only (not in git hooks)
Error Logging to New Relic¶
The application integrates with New Relic for error monitoring:
- Configuration:
newrelic.jswith license key and settings - Error Logger:
src/errorLogger.tswith Winston integration - Log Forwarding: Errors automatically forwarded to New Relic
- File Logging: Local error logs stored in
.errorLogs/directory - Queue Processing: Asynchronous error log processing
Redis Client for RBAC & Permissions¶
Redis is used for caching and session management:
- Redis Client:
src/redisClient.tswith singleton pattern - Connection Management: Automatic reconnection and error handling
- RBAC Integration: Caches user permissions and roles
- Session Storage: Stores user sessions and authentication tokens
Websocket Integration¶
The application uses Socket.IO for real-time communication with the frontend:
Deprecated (in progress): New realtime flows are being migrated to JaduSpine (Centrifugo). Keep Socket.IO usage only for legacy paths until migration is complete.
- Socket Service:
src/socketService.ts- Singleton pattern implementation - Event Definitions:
src/shared/socketEvents.ts- Centralized event constants - Authentication: JWT token verification for socket connections
- CORS Support: Configured for frontend communication
- User-based Messaging:
sendToUser(userId, event, ...)function sends messages to all socket connections for a specific user (handles multiple tabs/devices)
Available Events:
assetGenResponse: Response with generation status and results- Connection events:
connect,disconnect,error
Usage Example:
// Frontend connection
const socket = io('http://localhost:8081', {
auth: { token: 'your-jwt-token' },
transports: ['websocket', 'polling'],
});
// Listen for responses
socket.on('assetGenResponse', (response) => {
console.log('Asset generation result:', response);
});
// Backend usage - send to all user connections
socketService.sendToUser(userId, 'assetGenResponse', 200, 'Job completed', true, { job });
JaduSpine (Centrifugo) Integration¶
JaduSpine is a pub/sub messaging system built on Centrifugo for real-time backend-to-frontend communication:
- SDK:
@scenarix/jaduspine-sdk(private package) - Backend Singleton:
JaduSpineBackend- initialized once at server startup - Publishing: Backend publishes messages to user-specific channels
- Frontend: Connects via WebSocket to Centrifugo, receives messages in real-time
Initialization (in src/index.ts):
import { JaduSpineBackend } from '@scenarix/jaduspine-sdk';
// During server startup
await JaduSpineBackend.init({
apiUrl: process.env.CENTRIFUGO_API_URL!,
apiKey: process.env.CENTRIFUGO_API_KEY!,
debug: process.env.NODE_ENV === 'development',
});
Publishing Messages:
import { JaduSpineBackend, FrontendChannel, FrontendChannels } from '@scenarix/jaduspine-sdk';
// Publish to a specific user
await JaduSpineBackend.publish(new FrontendChannel(FrontendChannels.MINIMATICS, userId), { topic: 'guruResponse', data: { message: 'Hello!' } });
Environment Variables:
CENTRIFUGO_API_URL: Centrifugo HTTP API URLCENTRIFUGO_API_KEY: API key for authenticationGITHUB_PKG_TOKEN: GitHub Personal Access Token for installing private@scenarix/*packages (required fornpm install, see.npmrc)
See src/agenticGuru/io/ for the guru chat implementation using JaduSpine.
Docker (Preview Environments)¶
A multi-stage Dockerfile is provided for building and deploying preview environments via Coolify (or any container platform).
Build the image:
docker build --build-arg GITHUB_PKG_TOKEN=<your-github-pat-with-read:packages> -t studio-backend-preview .
Run locally:
docker run -p 8081:8081 --env-file .env studio-backend-preview
The app will be available at http://localhost:8081.
Notes:
- The GITHUB_PKG_TOKEN build arg is required to install private @scenarix/* packages during build. It is not present in the final image.
- Runtime env vars (MongoDB, Redis, API keys, etc.) must be injected at runtime via --env-file or the deployment platform — they are not baked into the image.
- The production image includes vips (runtime dependency for sharp).
CI / GitHub Actions¶
The repository uses GitHub Actions for continuous integration:
| Workflow | Trigger | What it does |
|---|---|---|
test.yml |
Push to main/staging, PRs targeting main/staging |
Runs Vitest, posts test results check + coverage comment on PR |
staging_to_main_validation.yml |
PR from staging → main |
Runs TypeScript build to catch type errors |
staging-to-main-pr.yml |
Weekly (Tuesday 10:30 AM IST) + manual | Auto-creates release PR from staging → main |
Test workflow outputs:
- Test Results (Check Run via dorny/test-reporter@v3) — pass/fail counts, failed test details with code annotations
- Coverage Report (PR comment via davelosert/vitest-coverage-report-action@v2) — coverage table with per-file breakdown
Requirements:
- Node 24 (matches local dev environment)
- SCENARIX_GITHUB_PKG_TOKEN secret — for installing private @scenarix/* packages
Deploy Build Commands¶
# Development
npm run dev # Start development server with nodemon
# Production
npm run build # Compile TypeScript to JavaScript
npm start # Start production server with New Relic
# Code Quality
npm run lint # Check with Biome (lint + format check)
npm run lint:fix # Auto-fix all issues
npm run format # Format codebase with Biome
npm run test # Run Vitest tests
# Setup
npm run setup # Install lefthook hooks
Linting & Code Formatting¶
The application uses Biome as an all-in-one linter and formatter:
- Config:
biome.json - Editor:
.vscode/settings.json— Biome as default formatter, format on save, organize imports on save - VS Code Extension: Install the Biome VS Code extension for in-editor linting, formatting, and auto-fix on save. See the official docs for setup instructions.
- VCS Integration: Respects
.gitignore, can process only staged/changed files
Key Rules:
- Biome recommended rules enabled
noConsole: Warns onconsole.logusage (use winston logger)noExplicitAny: Off (useanywhen needed)noUnusedImports/noUnusedVariables: Warn (auto-fixable)organizeImports: Auto-sorts imports on save and in pre-commit- TypeScript
noImplicitReturns: Enabled intsconfig.json
Commands:
npm run lint # Check entire codebase (no writes)
npm run lint:fix # Fix all auto-fixable issues
npm run format # Format entire codebase
npm run format:staged # Check + fix only staged files
npm run format:changed # Check + fix only files changed vs main
Mailer Integration¶
The application uses Resend for email delivery:
- Mailer Service:
src/mailer.tswith Handlebars templating - Email Templates: Templates in
src/emailTemplates/ - Resend Integration:
src/thirdPartyServices/resend.service.ts - Supported Emails: OTP emails, bug report notifications
Third-Party Services¶
The application integrates with multiple external services:
- AI Services: OpenAI, FalAI, xAI, Replicate
- Voice Generation: ElevenLabs
- File Storage: B2 Cloud Storage
- Email: Resend
- Monitoring: New Relic
- Project Management: Jira
- Video Processing: Vidu
- Workflow: Prefect
Bedrock Usage Notes¶
BedrockService is implemented in src/thirdPartyServices/bedrock.service.ts and called with BedrockService.generateText(...).
- Auth uses
AWS_BEARER_TOKEN_BEDROCKas a bearer token. - Bedrock model IDs are defined in
BedrockModelId(src/shared/sharedTypes.ts). - Current
BedrockModelIdvalues are inference profile ARNs (global inference profile ARNs), not plain foundation model IDs. - Requests use Bedrock Converse API:
POST /model/{modelId}/converse. - A
cachePointwithttl: "1h"is currently added in thesystemblock whensystemPromptis provided.
JSON schema output support
BedrockService.generateText supports optional jsonSchema, which is sent in Converse outputConfig.textFormat as json_schema.
Example:
const response = await BedrockService.generateText({
userPrompt: 'Generate character metadata',
systemPrompt: 'Return valid JSON only',
modelId: BedrockModelId.CLAUDE_SONNET_4_6,
jsonSchema: {
name: 'CharacterOutput',
description: 'Structured character response',
schema: {
type: 'object',
properties: {
title: { type: 'string' },
age: { type: 'number' },
},
required: ['title'],
additionalProperties: false,
},
},
});
Utility Services¶
The application provides utility services for common operations:
- Asset Scoring:
assetScoring.service.ts- AI-powered asset evaluation and scoring - Prompt Rewrite:
promptRewrite.service.ts- Intelligent prompt optimization and rewriting - Voice Generation:
voiceGen.service.ts- Text-to-speech and voice synthesis utilities
Environment Variables¶
See example in .env.local
API Endpoints¶
/api/auth/*- Authentication endpoints/api/rbac/*- Role-based access control/api/assetGen/*- Asset generation (seesrc/assetGen/README.mdfor voice settings flow)/api/stories/*- Story management/api/workbench/*- Workbench functionality/api/webhooks/*- Webhook endpoints/api/pipeline/*- Pipeline management (via Prefect)/api/bugReport/*- Bug reporting/api/imageEdit/*- Image editing/api/llmChat/*- LLM chat functionality
Contributing¶
- Follow the existing code structure (router → controller → validator → service)
- Add appropriate tests for new functionality if applicable
- Ensure all lefthook checks pass before committing
- Follow the established error logging patterns
- Update this README for significant architectural changes