Overview
:::info Source
Sourced from services/content-service/SERVICE_OVERVIEW.md in the documentation repo.
:::
Companion: 03 content-service · 02 DDD · 13 Security · 04 Event-Driven
1. Purpose
The content-service is the Content-Packaging authority within the Ghasi-edTech platform. It transforms authored course content into immutable, signed, runtime-ready PlayPackages, produces encrypted per-device Bundles for offline consumption, and drives SCORM/HTML5/xAPI export pipelines. The Player runtime treats PlayPackages as read-only artifacts; all build-time logic lives here.
2. Bounded Context
Content-Packaging — classified as Supporting domain. Downstream of Authoring; upstream of Catalog, Delivery, Sync, and the Player runtime.
Why Supporting, Not Core
Content-Packaging is essential but not differentiating. The platform's competitive advantage lies in authoring intelligence and adaptive learning paths (Core domains). Packaging is a well-understood transformation pipeline whose value comes from correctness and security, not novelty.
3. Responsibilities
| Area | What Content-Service Owns |
|---|---|
| PlayPackage build | Transforms a published course version into an immutable PlayPackage with manifest, pinned assets, navigation model, and AI config |
| Package signing | JWS signature over the SHA-256 hash of all assets using tenant signing key |
| Offline bundles | AES-256-GCM encrypted per-device bundles with HKDF-derived keys |
| License envelopes | Signed, time-bound, device-bound, feature-gated license tokens embedded in bundles |
| SCORM export | SCORM 1.2 and SCORM 2004 4th Edition zip generation with imsmanifest.xml |
| HTML5 export | Standalone HTML5 zip for LMS-less deployment |
| xAPI/cmi5 export | xAPI-compatible export with activity profiles |
| SCORM import | Sandboxed ingestion of third-party SCORM zips with manifest validation |
| Bundle revocation | Permanent revocation of packages and bundles; propagated via events |
| Tamper detection | Receives client-reported hash mismatches; escalates via security events |
4. Non-Responsibilities
| Area | Owner | Why Not Content-Service |
|---|---|---|
| Content authoring | authoring-service | Authoring owns the draft lifecycle; content-service consumes the published snapshot |
| Media transcoding | media-service | Content-service references media assets by ID; it does not own transcoding |
| Course catalog / discovery | catalog-service | Catalog projects PlayPackage metadata; content-service does not own listings |
| Enrollment decisions | enrollment-service | Content-service reacts to enrollment events but does not decide who enrolls |
| Sync protocol | sync-service | Sync-service owns delta pull/push; content-service registers bundles as sync entities |
| Runtime playback | delivery-service / Player | The Player is a dumb, deterministic renderer of PlayPackage manifests |
| Key management | KMS (Vault/AWS KMS) | Content-service uses KMS for signing and encryption but does not own key lifecycle |
5. Dependencies
5.1 Upstream Dependencies
| Dependency | Pattern | Purpose |
|---|---|---|
| authoring-service | Event consumer | Consumes authoring.course_draft.published.v1 to trigger PlayPackage builds |
| media-service | ACL (HTTP) | Resolves asset references, fetches asset metadata and download URLs |
| identity-service | Event consumer + ACL | Consumes identity.device.bound_for_offline.v1; fetches device public keys for bundle encryption |
| enrollment-service | Event consumer | Consumes enrollment.created.v1 to trigger bundle creation |
| marketplace-service | Event consumer | Consumes marketplace.license.revoked.v1 to trigger bundle revocation |
| KMS (Vault/AWS KMS) | Infrastructure | Tenant signing keys, HKDF key derivation for bundle encryption |
| S3/R2 | Infrastructure | Artifact storage for zips, bundles, and export outputs |
5.2 Downstream Consumers
| Consumer | Pattern | What They Consume |
|---|---|---|
| catalog-service | Event consumer | Consumes content.play_package.built.v1 to update catalog entries |
| delivery-service | HTTP (ACL) | Fetches PlayPackage manifests for runtime delivery |
| sync-service | Event consumer | Consumes content.play_package.bundle.published.v1 to register bundles for device sync |
| notification-service | Event consumer | Consumes export completion and tamper events for alerting |
| analytics-service | Event consumer | Consumes all content events for build metrics and tamper reporting |
5.3 Events Consumed
| Event | Producer | Purpose |
|---|---|---|
authoring.course_draft.published.v1 | authoring-service | Triggers PlayPackage build pipeline |
enrollment.created.v1 | enrollment-service | Triggers bundle creation for enrolled user's devices |
identity.device.bound_for_offline.v1 | identity-service | Registers device for bundle encryption; triggers bundle creation if enrollment exists |
marketplace.license.revoked.v1 | marketplace-service | Triggers bundle revocation for affected enrollments |
gdpr.subject_request.received.v1 | platform (cross-cutting) | Participates in GDPR erasure saga for bundle and license data |
6. Slice Involvement
| Slice | Scope | Milestone |
|---|---|---|
| S0 — Package Build Pipeline | PlayPackage build from published draft, manifest assembly, asset pinning, signing, basic GET APIs | M1 |
| S1 — Offline Bundles + License Enforcement | Per-device encrypted bundles, license envelopes, revocation flow, tamper detection | M1 |
| S2 — SCORM 1.2 Export | SCORM 1.2 imsmanifest.xml generation, zip packaging, SCORM Cloud validation | M2 |
| S4 — SCORM 2004 + xAPI Export | SCORM 2004 4th Ed, xAPI/cmi5 export, HTML5 standalone, SCORM import pipeline | M3 |
7. Architectural Freeze Points
| Freeze | What Is Frozen | Frozen By |
|---|---|---|
| F05 | LicenseEnvelope schema — field set, signing algorithm, device-binding derivation | Start of M1 |
| F15 | PlayPackage.manifest schema v1.0 — module structure, navigation model, assistant config shape | Start of M1 |
| F01 | EventEnvelope schema — all events conform to 04 Event-Driven | End of M0 |
After freeze, changes require architectural review and a new version with dual-publish window.
8. Service Readiness Levels
| Level | Description | Target Milestone |
|---|---|---|
| L3 | Package build pipeline operational, bundle encryption working, basic monitoring, contract tests, automated failover | M1 |
| L4 | Full SCORM/xAPI export, chaos-tested, production-grade observability, security pen-tested, SLO tracking | M3 |
9. Architecture Diagram
┌───────────────────────────────────────────────┐
│ API Gateway / Edge │
└──────────────────┬────────────────────────────┘
│
┌──────────────────▼────────────────────────────┐
│ content-service │
│ │
│ ┌─────────────┐ ┌──────────────────────┐ │
│ │ HTTP API │ │ NATS Subscribers │ │
│ │ (Inbound) │ │ (Event Consumers) │ │
│ └──────┬──────┘ └──────────┬───────────┘ │
│ │ │ │
│ ┌──────▼─────────────────────▼───────────┐ │
│ │ Application Layer │ │
│ │ │ │
│ │ BuildPlayPackage CreateBundle │ │
│ │ RevokePackage IssueLicense │ │
│ │ ExportSCORM ImportSCORM │ │
│ │ ExportHTML5 ExportXAPI │ │
│ │ DetectTamper HandleGDPR │ │
│ └──────────────────┬────────────────────┘ │
│ │ │
│ ┌──────────────────▼────────────────────┐ │
│ │ Domain Layer │ │
│ │ │ │
│ │ PlayPackage (Aggregate) │ │
│ │ PlayPackageBundle (Aggregate) │ │
│ │ LicenseEnvelope (Value Object) │ │
│ │ PackageManifest (Value Object) │ │
│ └──────────────────┬────────────────────┘ │
│ │ │
│ ┌──────────────────▼────────────────────┐ │
│ │ Infrastructure Layer │ │
│ │ │ │
│ │ PostgresRepo S3StorageClient │ │
│ │ NATSPublisher MediaClient (HTTP) │ │
│ │ KMSClient IdentityClient (HTTP) │ │
│ │ JWSSigner AESGCMEncryptor │ │
│ │ SCORMZipBuilder ManifestValidator │ │
│ └────────────────────────────────────────┘ │
└───────────────────────────────────────────────┘
│ │ │
┌────────────┘ ┌──────┘ ┌──────┘
▼ ▼ ▼
┌───────────┐ ┌───────────┐ ┌───────────┐
│ Postgres │ │ S3 / R2 │ │ KMS │
│ (content) │ │ (artifacts│ │ (Vault) │
│ │ │ bundles) │ │ │
└───────────┘ └───────────┘ └───────────┘
10. Key Design Decisions
10.1 PlayPackage Is Immutable After Build
Once a PlayPackage reaches built status, it is never modified. A new course version produces a new PlayPackage. This ensures:
- Deterministic Player behavior (same package = same experience)
- Tamper detection via SHA-256 hash comparison
- Safe caching at every layer
10.2 Bundle Per-(Enrollment, Device)
Each offline bundle is encrypted for exactly one device. This enables:
- Per-device key revocation without affecting other devices
- License enforcement at the cryptographic layer, not just the application layer
- Forensic tracing of any leaked content
10.3 Player Is Dumb, Service Is Smart
All build-time logic (manifest assembly, asset resolution, navigation computation, AI config injection) lives in content-service. The Player runtime is a deterministic renderer that reads the manifest and plays assets. This makes the Player portable, testable, and lightweight.
10.4 Export Formats Are Separate Artifacts
SCORM, HTML5, and xAPI exports are generated as separate FormatArtifacts on the PlayPackage, not transformations of the PlayPackage itself. This allows:
- Independent generation schedules (S2 vs S4 slices)
- Format-specific validation (SCORM Cloud, xAPI conformance)
- Different retention and distribution policies per format