Skip to content

Handoff: SVC-022-analytics-rebuildable-projection-proof analytics-service rebuildable projection proof

Scope

  • Service/area: analytics-service
  • Task ID: SVC-022-analytics-rebuildable-projection-proof
  • Goal: prove analytics projections can be rebuilt from versioned event sources through explicit hydrated snapshots, with replay-safe report metadata and guarded route rehearsal.
  • Non-goals: asynchronous rebuild worker, production backfill runner, owner-service database joins, canonical StudentMastery parity, public/default route promotion, browser/runtime parity, or changes to legacy source under /Users/velikho/Desktop/WORKING/HOCTAPAZ/.

Docs Read

  • docs/architecture/service-responsibility-matrix.md
  • docs/architecture/legacy-api-map.md
  • docs/agents/service-tasks/analytics-service.md
  • docs/agents/handoffs/SVC-022-mastery-projection-fixtures.md
  • docs/agents/service-agent-next-slice-queue.json
  • docs/agents/service-agent-next-slice-closeout-ledger.json
  • docs/agents/agent-handoff-format.md
  • docs/api/analytics-service.md
  • docs/qa/analytics-rebuildable-projection-proof.md
  • docs/qa/service-agent-goal-completion-audit.md
  • docs/qa/service-agent-readiness-smoke.md

Legacy Evidence Read

  • /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 analytics/progress/result/dashboard inputs were read-only evidence; no legacy source or Prisma table was changed.

Files Changed

  • services/analytics-service/internal/usecase/analytics_rebuild_test.go
  • services/analytics-service/internal/usecase/analytics.go
  • services/analytics-service/internal/domain/analytics.go
  • services/analytics-service/internal/http/server.go
  • services/analytics-service/internal/http/server_test.go
  • docs/api/analytics-service.md
  • docs/qa/analytics-rebuildable-projection-proof.md
  • docs/index.md
  • docs/.vitepress/config.ts
  • docs/agents/handoffs/SVC-022-analytics-rebuildable-projection-proof.md
  • docs/agents/service-agent-next-slice-closeout-ledger.json
  • docs/agents/service-agent-next-slice-closeout-ledger.md
  • docs/agents/service-agent-accepted-handoffs.md
  • docs/qa/service-agent-goal-completion-audit.md
  • docs/qa/service-agent-readiness-smoke.md
  • No producer event contract, migration, default gateway route, or legacy file was changed.

Behavior Implemented

  • Added focused proof coverage for the bounded rebuild workflow: list a versioned source event, replay it without mutation, apply an explicit hydrated result snapshot to the service-owned projection, and record/replay rebuild counters.
  • The existing analytics foundation stores sourceService plus sourceEventId and preserves event payloads for backfill selection. Result snapshots remain service-local upserts keyed by attemptId; analytics does not resolve owner data through database joins.
  • The existing rebuild-report API records QUEUED|RUNNING|COMPLETED|FAILED metadata, source ids, counters, and replay identity. This is rebuild evidence, not an asynchronous worker claim.
  • The producer evidence is explicit: attempt, exam, course, and classroom services emit versioned event sources with snapshots or projection references. A future worker/backfill runner must supply any missing hydrated display data through an owner API or explicit snapshot before calling analytics.
  • Non-admin analytics reads and event/rebuild writes now fail closed when the actor has no organization context or attempts to override it with a query or payload organization id. Admins and internal writers may select an explicit organization scope. Gateway-authenticated identity takes precedence over caller-supplied X-Actor-* compatibility headers.

