System Architecture
Last refreshed: 2026-05-21
Topology
Anuva CMS is a Next.js 15 App Router app with Payload CMS 3.65 embedded in the same runtime. React 19 powers the UI. Payload uses Postgres through @payloadcms/db-postgres.
Important entry points:
src/app/(frontend)/(public): public pages, auth pages, blog.src/app/(frontend)/app: authenticated app routes and server actions.src/app/(payload): Payload admin shell and generated API handlers.src/app/api: Better Auth, presentation orchestration APIs, worker render APIs, and Zoho webhook routes.src/mastra: Mastra runtime, agents, tools, workflows, memory, and TTS adapter.src/lib: shared app services, Payload helpers, auth, billing, RAG, presentation config, and Anuva contracts.
flowchart TB
subgraph next["⚛️ Next.js app runtime"]
public["🌐 Public routes"]
app["🧑💻 App routes"]
api["🔌 Route handlers"]
payloadAdmin["📦 Payload admin"]
end
app --> actions["🧱 Server actions"]
api --> services["🧰 Shared services"]
actions --> services
services --> payload["📦 Payload Local API"]
payload --> postgres["🗄️ Postgres"]
services --> mastra["🤖 Mastra runtime"]
mastra --> postgres
services --> storage["🪣 S3-compatible storage"]
services --> providers["✨ AI, email, and billing providers"]
Runtime Dependencies
- Database: Postgres via
DATABASE_URI. - Storage: S3-compatible buckets via
S3_*. - Email: Resend via
RESEND_API_KEY. - Auth: Better Auth integrated through
payload-auth. - AI: OpenAI, Google, and ElevenLabs keys are present in the active environment.
- Billing: Zoho Billing config and webhook processing.
Request Flow
- UI routes call server actions in
src/app/(frontend)/app/**/actions.ts. - Server actions call
requireAuthContextorhandleActionfromsrc/lib/server-actions.ts. - Payload Local API reads and writes workspace-scoped collections.
- Generation actions either run legacy action logic or call Mastra workflow/tool paths.
- Worker scripts pick up queued RAG and presentation generation jobs, and the external Python render worker talks to
/api/worker/v1.
sequenceDiagram
actor User
participant UI as App route
participant Action as Server action
participant Auth as Auth context
participant Payload as Payload Local API
participant Worker as Worker or Mastra
User->>UI: Submit product action
UI->>Action: Invoke action
Action->>Auth: Resolve user and workspace
Action->>Payload: Read/write scoped docs
Action->>Worker: Queue or run generation path
Worker->>Payload: Persist status and artifacts
External Render Worker
Final video rendering now has a dedicated worker-facing API under /api/worker/v1. The Next.js app
does not expose Payload collections directly to the Python worker. Instead, shared render-worker
services:
- list or claim
video_generation_jobs - build a
RenderJobPackagefrom persistedPresentationConfigPublic - issue signed asset and upload URLs against S3-compatible storage
- persist latest worker heartbeat state in
render_workers - persist append-only failure diagnostics in
render_worker_reports
flowchart LR
queue["video_generation_jobs"] --> api["/api/worker/v1"]
api --> package["RenderJobPackage"]
api --> workers["render_workers"]
api --> reports["render_worker_reports"]
package --> python["Anuva Python Server"]
python --> unity["Unity renderer"]
python --> s3["S3-compatible storage"]
Payload Relationship
Payload owns content and app data. Collections are registered in src/payload.config.ts through:
Users.AnuvaxCollections.Blog.PayloadUploads.PrivateUploads.
Payload globals are global-footer, global-terms, and global-privacy.
Mastra Relationship
src/mastra/runtime.ts creates a single Mastra instance with:
- workflow:
presentationVideoWorkflow. - agents: intent, knowledge, narrative, visual, presentation analyst/planner, director, edit, and
anuvaxTextAgent. - TTS:
anuvaxElevenLabsTts. - storage:
PostgresStoreusing the sameDATABASE_URI.
The runtime includes recovery code for missing Mastra storage tables.
Data Flow Summary
Presentation generation moves from product input to contracts, scenes, visuals, slide markup, direction, public config snapshots, audio/image tasks, and render/generation jobs. RAG ingestion moves from uploaded media or web source metadata to rag_sources, rag_chunks, and vector records in the anuvax_rag_chunks_v1 index.