Skip to main content

Overview

:::info Source Sourced from services/assignment-service/SERVICE_OVERVIEW.md in the documentation repo. :::

Companion: 03 assignment-service · 04 Event-Driven · 02 DDD & Bounded Contexts · 01 Enterprise Architecture


1. Mission Statement

The assignment-service is the single owner of compliance-driven course assignments on the Ghasi-edTech platform. It is responsible for translating business policy ("All new-hire nurses must complete Fire Safety within 30 days, annually thereafter, with 7-day grace") into deterministic, timeboxed, audit-grade ComplianceWindow instances that drive enrollments, reminders, escalations, and compliance reporting.

It is classified as a Core Domain because:

  • It is the primary competitive differentiator for regulated verticals (healthcare, finance, aviation, pharma).
  • It is where the "assigned learning" business process is codified; no off-the-shelf replacement can capture tenant-specific compliance semantics.
  • It fuses deterministic time logic (RRULE), policy (escalation, grace), saga orchestration (window lifecycle), and explainable AI (suggested assignments).

2. Bounded Context

AttributeValue
Context nameAssignment
Domain classCore
Upstream contextsIdentity (users), Tenant (org units, dynamic groups), Catalog (course metadata), AI Gateway (suggestions)
Downstream contextsEnrollment (creates enrollments), Notification (reminders, escalations), Progress (consumes completion), Analytics (compliance rollups), Certification (triggers cert on completion)
Shared kernel@ghasi/domain-primitivesTenantId, UserId, CourseId, CourseVersionId, EnrollmentId, I18nString, ISODate, ISODuration, RRULEString, AIProvenance

3. Aggregate Roots

AggregateClusterConsistency boundary
Assignmenttargets, escalation, reminderPolicy, rruleSingle transactional aggregate per assignment
ComplianceWindow(standalone)One window = one saga instance; materialised from Assignment.rrule

Why ComplianceWindow is its own aggregate: Windows have an independent lifecycle (open → in_progress → completed / closed_missed). A single Assignment may spawn tens of thousands of windows (10,000 nurses × 10 annual occurrences). Keeping them as a separate aggregate avoids a monstrous root and enables per-window concurrency.

4. Service Responsibilities

┌────────────────────────────────────────────────────────────────────────┐
│ assignment-service │
│ │
│ ┌─────────────────┐ ┌───────────────────┐ ┌──────────────────────┐ │
│ │ Assignment CRUD │ │ Target Resolver │ │ RRULE Materializer │ │
│ │ + state machine │ │ (user|OU|group) │ │ (cron, horizon=90d) │ │
│ └─────────────────┘ └───────────────────┘ └──────────────────────┘ │
│ ┌─────────────────┐ ┌───────────────────┐ ┌──────────────────────┐ │
│ │ Window Saga │ │ Escalation Engine │ │ Reminder Scheduler │ │
│ │ (open→closed) │ │ (policy-driven) │ │ (batch + per-window) │ │
│ └─────────────────┘ └───────────────────┘ └──────────────────────┘ │
│ ┌─────────────────┐ ┌───────────────────┐ ┌──────────────────────┐ │
│ │ Compliance │ │ AI Suggested │ │ GDPR Subject Request │ │
│ │ Reporting API │ │ Assignments (S5) │ │ Handler │ │
│ └─────────────────┘ └───────────────────┘ └──────────────────────┘ │
└────────────────────────────────────────────────────────────────────────┘

4.1 Owns (read + write)

  • Assignment aggregate (title, courseId, targets, rrule, policies, state)
  • ComplianceWindow instances (per user × occurrence)
  • Window state machine transitions
  • Escalation policy evaluation
  • Reminder scheduling plans
  • Course version policy (pin vs latest) at the assignment level
  • AI-suggested-assignment provenance
  • Compliance report query layer (read-model over windows)

4.2 Reads (via events / projections)

  • enrollment.created.v1 — transition window to in_progress
  • progress.completion.recorded.v1 — transition window to completed
  • tenant.dynamic_group.evaluated.v1 — recompute targets
  • tenant.membership_activated.v1 — attach new members to running assignments
  • gdpr.subject_request.received.v1 — purge/anonymize subject
  • catalog.course_version.published.v1 — pick up latest version when courseVersionPolicy='latest'

4.3 Does NOT own

  • The actual enrollment record (enrollment-service)
  • Progress tracking (progress-service)
  • Notification delivery (notification-service — we publish intent, they deliver)
  • Certification issuance (certification-service)
  • User identity and group membership (identity + tenant services)
  • Course content (content-service)

5. Technology Stack

ConcernChoiceRationale
RuntimeNode.js 22 LTS / TypeScript 5.6Monorepo alignment, strong typing for RRULE and policy
HTTPFastify 5Performance, schema validation, hook lifecycle
ORMDrizzle ORM (pg driver)Type-safe SQL, RLS-friendly
DBPostgreSQL 16 + pg_partman (windows partitioned by month)Volume: millions of windows/tenant/year
EventsNATS JetStream (subject assignment.*)At-least-once, durable consumers, per-tenant queue groups
Schedulercroner + rrule.js + in-DB jobs tableDeterministic, tenant-scoped, restartable
CacheRedis (L1)Target-resolution cache, dynamic group snapshots
ObservabilityOpenTelemetry SDK → OTLP → SigNozTraces, metrics, logs unified
AIAI Gateway client (@ghasi/ai-gateway-client)No direct model access

6. Position in M-Milestones and Slices

MilestoneReadinessScope
M1Not in scope
M2L1Skeleton, domain model compiles
M3L3S4: Assignments MVP — CRUD, RRULE, windows, escalation, reminders, compliance report
M4L4S5: AI-suggested assignments, dynamic-group rebinding, replay-complete saga
M5L4+Offline authoring of assignments by admins (sync projection)

Freeze points (from 14 Risks & Tradeoffs):

  • F25 — RRULE semantics frozen at start of M3
  • F26 — ComplianceWindow state machine frozen at start of M3

7. Non-Functional Targets

MetricTarget
Write latency (assignment create) p95< 250 ms
Write latency (window materialization batch of 10k)< 60 s
Event fan-out freshness (window.opened → enrollment.created) p95< 2 s
Compliance report query p95 (100k windows)< 1.5 s
Availability99.9%
Data durabilityRPO ≤ 5 min, RTO ≤ 30 min

8. Key Design Decisions (ADR index)

ADRDecision
ADR-AS-001ComplianceWindow is a separate aggregate, not child of Assignment
ADR-AS-002RRULE horizon capped at 90 days (rolling materialization)
ADR-AS-003Escalation is policy-driven, never hard-coded
ADR-AS-004Dynamic-group rebinding happens on tenant.dynamic_group.evaluated.v1 only
ADR-AS-005AI-suggested assignments always require human approval before activate
ADR-AS-006Per-tenant partitioning of compliance_window table

9. Success Signals

  • Business: Auditor produces compliance report in < 2 minutes for 100k users.
  • Engineering: Zero "phantom overdue" incidents (false-positive overdue events) in staging for 30 days pre-GA.
  • Product: ≥ 60% of active enterprise tenants use at least one recurring (rrule-based) assignment by M5.

10. Out of Scope (explicitly)

  • Grading or assessment logic → assessment-service
  • Cert issuance → certification-service
  • Direct notification delivery → notification-service
  • Learner-initiated enrollment → enrollment-service (/self-enroll)
  • Payment-driven enrollment → marketplace + enrollment services