cc89415a29
One "Queue Export" click now renders the EXR sequence, then rebuilds the shot headlessly with the studio slate/overlay template to produce the delivery MOV and review MP4. Implements RenderPipeline2 phases 1-2 plus the preview stage. Server: - New models Export, RenderJob, ExportEvent, Machine, WorkerHeartbeat, plus Project.deliveryConfig and per-submission slate fields (Export.vfxScope, Export.submissionNote, inherited from the shot's previous export). Both migrations are purely additive; no existing column is touched. - lib/render-pipeline: server-enforced state machine, transactional version increment with supersede, atomic FOR UPDATE SKIP LOCKED claim gated by machine availability windows, and a lease reaper run from instrumentation.ts. - /api/ext/* endpoints for the panel and workers; session-auth mirrors under /api/render and /api/machines for the web UI. - Pipeline pages: render queue, export detail, machine monitoring, plus an Exports tab on shot detail. RenderWorker (.NET 8 Windows service, new): - Registration, heartbeat as cancel channel, claim loop, aerender runner with progress parsing and stall watchdog, crash recovery and disk-spooled reporting that survives server downtime. - Preview stage: headless AE assembles the preview comp into a throwaway AEP with both output modules queued, then a single aerender pass renders them. Preview jobs are not claimed while an interactive AE session is open, so an artist's project is never taken over. AE panel: Queue Export with live status polling, urgent flag, retry, and the VFX Scope / Submission Note fields. Every existing panel action is unchanged. Preview chaining ships disabled behind SystemConfig preview.enabled. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
754 lines
22 KiB
Markdown
754 lines
22 KiB
Markdown
# Technical Architecture Report (Current State)
|
|
|
|
Date: 2026-07-31
|
|
Scope: Current implementation only (no redesign suggestions)
|
|
|
|
---
|
|
|
|
## 1. Database
|
|
|
|
Authoritative schema source: [prisma/schema.prisma](prisma/schema.prisma)
|
|
|
|
### Full Prisma Schema
|
|
The full schema is defined in [prisma/schema.prisma](prisma/schema.prisma).
|
|
|
|
### Models related to requested domains
|
|
|
|
- Users/Auth
|
|
- User
|
|
- Account
|
|
- Session
|
|
- VerificationToken
|
|
- ClientAccess
|
|
- Projects/Episodes
|
|
- Project
|
|
- EpisodeDueDate
|
|
- Client
|
|
- Shots/Tasks/Versions/Reviews
|
|
- Shot
|
|
- ShotGroup
|
|
- Task
|
|
- Version
|
|
- Comment
|
|
- CommentReply
|
|
- Annotation
|
|
- Approval
|
|
- ReviewSession
|
|
- Files/Storage
|
|
- FootagePlate
|
|
- ShotReference
|
|
- SystemConfig
|
|
- Delivery/Export adjacent
|
|
- Shot fields: highResKey, highResFilename, exrOutput, shotVersion
|
|
- Version fields: fileUrl, fileName, proxyUrl, thumbnailUrl, posterUrl
|
|
|
|
### Relationship summary
|
|
|
|
- Client 1:N Project
|
|
- Project 1:N Shot
|
|
- Project 1:N Task
|
|
- Project 1:N ReviewSession
|
|
- Project 1:N EpisodeDueDate
|
|
- Shot 1:N Task
|
|
- Shot 1:N Version
|
|
- Shot 1:N FootagePlate
|
|
- Shot 1:N ShotReference
|
|
- Task 1:N Version
|
|
- Version 1:N Comment
|
|
- Version 1:N Annotation
|
|
- Version 1:N Approval
|
|
- Comment 1:N CommentReply
|
|
- User has many assigned/created entities across shots, tasks, versions, comments, approvals
|
|
|
|
### Existing status enums
|
|
|
|
From [prisma/schema.prisma](prisma/schema.prisma):
|
|
|
|
- ProjectStatus: ACTIVE, ON_HOLD, COMPLETED, ARCHIVED
|
|
- ShotStatus: WAITING, IN_PROGRESS, INTERNAL_REVIEW, READY_FOR_CLIENT, CLIENT_REVIEW, REVISIONS, COMPLETE
|
|
- ShotApprovalStatus: PENDING, INTERNALLY_APPROVED, CLIENT_APPROVED
|
|
- TaskStatus: TODO, IN_PROGRESS, INTERNAL_REVIEW, CLIENT_REVIEW, CHANGES, DONE
|
|
- ApprovalStatus: PENDING_REVIEW, APPROVED, REJECTED, NEEDS_CHANGES
|
|
- ReviewStatus: PENDING, INTERNAL_APPROVED, CLIENT_APPROVED, NEEDS_CHANGES, FINAL_APPROVED
|
|
|
|
Notes:
|
|
- There is no dedicated Delivery model.
|
|
- There is no dedicated Export model.
|
|
- Delivery/export state is represented by file pointers and shot/version metadata fields.
|
|
|
|
---
|
|
|
|
## 2. API
|
|
|
|
### 2.1 Shots
|
|
|
|
#### External shot APIs
|
|
|
|
- GET /api/ext/projects
|
|
- URL: /api/ext/projects
|
|
- Method: GET
|
|
- Purpose: List projects for pipeline tools
|
|
- Request body: None
|
|
- Response: projects[] with id, name, code, showId, projectType, status, dates, _count
|
|
- Source: [app/api/ext/projects/route.ts](app/api/ext/projects/route.ts)
|
|
|
|
- GET /api/ext/projects/{projectCode}/episodes
|
|
- URL: /api/ext/projects/{projectCode}/episodes
|
|
- Method: GET
|
|
- Purpose: List distinct episodes and optionally shot payloads per episode
|
|
- Request body: None
|
|
- Response: project + episodes[]; optional shots[] includes exrOutput/timecodes
|
|
- Source: [app/api/ext/projects/[projectCode]/episodes/route.ts](app/api/ext/projects/%5BprojectCode%5D/episodes/route.ts)
|
|
|
|
- GET /api/ext/projects/{projectCode}/shots
|
|
- URL: /api/ext/projects/{projectCode}/shots
|
|
- Method: GET
|
|
- Purpose: List shots by project code with filters/pagination
|
|
- Request body: None
|
|
- Response: project + pagination + shots[]
|
|
- Source: [app/api/ext/projects/[projectCode]/shots/route.ts](app/api/ext/projects/%5BprojectCode%5D/shots/route.ts)
|
|
|
|
- GET /api/ext/shots
|
|
- URL: /api/ext/shots
|
|
- Method: GET
|
|
- Purpose: Legacy listing by projectId
|
|
- Request body: None
|
|
- Response: shots[] + total
|
|
- Source: [app/api/ext/shots/route.ts](app/api/ext/shots/route.ts)
|
|
|
|
- POST /api/ext/shots
|
|
- URL: /api/ext/shots
|
|
- Method: POST
|
|
- Purpose: Create shot from external tool (JSON or multipart thumbnail)
|
|
- Request body:
|
|
- projectId, scene
|
|
- optional episode, description, artistId, priority, fps, frameStart, frameEnd, dueDate, thumbnailUrl, shotGroupName, shotCode
|
|
- optional thumbnail file (multipart)
|
|
- Response: created shot object
|
|
- Source: [app/api/ext/shots/route.ts](app/api/ext/shots/route.ts)
|
|
|
|
- GET /api/ext/shots/lookup
|
|
- URL: /api/ext/shots/lookup
|
|
- Method: GET
|
|
- Purpose: Canonical shot lookup by shotCode (+ optional projectCode)
|
|
- Request body: None
|
|
- Response: shot object with project, artist, tasks, latest version, exrOutput, shotVersion, source/seq timecodes
|
|
- Source: [app/api/ext/shots/lookup/route.ts](app/api/ext/shots/lookup/route.ts)
|
|
|
|
- GET /api/ext/shots/{shotId}
|
|
- URL: /api/ext/shots/{shotId}
|
|
- Method: GET
|
|
- Purpose: Shot detail by DB id, or byCode mode
|
|
- Request body: None
|
|
- Response: full shot detail with tasks/latest version/counts
|
|
- Source: [app/api/ext/shots/[shotId]/route.ts](app/api/ext/shots/%5BshotId%5D/route.ts)
|
|
|
|
- PATCH /api/ext/shots/{shotId}
|
|
- URL: /api/ext/shots/{shotId}
|
|
- Method: PATCH
|
|
- Purpose: Update mutable shot field(s) from pipeline tools
|
|
- Request body: shotVersion (v###) currently supported
|
|
- Response: success + updated shot id/shotVersion
|
|
- Source: [app/api/ext/shots/[shotId]/route.ts](app/api/ext/shots/%5BshotId%5D/route.ts)
|
|
|
|
#### Internal shot APIs
|
|
|
|
- GET /api/shots/{shotId}
|
|
- URL: /api/shots/{shotId}
|
|
- Method: GET
|
|
- Purpose: Internal dashboard shot detail payload
|
|
- Request body: None
|
|
- Response: shot + tasks + artists + permissions flags
|
|
- Source: [app/api/shots/[shotId]/route.ts](app/api/shots/%5BshotId%5D/route.ts)
|
|
|
|
- GET /api/projects/{projectId}/episodes
|
|
- URL: /api/projects/{projectId}/episodes
|
|
- Method: GET
|
|
- Purpose: Internal distinct episode list for project
|
|
- Request body: None
|
|
- Response: episodes[]
|
|
- Source: [app/api/projects/[projectId]/episodes/route.ts](app/api/projects/%5BprojectId%5D/episodes/route.ts)
|
|
|
|
### 2.2 Reviews
|
|
|
|
- GET /api/review-sessions
|
|
- Purpose: list review sessions
|
|
- POST /api/review-sessions
|
|
- Purpose: create review session token and portal link
|
|
- DELETE /api/review-sessions
|
|
- Purpose: deactivate review session
|
|
- Source: [app/api/review-sessions/route.ts](app/api/review-sessions/route.ts)
|
|
|
|
- POST /api/client/{token}/auth
|
|
- Purpose: review password check + unlock cookie
|
|
- Source: [app/api/client/[token]/auth/route.ts](app/api/client/%5Btoken%5D/auth/route.ts)
|
|
|
|
- GET /api/client/{token}/project
|
|
- Purpose: client portal project payload (shared shots/versions)
|
|
- Source: [app/api/client/[token]/project/route.ts](app/api/client/%5Btoken%5D/project/route.ts)
|
|
|
|
- GET /api/client/{token}/versions/{versionId}
|
|
- Purpose: client review detail payload
|
|
- Source: [app/api/client/[token]/versions/[versionId]/route.ts](app/api/client/%5Btoken%5D/versions/%5BversionId%5D/route.ts)
|
|
|
|
- POST /api/client/{token}/comment
|
|
- Purpose: client frame comment
|
|
- Request body: versionId, frameNumber, timestamp, text
|
|
- Response: created comment
|
|
- Source: [app/api/client/[token]/comment/route.ts](app/api/client/%5Btoken%5D/comment/route.ts)
|
|
|
|
- POST /api/client/{token}/annotation
|
|
- Purpose: client annotation write
|
|
- Request body: versionId, frameNumber, drawingData, optional color
|
|
- Response: annotation
|
|
- Source: [app/api/client/[token]/annotation/route.ts](app/api/client/%5Btoken%5D/annotation/route.ts)
|
|
|
|
- POST /api/client/{token}/approve
|
|
- Purpose: shot-level approve/changes and legacy version-level approval
|
|
- Request body:
|
|
- shot mode: shotId + action
|
|
- version mode: versionId + status + notes
|
|
- Response: success
|
|
- Source: [app/api/client/[token]/approve/route.ts](app/api/client/%5Btoken%5D/approve/route.ts)
|
|
|
|
- GET /api/versions/{versionId}/comments
|
|
- Purpose: internal comments read
|
|
- Source: [app/api/versions/[versionId]/comments/route.ts](app/api/versions/%5BversionId%5D/comments/route.ts)
|
|
|
|
- GET /api/versions/{versionId}/annotations
|
|
- Purpose: internal annotations read
|
|
- Source: [app/api/versions/[versionId]/annotations/route.ts](app/api/versions/%5BversionId%5D/annotations/route.ts)
|
|
|
|
- GET /api/playlist
|
|
- Purpose: latest version per shot playlist
|
|
- Source: [app/api/playlist/route.ts](app/api/playlist/route.ts)
|
|
|
|
### 2.3 File uploads
|
|
|
|
- POST /api/upload
|
|
- Purpose: authenticated upload to Hetzner via app server
|
|
- Body: multipart file (+ type)
|
|
- Response: url, key
|
|
- Source: [app/api/upload/route.ts](app/api/upload/route.ts)
|
|
|
|
- POST /api/upload/local
|
|
- Purpose: authenticated video upload path
|
|
- Body: multipart file
|
|
- Response: url, key
|
|
- Source: [app/api/upload/local/route.ts](app/api/upload/local/route.ts)
|
|
|
|
- POST /api/upload/presign
|
|
- Purpose: direct browser->object-storage upload URL
|
|
- Body: fileName, contentType, optional folder
|
|
- Response: presignedUrl, key, url
|
|
- Source: [app/api/upload/presign/route.ts](app/api/upload/presign/route.ts)
|
|
|
|
- GET/POST /api/uploadthing
|
|
- Purpose: UploadThing route handler passthrough (if configured)
|
|
- Source: [app/api/uploadthing/route.ts](app/api/uploadthing/route.ts)
|
|
|
|
- POST /api/batch-upload/presign
|
|
- Purpose: presign high-res upload key
|
|
- Body: fileName
|
|
- Response: presignedUrl, key
|
|
- Source: [app/api/batch-upload/presign/route.ts](app/api/batch-upload/presign/route.ts)
|
|
|
|
- POST /api/batch-upload/preview
|
|
- Purpose: classify upload actions before upload
|
|
- Body: projectId, fileNames[]
|
|
- Response: items[] with statuses (new-version, rename-and-upload, create-task, update-highres, etc)
|
|
- Source: [app/api/batch-upload/preview/route.ts](app/api/batch-upload/preview/route.ts)
|
|
|
|
- POST /api/batch-upload/upload
|
|
- Purpose: commit highres key or create version records
|
|
- Body:
|
|
- update-highres: action, shotId, projectId, key, fileName
|
|
- version upload: action, shotId, projectId, file, task routing fields
|
|
- Response: success + action result
|
|
- Source: [app/api/batch-upload/upload/route.ts](app/api/batch-upload/upload/route.ts)
|
|
|
|
### 2.4 EXRs / Rendering / Delivery / Storage / Metadata
|
|
|
|
- GET /api/files/{...key}
|
|
- Purpose: file serving, range requests, local/Hetzner routing
|
|
- Source: [app/api/files/[...key]/route.ts](app/api/files/%5B...key%5D/route.ts)
|
|
|
|
- GET/POST /api/admin/migration
|
|
- Purpose: local uploads migration status and per-key migration to Hetzner
|
|
- Source: [app/api/admin/migration/route.ts](app/api/admin/migration/route.ts)
|
|
|
|
- POST/DELETE /api/storage-test
|
|
- Purpose: upload test object / delete test object
|
|
- Source: [app/api/storage-test/route.ts](app/api/storage-test/route.ts)
|
|
|
|
- POST/DELETE /api/shots/{shotId}/highres
|
|
- Purpose: upload/remove high-res deliverable on shot
|
|
- Source: [app/api/shots/[shotId]/highres/route.ts](app/api/shots/%5BshotId%5D/highres/route.ts)
|
|
|
|
- GET /api/shots/{shotId}/highres/download
|
|
- Purpose: internal presigned download URL for high-res
|
|
- Source: [app/api/shots/[shotId]/highres/download/route.ts](app/api/shots/%5BshotId%5D/highres/download/route.ts)
|
|
|
|
- GET /api/client/{token}/shots/{shotId}/highres/download
|
|
- Purpose: client token-gated presigned high-res download URL
|
|
- Source: [app/api/client/[token]/shots/[shotId]/highres/download/route.ts](app/api/client/%5Btoken%5D/shots/%5BshotId%5D/highres/download/route.ts)
|
|
|
|
- GET/POST/DELETE /api/shots/{shotId}/references
|
|
- Purpose: shot reference image management
|
|
- Source: [app/api/shots/[shotId]/references/route.ts](app/api/shots/%5BshotId%5D/references/route.ts)
|
|
|
|
- GET /api/storyboard/pdf
|
|
- Purpose: server-rendered printable storyboard HTML with metadata options
|
|
- Source: [app/api/storyboard/pdf/route.ts](app/api/storyboard/pdf/route.ts)
|
|
|
|
Notes:
|
|
- No dedicated REST endpoint that runs ffmpeg in this repository.
|
|
- No dedicated REST endpoint that performs EXR rendering on the server.
|
|
- No dedicated deliveries API namespace.
|
|
|
|
---
|
|
|
|
## 3. Storage
|
|
|
|
Primary storage abstraction: [lib/storage.ts](lib/storage.ts)
|
|
|
|
### Provider modes
|
|
|
|
- local
|
|
- uploadthing
|
|
- s3
|
|
- r2
|
|
- b2
|
|
- minio
|
|
|
|
### Dedicated high-res object storage path
|
|
|
|
- Hetzner object storage helper methods are used for high-res and presigned direct uploads.
|
|
- Config source precedence:
|
|
- SystemConfig table keys
|
|
- env fallback
|
|
|
|
### Folder/key layout in object storage (current code paths)
|
|
|
|
- videos/
|
|
- image/
|
|
- highres/
|
|
- storage-test/
|
|
|
|
### Local storage
|
|
|
|
- LOCAL_UPLOAD_DIR (default ./uploads)
|
|
- Served via /api/files catch-all route
|
|
|
|
### File naming conventions
|
|
|
|
- Key format: {folder}/{uuid}-{sanitized-file-name}
|
|
- Sanitization done by sanitizeFileName to avoid URL/signature problems in object keys
|
|
|
|
### EXR locations
|
|
|
|
Within web app/runtime:
|
|
- EXR references are naming metadata (Shot.exrOutput) and file-serving pathing.
|
|
|
|
Within DCC tooling docs/scripts:
|
|
- AE/Nuke workflows target shared export roots and per-shot folders.
|
|
|
|
### Preview locations
|
|
|
|
- Version media URLs stored in Version.fileUrl
|
|
- Accessed through app player routes and /api/files routing where applicable
|
|
|
|
### Thumbnail locations
|
|
|
|
- Shot.thumbnailUrl
|
|
- Version.thumbnailUrl
|
|
- Can point to /api/files/{key} or external provider URL
|
|
|
|
Relevant sources:
|
|
- [lib/storage.ts](lib/storage.ts)
|
|
- [app/api/files/[...key]/route.ts](app/api/files/%5B...key%5D/route.ts)
|
|
- [actions/settings.ts](actions/settings.ts)
|
|
|
|
---
|
|
|
|
## 4. Export Pipeline (Current)
|
|
|
|
### AE panel
|
|
|
|
Documented in repo:
|
|
- [VFXReviewConnector.md](VFXReviewConnector.md)
|
|
- [EXT_API_REFERENCE.md](EXT_API_REFERENCE.md)
|
|
|
|
Implemented panel script also exists on the host AE installation (outside workspace), and behavior aligns with docs:
|
|
- Episodes/shots discovery via ext APIs
|
|
- Shot lookup API usage for metadata
|
|
- Overlay/slate essential property updates (burn-in style overlays)
|
|
- Queue EXR / Queue MP4 / Queue MOV render queue actions
|
|
- Queue EXR (review convention)
|
|
- Import exported EXR and import renders
|
|
- Pull picture lock using seq timecodes
|
|
- Increment shot version by PATCH call
|
|
- Delivery prep that copies/renames EXR files to delivery folder convention
|
|
|
|
### External API endpoints used by DCC tools
|
|
|
|
- GET /api/ext/projects/{projectCode}/episodes
|
|
- GET /api/ext/projects/{projectCode}/shots
|
|
- GET /api/ext/shots/lookup
|
|
- PATCH /api/ext/shots/{shotId}
|
|
|
|
### Existing render scripts and pipelines
|
|
|
|
- AE panel render queue automation (external script)
|
|
- Nuke connector script creating write-node outputs and shot scripts:
|
|
- [VFXReviewConnector.py](VFXReviewConnector.py)
|
|
|
|
### ffmpeg scripts
|
|
|
|
- None found in this repository.
|
|
|
|
### Proxy generation
|
|
|
|
- Version.proxyUrl field exists in schema.
|
|
- No implemented proxy-generation worker/function found.
|
|
|
|
### Thumbnail generation
|
|
|
|
- Upload/assignment flows exist.
|
|
- No server-side frame-extract thumbnail generator found.
|
|
|
|
### Metadata extraction
|
|
|
|
- EDL / picture-tracker CSV metadata parsing implemented:
|
|
- [lib/edl-utils.ts](lib/edl-utils.ts)
|
|
- [actions/shots.ts](actions/shots.ts)
|
|
|
|
### Burn-in generation
|
|
|
|
- Achieved via DCC overlay/slate layers and essential properties in AE/Nuke tool workflows.
|
|
- No ffmpeg burn-in path found.
|
|
|
|
---
|
|
|
|
## 5. Review System
|
|
|
|
### Current review workflow
|
|
|
|
Core status derivation:
|
|
- [lib/shot-status.ts](lib/shot-status.ts)
|
|
|
|
Server action orchestration:
|
|
- [actions/versions.ts](actions/versions.ts)
|
|
- [actions/approvals.ts](actions/approvals.ts)
|
|
- [actions/tasks.ts](actions/tasks.ts)
|
|
- [actions/shots.ts](actions/shots.ts)
|
|
- [actions/comments.ts](actions/comments.ts)
|
|
|
|
### Internal review
|
|
|
|
- Version upload:
|
|
- marks previous versions non-latest
|
|
- creates new latest version
|
|
- moves Task to INTERNAL_REVIEW
|
|
- recalculates Shot.status
|
|
|
|
### Client review
|
|
|
|
- Tokenized ReviewSession links
|
|
- Optional password gate with signed cookie unlock
|
|
- Client comment/annotation/approval endpoints
|
|
- Share/unshare semantics via shot and version visibility fields
|
|
|
|
### Task status flow
|
|
|
|
Observed statuses:
|
|
- TODO
|
|
- IN_PROGRESS
|
|
- INTERNAL_REVIEW
|
|
- CLIENT_REVIEW
|
|
- CHANGES
|
|
- DONE
|
|
|
|
### Shot status flow
|
|
|
|
Derived in priority order:
|
|
- REVISIONS (any task CHANGES)
|
|
- COMPLETE (shotApprovalStatus CLIENT_APPROVED)
|
|
- CLIENT_REVIEW / READY_FOR_CLIENT (internally approved + share flag)
|
|
- IN_PROGRESS (task TODO/IN_PROGRESS)
|
|
- INTERNAL_REVIEW (tasks exist)
|
|
- WAITING (no tasks)
|
|
|
|
### Approval process
|
|
|
|
- Version-level approvals create Approval rows and update Version.approvalStatus
|
|
- Shot-level client actions supported via client approve endpoint and shot actions
|
|
|
|
Reference doc in repo:
|
|
- [Shot task workflow.md](Shot%20task%20workflow.md)
|
|
|
|
---
|
|
|
|
## 6. Authentication
|
|
|
|
### External tools
|
|
|
|
- /api/ext/* routes authenticate using API_SECRET_KEY via:
|
|
- Authorization: Bearer <key>
|
|
- x-api-key header
|
|
|
|
### Client review links
|
|
|
|
- tokenized route with ReviewSession lookup
|
|
- optional password hash validation and signed unlock cookie
|
|
|
|
### App users
|
|
|
|
- NextAuth credentials provider
|
|
- bcrypt password hash compare
|
|
- JWT session strategy
|
|
|
|
### Middleware behavior
|
|
|
|
- Route classes allowed through middleware auth gate:
|
|
- /api/ext/
|
|
- /api/client/
|
|
- /api/display/
|
|
- /api/files/
|
|
- /api/uploadthing
|
|
- Per-route auth still enforced in handlers
|
|
|
|
Sources:
|
|
- [auth.ts](auth.ts)
|
|
- [auth.config.ts](auth.config.ts)
|
|
- [middleware.ts](middleware.ts)
|
|
- [lib/review-auth.ts](lib/review-auth.ts)
|
|
|
|
---
|
|
|
|
## 7. Existing Background Jobs
|
|
|
|
### Cron jobs
|
|
- None found.
|
|
|
|
### Queues
|
|
- None found.
|
|
|
|
### Workers
|
|
- None found.
|
|
|
|
### Polling services
|
|
- Display devices poll:
|
|
- /api/display/events
|
|
- /api/dashboard/stats
|
|
|
|
### Docker containers
|
|
- vfxreview app container
|
|
- postgres container
|
|
- Source: [docker-compose.yml](docker-compose.yml)
|
|
|
|
### Scheduled tasks
|
|
- Startup migration commands in container entrypoint:
|
|
- [entrypoint.sh](entrypoint.sh)
|
|
- AE panel Prep Delivery launches background PowerShell copy scripts on workstation (outside web app runtime)
|
|
|
|
---
|
|
|
|
## 8. After Effects Integration (Implemented Features)
|
|
|
|
Repo-level references:
|
|
- [VFXReviewConnector.md](VFXReviewConnector.md)
|
|
- [EXT_API_REFERENCE.md](EXT_API_REFERENCE.md)
|
|
|
|
Implemented capabilities observed/documented:
|
|
|
|
- API calls
|
|
- episodes/shots listing and shot lookup
|
|
- shot version PATCH
|
|
- Authentication
|
|
- bearer API token in script
|
|
- Comp discovery
|
|
- shot code extraction from comp names and dropdown selection
|
|
- Render queue integration
|
|
- EXR Sequence
|
|
- REVIEW_PREVIEW (MP4)
|
|
- 4444 Tri (MOV)
|
|
- EXR review sequence queue variant
|
|
- Output path generation
|
|
- shot/version naming conventions + export root paths
|
|
- Shot lookup
|
|
- uses /api/ext/shots/lookup for metadata and naming decisions
|
|
- Upload features
|
|
- no direct upload-to-web API flow in panel docs/script (render/output handled in DCC/filesystem)
|
|
- Burn-in generation
|
|
- overlay and slate essential properties
|
|
- Review integration
|
|
- preview comp build and version increment sync
|
|
|
|
---
|
|
|
|
## 9. Configuration
|
|
|
|
### Environment variables
|
|
|
|
Primary reference: [.env.example](.env.example)
|
|
|
|
Observed vars in code/docs include:
|
|
|
|
- DATABASE_URL
|
|
- NEXTAUTH_SECRET
|
|
- NEXTAUTH_URL
|
|
- NEXT_PUBLIC_APP_URL
|
|
- NEXT_PUBLIC_APP_NAME
|
|
- API_SECRET_KEY
|
|
- AUTH_SECRET
|
|
- STORAGE_PROVIDER
|
|
- LOCAL_UPLOAD_DIR
|
|
- AWS_ACCESS_KEY_ID
|
|
- AWS_SECRET_ACCESS_KEY
|
|
- AWS_REGION
|
|
- AWS_BUCKET_NAME
|
|
- R2_ACCESS_KEY_ID
|
|
- R2_SECRET_ACCESS_KEY
|
|
- R2_ACCOUNT_ID
|
|
- R2_BUCKET_NAME
|
|
- R2_PUBLIC_URL
|
|
- B2_APPLICATION_KEY_ID
|
|
- B2_APPLICATION_KEY
|
|
- B2_BUCKET_NAME
|
|
- B2_ENDPOINT
|
|
- MINIO_ENDPOINT
|
|
- MINIO_ACCESS_KEY
|
|
- MINIO_SECRET_KEY
|
|
- MINIO_BUCKET_NAME
|
|
- HETZNER_ENDPOINT
|
|
- HETZNER_ACCESS_KEY
|
|
- HETZNER_SECRET_KEY
|
|
- HETZNER_BUCKET_NAME
|
|
- UPLOADTHING_SECRET
|
|
- UPLOADTHING_APP_ID
|
|
- EMAIL_FROM
|
|
- EMAIL_SERVER_HOST
|
|
- EMAIL_SERVER_PORT
|
|
- EMAIL_SERVER_USER
|
|
- EMAIL_SERVER_PASSWORD
|
|
- SLACK_DEFAULT_WEBHOOK
|
|
|
|
### Storage configuration
|
|
|
|
- Provider abstraction in [lib/storage.ts](lib/storage.ts)
|
|
- Hetzner overrides in [actions/settings.ts](actions/settings.ts) and SystemConfig table
|
|
|
|
### Render configuration
|
|
|
|
- No server-side renderer configuration module found.
|
|
- DCC render templates are documented in [VFXReviewConnector.md](VFXReviewConnector.md).
|
|
|
|
### ffmpeg configuration
|
|
|
|
- None found in repository.
|
|
|
|
### Object storage configuration
|
|
|
|
- Implemented for AWS S3/R2/B2/MinIO + dedicated Hetzner helper path
|
|
|
|
---
|
|
|
|
## 10. Existing Utility Functions (Reusable)
|
|
|
|
### Metadata extraction
|
|
|
|
- parseEdlCsv
|
|
- parsePictureTrackerCsv
|
|
- Source: [lib/edl-utils.ts](lib/edl-utils.ts)
|
|
|
|
### File scanning
|
|
|
|
- Local upload tree walker in migration route
|
|
- Nuke connector plate/render directory scanners
|
|
- Sources:
|
|
- [app/api/admin/migration/route.ts](app/api/admin/migration/route.ts)
|
|
- [VFXReviewConnector.py](VFXReviewConnector.py)
|
|
|
|
### EXR sequence detection
|
|
|
|
- Nuke connector helper sequence detectors and pattern conversion
|
|
- Source: [VFXReviewConnector.py](VFXReviewConnector.py)
|
|
|
|
### MOV generation
|
|
|
|
- No server-side MOV generation utility found.
|
|
- MOV outputs are DCC render queue outputs in external scripts/docs.
|
|
|
|
### Checksums
|
|
|
|
- No checksum utility found.
|
|
|
|
### Frame counting
|
|
|
|
- durationToFrameCount and frame math helpers
|
|
- Source: [lib/frame-utils.ts](lib/frame-utils.ts)
|
|
|
|
### Timecode extraction/conversion
|
|
|
|
- frameToTimecode / formatTimecode
|
|
- CSV timecode validation/parsing
|
|
- Sources:
|
|
- [lib/frame-utils.ts](lib/frame-utils.ts)
|
|
- [lib/utils.ts](lib/utils.ts)
|
|
- [lib/edl-utils.ts](lib/edl-utils.ts)
|
|
|
|
---
|
|
|
|
## 11. High-Level Architecture Diagram
|
|
|
|
```mermaid
|
|
flowchart LR
|
|
A[AE Panel / Nuke Connector\nExternal DCC tools] -->|API key auth| B[Next.js App Router APIs]
|
|
B --> C[Prisma ORM]
|
|
C --> D[(PostgreSQL)]
|
|
|
|
B --> E[Storage Abstraction]
|
|
E --> F[(Hetzner Object Storage)]
|
|
E --> G[(S3/R2/B2/MinIO)]
|
|
B --> H[(Local uploads dir)]
|
|
|
|
I[Internal reviewers\nNextAuth session] --> B
|
|
J[Client reviewers\nToken review sessions] --> B
|
|
|
|
K[ESP32 display client] -->|x-display-key polling| B
|
|
|
|
A --> L[Shared filesystem render roots\nEXR/MP4/MOV outputs]
|
|
L -->|served/linked via app metadata| B
|
|
```
|
|
|
|
---
|
|
|
|
## 12. Files Inspected (Primary)
|
|
|
|
- [prisma/schema.prisma](prisma/schema.prisma)
|
|
- [lib/storage.ts](lib/storage.ts)
|
|
- [lib/shot-status.ts](lib/shot-status.ts)
|
|
- [lib/review-auth.ts](lib/review-auth.ts)
|
|
- [lib/edl-utils.ts](lib/edl-utils.ts)
|
|
- [lib/frame-utils.ts](lib/frame-utils.ts)
|
|
- [lib/utils.ts](lib/utils.ts)
|
|
- [auth.ts](auth.ts)
|
|
- [auth.config.ts](auth.config.ts)
|
|
- [middleware.ts](middleware.ts)
|
|
- [next.config.ts](next.config.ts)
|
|
- [.env.example](.env.example)
|
|
- [docker-compose.yml](docker-compose.yml)
|
|
- [Dockerfile](Dockerfile)
|
|
- [entrypoint.sh](entrypoint.sh)
|
|
- [EXT_API_REFERENCE.md](EXT_API_REFERENCE.md)
|
|
- [VFXReviewConnector.md](VFXReviewConnector.md)
|
|
- [VFXReviewConnector.py](VFXReviewConnector.py)
|
|
- [# VFXReview Connector for Nuke.md](#%20VFXReview%20Connector%20for%20Nuke.md)
|
|
- API handlers under [app/api](app/api)
|
|
- Server actions under [actions](actions)
|
|
|
|
---
|
|
|
|
End of current-state report.
|