Scope:lesson-videos bucket — /mnt/fusionio/spikersoft/lesson-videos (+ uploads/lesson-videos staging prefix in the uploads batch).
Current state:SpikerSoft.EventHandlers.LessonVideoProcessor is filesystem-only. Key files: Services/FfmpegVideoTranscoder.cs (ffmpeg reads/writes local paths — transcode via local temp files: download from S3 to temp, transcode, upload result), LessonVideoMoveConsumer.cs, LessonVideoScanConsumer.cs, LessonVideoTranscodeConsumer.cs. Also SpikerSoft.Business/Services/LessonVideoStagingService.cs (staging writer) and API static serving of /app/lesson-videos at /lesson-videos (covered by the API media-serving ticket).
Steps: bucket + scoped key → backend PR (S3 behind Storage:UseS3; ffmpeg works on temp copies) → mc mirror backfill → dual-run → cut over stack file, relax placement.
Parent epic: #413. Per-service MinIO migration (recipe: `docs/minio-storage-migration.md`).
**Scope:** `lesson-videos` bucket — `/mnt/fusionio/spikersoft/lesson-videos` (+ `uploads/lesson-videos` staging prefix in the uploads batch).
**Current state:** `SpikerSoft.EventHandlers.LessonVideoProcessor` is **filesystem-only**. Key files: `Services/FfmpegVideoTranscoder.cs` (ffmpeg reads/writes local paths — transcode via local temp files: download from S3 to temp, transcode, upload result), `LessonVideoMoveConsumer.cs`, `LessonVideoScanConsumer.cs`, `LessonVideoTranscodeConsumer.cs`. Also `SpikerSoft.Business/Services/LessonVideoStagingService.cs` (staging writer) and API static serving of `/app/lesson-videos` at `/lesson-videos` (covered by the API media-serving ticket).
**Steps:** bucket + scoped key → backend PR (S3 behind `Storage:UseS3`; ffmpeg works on temp copies) → `mc mirror` backfill → dual-run → cut over stack file, relax placement.
Backend PR #262: LessonVideoMoveConsumer dual-writes moved video+thumbnail to the lesson-videos bucket (same relative keys served today → #528/#531 cutover = prefix swap). Transcoder deliberately unchanged (local paths) — S3-temp transcode is cutover-phase work with the #529 staging batch. This was the LAST per-tree migration under #413: every bucket in the map now has a dual-writing producer merged or in review.
Backend PR #262: LessonVideoMoveConsumer dual-writes moved video+thumbnail to the lesson-videos bucket (same relative keys served today → #528/#531 cutover = prefix swap). Transcoder deliberately unchanged (local paths) — S3-temp transcode is cutover-phase work with the #529 staging batch. This was the LAST per-tree migration under #413: every bucket in the map now has a dual-writing producer merged or in review.
The deploy blocker is gone: #581 (VIDEOS_S3_SECRET_KEY never created) was fixed 2026-07-15 via backend #303 — the workflow now fetches the key from OpenBao (secret/ci/backend/minio/videos), so the deploy guard passes
lesson-videos bucket exists (created in the 2026-07-14 phase 0); it is empty because there are no lesson videos anywhere, disk included — correct, not a gap
The related serving bug #599 (root-relative URLs hitting nginx) is also closed
**Epic #413 accuracy pass (2026-07-18) — closing: migration scope complete; residuals are #529 lines.**
Verified against current masters:
- Code merged: backend #262 (`LessonVideoMoveConsumer` dual-writes video + thumbnail to `lesson-videos`, keys match served URLs) — on backend master
- Stack ready: `spikersoft-lesson-video-processor/docker-stack.yml` carries `Storage__UseS3=true` + `videos-svc`
- The deploy blocker is gone: #581 (VIDEOS_S3_SECRET_KEY never created) was fixed 2026-07-15 via backend #303 — the workflow now fetches the key from OpenBao (`secret/ci/backend/minio/videos`), so the deploy guard passes
- `lesson-videos` bucket exists (created in the 2026-07-14 phase 0); it is empty **because there are no lesson videos anywhere, disk included** — correct, not a gap
- The related serving bug #599 (root-relative URLs hitting nginx) is also closed
Residuals, both already #529's:
1. one-time confirmation the processor actually deployed post-#581 and writes the bucket when the first real video flows (phase 1 soak line)
2. S3-temp transcode (deliberately deferred to cutover per this ticket's own scoping) — phase 2
Residual tracked in: #529.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Parent epic: #413. Per-service MinIO migration (recipe:
docs/minio-storage-migration.md).Scope:
lesson-videosbucket —/mnt/fusionio/spikersoft/lesson-videos(+uploads/lesson-videosstaging prefix in the uploads batch).Current state:
SpikerSoft.EventHandlers.LessonVideoProcessoris filesystem-only. Key files:Services/FfmpegVideoTranscoder.cs(ffmpeg reads/writes local paths — transcode via local temp files: download from S3 to temp, transcode, upload result),LessonVideoMoveConsumer.cs,LessonVideoScanConsumer.cs,LessonVideoTranscodeConsumer.cs. AlsoSpikerSoft.Business/Services/LessonVideoStagingService.cs(staging writer) and API static serving of/app/lesson-videosat/lesson-videos(covered by the API media-serving ticket).Steps: bucket + scoped key → backend PR (S3 behind
Storage:UseS3; ffmpeg works on temp copies) →mc mirrorbackfill → dual-run → cut over stack file, relax placement.Backend PR #262: LessonVideoMoveConsumer dual-writes moved video+thumbnail to the lesson-videos bucket (same relative keys served today → #528/#531 cutover = prefix swap). Transcoder deliberately unchanged (local paths) — S3-temp transcode is cutover-phase work with the #529 staging batch. This was the LAST per-tree migration under #413: every bucket in the map now has a dual-writing producer merged or in review.
Code MERGED (backend #262). Remaining = ops via #529 (lesson-videos bucket + videos-svc key + VIDEOS_S3_SECRET_KEY — backend #264/infra #60 — backfill, phase-2 bind drop). S3-temp transcode deferred to cutover per ticket.
Epic #413 accuracy pass (2026-07-18) — closing: migration scope complete; residuals are #529 lines.
Verified against current masters:
LessonVideoMoveConsumerdual-writes video + thumbnail tolesson-videos, keys match served URLs) — on backend masterspikersoft-lesson-video-processor/docker-stack.ymlcarriesStorage__UseS3=true+videos-svcsecret/ci/backend/minio/videos), so the deploy guard passeslesson-videosbucket exists (created in the 2026-07-14 phase 0); it is empty because there are no lesson videos anywhere, disk included — correct, not a gapResiduals, both already #529's:
Residual tracked in: #529.