Skip to main content

Migration Plan

:::info Source Sourced from services/content-service/MIGRATION_PLAN.md in the documentation repo. :::

1. Core Rules

  • PlayPackage manifest (F15) frozen M1 start; additive only; breaking → PlayPackage v2.
  • LicenseEnvelope (F05) frozen M1 start; additive only; signature algorithm pinned.
  • Offline bundles live forever on devices; schema changes must be forward-compatible or trigger re-download.
  • Bundle signatures pinned per algorithm; migration requires dual-signing window.

2. Database Evolution

  • Add column: ✅ same minor (nullable).
  • Drop column: ❌ without major + deprecation.
  • JSONB manifest shape versioned via manifest.version.
  • Indexes CONCURRENTLY.

3. PlayPackage Manifest Evolution

3.1 Adding Optional Fields

Same version; player tolerates unknown fields; documented in manifest schema.

3.2 Adding Required Fields

New manifest version; old bundles remain valid; new builds use new version; player supports both.

3.3 Breaking Change → Manifest v2

  • Dual-publish window ≥ 1 milestone.
  • Player supports v1 + v2 for overlap.
  • Old bundles never re-keyed; continue on v1 until expiry.
  • New builds emit v2.

4. Bundle Encryption Evolution

  • Algorithm: AES-256-GCM pinned.
  • Key derivation: HKDF — additive inputs only.
  • If algorithm changes (e.g., post-quantum), new bundles use new alg; old remain on current alg until re-download.

5. LicenseEnvelope Evolution

  • Feature flags (aiTutor, assessments, certificate, copyDownloadable) additive.
  • New flags default to tenant plan entitlement; existing licenses keep their feature set.
  • Signature algorithm pinned per envelope; migration requires re-issue.

6. SCORM / xAPI / cmi5 Export Evolution

  • Export formats versioned.
  • New format added alongside existing; customer can choose at export time.
  • Deprecated format supported ≥ 2 milestones after successor.

7. Event Evolution

EventVersionPolicy
content.play_package.built.v1v1Additive
content.play_package.bundle.published.v1v1Additive
content.play_package.bundle.revoked.v1v1Additive
content.bundle.tamper_detected.v1v1Additive
content.export.completed.v1v1Format field additive (new enum values)
content.import.completed.v1v1SCORM versions additive

8. Offline Bundle Forward Compatibility

Per docs/roadmap/migration-backward-compatibility.md:

  • Manifest version + envelope version pinned in bundle.
  • New optional fields ignored; new required fields → new manifest version.
  • Block-kind additions show "not supported" stub on older players.
  • Forced re-download only on: revocation, expiry, major manifest version bump, asset changes.

9. KMS Key Rotation Procedure

  1. Generate new tenant signing key in KMS with kid = <tid>-<timestamp>.
  2. Publish pubkey to /.well-known/content-keys.json.
  3. Sync distributes updated key map to devices.
  4. Wait 2-day overlap.
  5. Switch primary signing kid to new one.
  6. Old kid remains valid for already-issued bundles until their expiresAt.
  7. After last bundle with old kid expires, retire old kid from KMS.

Emergency rotation (< 2-day window): forced re-issue of all active bundles; users notified.

10. Tenant Migration Runbook

See ../tenant-service/MIGRATION_PLAN.md §10.

11. Data Residency Migration

Participate in Data Residency Migration Saga:

  • Copy packages + bundles + license envelopes to target region's S3.
  • Verify checksums match.
  • Target-region content-service starts serving after cutover.
  • Old bundles on devices continue to work (encrypted with device key derivable in any region given tenant key).

12. Changelog

Breaking changes tagged in GitHub release + CHANGELOG.md with migration guide.