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
| Event | Version | Policy |
|---|---|---|
content.play_package.built.v1 | v1 | Additive |
content.play_package.bundle.published.v1 | v1 | Additive |
content.play_package.bundle.revoked.v1 | v1 | Additive |
content.bundle.tamper_detected.v1 | v1 | Additive |
content.export.completed.v1 | v1 | Format field additive (new enum values) |
content.import.completed.v1 | v1 | SCORM 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
- Generate new tenant signing key in KMS with
kid = <tid>-<timestamp>. - Publish pubkey to
/.well-known/content-keys.json. - Sync distributes updated key map to devices.
- Wait 2-day overlap.
- Switch primary signing
kidto new one. - Old
kidremains valid for already-issued bundles until theirexpiresAt. - After last bundle with old
kidexpires, retire oldkidfrom 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.