Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
5.2 KiB
Implementation Plan: p3-17-media-processing-s3
Branch: [p3-17-media-processing-s3] | Date: 2026-02-04 | Spec: docs/todo_list.md#17
Input: P3-17 “媒体处理管线适配对象存储(S3/MinIO)” + user request to extract a cover from fixtures/demo.mp4 via ffmpeg.
Summary
Adapt the media processing worker to support S3/MinIO storage by downloading source media to a temp directory, running ffmpeg to generate a cover image, uploading derived assets via the storage provider, and preserving the existing local filesystem path. Include fixture-based verification using fixtures/demo.mp4.
Technical Context
Language/Version: Go 1.x (project standard)
Primary Dependencies: River (jobs), MinIO SDK (S3 compatible), Fiber
Storage: PostgreSQL + local filesystem / S3-compatible storage
Testing: go test (service/job tests), ffmpeg CLI for fixture validation
Target Platform: Linux server
Project Type: Web application (backend + frontend, backend-only changes)
Performance Goals: N/A (processing path only)
Constraints: Preserve local storage behavior; do not edit generated files; follow backend/llm.txt; ensure temp files are cleaned
Scale/Scope: Media processing worker + storage provider only
Constitution Check
- Follow
backend/llm.txtconventions and Chinese comments for business logic. - Do not edit generated files (
*.gen.go,backend/docs/docs.go). - Keep controller thin; changes limited to jobs/services/providers.
- Preserve local provider behavior; add S3 path without regression.
Project Structure
Documentation (this feature)
docs/
└── plan.md # This plan
Source Code (repository root)
backend/
├── app/
│ ├── jobs/
│ │ ├── media_process_job.go
│ │ └── args/media_asset_process.go
│ └── services/
│ └── common.go
└── providers/
└── storage/provider.go
fixtures/
└── demo.mp4
Structure Decision: Web application backend; scope limited to media processing worker and storage provider integration.
Plan Phases
- Design & plumbing: Define temp file conventions and storage download API for S3/local.
- Implementation: Add S3 processing flow to worker and cover asset registration; keep local path intact.
- Verification: Add tests (or integration checks) and run fixture-based ffmpeg validation.
Tasks
-
Define storage download interface
- Add a storage provider helper to download an object to a local temp file (local: copy from
LocalPath/objectKeywithout rename; S3:FGetObject). - Ensure helper never mutates/deletes the source object, creates parent dirs for destination, and overwrites the destination if it already exists.
- Ensure API is used by jobs without leaking provider-specific logic.
- Add a storage provider helper to download an object to a local temp file (local: copy from
-
Adapt
MediaProcessWorkerfor S3/MinIO- For non-local providers, download the source object into a temp directory.
- Run ffmpeg to extract a cover image from the temp file.
- Upload the cover via
storage.PutObjectand register the derived media asset. - Ensure temp directories/files are cleaned on success or failure.
-
Update cover asset registration
- For non-local providers, avoid filesystem rename; upload via storage provider and keep object key conventions.
- Use
storage.PutObject(ctx, objectKey, coverTempPath, "image/jpeg"), then cleanup temp files/dirs. - Keep local path move behavior unchanged.
-
Add tests / verification hooks
- Add a job/service test for S3 path (gated by MinIO env if needed).
- Keep/extend local path test to ensure no regression.
- Validate
fixtures/demo.mp4can produce a cover with ffmpeg.
Dependencies
- Task 1 must complete before Task 2 (worker needs download API).
- Task 2 must complete before Task 3 (cover registration requires new flow).
- Task 4 depends on Task 2 & 3 (tests rely on updated pipeline).
Acceptance Criteria
- Local path unchanged:
MediaProcessWorkerstill generates a cover image for local provider when ffmpeg is available. - S3/MinIO path works: For
Storage.Type = s3, the worker downloads source media, generates cover via ffmpeg, uploads cover to bucket, and creates a derivedmedia_assetsrecord with correct object key. - Fixture validation:
ffmpeg -y -i fixtures/demo.mp4 -ss 00:00:00.000 -vframes 1 /tmp/demo_cover.jpgsucceeds locally and produces a non-empty file. - S3/MinIO test config: tests load Storage config with
Type=s3,Endpoint,AccessKey,SecretKey,Bucket,PathStyle(true for MinIO). - Automated checks (to be added in this phase):
go test ./backend/app/jobs -run TestMediaProcessWorkerS3 -count=1passes (with S3/MinIO config loaded).go test ./backend/app/jobs -run TestMediaProcessWorkerLocal -count=1passes.
Risks
- ffmpeg not installed: Worker should detect and log; processing should fail gracefully.
- Temp storage pressure: Large media downloads may exceed disk; ensure cleanup on all paths.
- S3 connectivity/transient errors: Add retry or error propagation to avoid silent failures.
- Access policies: Misconfigured bucket policies may prevent download/upload; surface clear errors.