Overview
:::info Source
Sourced from services/authoring-service/01-SERVICE_OVERVIEW.md in the documentation repo.
:::
Companion: 03 authoring-service · 10 Authoring Tool Spec · 04 Event-Driven · 01 Enterprise Architecture
1. Mission Statement
The authoring-service is the single owner of the mutable course authoring workspace. It manages the full lifecycle of course drafts — from creation through AI-assisted block editing to the publish saga that hands off immutable content to the rest of the platform. It is classified as a Core Domain service and is the primary competitive differentiator of the Ghasi-edTech platform.
2. Bounded Context
| Attribute | Value |
|---|---|
| Context name | Authoring |
| Domain class | Core |
| Upstream contexts | Identity (authentication), Tenant (tenancy), Media (asset pipeline), AI Services (co-authoring) |
| Downstream contexts | Content-Packaging (PlayPackage build), Catalog (course registration), Delivery (learner consumption) |
| Shared kernel | Common value objects (TenantId, UserId, I18nString, AIProvenance, Locale, MediaRef) from @ghasi/domain-primitives |
3. Aggregate Roots
| Aggregate | Cluster | Consistency boundary |
|---|---|---|
| CourseDraft | ModuleDraft → LessonDraft → Block[] | Entire draft tree is a single transactional aggregate |
| CollaborationSession | participants, yDocUpdateLog | Per-draft collaboration state |
4. Service Responsibilities
┌─────────────────────────────────────────────────────────────────────┐
│ authoring-service │
│ │
│ ┌────────────┐ ┌────────────────┐ ┌───────────────────────────┐ │
│ │ CourseDraft│ │ Block Registry │ │ Course Publish Saga │ │
│ │ Lifecycle │ │ & Editor Logic │ │ (orchestrated, 5-step) │ │
│ └────────────┘ └────────────────┘ └───────────────────────────┘ │
│ ┌────────────┐ ┌────────────────┐ ┌───────────────────────────┐ │
│ │ AI │ │ SCORM Import │ │ Real-time Collaboration │ │
│ │ Co-Author │ │ Pipeline │ │ (Yjs, M4+) │ │
│ └────────────┘ └────────────────┘ └───────────────────────────┘ │
│ ┌────────────┐ ┌────────────────┐ ┌───────────────────────────┐ │
│ │ Review & │ │ GDPR Subject │ │ Sync Projection │ │
│ │ Approval │ │ Request Handler│ │ (offline authoring, S5) │ │
│ └────────────┘ └────────────────┘ └───────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
4.1 Owns (read + write)
CourseDraftaggregate (modules, lessons, blocks)- Block ordering and structural integrity
- Draft state machine (
editing → in_review → approved → publishing → published_idle) - AI co-authoring flows (generate, improve, translate, quiz)
- HITL acceptance/rejection of AI-generated blocks
- Course Publish Saga orchestration
- Collaboration sessions (Yjs state)
- SCORM import pipeline
- Block version history
4.2 Reads (via events/projections)
media.asset.ready.v1— resolve media references in blocksai.completion.finished.v1— attach AI completions to draft blockscontent.play_package.built.v1— advance publish sagacatalog.course_version.published.v1— advance publish sagacontent.play_package.bundle.published.v1— advance publish sagagdpr.subject_request.received.v1— anonymize/delete user data
4.3 Does NOT own
- Immutable published course content (content-service)
- Course catalog entry (catalog-service)
- Media asset transcoding (media-service)
- AI model execution (ai-gateway-service)
- Learner progress or completion (progress-service)
- Assessment quiz bank internals (assessment-service)
5. Technology Stack
| Layer | Technology |
|---|---|
| Runtime | Node.js 22 LTS |
| Framework | NestJS 11 (Clean/Hexagonal Architecture) |
| Language | TypeScript 5.6+ (strict mode) |
| Database | PostgreSQL 16 with RLS |
| Message broker | NATS JetStream |
| Real-time | WebSocket (ws) + Yjs protocol |
| ORM | Drizzle ORM |
| Validation | Zod |
| Observability | OpenTelemetry SDK |
| Testing | Vitest + Playwright (E2E) + Pact (contract) |
| Container | Docker (distroless Node base) |
6. Architecture Layers
┌─────────────── Presentation ─────────────────────────────────────┐
│ NestJS Controllers · WebSocket Gateway · SSE endpoints │
│ DTOs (Zod schemas) · OpenAPI decorators │
└──────────────────────────┬───────────────────────────────────────┘
│
┌─────────────── Application ──────────────────────────────────────┐
│ Use-Cases (commands + queries) · Saga Orchestrator │
│ Ports (interfaces) · Mappers · Application Events │
└──────────────────────────┬───────────────────────────────────────┘
│
┌─────────────── Domain (pure TS, zero deps) ──────────────────────┐
│ CourseDraft aggregate · Block discriminated union · VOs │
│ State machine · Invariant enforcement · Domain events │
└──────────────────────────┬───────────────────────────────────────┘
│
┌─────────────── Infrastructure ───────────────────────────────────┐
│ Postgres repos (Drizzle) · NATS publisher/subscriber │
│ Outbox relay · AI Gateway HTTP client · Media client │
│ Yjs persistence adapter · SCORM parser · Sync projector │
└──────────────────────────────────────────────────────────────────┘
7. Service Readiness Levels
| Milestone | Level | Capabilities |
|---|---|---|
| M1 | L1 | CRUD drafts, block editor, basic AI co-author, publish saga v1 |
| M2 | L3 | Full block registry (frozen F17), SCORM import v1, observability, contract tests |
| M4 | L4 | Live collaboration (Yjs), offline authoring, branching scenarios |
8. Freeze Points
| ID | Artifact | Frozen at |
|---|---|---|
| F17 | Block registry + BlockBase shape | M2 start |
| F15 | PlayPackage manifest schema | M1 start |
9. Slice Assignments
| Slice | Features |
|---|---|
| S2 | Block editor + AI co-author + publish saga + SCORM import v1 |
| S4 | Branching scenarios, SCORM 2004 |
| S5 | Live collab (Yjs), offline authoring |
10. Key Design Decisions
| Decision | Rationale |
|---|---|
| Single aggregate for entire draft tree | Block ordering invariants + tenant consistency require atomic writes; Yjs merge at aggregate level |
| Saga orchestrator (not choreography) for publish | 5-step publish with compensation requires explicit state machine; choreography would scatter the logic |
| AI blocks as first-class domain concept | HITL requirement means AI output must be tracked, reviewed, and audited at the domain level |
| Yjs in infrastructure layer | Domain stays framework-free; Yjs is a persistence/sync concern, not a domain concern |
| Block discriminated union (not inheritance) | TypeScript ADTs are more type-safe and serialization-friendly than class hierarchies |
11. Dependency Diagram
┌──────────────┐
│ identity │
│ service │
└──────┬───────┘
│ JWT validation
▼
┌──────────┐ ┌──────────────────────┐ ┌─────────────────┐
│ tenant │◄───│ authoring-service │───►│ ai-gateway │
│ service │ │ │ │ service │
└──────────┘ └──────────┬───────────┘ └─────────────────┘
│ │ │
┌──────────┘ │ └──────────┐
▼ ▼ ▼
┌─────────────┐ ┌──────────────┐ ┌──────────────────┐
│ content │ │ catalog │ │ media │
│ service │ │ service │ │ service │
└─────────────┘ └──────────────┘ └──────────────────┘
│ │
└────────┬────────┘
▼
┌────────────┐
│ delivery │
│ service │
└────────────┘
All cross-service communication is via NATS JetStream events, except:
- Tenant resolution: synchronous HTTP (1-hop, cached)
- AI gateway requests: synchronous HTTP with SSE streaming