Tests And Verification

  • Command: GOTOOLCHAIN=go1.25.11 go test ./services/analytics-service/...
  • Result: passed with -count=1.
  • Evidence: the new rebuild workflow test passed source event replay, event listing, hydrated result upsert, rebuild counters, and rebuild-report replay; existing HTTP/use-case tests also passed result, weak-topic, event, and report paths.
  • Command: make test-analytics-routes
  • Result: passed.
  • Evidence: route guard evidence passed for the default legacy table and both non-default native examples.
  • Command: GOTOOLCHAIN=go1.25.11 go test ./services/attempt-service/... ./services/course-service/... ./services/exam-service/... ./services/classroom-service/... -count=1
  • Result: passed.
  • Evidence: producer source-event and analytics sink packages passed for attempt, course, exam, and classroom services.
  • Command: pnpm docs:build
  • Result: passed after the QA page and analytics API link were added to VitePress.
  • Command: git diff --check
  • Result: passed.
  • Command: GOTOOLCHAIN=go1.25.11 go test ./services/analytics-service/... -count=1
  • Result: passed after the organization-scope hardening.
  • Evidence: non-admin query/payload organization overrides return ANALYTICS_FORBIDDEN without writing or reading another tenant's data.
  • Command: GOTOOLCHAIN=go1.25.11 go test -race ./services/analytics-service/internal/http ./services/analytics-service/internal/repository -count=1
  • Result: passed.
  • Runtime recheck: an isolated analytics-service and disposable PostgreSQL database accepted one versioned attempt event, preserved the original event on a changed-payload replay, upserted one explicitly hydrated result snapshot, and preserved the original completed rebuild report on replay. The same teacher actor received ANALYTICS_FORBIDDEN when querying another organization. Evidence is retained in output/qa/analytics-rebuildable-projection-proof-20260713/.
  • Gateway recheck: the non-default routes.analytics-read-native-localhost-example.json routed exact results and weak-topic reads with X-Gateway-Route-State: native_read; the active default table still returned X-Gateway-Route-State: legacy_proxy against a deliberately unavailable legacy target. The temporary Compose stack and Gateway were removed after capture.

Required Evidence

  • rebuildable projection proof: services/analytics-service/internal/usecase/analytics_rebuild_test.go exercises source-event selection, explicit hydrated result upsert, and replay-safe rebuild report counters without owner database joins.
  • event-source proof: docs/qa/analytics-rebuildable-projection-proof.md records the versioned attempt, exam, course, and classroom event contracts; producer package tests passed and analytics stores source idempotency metadata.
  • route guard evidence: make test-analytics-routes passed and confirms only exact non-default result/weak-topic reads are rehearsed as native routes.
  • tenant boundary evidence: analytics HTTP tests cover mismatched query and event payload organization ids for a teacher actor.
  • isolated runtime evidence: output/qa/analytics-rebuildable-projection-proof-20260713/ contains the event-source replay, hydrated projection, replay-safe rebuild report, tenant boundary, native-read header, and default rollback header captures.

Route State

  • Legacy route: /api/analytics*, /api/exams*, /api/classrooms*, /api/students*, /api/parents*, and fallback routes remain on the default legacy gateway table.
  • Native route: non-default examples rehearse only exact GET /api/analytics/results and GET /api/analytics/weak-topics reads with gateway auth, ADMIN/TEACHER role checks, and organization scope.
  • Gateway state: analytics route changes require rebuildable projection/event-source proof and route guard evidence. This handoff does not approve a default route change.
  • Delegated gateway scope: route proof only; default gateway route tables remain orchestrator-owned.
  • Rollback notes: keep deploy/gateway/routes.json active; remove the non-default analytics route examples or disable native analytics callers if freshness, parity, access adapters, or runtime/browser proof regresses.

Data Notes

  • Tables touched: the isolated analytics PostgreSQL database only; no shared or legacy database was modified.
  • Migration run: analytics migrations were applied only inside the disposable hoctapaz-analytics-proof-20260713 Compose project, which was removed with its volumes after capture.
  • Validation report: focused service, producer, route, race, isolated runtime, docs, and diff checks passed; no production data or backfill job was executed.

Risks / Blockers

  • The bounded proof does not provide an asynchronous rebuild worker or production-like backfill run report; those remain separate tasks.
  • Source replay identity is still keyed by (sourceService, sourceEventId); tenant-qualified replay keys require a coordinated schema/producer migration.
  • Parent/teacher/admin visibility adapters, full legacy filter parity, and browser proof remain open before public promotion. The isolated runtime and default-route rollback rehearsals are evidence only, not promotion approval.
  • Canonical course mastery and profile/classroom recipient resolution remain outside analytics ownership.
  • IAM/Profile production-like populated-target cutover and rollback proof remain open for the broader goal.

Next Step

  • Build a named owner-service backfill runner or projection worker against disposable event fixtures, attach runtime/browser and rollback evidence, and only then review any default analytics route promotion.

Go-platform documentation is generated from repository Markdown.