Kind: Service
Source: atloria-monorepo/apps/api/src/documentation/manual-video.service.ts
ManualVideo service (D1) — the read/edit surface behind the reader's "Video" tab.
Every query is org-scoped (fail-closed): a ManualVideo carries organizationId and
is only ever returned/updated when it matches the caller's org — a missing/foreign
row is a 404, never a cross-tenant read. Editing the narration script marks the
row stale; requesting a regen enqueues a videoOnly re-render (TTS + assembly from
the cached clips) that patches the ACTIVE version in place — the video mirror of the
screenshot asset-update loop.
ManualVideoService provides the organization-scoped read and edit surface for a manual’s Video tab. It lists and retrieves manual videos, updates narration scripts, and requests video-only regeneration using cached clips; script edits mark the video as stale, while regeneration patches the active version in place.
Methods
| Method | Signature | Returns | Description |
|---|---|---|---|
listForProject | listForProject(projectId: string, user: JwtPayload) | unknown | All page videos for a project (Video tab list), newest first. |
get | get(id: string, user: JwtPayload) | unknown | One video, org-scoped (404 if missing or foreign). |
getPublicForEmbed | getPublicForEmbed(id: string) | unknown | PUBLIC render payload for the standalone /embed/video/:id page + iframe embeds. |
updateScript | updateScript(id: string, script: ManualVideoScript, user: JwtPayload) | unknown | Save an edited narration script. |
requestRegen | requestRegen(id: string, user: JwtPayload) | unknown | Request a videoOnly re-render from the edited script + cached clips. |
Dependencies
PrismaServiceQueue
Where it refuses work
ManualVideoServicestops the work withNotFoundExceptionwhen!video— “Manual video not found”.ManualVideoServicestops the work withNotFoundExceptionwhen!video || !video.videoUrl || !video.documentId— “Video not found”.ManualVideoServicestops the work withNotFoundExceptionwhen!doc— “Video not found”.ManualVideoServicestops the work withBadRequestExceptionwhen!script || typeof script !== 'object' || typeof script.steps !== 'object'— “script must be { intro?, steps: {n: text}, outro? }”.ManualVideoServicestops the work withBadRequestExceptionwhen!sourceJobId— “No source generation run found for this video — run a full generation first”.ManualVideoServicestops the work withBadRequestExceptionwhen!botPassword— “ATLORIX_BOT_PASSWORD env not set — cannot enqueue atlorix jobs without a service account …”.
When something fails
ManualVideoServicehandles failure in 1 place: it lets it reach the caller in all 1.
Diagram
mermaidsequenceDiagram participant Client participant Service as ManualVideoService participant DB as Database participant Renderer as Video Render Queue Client->>Service: updateScript(orgId, videoId, script) Service->>DB: Find video by id + organizationId alt Video missing or belongs to another org DB-->>Service: No matching row Service-->>Client: 404 Not Found else Authorized video DB-->>Service: ManualVideo Service->>DB: Update script and set stale = true Service-->>Client: Updated stale video end Client->>Service: requestRegen(orgId, videoId) Service->>DB: Find video by id + organizationId Service->>Renderer: Enqueue videoOnly render (TTS + cached clips) Renderer->>DB: Patch ACTIVE version in place Service-->>Client: Regeneration requested
Usage
tsimport { Injectable } from '@nestjs/common';
import { ManualVideoService } from './documentation/manual-video.service';
@Injectable()
export class ManualVideoController {
constructor(private readonly manualVideoService: ManualVideoService) {}
async updateNarration(
organizationId: string,
videoId: string,
script: string,
) {
const video = await this.manualVideoService.updateScript(
organizationId,
videoId,
script,
);
// The updated video is now stale and can be regenerated.
await this.manualVideoService.requestRegen(organizationId, video.id);
return video;
}
async listProjectVideos(organizationId: string, projectId: string) {
return this.manualVideoService.listForProject(organizationId, projectId);
}
}
AI Coding Instructions
- Always pass and enforce
organizationIdfor authenticated reads and mutations; missing or foreign video records must resolve as404, not authorization-specific responses. - When changing a narration
script, mark the associated video asstaleso clients can indicate that the rendered output is outdated. - Use
requestRegen()for video-only rendering flows; it should reuse cached clips and trigger TTS plus video assembly rather than a full screenshot/render pipeline. - Preserve the active-version patching behavior: completed regeneration updates the existing ACTIVE version in place.
- Use
getPublicForEmbed()only for intentionally public embed access; do not substitute it for organization-scoped internal retrieval.
Relationships
- DEPENDS_ON →
PrismaService - DEPENDS_ON →
queue
Referenced By
DocumentationModule(MODULE_PROVIDES)ManualVideoController(DEPENDS_ON)PublicManualVideoController(DEPENDS_ON)
Was this page helpful?