Skip to content

feat(backend): modularize services and clean deps (#813 #814 #815 #821) - #1

Open
marvel6828 wants to merge 1 commit into
mainfrom
feat/be-modularize-services-813-814-815-821
Open

feat(backend): modularize services and clean deps (#813 #814 #815 #821)#1
marvel6828 wants to merge 1 commit into
mainfrom
feat/be-modularize-services-813-814-815-821

Conversation

@marvel6828

@marvel6828 marvel6828 commented Jul 29, 2026

Copy link
Copy Markdown
Owner

Summary

closes BrainTease#821
closes BrainTease#813
closes BrainTease#814
closes BrainTease#815

Resolves four backend technical-debt issues in a single cohesive PR.


BrainTease#821 — Analytics ingestion pipeline modularized

Problem: AnalyticsService.aggregateCourse was a monolith mixing database I/O, metric calculation, persistence, and cache invalidation in one method.

Solution: Introduced four discrete pipeline stages under src/analytics/pipeline/:

Stage Responsibility
DataCollectionStage Parallel DB queries — pure I/O, no computation
AggregationStage Metric calculations — pure computation, no I/O
PersistenceStage Upserts the computed record — one write per run
CacheStage Invalidates the stale cache key

AnalyticsPipeline orchestrates the stages in order. AnalyticsService.aggregateCourse now delegates entirely to pipeline.run(courseId).

Tests: analytics.pipeline.spec.ts — stage isolation + orchestrator ordering


BrainTease#815 — Royalty-distribution calculation extracted into a service

Problem: Revenue/royalty math was inlined inside PayoutsService.calculatePayouts, mixing business logic with persistence.

Solution: Created RoyaltyCalculationService with:

  • calculate(input) — single-course royalty (completions × price − platform fee)
  • calculateBatch(inputs) — filters zero-completion courses, maps calculate
  • getCoursePrice(courseId) / getPlatformFeePercent() — config accessors

PayoutsService now delegates all math to this service.

Tests: royalty-calculation.service.spec.ts — covers all public methods


BrainTease#814 — Remove unused npm dependencies

Analysis method: Static import scan across all src/**/*.ts files.

Removed:

  • apollo-server-express — zero imports; GraphQL runs through @nestjs/graphql / @nestjs/apollo
  • graphql-query-complexity — zero imports

Retained (confirmed in use): class-sanitizer, otplib, qrcode, xml2js, adm-zip, passport-google-oauth20, cache-manager-redis-store, graphql-depth-limit, @elastic/elasticsearch


BrainTease#813 — Dispute-resolution service refactored

Problem: AdminService mixed user management with dispute lifecycle logic, increasing cyclomatic complexity through nested guards and status checks.

Solution: Extracted DisputeResolutionService with:

  • createDispute, listDisputes, getDisputeOrThrow, resolveDispute
  • Private isTerminal(status) helper replacing repeated inline status comparisons
  • AdminService now owns only user management and thin delegators

Tests: dispute-resolution.service.spec.ts — 7 cases covering happy paths and all guard branches


Testing

All new code is covered by unit tests that run without a database or real cache:

# Run all new unit tests
npx jest --testPathPattern="analytics/pipeline|royalty-calculation|dispute-resolution" --no-coverage

Checklist

…inTease#814 BrainTease#815 BrainTease#821)

BrainTease#821 — Analytics ingestion pipeline modularized into discrete stages
- Add pipeline/ folder under src/analytics/ with four stages:
  DataCollectionStage (I/O), AggregationStage (computation),
  PersistenceStage (upsert), CacheStage (invalidation)
- Add AnalyticsPipeline orchestrator that sequences the stages
- Refactor AnalyticsService.aggregateCourse to delegate to the pipeline
- Update AnalyticsModule to register all pipeline providers
- Add analytics.pipeline.spec.ts unit tests (stage isolation + orchestrator)

BrainTease#815 — Royalty-distribution calculation extracted into a service
- Add RoyaltyCalculationService with RoyaltyInput/RoyaltyResult interfaces
- Expose calculate(), calculateBatch(), getCoursePrice(),
  getPlatformFeePercent() — pure computation, no I/O
- Refactor PayoutsService.calculatePayouts to delegate to the new service
- Update PayoutsModule to register RoyaltyCalculationService
- Add royalty-calculation.service.spec.ts unit tests

BrainTease#814 — Remove unused npm dependencies
- Remove apollo-server-express (zero imports; GraphQL runs via @nestjs/graphql)
- Remove graphql-query-complexity (zero imports)
- Confirmed all other suspect deps (class-sanitizer, otplib, qrcode, xml2js,
  adm-zip, passport-google-oauth20, cache-manager-redis-store,
  graphql-depth-limit, @elastic/elasticsearch) are actively used

BrainTease#813 — Dispute-resolution service refactored (reduced cyclomatic complexity)
- Extract DisputeResolutionService with isTerminal() guard helper
- AdminService now owns only user management; delegates dispute methods
- Update AdminModule to register DisputeResolutionService
- Add dispute-resolution.service.spec.ts unit tests (7 cases)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant