Technical reference covering data models, database schema, API contracts, events, worker queues, configuration, environment variables, and integration points. Every entry below is traceable to source code in
libs/yemaya/*orapps/yemaya/*.
This document is the implementation contract for Yemaya. It defines the exact data model (table names, field types, foreign key strategies), the API surface (route files, mount paths, middleware chain), the event bus contracts (12 published events, 6 subscribed events, consumer group names), the BullMQ queue configuration (queue names, retry policies), and the environment variables required to run the API and worker processes.
Everything here is derived directly from source: the Prisma schema at
libs/yemaya/database/prisma/schema.prisma, the app entry points at
apps/yemaya/api/src/app.ts and apps/yemaya/workers/src/queues.ts, and the
contracts package at libs/contracts/src/events/yemaya.ts.
Database Configuration#
Yemaya uses a dedicated PostgreSQL database, separate from the databases of
every other Oshun domain. The Prisma schema lives at
libs/yemaya/database/prisma/schema.prisma and the generated client at
libs/yemaya/database/src/generated/client.
| Property | Value |
|---|---|
| Engine | PostgreSQL |
| ORM | Prisma (prisma-client-js generator) |
| Schema location | libs/yemaya/database/prisma/schema.prisma |
| Environment variable | YEMAYA_DATABASE_URL |
| Generated client | libs/yemaya/database/src/generated/client |
| Preview features | fullTextSearch, fullTextIndex |
Source: libs/yemaya/database/prisma/schema.prisma lines 21–30.
The schema is intentionally scoped to platform concerns. Capability-domain data lives in separate databases and is referenced by ID, not by foreign key. This means no Yemaya migration can break Isis, Hathor, Sophia, or Bellona, and vice versa:
| Domain | Database | Responsibility |
|---|---|---|
| Isis | isis |
Generation jobs, GPU execution, workflows |
| Hathor | hathor |
Worldbuilding, narrative, pre-production, scheduling |
| Sophia | sophia |
Research, knowledge, documents |
| Bellona | bellona |
Engine integration, build pipelines |
Data Models#
All models below are defined in libs/yemaya/database/prisma/schema.prisma.
Primary keys default to cuid() (@db.VarChar(25)) unless otherwise noted; the
canonical-library models (Collection, Incident, SupportCase) use uuid().
Most platform models carry createdAt, updatedAt, and a nullable deletedAt
for soft deletion.
User#
The core user account model — authentication identity, display profile, and session tracking all hang off this record.
| Field | Type | Default | Description |
|---|---|---|---|
id |
String |
cuid() |
Primary key |
email |
String |
— | Email address (unique) |
emailVerified |
DateTime? |
— | Email verification timestamp |
passwordHash |
String? |
— | Password hash |
firstName |
String? |
— | First name |
lastName |
String? |
— | Last name |
displayName |
String? |
— | Display name |
avatarUrl |
String? |
— | Avatar URL |
bio |
String? |
— | Bio text |
locale |
String |
"en" |
UI locale |
timezone |
String |
"UTC" |
Timezone |
status |
UserStatus |
ACTIVE |
Account status |
lastLoginAt |
DateTime? |
— | Last login timestamp |
Table: users Relations: accounts, sessions, memberships,
ownedProjects, projectMembers, assets, comments, activities,
notifications, preferences, apiKeys.
UserPreference#
Per-user UI and notification preferences, stored as a one-to-one extension of the User record so the core User table stays lean.
| Field | Type | Default | Description |
|---|---|---|---|
userId |
String |
— | FK to User (unique — one-to-one) |
theme |
String |
"system" |
UI theme |
compactMode |
Boolean |
false |
Compact layout flag |
notifyEmail |
Boolean |
true |
Email notification opt-in |
notifyInApp |
Boolean |
true |
In-app notification opt-in |
autoSave |
Boolean |
true |
Auto-save flag |
autoSaveInterval |
Int |
60 |
Auto-save interval (seconds) |
preferences |
Json |
{} |
Arbitrary additional preferences |
Table: user_preferences.
Account#
OAuth and social provider accounts linked to a user. A single user can have multiple OAuth accounts from different providers (Google, GitHub, etc.).
| Field | Type | Description |
|---|---|---|
userId |
String |
FK to User |
type |
String |
Account type |
provider |
String |
Provider name (google, github, etc.) |
providerAccountId |
String |
Provider-side account ID |
refreshToken |
String? |
OAuth refresh token |
accessToken |
String? |
OAuth access token |
expiresAt |
Int? |
Token expiry (epoch seconds) |
tokenType |
String? |
Token type |
scope |
String? |
Granted OAuth scopes |
idToken |
String? |
OIDC ID token |
sessionState |
String? |
Provider session state |
Unique: [provider, providerAccountId] Table: accounts.
Session and ApiKey#
These two models handle the two authentication mechanisms: browser sessions (JWT-backed, expiring) and server-to-server API keys (hashed, scoped).
| Model | Key Fields |
|---|---|
Session |
userId, token (unique), expiresAt, ipAddress, userAgent |
ApiKey |
userId, name, keyHash (unique), keyPrefix, scopes[], lastUsedAt, expiresAt |
Tables: sessions, api_keys.
Organization#
Multi-tenant organizations are the top-level billing and access boundary. Every project belongs either to an organization or directly to a user, and plan-based feature gating applies at the organization level.
| Field | Type | Default | Description |
|---|---|---|---|
name |
String |
— | Organization name |
slug |
String |
— | URL slug (unique) |
description |
String? |
— | Description |
logoUrl |
String? |
— | Logo URL |
website |
String? |
— | Website URL |
plan |
OrganizationPlan |
FREE |
Subscription plan tier |
settings |
Json |
{} |
Organization settings |
Table: organizations Relations: members, teams, projects,
invitations, subscription.
Team and Membership Models#
Teams sit between organizations and projects, providing an intermediate grouping level for large studios. The join tables below track who belongs to what and at what access level.
| Model | Key Fields | Purpose |
|---|---|---|
OrganizationMember |
organizationId, userId, role (OrganizationRole), joinedAt |
Org membership |
OrganizationInvitation |
organizationId, email, role, token (unique), expiresAt, acceptedAt |
Pending invitations |
Team |
organizationId, name, slug, description, color, iconUrl, settings |
Sub-team grouping |
TeamMember |
teamId, userId, role (TeamRole), joinedAt |
Team membership |
TeamProject |
teamId, projectId, access (ProjectAccess) |
Team-project access |
OrganizationMember is unique on [organizationId, userId]; TeamMember on
[teamId, userId]; Team on [organizationId, slug]; TeamProject on
[teamId, projectId].
Project#
The central creative container in Yemaya. A project holds all assets, scripts,
storyboards, and configuration for a production. Cross-domain capability
references (hathorWorldId, isisWorkflowIds[], sophiaPackIds[]) are stored
here as plain ID fields, not foreign keys, preserving database isolation.
| Field | Type | Default | Description |
|---|---|---|---|
name |
String |
— | Project name |
slug |
String |
— | URL slug |
description |
String? |
— | Description |
thumbnailUrl |
String? |
— | Thumbnail URL |
type |
ProjectType |
OTHER |
Production type |
status |
ProjectStatus |
DRAFT |
Lifecycle status |
visibility |
Visibility |
PRIVATE |
Access level |
organizationId |
String? |
— | FK to Organization (SetNull on delete) |
ownerId |
String |
— | FK to User (owner) |
settings |
Json |
{} |
Project settings |
metadata |
Json |
{} |
Arbitrary metadata |
hathorWorldId |
String? |
— | Cross-domain: Hathor world ID |
isisWorkflowIds |
Json |
[] |
Cross-domain: array of Isis workflow IDs |
sophiaPackIds |
Json |
[] |
Cross-domain: array of Sophia pack IDs |
Unique: [organizationId, slug] Table: projects Relations:
organization, owner, members, teams, assets, folders, tags,
activities.
Cross-Domain Reference Fields#
hathorWorldId, isisWorkflowIds[], and sophiaPackIds[] are resolved via
internal API calls (or the capability proxy), never by database foreign key, so
each domain database stays isolated.
Asset#
A digital file managed within a project's asset library. Assets carry both a
reference to object storage (storageKey) and cross-domain references into Isis
and Bellona for the generation job that produced them and the engine-processed
variant respectively.
| Field | Type | Default | Description |
|---|---|---|---|
projectId |
String |
— | FK to Project (Cascade on delete) |
folderId |
String? |
— | FK to Folder (SetNull on delete) |
creatorId |
String |
— | FK to User |
name |
String |
— | Asset name |
description |
String? |
— | Description |
type |
AssetType |
— | Asset category |
status |
AssetStatus |
DRAFT |
Review lifecycle status |
mimeType |
String? |
— | MIME type |
fileSize |
BigInt? |
— | File size in bytes |
storageKey |
String |
— | Object storage key (MinIO/S3) |
storageUrl |
String? |
— | Direct access URL |
thumbnailUrl |
String? |
— | Thumbnail URL |
previewUrl |
String? |
— | Preview URL |
metadata |
Json |
{} |
Extracted metadata |
version |
Int |
1 |
Version number |
checksum |
String? |
— | File checksum (VarChar(64)) |
isisGenerationId |
String? |
— | Cross-domain: Isis generation job ID |
bellonaAssetId |
String? |
— | Cross-domain: Bellona asset ID |
Table: assets Relations: project, folder, creator, tags
(AssetTag[]), usages (AssetUsage[]), comments.
Folder#
Hierarchical self-referential folder structure for organizing assets within a
project. The parentId self-reference creates an arbitrarily deep tree.
| Field | Type | Default | Description |
|---|---|---|---|
projectId |
String |
— | FK to Project |
parentId |
String? |
— | FK to parent Folder (FolderHierarchy self-ref) |
name |
String |
— | Folder name |
color |
String? |
— | Display color |
icon |
String? |
— | Display icon identifier |
sortOrder |
Int |
0 |
Sort position |
Table: folders.
Tagging Models#
Tags are organization-scoped and applied to both assets and projects through
join tables. The AssetUsage model tracks where an asset is referenced so
safe-to-delete analysis is always available.
| Model | Key Fields | Purpose |
|---|---|---|
Tag |
organizationId?, name, slug, color, description |
Tag definition (org-scoped) |
AssetTag |
assetId, tagId — unique [assetId, tagId] |
Asset ↔ Tag join |
ProjectTag |
projectId, tagId — unique [projectId, tagId] |
Project ↔ Tag join |
AssetUsage |
assetId, context, entityId |
Tracks where an asset is used |
Tag is unique on [organizationId, slug]. Tables: tags, asset_tags,
project_tags, asset_usages.
Comment#
Threaded comments on assets, with resolution and pinning support for formal review workflows.
| Field | Type | Default | Description |
|---|---|---|---|
assetId |
String? |
— | FK to Asset (Cascade on delete) |
authorId |
String |
— | FK to User |
parentId |
String? |
— | FK to parent Comment (CommentReplies) |
content |
String |
— | Comment content |
resolved |
Boolean |
false |
Resolution status |
pinned |
Boolean |
false |
Pinned status |
metadata |
Json |
{} |
Metadata |
Table: comments.
Activity and Notification#
Activity records form the project-level audit feed visible to team members. Notifications are per-user inbox items delivered to the UI and optionally via email or push.
| Model | Key Fields | Purpose |
|---|---|---|
Activity |
projectId?, userId, type (ActivityType), action, entityId?, details, ipAddress |
Project activity feed |
Notification |
userId, type (NotificationType), title, message?, link?, read, readAt?, metadata |
User notifications |
Tables: activities, notifications.
Canonical Library, Support, and Incident Records#
These three UUID-keyed models back cross-domain library curation and operational
support workflows. They use uuid() primary keys (rather than cuid()) to
align with cross-domain reference conventions.
Collection#
A curated library collection (@@map("collections")).
| Field | Type | Description |
|---|---|---|
slug |
String |
URL slug (unique) |
title, summary |
String |
Display title and summary |
primaryDomain, domains[] |
String |
Owning domain and additional domains |
origin, status, visibility, kind |
String |
Lifecycle/classification fields |
membershipMode |
String |
How items join (manual, smart, etc.) |
itemCount |
Int |
Number of items |
progressPercent |
Float? |
Completion percentage |
coverImageUrl |
String? |
Cover image |
lastOpenedAt, lastPublishedAt |
DateTime? |
Activity timestamps |
tags[] |
String[] |
Tags |
smartConfig |
Json? |
Smart-collection rules |
collaborators, sections, items |
Json |
Embedded collaborator/section/item data |
ownerId |
String? |
Owner (UUID) |
Incident#
An operational incident record (@@map("incidents")).
| Field | Type | Description |
|---|---|---|
incidentKey, slug |
String |
Human key and slug (both unique) |
title, summary, description |
String |
Narrative fields |
primaryDomain, domains[] |
String |
Owning + related domains |
category, severity, status, queue |
String |
Triage/classification |
blastRadius |
String |
Impact scope |
source, customerImpact |
Json |
Structured source and impact data |
declaredById, commanderId, ownerId, acknowledgedById, resolvedById, closedById |
String? |
Role assignments (UUID) |
detectedAt, declaredAt, acknowledgedAt, nextUpdateDueAt, resolvedAt, closedAt |
DateTime |
Lifecycle timestamps |
affectedResources, linkedResources, handoffs, communications, slaClocks, history |
Json |
Append-only operational logs |
mitigation, postmortem |
Json |
Mitigation and postmortem records |
tags[], metadata |
— | Tags and metadata |
SupportCase#
A customer support case (@@map("support_cases")).
| Field | Type | Description |
|---|---|---|
caseKey, slug |
String |
Human key and slug (both unique) |
title, summary, description |
String |
Narrative fields |
primaryDomain, domains[] |
String |
Owning + related domains |
kind, category, status, priority, channel, queue |
String |
Triage/classification |
requester |
Json |
Requester contact data |
openedById, assignedToId |
String? |
Role assignments (UUID) |
linkedResources, escalations, slaClocks, history |
Json |
Operational logs |
resolution, satisfaction |
Json? |
Resolution and CSAT records |
tags[], metadata |
— | Tags and metadata |
Webhooks#
Webhooks allow external systems to receive Yemaya events via HTTP. Each
Webhook configuration has a companion WebhookDelivery record for every
delivery attempt, enabling retry tracking and audit.
| Model | Key Fields | Purpose |
|---|---|---|
Webhook |
organizationId?, projectId?, name, url, secret?, events[], headers, enabled, retryCount (default 3), retryDelay (default 60), lastTriggeredAt |
Webhook configuration |
WebhookDelivery |
webhookId, event, payload, status (WebhookDeliveryStatus), statusCode?, response?, errorMessage?, attempts, nextRetryAt?, deliveredAt? |
Delivery tracking |
Tables: webhooks, webhook_deliveries.
Subscription and Billing#
The billing model tracks the organization's active subscription plan, invoices,
and credit balance. UsageRecord provides per-metric metering for credit-based
services like AI generation.
| Model | Key Fields | Purpose |
|---|---|---|
Subscription |
organizationId (unique), plan (SubscriptionPlan), status (SubscriptionStatus), stripeCustomerId?, stripeSubId?, currentPeriodStart/End, cancelAtPeriodEnd, trialEndsAt |
Organization billing |
Invoice |
subscriptionId, stripeInvoiceId?, number?, status (InvoiceStatus), amount, currency (default "usd"), periodStart/End, paidAt?, dueDate?, pdf? |
Invoice records |
InvoiceLineItem |
invoiceId, description, quantity, unitAmount, amount |
Line-item detail |
UsageRecord |
subscriptionId, metric, quantity, timestamp, metadata |
Usage metering |
CreditBalance |
subscriptionId (unique), balance, currency |
Credit wallet |
CreditTransaction |
creditBalanceId, type (CreditTransactionType), amount, description?, referenceId? |
Credit movements |
Tables: subscriptions, invoices, invoice_line_items, usage_records,
credit_balances, credit_transactions.
Plugin Marketplace#
The plugin data model stores the plugin registry, version history, per-scope installation records, and community reviews.
| Model | Key Fields | Purpose |
|---|---|---|
Plugin |
slug (unique), name, shortDescription?, description?, category (PluginCategory), iconUrl?, coverUrl?, authorName, authorUrl?, repositoryUrl?, documentationUrl?, supportUrl?, license?, pricing (PluginPricing), price?, status (PluginStatus), featured, verified, downloadCount, rating?, reviewCount |
Marketplace plugin |
PluginVersion |
pluginId, version, changelog?, minAppVersion?, maxAppVersion?, downloadUrl, checksum?, fileSize?, published — unique [pluginId, version] |
Version record |
PluginInstallation |
pluginId, organizationId?, projectId?, userId?, version, enabled, settings — unique [pluginId, organizationId, projectId, userId] |
Install record |
PluginReview |
pluginId, userId, rating (SmallInt), title?, content?, helpful, verified — unique [pluginId, userId] |
Community review |
Tables: plugins, plugin_versions, plugin_installations,
plugin_reviews.
AuditLog#
The AuditLog model captures an immutable before/after snapshot of every
audited action for GDPR and SOC2 compliance reporting.
| Field | Type | Description |
|---|---|---|
organizationId |
String? |
Organization scope |
userId |
String? |
Actor user ID |
action |
String |
Action performed |
entityType |
String? |
Entity type (Project, Asset, etc.) |
entityId |
String? |
Entity ID |
oldValues |
Json? |
Previous state snapshot |
newValues |
Json? |
New state snapshot |
ipAddress |
String? |
Client IP address |
userAgent |
String? |
Client user agent |
metadata |
Json |
Additional metadata |
Table: audit_logs.
Key Enumerations#
All Prisma enums below are defined in
libs/yemaya/database/prisma/schema.prisma. These values are the only valid
states for their respective fields — the database and Prisma client both enforce
membership.
UserStatus#
ACTIVE, INACTIVE, SUSPENDED, PENDING_VERIFICATION
OrganizationPlan / SubscriptionPlan#
FREE, STARTER, PROFESSIONAL, ENTERPRISE (two separate enums with the
same members).
OrganizationRole#
OWNER, ADMIN, MEMBER, VIEWER
TeamRole#
LEAD, MEMBER
ProjectAccess#
VIEW, EDIT, ADMIN
ProjectType#
FILM, GAME, ANIMATION, COMMERCIAL, MUSIC_VIDEO, DOCUMENTARY, OTHER
ProjectStatus#
DRAFT, ACTIVE, REVIEW, COMPLETED, ARCHIVED
ProjectRole#
OWNER, ADMIN, EDITOR, CONTRIBUTOR, VIEWER
Visibility#
PRIVATE, TEAM, ORGANIZATION, PUBLIC
AssetType (15 values)#
IMAGE, VIDEO, AUDIO, MODEL_3D, DOCUMENT, SCRIPT, STORYBOARD,
CHARACTER_DESIGN, ENVIRONMENT_DESIGN, ANIMATION, VFX, MATERIAL,
TEXTURE, FONT, OTHER
AssetStatus#
DRAFT, PROCESSING, REVIEW, APPROVED, REJECTED, ARCHIVED
SubscriptionStatus#
ACTIVE, PAST_DUE, CANCELLED, TRIALING, PAUSED
InvoiceStatus#
DRAFT, OPEN, PAID, VOID, UNCOLLECTIBLE
CreditTransactionType#
PURCHASE, USAGE, REFUND, BONUS, ADJUSTMENT, EXPIRATION
ActivityType#
PROJECT, ASSET, USER, TEAM, ORGANIZATION, SYSTEM
NotificationType#
MENTION, COMMENT, INVITATION, ASSIGNMENT, APPROVAL, SYSTEM, ALERT
WebhookDeliveryStatus#
PENDING, SUCCESS, FAILED, RETRYING
PluginCategory#
GENERATION, EDITING, EXPORT, INTEGRATION, UTILITY, COLLABORATION,
ANALYTICS, AUTOMATION, OTHER
PluginPricing#
FREE, PAID, FREEMIUM, SUBSCRIPTION
PluginStatus#
PENDING, APPROVED, REJECTED, PUBLISHED, DEPRECATED, REMOVED
Library-Level Enumerations#
Several Yemaya libraries define their own typed constant objects (TypeScript
as const unions, not Prisma enums). These live inside individual library
packages rather than in the database schema.
@yemaya/canon-enforcement (libs/yemaya/canon-enforcement/src/types.ts):
These constants drive the tier hierarchy and workflow states used by the canon management system to classify established creative facts.
| Constant | Values |
|---|---|
CANON_TIER |
primary, secondary, tertiary, non-canon |
CANON_STATUS |
verified, pending, conflict, retconned |
STYLE_DOMAIN |
visual, writing, dialogue, audio, ui, animation, cinematography |
CONSISTENCY_LEVEL |
perfect, high, moderate, low, inconsistent |
@yemaya/human-override (libs/yemaya/human-override/src/types.ts):
These constants define the types of human interventions available, the conditions that trigger automatic escalation, and the recovery lifecycle.
| Constant | Values |
|---|---|
OVERRIDE_TYPE |
emergency-stop, decision-injection, constraint-override, quality-override, budget-override, timeline-override, scope-override |
ESCALATION_CATEGORY |
quality-failure, budget-overrun, timeline-slip, repeated-failure, creative-deadlock, ethical-concern, legal-compliance, security-concern, system-health |
RECOVERY_STATUS |
pending, in-progress, completed, failed |
@yemaya/production-verification
(libs/yemaya/production-verification/src/types.ts):
These constants model the asset completeness taxonomy and the four-state sign-off workflow used by pre-delivery verification checks.
| Constant | Values |
|---|---|
ASSET_CATEGORY |
visual, audio, narrative, gameplay, ui, localization, accessibility, documentation, marketing, certification |
COMPLETENESS_STATUS |
complete, partial, missing, not-applicable |
BENCHMARK_RESULT |
exceeds, meets, below, fails |
SIGNOFF_STATUS |
pending, approved, approved-with-exceptions, rejected |
Pipeline Schema#
The orchestration pipeline model is defined as Zod schemas in
libs/yemaya/orchestration/src/schemas/pipeline.ts. These schemas are the
runtime contract: every pipeline created or received by the orchestration layer
is validated against them.
Pipeline#
A pipeline is the top-level execution unit: it holds a list of steps with explicit dependencies, a progress counter, and the variables injected at runtime.
| Field | Type | Description |
|---|---|---|
id |
uuid |
Pipeline ID |
projectId |
uuid |
Owning project |
name |
string (1–255) |
Pipeline name |
description |
string (≤2000, optional) |
Description |
status |
PipelineStatus |
Lifecycle status |
steps |
PipelineStep[] |
Ordered step list |
progress |
number (0–100, default 0) |
Progress percentage |
currentStepId |
uuid? |
Currently executing step |
variables |
Record<string, unknown> |
Execution context variables |
stopOnError |
boolean (default true) |
Halt pipeline on step failure |
errorMessage |
string? |
Pipeline-level error |
createdBy |
uuid |
Creator user ID |
PipelineStatus: draft, ready, running, paused, completed,
failed, cancelled.
PipelineStep#
Each step in a pipeline carries its own retry configuration, timeout, and
dependency list. The dependsOn field specifies which step IDs must complete
before this step can start, enabling the orchestrator to build a correct
topological execution order.
| Field | Type | Default | Description |
|---|---|---|---|
id |
uuid |
— | Step ID |
name |
string (1–255) |
— | Step name |
type |
StepType |
— | Step type (see below) |
status |
StepStatus |
— | Step status |
config |
Record<string, unknown> |
{} |
Step configuration |
dependsOn |
uuid[] |
[] |
Prerequisite step IDs |
condition |
string? |
null |
Conditional-run expression |
maxRetries |
number (0–10) |
3 |
Retry limit |
retryCount |
number |
0 |
Retries used |
retryDelay |
number (ms) |
5000 |
Delay between retries |
timeout |
number (ms) |
300000 |
Step timeout |
inputs, outputs |
Record<string, unknown> |
{} |
Step I/O payloads |
error |
string? |
null |
Step error |
queuedAt, startedAt, completedAt |
date? |
null |
Timing |
StepStatus: pending, queued, running, completed, failed,
skipped, cancelled.
StepType (40 values)#
The StepType enum defines every action a pipeline can request. Values are
namespaced by domain so it is always clear which system will execute a given
step. The 40 values span generation (Isis), research (Sophia), worldbuilding
(Hathor), engine integration (Bellona), DCC orchestration (MCP), studio actions
(Yemaya), and data-flow utilities.
| Group | Step Types |
|---|---|
| Isis (Generation) | isis:generate_image, isis:generate_3d, isis:generate_audio, isis:generate_video, isis:inpaint, isis:upscale, isis:style_transfer |
| Sophia (Research) | sophia:research, sophia:analyze, sophia:summarize, sophia:embed |
| Hathor (Worldbuild) | hathor:create_character, hathor:create_location, hathor:compile_lore, hathor:generate_dialogue |
| Bellona (Build) | bellona:export, bellona:build, bellona:sync, bellona:convert |
| MCP DCC orchestration | mcp:execute_dcc, mcp:cross_dcc_transfer, mcp:material_consistency, mcp:animation_round_trip, mcp:production_status, mcp:resource_schedule, mcp:voice_trigger, mcp:voice_steer, mcp:voice_review, mcp:voice_progress |
| Yemaya (Studio) | yemaya:review, yemaya:approve, yemaya:publish, yemaya:notify |
| Utility | transform, filter, merge, split, conditional, loop, parallel, wait |
PipelineTemplate#
A PipelineTemplate is a runtime-state-free pipeline definition — it stores the
step graph, variable schema, and metadata but no execution state. Templates can
be public (shared across the platform), built-in (shipped with Yemaya), or
private to an organization.
A reusable, runtime-state-free pipeline definition: id, name,
description?, category, stepTemplates[] (name/type/config/
dependsOn only), variables (typed schema with type ∈
string/number/boolean/array/object, optional default, required
flag), isPublic, isBuiltIn, tags[], usageCount.
Built-In Pipelines#
@yemaya/autonomous-pipelines exports factory functions that produce
CreatePipelineInput objects. These are the ready-made production pipeline
definitions shipped with Yemaya:
- Film pipeline (
createFilmPipeline) —FilmPipelineStage=pre_production,world_building,asset_generation,scene_assembly,animation,rendering,post_production,export. Steps cover script analysis (sophia:analyze), visual research (sophia:research), character/ location creation (hathor:*), 3D asset generation (isis:generate_3d), audio (isis:generate_audio), scene assembly / camera / lighting / render / composite / export viamcp:execute_dccagainst Blender and DaVinci, and a closingyemaya:reviewstep. - Game pipeline (
createGamePipeline) —libs/yemaya/autonomous-pipelines/src/pipelines/game.ts. - Curation and QC pipelines —
libs/yemaya/autonomous-pipelines/src/pipelines/curation.tsandqc.ts.
The film pipeline's qualityPreset accepts draft, preview, production,
final.
API Surface#
The Yemaya REST API is an OpenAPIHono (@hono/zod-openapi) application
defined in apps/yemaya/api/src/app.ts, listening on port 3000 by default.
Routes respond with RFC 7807 problem details on error
(problemDetailsErrorHandler). The OpenAPI document is served at
GET /openapi.json; interactive docs at GET /docs (Swagger UI),
GET /reference and GET /playground (Scalar).
Route Mounting#
app.ts makes 30 app.route() calls across 24 distinct base paths. Several
base paths host multiple routers (for example /v1/schedules and
/v1/budgets), and one router file (websocket.ts) provides the /ws upgrade
endpoint. The table below maps every router file to its mount path and describes
its responsibility:
Router file (in apps/yemaya/api/src/routes/) |
Mount path | Description |
|---|---|---|
auth.ts |
/v1/auth |
Login, registration, OAuth, sessions, API keys |
users.ts |
/v1/users |
User profiles, preferences, profile export |
projects.ts |
/v1/projects |
Project CRUD, members, comments, activity, archive/restore |
assets.ts |
/v1/projects/:projectId/assets |
Asset upload, versioning, folders, metadata |
organizations.ts |
/v1/organizations |
Organizations, teams, invitations, members, audit logs |
scripts.ts |
/v1/scripts |
Scripts, scenes, script elements, story beats, characters |
storyboards.ts |
/v1/storyboards |
Storyboards, panels, annotations, panel layers |
schedules.ts |
/v1/schedules |
Production schedules, milestones, schedule items, resources |
schedule-optimization.ts |
/v1/schedules |
AI schedule optimization, critical path, suggestions |
schedule-sharing.ts |
/v1/schedules |
Schedule sharing and multi-format export (PDF/CSV/ICS/XLSX/HTML/XML) |
crew.ts |
/v1/crew |
Crew, skills, availability, assignments, role definitions |
call-sheets.ts |
/v1/call-sheets |
Call sheet generation, entries, distribution, export |
location.ts |
/v1/locations |
Location scouting, contacts, permits, checklists, media, weather, maps |
budgets.ts |
/v1/budgets |
Budgets, categories, expenses, purchase orders, invoices |
budget-line-items.ts |
/v1/budgets |
Line items with variance, forecasting, bulk ops, import/export |
budget-templates.ts |
/v1/budget-templates |
Industry-standard and custom budget templates |
cost-prediction.ts |
/v1/budgets |
ML cost prediction, trend analysis, scenario planning |
variance-tracking.ts |
/v1/budgets |
EVM metrics, thresholds, alerts, approvals, trend analysis |
multi-currency.ts |
/v1/currency |
Exchange rates, conversions, FX impact, hedges |
collaboration.ts |
/v1/collaboration |
Collaboration sessions, threads, reviews, locks, presence |
websocket.ts |
/ws |
WebSocket upgrade and real-time event channels |
agent-management.ts |
/v1/agents |
Agent registration, commands, tasks, pools, messaging, metrics |
plugins.ts |
/v1/plugins |
Plugin installation, hooks, marketplace browse |
webhooks.ts |
/v1/webhooks |
Webhook config, deliveries, events, statistics |
search.ts |
/v1/search |
Unified search, saved searches, search history, index admin |
analytics.ts |
/v1/analytics |
Metrics, events, funnels, cohorts, dashboards, reports |
score-editor.ts |
/v1/score-editor |
Entitlement-gated AAA scene-score editor BFF surface |
admin.ts |
/v1/admin |
System administration, users, moderation, feature flags, jobs |
versioning.ts |
/v1/versions |
API version info, migration guides, deprecation status |
capabilities.ts |
/v1/capabilities |
Reverse proxy to Isis, Sophia, Hathor, Bellona domain APIs |
Engine integrations (Blender, Godot, Unreal, Houdini, DaVinci) and AI generation (image/3D/audio/video) are not separate Yemaya route files. They are reached either through the
/v1/capabilities/{domain}/...proxy or through pipeline steps (isis:*,bellona:*,mcp:execute_dcc).
Project Endpoints (representative)#
projects.ts defines the following createRoute operations. The pattern
follows OpenAPIHono convention and every operation gets a unique operationId
in the generated OpenAPI document:
| Method | Path | Operation |
|---|---|---|
GET |
/ |
List projects |
POST |
/ |
Create project |
GET |
/{id} |
Get project |
PATCH |
/{id} |
Update project |
DELETE |
/{id} |
Delete project |
POST |
/{id}/archive |
Archive project |
POST |
/{id}/restore |
Restore project |
POST |
/{id}/duplicate |
Duplicate project |
POST |
/{id}/thumbnail |
Upload project thumbnail |
GET |
/{id}/members |
List members |
POST |
/{id}/members |
Add member |
PATCH |
/{id}/members/{userId} |
Update member role |
DELETE |
/{id}/members/{userId} |
Remove member |
POST |
/{id}/leave |
Leave project |
GET |
/{id}/comments |
List comments |
POST |
/{id}/comments |
Create comment |
PATCH |
/{id}/comments/{commentId} |
Update comment |
The remaining routers follow the same Zod-OpenAPI createRoute pattern; the
OpenAPI tag list in app.ts enumerates the full set of resource groups
(Authentication, Sessions, API Keys, Users, Organizations, Teams, Projects,
Assets, Scripts, Scenes, Characters, Worlds, Storyboards, Schedules, Budgets,
Crew, Call Sheets, Locations, Collaboration, Agents, Plugins, Webhooks, Search,
Analytics, Admin, API Versioning, Capabilities, WebSocket events, and more).
Score Editor Entitlement Gate#
The score-editor BFF surface is tier-gated to prevent free or starter plan users
from accessing AAA features. score-editor.ts resolves an EditorTier from
request headers (x-yemaya-tier ∈ contemplative / aaa-creator / operator)
and a roles list (x-yemaya-roles / x-user-role). Access to the scene-score
editor requires the aaa-creator or operator tier, or an admin role.
Health and Metrics#
These endpoints do not require authentication and are used by load balancers, monitoring systems, and CI/CD pipelines:
| Endpoint | Description |
|---|---|
GET /health |
Liveness summary with version |
GET /health/ready |
Readiness — checks database, cache, storage (503 if degraded) |
GET /health/live |
Minimal liveness probe |
GET /metrics |
Performance metrics (JSON or Prometheus based on Accept) |
GET /metrics/validation |
Benchmark validation endpoint |
Middleware Chain#
The middleware chain runs in a fixed order on every request. Understanding this order is important when debugging: each middleware may short-circuit the chain if it rejects a request.
app.ts applies, in order: request ID (X-Request-ID), request context (async
local storage), performance metrics (p95 target 100 ms), RFC 7807 error handler,
security headers (CSP, HSTS, frame options), CORS (origin allowlist), request
logging (non-production only), gzip compression, server timing, input
sanitization (/v1/*), asset metadata sanitization (/v1/assets/*), rate
limiting (/v1/*), and API versioning (path + header, header
X-API-Version). Additional middleware modules in
apps/yemaya/api/src/middleware/ include circuit-breaker.ts,
gdpr-compliance.ts, soc2-compliance.ts, and proxy-auth.ts.
Event Contracts#
Yemaya publishes and consumes events via @oshun/event-bus, which is
Redis-backed — it uses ioredis for Redis pub/sub fan-out plus TTL-bounded
keys for replay, durable sorted sets for delayed/retried delivery, and consumer
groups for at-most-once delivery. It is not Kafka. (Source:
libs/shared/event-bus/src/event-bus.ts, module header and
import { Redis } from 'ioredis'.)
The API server initializes the event bus with keyPrefix: 'oshun:events',
persistence: true, eventTtl: 86400 (24 h), exponential retry
(maxAttempts: 3), and a 7-day dead-letter retention
(apps/yemaya/api/src/index.ts).
Events Published by Yemaya#
YemayaEventTypes is defined in libs/contracts/src/events/yemaya.ts and is
the canonical source of published event names. Publishing is handled by
YemayaEventPublisher
(libs/yemaya/event-publisher/src/yemaya-event-publisher.ts), which exposes a
typed method per event and fails soft — a publish error is logged but does not
break the request flow. Each payload has a corresponding Zod schema in
libs/contracts/src/events/yemaya.ts.
The 12 events and their default notification targets are:
| Event | Constant | Default targets |
|---|---|---|
yemaya.project.created |
PROJECT_CREATED |
Hathor, Isis |
yemaya.project.updated |
PROJECT_UPDATED |
— |
yemaya.project.archived |
PROJECT_ARCHIVED |
Hathor, Isis, Bellona |
yemaya.member.joined |
MEMBER_JOINED |
— |
yemaya.member.left |
MEMBER_LEFT |
— |
yemaya.asset.uploaded |
ASSET_UPLOADED |
Isis, Bellona |
yemaya.asset.processed |
ASSET_PROCESSED |
— |
yemaya.asset.approved |
ASSET_APPROVED |
Isis, Bellona |
yemaya.asset.rejected |
ASSET_REJECTED |
— |
yemaya.comment.created |
COMMENT_CREATED |
— |
yemaya.comment.resolved |
COMMENT_RESOLVED |
— |
yemaya.session.joined |
SESSION_JOINED |
Bellona |
Events Consumed by Yemaya#
YEMAYA_SUBSCRIPTIONS in libs/yemaya/event-handlers/src/index.ts is the
canonical list of subscribed events. Handlers run under the consumer group
yemaya-api (set by the API server) or yemaya-handlers (default). Each
handler updates the Yemaya project state in response to a completed action in a
capability domain.
The 6 subscribed events and their handlers are:
| Event | Source | Handler | Concurrency |
|---|---|---|---|
isis.asset.generated |
Isis | handleIsisAssetGenerated |
10 |
isis.job.failed |
Isis | handleIsisJobFailed |
5 |
sophia.document.ingested |
Sophia | handleSophiaDocumentIngested |
5 |
hathor.world.published |
Hathor | handleHathorWorldPublished |
3 |
bellona.build.completed |
Bellona | handleBellonaBuildCompleted |
3 |
bellona.export.ready |
Bellona | handleBellonaExportReady |
10 |
Worker Queues#
Background job processing uses BullMQ over Redis. Queue names and worker types
are defined in apps/yemaya/workers/src/queues.ts and
apps/yemaya/workers/src/config.ts.
Per the queues.ts header comment, capability-domain execution queues live with
their owning domains (Isis owns generative/3D execution; Bellona owns media,
render, export, and engine execution). Yemaya workers only coordinate those
queues and process studio-level events.
Queues (QUEUE_NAMES)#
Each queue has its own retry and backoff policy tuned to the expected job duration. Notification retries are faster (short backoff, 5 attempts) while pipeline orchestration jobs are slower and less likely to benefit from rapid retries.
| Queue | Default attempts | Backoff (initial) | Purpose |
|---|---|---|---|
yemaya:notification |
5 | 1 s exponential | Email, webhook, push, and digest delivery |
yemaya:rendering |
3 | 5 s exponential | Rendering orchestration |
yemaya:export |
3 | 5 s exponential | Export orchestration |
yemaya:pipeline |
2 | 10 s exponential | Pipeline orchestration |
yemaya:event |
3 | 2 s exponential | Cross-domain event consumption |
Worker Processes#
Worker implementations in apps/yemaya/workers/src/workers/:
notification-worker.ts, rendering-orchestration-worker.ts,
export-orchestration-worker.ts, pipeline-orchestration-worker.ts,
event-consumer.ts.
The WORKER_TYPE value (parsed from a --worker= CLI argument; defaults to
all) selects which worker(s) run. Valid values from the config Zod enum:
all, notification, rendering, export, pipeline, event-consumer,
orchestration. Concurrency is set via WORKER_CONCURRENCY (1–100, default 5).
Notification Job Types#
The notification queue handles four job types dispatched under different delivery channels. These job type strings are the discriminant used inside the notification worker to route each job to the right delivery path:
notification.send-email, notification.send-webhook,
notification.send-push, notification.digest.
Environment Variables#
API Server (apps/yemaya/api)#
| Variable | Default | Purpose |
|---|---|---|
PORT |
3000 |
HTTP listen port |
HOST |
0.0.0.0 |
HTTP bind address |
REDIS_URL |
redis://localhost:6379 |
Event bus Redis connection |
YEMAYA_DATABASE_URL |
— | PostgreSQL connection (Prisma datasource) |
NODE_ENV |
— | development / production / test |
ALLOWED_ORIGINS |
— | Comma-separated CORS origin allowlist (production) |
YEMAYA_EVENTS_ENABLED |
true |
Set to false to disable event publishing |
In production, CORS defaults to https://yemaya.io, https://app.yemaya.io,
https://api.yemaya.io plus any ALLOWED_ORIGINS entries.
Workers (apps/yemaya/workers)#
| Variable | Default | Purpose |
|---|---|---|
REDIS_HOST |
localhost |
Redis host |
REDIS_PORT |
6379 |
Redis port |
REDIS_PASSWORD |
— | Redis password |
REDIS_DB |
0 |
Redis database index |
WORKER_CONCURRENCY |
5 |
Concurrency per worker |
WORKER_JOB_TIMEOUT_MS |
300000 |
Job timeout |
WORKER_STALLED_INTERVAL |
30000 |
Stalled-job check interval |
WORKER_MAX_STALLED_COUNT |
3 |
Max stalled count before fail |
DATABASE_URL |
postgresql://yemaya:yemaya@localhost:5432/yemaya |
PostgreSQL connection |
MINIO_ENDPOINT |
localhost |
MinIO host |
MINIO_PORT |
9000 |
MinIO port |
MINIO_ACCESS_KEY |
minioadmin |
MinIO access key |
MINIO_SECRET_KEY |
minioadmin |
MinIO secret key |
MINIO_USE_SSL |
false |
MinIO TLS flag |
LOG_LEVEL |
info |
Log level |
LOG_PRETTY |
non-production | Pretty-print logs |
The worker type is selected by a --worker=<type> process argument.
Integration Points#
Storage#
Asset files are stored in MinIO (development) or S3-compatible storage
(production). Each Asset row references storage by storageKey; storageUrl
holds a direct (pre-signed in production) access URL. The API's storage client
lives in apps/yemaya/api/src/services/storage-client.ts and
storage-utils.ts; chunked uploads are handled by chunked-upload.ts.
Authentication#
Yemaya supports three authentication mechanisms, all registering as OpenAPI
security schemes in app.ts:
- JWT Bearer tokens — registered OpenAPI security scheme
bearerAuth(http/bearer/JWT). Obtained via login or OAuth. - API keys — registered scheme
apiKey, headerX-API-Key, for server-to-server access. Backed by theApiKeymodel (hashedkeyHash,keyPrefix,scopes[]). - OAuth 2.0 — social login; provider records in the
accountstable. API OAuth logic inapps/yemaya/api/src/services/oauth.ts. - The
@yemaya/authlibrary provides JWT and session primitives.
Capability Domain Proxy#
The capabilities proxy is the synchronous integration path to the four capability domains. It handles authentication, circuit-breaking, and health checking so that individual feature routes do not need to implement these concerns.
apps/yemaya/api/src/routes/capabilities.ts plus
apps/yemaya/api/src/services/proxy.ts implement a reverse proxy to the four
capability domains. A CapabilityDomain request is forwarded with service
headers built from the caller's proxy-auth claims; proxy-auth.ts middleware
gates access. The proxy includes circuit-breaker protection and health checks
(OpenAPI tag Capabilities - Health).
Cross-Domain References#
The Yemaya database stores only lightweight IDs pointing into other domain
databases (Project.hathorWorldId, Project.isisWorkflowIds[],
Project.sophiaPackIds[], Asset.isisGenerationId, Asset.bellonaAssetId).
Resolution happens at query time through internal service calls or the
capability proxy — never through SQL joins.
Real-Time Collaboration#
WebSocket connections terminate at /ws on the same Hono process as the REST
API (apps/yemaya/api/src/routes/websocket.ts,
apps/yemaya/api/src/websocket/). The @yemaya/collaboration library provides
the Yjs-CRDT sync, presence, and cursor logic. Presence data is ephemeral and is
not persisted to PostgreSQL.
Webhook Delivery#
Webhook delivery runs asynchronously through the BullMQ notification queue. Each
configured Webhook row is delivered by the notification worker
(notification.send-webhook job). Each attempt creates a WebhookDelivery row;
failures retry with exponential backoff. Webhook.retryCount defaults to 3 and
retryDelay to 60 seconds. Delivery status follows WebhookDeliveryStatus:
PENDING → SUCCESS | FAILED → RETRYING → ….
Authentication and Security#
All API routes are protected by the layered middleware described in the Middleware Chain section. The key security rules are:
- All
/v1/*routes pass through input sanitization (XSS / SQL / command injection protection) and rate limiting; documentation, health, and metrics endpoints are exempt from rate limiting. - Security headers: Content-Security-Policy,
Strict-Transport-Security(max-age=31536000; includeSubDomains),X-Content-Type-Options: nosniff,X-Frame-Options: DENY,X-XSS-Protection, andReferrer-Policy: strict-origin-when-cross-origin. - Compliance middleware (
gdpr-compliance.ts,soc2-compliance.ts) applies audit logging uniformly; theAuditLogmodel captures actor, action, entity, before/after snapshots, IP, and user agent. - Errors are RFC 7807 problem details with a propagated
requestId.
Acceptance Criteria#
A Yemaya deployment is correct when all of the following conditions hold simultaneously. These criteria are the observable contract between the specifications and a running system:
- Schema parity — the running database matches
libs/yemaya/database/prisma/schema.prisma;GET /health/readyreports the database check healthy. - API contract —
GET /openapi.jsonreturns a valid OpenAPI 3.1 document covering all 30 mounted route operations; every operation has a uniqueoperationId. - Event bus — the API logs the count of active event subscriptions on
startup; all 6 entries of
YEMAYA_SUBSCRIPTIONSsubscribe successfully, and the bus connects to Redis with prefixoshun:events. - Workers — each BullMQ queue in
QUEUE_NAMESis created with its configured retry/backoff policy; the selectedWORKER_TYPEstarts without error. - Pipeline validity — pipelines created from
@yemaya/autonomous-pipelinesfactories validate againstPipelineSchema; every steptypeis a member of the 40-valueStepTypeenum. - Cross-domain isolation — no foreign keys exist from the Yemaya database into Isis/Hathor/Sophia/Bellona databases; all such references are stored as ID columns and resolved over the network.
- Capability proxy —
/v1/capabilities/{domain}/...forwards to the configured domain API, with circuit-breaker protection and a passing health check. - Compliance — GDPR/SOC2 middleware records an
AuditLogentry for audited actions; problem-details responses carry arequestId.