Skip to content

analytics-service Agent Tasks

Agent workflow: follow README.md for Audit -> Investigate -> Code -> Test -> Fix; keep this pack's writable scope and verification commands authoritative.

Dispatch type: per-service

Dispatch ID: SVC-022

Current implementation: services/analytics-service.

Owns: result/progress/mastery/dashboard projections, analytics events, weak-topic rollups, summary read models, and rebuild/backfill metadata.

Must read:

  • docs/agents/handoff-phase-9-analytics-foundation.md
  • legacy analytics/progress/result/dashboard modules: /Users/velikho/Desktop/WORKING/HOCTAPAZ/node-platform/apps/api/src/modules/analytics/analytics.service.ts, /Users/velikho/Desktop/WORKING/HOCTAPAZ/node-platform/apps/api/src/modules/analytics/analytics.controller.ts, /Users/velikho/Desktop/WORKING/HOCTAPAZ/node-platform/apps/api/src/modules/app-data/app-data.exams-analytics.ts, /Users/velikho/Desktop/WORKING/HOCTAPAZ/node-platform/apps/api/src/modules/app-data/app-data.progress-overview.ts, /Users/velikho/Desktop/WORKING/HOCTAPAZ/node-platform/apps/api/src/modules/app-data/app-data.learning-progress.ts, /Users/velikho/Desktop/WORKING/HOCTAPAZ/node-platform/apps/api/src/modules/progress/progress.controller.ts, /Users/velikho/Desktop/WORKING/HOCTAPAZ/node-platform/apps/api/src/modules/exams/exam-core.service.ts, /Users/velikho/Desktop/WORKING/HOCTAPAZ/node-platform/apps/api/src/modules/attempts/attempts.controller.ts.

Legacy source evidence:

  • /Users/velikho/Desktop/WORKING/HOCTAPAZ/node-platform/apps/api/src/modules/analytics/**
  • progress and parent dashboard inputs under /Users/velikho/Desktop/WORKING/HOCTAPAZ/node-platform/apps/api/src/modules/app-data/**
  • result/progress inputs under /Users/velikho/Desktop/WORKING/HOCTAPAZ/node-platform/apps/api/src/modules/exams/**
  • attempt inputs under /Users/velikho/Desktop/WORKING/HOCTAPAZ/node-platform/apps/api/src/modules/attempts/**.

Writable files:

  • services/analytics-service/**
  • contracts/openapi/services/analytics-service.yaml
  • docs/api/analytics-service.md

Orchestrator-owned files:

  • attempt/exam/course/classroom event contracts, profile hydration contracts, gateway route cutovers, and shared deploy manifests unless delegated.

Delegated gateway verification scope:

  • Only when the orchestrator assigns an analytics route/live/browser proof subtask, this service agent may update non-default deploy/gateway/routes.analytics-*.json examples, scripts/test/analytics-*.sh, docs/qa/analytics-*.md, and root Makefile test-analytics-* targets.
  • Producer event contracts, profile/classroom visibility adapters, default gateway routes, and frontend dashboard pages remain orchestrator-owned unless explicitly delegated. Public promotion still requires browser/runtime proof and rollback notes.

Initial tasks:

  • Done: foundation workflow tests exist for result snapshot -> weak topics -> class/student/exam summaries. Add new tests only for new projections or route promotions.
  • Done: result snapshots carry normalized source-exam question difficulties (EASY, MEDIUM, HARD, VERY_HARD), and result list plus weak-topic filters match legacy difficulty queries through memory, Postgres JSONB containment, OpenAPI, and docs. Public route promotion still depends on access adapters and runtime proof.
  • Done: analytics event ingestion accepts sourceService + sourceEventId, stores replay metadata in memory/Postgres, filters by sourceService, and returns the original event on replay without mutation.
  • Add producer adapter callers from attempt/exam/course/classroom. Done: attempt-service now best-effort emits attempt.submitted.v1 and attempt.graded.v1; course-service now best-effort emits course.enrollment.granted.v1 and course.lesson_progress.saved.v1, course.video_progress.saved.v1, and course.material_view.saved.v1; exam-service now best-effort emits exam.published.v1, exam.assigned.v1, and exam.results_released.v1; classroom-service now best-effort emits classroom.membership.snapshot.v1 after native membership mutations. Remaining slices: broader mastery projections and notification handoffs. Events must include enough display snapshots or projection refs to avoid cross-service DB joins.
  • Add result visibility and parent/teacher/admin access adapter tasks before public route promotion. Gateway/BFF or owner-service adapters must supply parent-child, classroom, and organization access decisions.
  • Keep filter-parity checks for legacy result/weak-topic queries attached to route promotion, including classroomId, examId, subjectId, gradeLevel, difficulty, topic, from, to, page, and limit.
  • Add classroom report/export and parent progress task slices separately from the current teacher results/weak-topic read rehearsal.
  • Done: analytics-service records replay-safe rebuild/backfill report metadata through POST /v1/analytics/rebuild-reports and lists it through GET /v1/analytics/rebuild-reports. Reports store source idempotency, scope, status, counters, error/metadata, and started/finished timestamps for owner-service event streams or read-only backfill jobs.
  • Done: POST /internal/v1/analytics/rebuild/attempt-results materializes organization-scoped stored attempt.graded.v1 events into result, weak-topic, and summary inputs. It requires the v1 copied student/exam/result/question snapshot, rejects malformed or incomplete events without partial rows, uses a cursorable unmaterialized-event scan, and writes the result plus attempt-result-v1 receipt atomically. The endpoint stays outside Gateway tables; no public analytics route is promoted. attempt-service persists and publishes student.fullName so replay does not require profile joins. Broader generic attempt-result consumer workers remain separate slices.
  • Course mastery, recommendation, and report implementation is gated by analytics-course-learning-projection.md. Do not infer course membership from an examId: only a Course-validated context persisted by attempt-service in a new graded event version can attach an attempt result to a course projection.
  • Done: POST /internal/v1/analytics/rebuild/course-learning consumes only stored Course catalog/progress snapshots and trusted attempt.graded.v2 events for one organization. 000007 owns the local catalog, latest progress, course-attempt facts, and mastery rows; each accepted source event gets a separate course-learning-v1 receipt. The materializer computes the legacy formula and recommendation thresholds from local copies only, drops stale catalog mappings deterministically, and never infers a Course from an examId. make test-analytics-postgres-rebuild proves catalog/progress/v2, replay, and organization isolation in a disposable PostgreSQL schema.
  • Done: Course may opt in to a durable owner-side catalog delivery worker after 000006_course_learning_catalog_outbox.sql. It posts immutable course.learning_catalog.changed.v1 source pairs through the existing Analytics ingestion endpoint with lease/retry/dead-letter ownership retained in Course. This is transport only: it neither makes Analytics poll Course nor starts the internal rebuild worker, and it does not add a Gateway route.
  • Done: 000008_course_learning_projection_outbox.sql makes Analytics ingest durable without joining owner storage. Its trigger enqueues only the Course catalog/progress and trusted Attempt v2 contracts; the opt-in PostgreSQL worker lease-claims them, materializes locally, then retries or dead-letters validation failures. ANALYTICS_COURSE_LEARNING_PROJECTION_WORKER_ENABLED remains false by default. This worker never polls Course, runs outside HTTP ingestion latency, and does not add an endpoint or Gateway route. make test-analytics-course-learning-projection-worker-config keeps the Compose, raw Kubernetes, and Helm defaults explicitly disabled until an orchestrator enables both delivery sides.
  • Done: GET /internal/v1/analytics/courses/{courseId}/masteries exposes the local course-learning rows only to an internal adapter. STUDENT is forced to self, TEACHER/ADMIN are organization-scoped, and PARENT is denied. Course enrollment and current teacher visibility remain Course/Gateway owner decisions, so this endpoint is absent from all Gateway tables.
  • Done: make test-analytics-postgres-rebuild starts a disposable PostgreSQL container and runs the HTTP materializer against an isolated schema. It proves one result and receipt from a valid source event, no duplicate data after replay, and no partial result/receipt after a bad schema version. It does not use a configured service database or promote an analytics Gateway route. The runner writes a reproducible local bundle with summary.json and go-test.log; the latest is output/qa/analytics-postgres-rebuild-20260715-033318/.
  • Done: analytics-service exposes GET /v1/analytics/weak-topic-alert-intents as a bounded preview over the existing weak-topic rollup. It returns only shouldAlert=true topics with deterministic sourceService=analytics-service and sourceEventId metadata, notification preference/type hints, topic counts, affected counts, scope filters, and adapter payload metadata. It does not resolve parent recipients, call notification-service, or read profile/classroom databases. These native intent rows are topic/filter metadata; any dispatch adapter must receive or derive concrete studentId values before asking profile-service for parent recipients.

Acceptance:

  • Analytics stores projections, not canonical exam/attempt/course/question state.
  • Result visibility and parent/teacher/admin filters preserve legacy behavior.
  • Projections can be rebuilt from events/backfill.
  • Rebuild/backfill report metadata is service-owned and replay-safe.
  • Cross-service display snapshots are by value or through explicit owner-service APIs; analytics-service never reads owner databases directly.
  • Weak-topic alert production is an event to notification-service with resolved alert intent only; parent recipient resolution remains outside analytics.

Verification:

  • GOTOOLCHAIN=go1.25.11 go test ./services/analytics-service/...
  • make test-analytics-routes
  • ANALYTICS_POSTGRES_REBUILD_CONFIRM=disposable-postgres make test-analytics-postgres-rebuild
  • Future projection slices must add focused producer/backfill worker tests, route guards for any promoted public paths, and browser/runtime evidence before default route cutover.

Go-platform documentation is generated from repository Markdown.