Skip to main content

Object storage and streaming

Lesson video and class recordings live in one OCI Object Storage bucket, startupos-production-lms-content. The bucket is private (NoPublicAccess) and has versioning on. The LMS service reaches it through the S3-compatible API of the tenancy, using a Customer Secret Key held in a Kubernetes Secret.

Upload​

A moderator uploads a lesson video with POST /api/v1/lms/lessons/{lessonId}/video, a multipart request. Moderators are the Administrator, Spoke Coordinator, Mentor and content roles. The service writes the request body to a temporary file and streams it to the bucket, then records the object key, content type and size on the lesson. A dedicated ingress rule for /api/v1/lms/lessons raises the body limit to 2 GB, turns off request buffering and extends the timeouts to one hour.

Playback by Range request​

Playback is progressive download with HTTP Range support, not HLS. The browser's native <video> element needs no player library. The stream endpoint passes the Range header to the bucket and answers 206 Partial Content with Content-Range, or 200 for a whole-object request. Both carry Accept-Ranges: bytes. See ADR 5.

The stream token​

A <video src> request from the browser cannot send an Authorization header. So playback uses two requests:

  1. An authenticated call to GET /api/v1/lms/lessons/{lessonId}/stream-token checks that the caller is enrolled in the lesson's course and returns a signed token.
  2. The <video> element loads GET /api/v1/lms/lessons/{lessonId}/stream?token=.... This path is public at the HTTP layer. The service verifies the token before it sends any byte.

The token is an HS256 JWT with lessonId, sub (the participant) and exp claims. It is signed with a dedicated secret and lasts 21600 seconds (6 hours) unless configured otherwise. Recordings work the same way at /api/v1/lms/recordings/{recordingId}/stream-token and /stream, with the recording id in the claim and an enrolment check against the recording's course. See ADR 4 and the upload and streaming flow.

Sources: services/lms-service/src/main/java/com/rtih/startupos/lms/{resource/LessonResource,resource/RecordingResource,service/LmsStreamTokenService}.java, services/lms-service/src/main/resources/application.yml, infra/k8s/ingress-lms-uploads.yaml, infra/k8s/configmap.yaml (bucket and endpoint names), .agents/tasks/lms-video-studio/plan.md.