32 KiB
Analytics Backend Refactoring - Implementation Checklist
Purpose: Step-by-step checklist for implementing the refactoring design. Estimated Total Time: 16-23 hours (2-3 days) Status: Not Started
Pre-Implementation Checklist
- Read full design document (
REFACTORING-DESIGN.md) - Review architecture diagrams (
ARCHITECTURE-DIAGRAM.md) - Ensure all tests pass on main branch
- Create feature branch:
refactor/analytics-srp-compliance - Set up test coverage tracking (aim for 80%+)
Phase 1: ProfileAnalyticsService (P0) - CRITICAL
Estimated Time: 4-6 hours Start Date: ___________ Completion Date: ___________
1.1 Setup Directory Structure
- Create
src/services/profile-analytics/directory - Create
index.ts(barrel export file) - Create test directory
src/services/profile-analytics/__tests__/
1.2 Extract ProfileEventTrackerService
File: src/services/profile-analytics/profile-event-tracker.service.ts (~250 lines)
- Create new file
- Copy imports from original service
- Extract constructor dependencies:
@InjectRepository(ProfileEvent) eventRepoRedisService
- Extract methods (lines 104-313):
trackDiscovery(input: TrackDiscoveryInput): Promise<void>trackDiscoveryBatch(inputs: TrackDiscoveryInput[]): Promise<void>trackProfileView(input: TrackProfileViewInput): Promise<void>trackPhotoView(input: TrackPhotoViewInput): Promise<void>trackEngagement(input: TrackEngagementInput): Promise<void>
- Extract helper method:
private getDateKey(date: Date): string(line 1053-1058)
- Add UUID validation helper:
private validateUuid(id: string, fieldName: string): void { if (!isUuid(id)) { throw new BadRequestException(`Invalid ${fieldName} format`) } } - Refactor validation to use new helper (remove repetitive code)
- Add
@Injectable()decorator - Verify line count ≤ 300 lines
Testing:
- Create
profile-event-tracker.service.spec.ts - Test:
trackDiscoverywith valid input saves event + updates Redis - Test:
trackDiscoverywith invalid UUID throws BadRequestException - Test:
trackDiscoveryBatchprocesses all events - Test:
trackProfileViewsaves event with correct source - Test:
trackPhotoViewsaves event with photoId in context - Test:
trackEngagementmaps engagement type correctly - Test: Redis counter increments and expires correctly
- Run tests:
pnpm test profile-event-tracker.service.spec.ts - Verify coverage ≥ 80%
1.3 Extract ProfileMetricsQueryService
File: src/services/profile-analytics/profile-metrics-query.service.ts (~280 lines)
- Create new file
- Copy imports
- Extract constructor dependencies:
@InjectRepository(ProfilePerformance) performanceRepo@InjectRepository(DuoReferralStats) duoStatsRepo@InjectRepository(ProfileEvent) eventRepo
- Extract public methods (lines 319-570):
getProfileOverview(profileId, dateRange): Promise<ProfileAnalyticsOverview>getProfileChart(profileId, dateRange, metric): Promise<ProfileChartResponse>getDuoPartnerReferrals(profileId, dateRange): Promise<DuoReferralsResponse>getConversionFunnel(profileId, dateRange): Promise<ProfileFunnelResponse>getMessageSourceBreakdown(profileId, dateRange): Promise<MessageSourceBreakdown>
- Extract private helper methods (lines 910-1048):
private getAggregatedMetrics(profileId, startDate, endDate)private getTopSources(profileId, startDate, endDate)private getPositionStats(profileId, startDate, endDate)private calculateTrend(current, previous): MetricWithTrend
- Extract date calculation (lines 876-908):
private calculateDateRanges(dateRange): { startDate, endDate, comparisonStart, comparisonEnd }
- Add
@Injectable()decorator - Verify line count ≤ 300 lines
Testing:
- Create
profile-metrics-query.service.spec.ts - Test:
getProfileOverviewreturns correct metrics with trends - Test:
getProfileChartreturns chart data for all metric types - Test:
getDuoPartnerReferralsaggregates by referrer correctly - Test:
getConversionFunnelcalculates funnel steps - Test:
getMessageSourceBreakdownbreaks down by source - Test:
calculateTrenddetermines up/down/neutral correctly - Test:
calculateDateRangescomputes correct comparison period - Mock repository responses with realistic data
- Run tests:
pnpm test profile-metrics-query.service.spec.ts - Verify coverage ≥ 80%
1.4 Extract ProfileAggregationService
File: src/services/profile-analytics/profile-aggregation.service.ts (~320 lines)
- Create new file
- Copy imports
- Extract constructor dependencies:
@InjectRepository(ProfileEvent) eventRepo@InjectRepository(ProfilePerformance) performanceRepo@InjectRepository(DuoReferralStats) duoStatsRepoLogger(for logging aggregation progress)
- Extract public method (lines 580-628):
aggregateDaily(targetDate?: Date): Promise<{ profilesProcessed, errors }>
- Extract private methods (lines 633-867):
private aggregateProfileDaily(profileId, startOfDay, endOfDay): Promise<void>private aggregateDuoReferrals(startOfDay, endOfDay): Promise<void>
- Add
@Injectable()decorator - Verify line count ≤ 350 lines
Testing:
- Create
profile-aggregation.service.spec.ts - Test:
aggregateDailyprocesses all profiles with events - Test:
aggregateDailyhandles profiles with no events gracefully - Test:
aggregateProfileDailycalculates all metrics correctly - Test:
aggregateDuoReferralsgroups by beneficiary + referrer - Test: CTR calculations are accurate (discoveries → views → messages)
- Test: Position statistics computed correctly
- Test: Upsert logic (update existing vs create new)
- Run tests:
pnpm test profile-aggregation.service.spec.ts - Verify coverage ≥ 80%
1.5 Extract Shared Date Helpers
File: src/services/profile-analytics/date-helpers.ts (~50 lines)
- Create new file
- Extract helper class:
export class ProfileAnalyticsDateHelper { static calculateDateRanges(dateRange: DateRange): { startDate, endDate, comparisonStart, comparisonEnd } static getDateKey(date: Date): string } - Update services to import from date-helpers
- Remove duplicate date logic from services
Testing:
- Create
date-helpers.spec.ts - Test:
calculateDateRanges('7d')returns correct 7-day period - Test:
calculateDateRanges('30d')returns correct 30-day period - Test: Comparison period is correctly offset
- Test:
getDateKeyformats as 'YYYY-MM-DD' - Run tests:
pnpm test date-helpers.spec.ts
1.6 Create ProfileAnalyticsService Facade
File: src/services/profile-analytics/profile-analytics-facade.service.ts (~200 lines)
- Create new file
- Add constructor with dependencies:
constructor( private tracker: ProfileEventTrackerService, private query: ProfileMetricsQueryService, private aggregation: ProfileAggregationService, ) {} - Implement delegation for all 15 public methods:
- Tracking methods (5):
trackDiscovery,trackDiscoveryBatch,trackProfileView,trackPhotoView,trackEngagement - Query methods (5):
getProfileOverview,getProfileChart,getDuoPartnerReferrals,getConversionFunnel,getMessageSourceBreakdown - Aggregation method (1):
aggregateDaily
- Tracking methods (5):
- Add
@Injectable()decorator - Export as
ProfileAnalyticsService(original name)
Testing:
- Create
profile-analytics-facade.service.spec.ts - Mock all 3 sub-services
- Test: Each facade method calls correct sub-service method
- Test: Arguments passed through unchanged
- Test: Return values passed through unchanged
- Test: Errors propagate correctly
- Run tests:
pnpm test profile-analytics-facade.service.spec.ts - Verify coverage = 100% (simple delegation)
1.7 Update Barrel Export
File: src/services/profile-analytics/index.ts
- Create barrel export:
// Main facade (for backwards compatibility) export { ProfileAnalyticsService } from './profile-analytics-facade.service' // Individual services (for direct imports) export { ProfileEventTrackerService } from './profile-event-tracker.service' export { ProfileMetricsQueryService } from './profile-metrics-query.service' export { ProfileAggregationService } from './profile-aggregation.service' // Types and interfaces export * from './types'
1.8 Update Module Registration
File: src/app.module.ts (or relevant feature module)
- Add all 4 services to providers array:
providers: [ ProfileAnalyticsService, // Facade ProfileEventTrackerService, // New ProfileMetricsQueryService, // New ProfileAggregationService, // New // ... other providers ]
1.9 Update Main Index Export
File: src/services/index.ts
- Update export to point to new location:
export { ProfileAnalyticsService } from './profile-analytics'
1.10 Delete Original File
- ONLY AFTER ALL TESTS PASS: Delete
src/services/profile-analytics.service.ts - Verify no import errors:
pnpm build
1.11 Final Verification
- Run full test suite:
pnpm test - Run E2E tests:
pnpm test:e2e - Build project:
pnpm build - Check bundle size (should be similar or smaller)
- Verify no runtime errors in dev mode:
pnpm dev - Test profile tracking endpoint manually
- Test profile analytics dashboard manually
Phase 2: AdminAnalyticsController (P1)
Estimated Time: 3-4 hours Start Date: ___________ Completion Date: ___________
2.1 Setup Directory Structure
- Create
src/controllers/admin/directory - Create test directory
src/controllers/admin/__tests__/
2.2 Extract AdminRevenueController
File: src/controllers/admin/admin-revenue.controller.ts (~220 lines)
- Create new file
- Copy decorators:
@ApiTags,@ApiBearerAuth,@Controller,@UseGuards - Update controller path:
@Controller('analytics/admin/revenue') - Copy constructor dependencies:
AdminAnalyticsService
- Extract endpoints (lines 55-198):
- Revenue endpoints (3):
GET /metrics,GET /trend,GET /breakdown - Transaction endpoints (2):
GET /transactions,GET /transactions/:id - P&L endpoints (3):
GET /pnl/statement,GET /pnl/trend,GET /reserve/progress - Cost endpoints (4):
GET /costs/metrics,GET /costs/breakdown,GET /costs/trend,GET /budget/comparison
- Revenue endpoints (3):
- Update route paths (remove
/revenueprefix where nested) - Add JSDoc comments for controller purpose
Testing:
- Create
admin-revenue.controller.spec.ts - Test: All 12 endpoints return correct responses
- Test: Query parameters parsed correctly
- Test: NotFoundException thrown for missing transaction
- Mock
AdminAnalyticsServicemethods - Run tests:
pnpm test admin-revenue.controller.spec.ts
2.3 Extract AdminPlatformController
File: src/controllers/admin/admin-platform.controller.ts (~180 lines)
- Create new file
- Setup decorators with path
@Controller('analytics/admin/platform') - Extract dependencies:
AdminAnalyticsService - Extract endpoints (lines 202-302):
- Real-time endpoints (3):
GET /realtime/metrics,GET /realtime/activity,GET /realtime/active-users - Performance endpoints (3):
GET /performance/metrics,GET /performance/history,GET /performance/endpoints - Error endpoints (4):
GET /errors/metrics,GET /errors/by-type,GET /errors/trends,GET /errors/recent
- Real-time endpoints (3):
Testing:
- Create
admin-platform.controller.spec.ts - Test: All 10 endpoints
- Test: Throttling decorators present on real-time endpoints
- Test: Cache TTLs configured correctly
- Run tests:
pnpm test admin-platform.controller.spec.ts
2.4 Extract AdminConversionController
File: src/controllers/admin/admin-conversion.controller.ts (~150 lines)
- Create new file
- Setup with path
@Controller('analytics/admin/conversion') - Extract dependencies:
AdminAnalyticsService - Extract endpoints (lines 306-379):
- Funnel endpoints (4):
GET /funnel/metrics,GET /funnel/data,GET /funnel/by-source,GET /funnel/data-by-source - A/B test endpoints (3):
GET /ab-tests/metrics,GET /ab-tests/active,GET /ab-tests/results/:testId
- Funnel endpoints (4):
Testing:
- Create
admin-conversion.controller.spec.ts - Test: All 7 endpoints
- Test: NotFoundException for invalid testId
- Run tests:
pnpm test admin-conversion.controller.spec.ts
2.5 Extract AdminFeaturesController
File: src/controllers/admin/admin-features.controller.ts (~280 lines)
- Create new file
- Setup with path
@Controller('analytics/admin/features') - Extract dependencies:
SubscriptionFunnelServiceGiftAnalyticsServiceFmtyAnalyticsService
- Extract endpoints (lines 383-634):
- Subscription endpoints (9): Funnel metrics, limit hits, upgrades, MRR, tier analytics, etc.
- Gift endpoints (5): Metrics, trend, by template, top gifters, top recipients
- FMTY endpoints (4): Metrics, comparison, trends, routes
Testing:
- Create
admin-features.controller.spec.ts - Test: All 18 endpoints
- Test: Date parsing for optional query params
- Test: Default values applied correctly
- Run tests:
pnpm test admin-features.controller.spec.ts
2.6 Update Module Registration
File: src/app.module.ts
- Remove old
AdminAnalyticsControllerfrom controllers array - Add 4 new controllers:
controllers: [ AdminRevenueController, AdminPlatformController, AdminConversionController, AdminFeaturesController, // ... other controllers ]
2.7 Update Controller Index Export
File: src/controllers/index.ts
- Remove old export
- Add new exports:
export * from './admin/admin-revenue.controller' export * from './admin/admin-platform.controller' export * from './admin/admin-conversion.controller' export * from './admin/admin-features.controller'
2.8 Delete Original File
- ONLY AFTER TESTS PASS: Delete
src/controllers/admin-analytics.controller.ts - Delete old test file:
src/controllers/admin-analytics.controller.spec.ts
2.9 Final Verification
- Run full test suite:
pnpm test - Run E2E tests for all 47 admin endpoints
- Verify OpenAPI spec unchanged:
pnpm build && check-swagger - Test admin dashboard manually
- Verify all routes return 200/201 (not 404)
Phase 3: AnalyticsService (P1)
Estimated Time: 3-4 hours Start Date: ___________ Completion Date: ___________
3.1 Setup Directory Structure
- Create
src/services/analytics/directory - Create test directory
src/services/analytics/__tests__/
3.2 Extract AnalyticsTrackingService
File: src/services/analytics/analytics-tracking.service.ts (~120 lines)
- Create new file
- Extract dependency:
QueueService - Extract methods (lines 72-106):
trackView(dto: TrackViewEvent): Promise<void>trackRevenue(dto: TrackRevenueDto): Promise<void>trackEngagement(dto: TrackEngagementEvent): Promise<void>trackInteraction(dto: TrackInteractionDto): Promise<void>private mapEventTypeToInteractionType(eventType: string): InteractionType
Testing:
- Create
analytics-tracking.service.spec.ts - Test: Each method calls correct queue service method
- Test:
mapEventTypeToInteractionTypehandles all event types - Test: Unknown event type defaults to CLICK
- Run tests:
pnpm test analytics-tracking.service.spec.ts
3.3 Extract AnalyticsMetricsQueryService
File: src/services/analytics/analytics-metrics-query.service.ts (~200 lines)
- Create new file
- Extract dependencies (3 repositories):
ContentViewRepositoryRevenueMetricRepositoryEngagementMetricRepository
- Extract public methods (lines 108-192):
getMetrics(userId, startDate, endDate): Promise<UserMetrics>getContentAnalytics(contentId): Promise<ContentMetrics>
- Extract helper methods (lines 467-542):
private getViewMetrics(userId, startDate, endDate): Promise<ViewMetrics>private getRevenueMetrics(userId, startDate, endDate): Promise<RevenueMetrics>private getEngagementMetrics(userId, startDate, endDate): Promise<EngagementMetrics>
- Make
calculateMetrics()public (needed by AggregationService):calculateMetrics(userId, startDate, endDate): Promise<DashboardMetrics>
Testing:
- Create
analytics-metrics-query.service.spec.ts - Test:
getMetricsaggregates views, revenue, engagement - Test:
getContentAnalyticsreturns views by device - Test: Empty results return zero values (not null)
- Test:
calculateMetricscomputes all fields correctly - Run tests:
pnpm test analytics-metrics-query.service.spec.ts
3.4 Extract AnalyticsDashboardService
File: src/services/analytics/analytics-dashboard.service.ts (~250 lines)
- Create new file
- Extract dependencies (4 repositories)
- Extract public methods (lines 132-434):
getDashboardData(userId, type): Promise<DashboardMetrics>getAnalyticsOverview(userId): Promise<Overview>getRevenueChart(userId, period): Promise<ChartData>getSubscriberChart(userId, period): Promise<ChartData>getTopContentForUser(userId, limit): Promise<TopContent>getConversionFunnel(userId): Promise<Funnel>getActivityHeatmap(userId): Promise<Heatmap>
- Extract helper methods (lines 462-579):
private calculatePercentageChange(oldValue, newValue): numberprivate getStartDate(type: SnapshotType): Date
Testing:
- Create
analytics-dashboard.service.spec.ts - Test:
getDashboardDatareturns snapshot or calculates fresh - Test:
getAnalyticsOverviewcomputes trends correctly - Test: Chart methods fill missing dates with zeros
- Test:
getActivityHeatmapgroups by day + hour - Run tests:
pnpm test analytics-dashboard.service.spec.ts
3.5 Extract AnalyticsAggregationService
File: src/services/analytics/analytics-aggregation.service.ts (~180 lines)
- Create new file
- Extract dependencies:
AnalyticsMetricsQueryService(for calculateMetrics)RevenueMetricRepositoryDashboardSnapshotRepository
- Extract CRON method (lines 436-460):
@Cron(CronExpression.EVERY_DAY_AT_2AM)aggregateDailyMetrics(): Promise<void>
- Extract helper (lines 581-588):
private getCreatorIds(): Promise<string[]>
- Inject
AnalyticsMetricsQueryServiceand callcalculateMetrics()
Testing:
- Create
analytics-aggregation.service.spec.ts - Test: CRON job processes all creators
- Test: Snapshots upserted correctly (update existing, create new)
- Test: Handles errors for individual creators gracefully
- Run tests:
pnpm test analytics-aggregation.service.spec.ts
3.6 Create AnalyticsService Facade
File: src/services/analytics/analytics-facade.service.ts (~150 lines)
- Create new file
- Add constructor with 4 dependencies
- Implement delegation for all 13 public methods
- Export as
AnalyticsService(original name)
Testing:
- Create
analytics-facade.service.spec.ts - Test: All delegations work correctly
- Run tests:
pnpm test analytics-facade.service.spec.ts
3.7 Update Barrel Export
File: src/services/analytics/index.ts
- Create barrel export with facade + individual services
3.8 Update Module and Delete Original
- Update
app.module.tsproviders - Update
src/services/index.tsexport - Delete original
analytics.service.ts - Delete original test file
3.9 Final Verification
- Run full test suite
- Verify CRON job scheduled correctly (check logs)
- Test analytics tracking endpoints
- Test dashboard endpoints
Phase 4: AnalyticsProcessor (P2)
Estimated Time: 2-3 hours Start Date: ___________ Completion Date: ___________
4.1 Setup Directory Structure
- Create
src/processors/handlers/directory - Create test directory
src/processors/handlers/__tests__/
4.2 Extract AnalyticsEventHandler
File: src/processors/handlers/analytics-event-handler.service.ts (~170 lines)
- Create new file
- Extract dependencies (3 repositories + Redis)
- Extract event processing methods (lines 91-170):
handle(job: Job): Promise<EventJobResult>private processView(data: ViewJobData): Promise<ViewJobResult>private processEngagement(data: EngagementJobData): Promise<EngagementJobResult>private processRevenue(data: RevenueJobData): Promise<RevenueJobResult>
- Extract helpers:
private getHourKey(date: Date): stringprivate getDateKey(date: Date): string
Testing:
- Create
analytics-event-handler.service.spec.ts - Test:
processViewsaves to DB and updates Redis - Test:
processEngagementsaves with correct metric type - Test:
processRevenueconverts to cents and updates Redis - Test: GeoIP lookup works when IP provided
- Run tests:
pnpm test analytics-event-handler.service.spec.ts
4.3 Extract AnalyticsAggregationHandler
File: src/processors/handlers/analytics-aggregation-handler.service.ts (~300 lines)
- Create new file
- Extract dependencies (4 repositories + Redis + DomainEvents)
- Extract aggregation methods (lines 172-388):
handle(job: Job): Promise<AggregationJobResult>private aggregateDaily(data): Promise<DailyResult>private aggregateHourly(data): Promise<HourlyResult>
- Extract helper (lines 390-446):
private calculateUserMetrics(userId, startDate, endDate): Promise<DashboardMetrics>
- Extract key helpers:
private getHourKey(date: Date): stringprivate getDateKey(date: Date): string
Testing:
- Create
analytics-aggregation-handler.service.spec.ts - Test:
aggregateDailyprocesses all users with activity - Test:
aggregateHourlyupdates Redis counters - Test: Domain events emitted after successful aggregation
- Test:
calculateUserMetricscomputes all fields - Run tests:
pnpm test analytics-aggregation-handler.service.spec.ts
4.4 Refactor AnalyticsProcessor
File: src/processors/analytics.processor.ts (~150 lines)
- Update constructor to inject both handlers:
constructor( private eventHandler: AnalyticsEventHandler, private aggregationHandler: AnalyticsAggregationHandler, ) { super() } - Simplify
process()method:async process(job: Job<AnalyticsJobData>): Promise<AnalyticsJobResult> { if (job.name.startsWith('TRACK_')) { return this.eventHandler.handle(job) } else if (job.name.startsWith('AGGREGATE_')) { return this.aggregationHandler.handle(job) } throw new Error(`Unknown job type: ${job.name}`) } - Remove all processing logic (moved to handlers)
Testing:
- Update
analytics.processor.spec.ts - Test: Jobs routed to correct handler
- Test: Unknown job types throw error
- Mock both handlers
- Run tests:
pnpm test analytics.processor.spec.ts
4.5 Update Module Registration
File: src/app.module.ts
- Add handlers to providers:
providers: [ AnalyticsProcessor, AnalyticsEventHandler, // New AnalyticsAggregationHandler, // New // ... ]
4.6 Final Verification
- Run full test suite
- Queue test jobs and verify processing
- Check job logs for correct routing
- Verify aggregation jobs complete successfully
Phase 5: FmtyAnalyticsService (P2)
Estimated Time: 2-3 hours Start Date: ___________ Completion Date: ___________
5.1 Setup Directory Structure
- Create
src/services/fmty/directory - Create test directory
src/services/fmty/__tests__/
5.2 Extract FmtyAnalyticsTrackingService
File: src/services/fmty/fmty-analytics-tracking.service.ts (~150 lines)
- Create new file
- Extract dependency:
FmtyAnalyticsMetricRepository - Extract tracking methods (lines 77-147):
trackImpression(providerId, searchRegion, providerRegion): Promise<void>trackClick(providerId, userId, searchRegion): Promise<void>trackBooking(providerId, userId, revenueCents, searchRegion): Promise<void>
- Extract helper (lines 416-453):
private incrementMetric(metricType, sourceRegion, providerRegion, count?, revenue?): Promise<void>
Testing:
- Create
fmty-analytics-tracking.service.spec.ts - Test: Each tracking method increments correct metric
- Test: Bookings also track revenue
- Test: Upsert logic works (update vs create)
- Run tests:
pnpm test fmty-analytics-tracking.service.spec.ts
5.3 Extract FmtyAnalyticsQueryService
File: src/services/fmty/fmty-analytics-query.service.ts (~320 lines)
- Create new file
- Extract dependency:
FmtyAnalyticsMetricRepository - Extract query methods (lines 151-407):
getFmtyDashboardMetrics(period): Promise<FmtyDashboardMetrics>getComparison(period): Promise<FmtyComparison>getFmtyTrends(period): Promise<FmtyTrendPoint[]>getTopRoutes(period, limit): Promise<Route[]>
- Extract helper (lines 458-465):
private getStartDate(period): Date
Testing:
- Create
fmty-analytics-query.service.spec.ts - Test: Dashboard metrics aggregate correctly
- Test: CTR and conversion rate calculated
- Test: Top regions sorted by count
- Test: Trends grouped by date
- Test: Routes include source → provider mapping
- Run tests:
pnpm test fmty-analytics-query.service.spec.ts
5.4 Create FmtyAnalyticsService Facade
File: src/services/fmty/fmty-analytics-facade.service.ts (~120 lines)
- Create new file
- Implement delegation for 7 methods
- Export as
FmtyAnalyticsService
Testing:
- Create
fmty-analytics-facade.service.spec.ts - Test: All delegations work
- Run tests:
pnpm test fmty-analytics-facade.service.spec.ts
5.5 Update Barrel Export and Module
- Create
src/services/fmty/index.ts - Update
app.module.tsproviders - Update
src/services/index.tsexport - Delete original
fmty-analytics.service.ts
5.6 Final Verification
- Run full test suite
- Test FMTY tracking endpoints
- Test FMTY dashboard endpoints
Phase 6: ProfileAnalytics DTOs (P3)
Estimated Time: 1-2 hours Start Date: ___________ Completion Date: ___________
6.1 Setup Directory Structure
- Create
src/dto/profile-analytics/directory
6.2 Extract Tracking DTOs
File: src/dto/profile-analytics/tracking.dto.ts (~250 lines)
- Create new file
- Copy lines 17-254 from original file:
DiscoverySourceContextDtoTrackProfileDiscoveryDtoTrackProfileDiscoveryBatchDtoTrackProfileViewDtoTrackPhotoViewDtoProfileEngagementTypeenumTrackProfileEngagementDto
6.3 Extract Query DTOs
File: src/dto/profile-analytics/query.dto.ts (~50 lines)
- Create new file
- Copy lines 260-300:
DateRangetypeProfileAnalyticsQueryDtoProfileChartQueryDto
6.4 Extract Response Types
File: src/dto/profile-analytics/responses.dto.ts (~150 lines)
- Create new file
- Copy lines 305-428:
TrendDirectiontypeMetricWithTrendinterfaceProfileAnalyticsOverviewinterfaceChartDataPointinterfaceProfileChartResponseinterfaceDuoReferralSummaryinterfaceDuoReferralsResponseinterfaceFunnelStepinterfaceProfileFunnelResponseinterfaceMessageSourceBreakdowninterface
6.5 Create Barrel Export
File: src/dto/profile-analytics/index.ts
- Create barrel export:
export * from './tracking.dto' export * from './query.dto' export * from './responses.dto'
6.6 Update Imports Across Codebase
- Find all imports of
profile-analytics.dto:grep -r "from '@/dto/profile-analytics.dto'" src/ - Update to new path:
// Old import { TrackProfileDiscoveryDto } from '@/dto/profile-analytics.dto' // New import { TrackProfileDiscoveryDto } from '@/dto/profile-analytics' - Files to update (likely):
profile-tracking.controller.tsprofile-analytics-facade.service.tsprofile-event-tracker.service.tsprofile-metrics-query.service.ts
6.7 Delete Original File
- Delete
src/dto/profile-analytics.dto.ts
6.8 Final Verification
- Run build:
pnpm build - Verify no import errors
- Run full test suite
- Check TypeScript compiler output (no errors)
Post-Implementation Verification
Code Quality Checks
- Run linter:
pnpm lint - Fix all linting warnings
- Run prettier:
pnpm format - Check for unused imports:
pnpm lint:unused-imports
Test Coverage
- Run test coverage report:
pnpm test:cov - Verify overall coverage ≥ 80%
- Verify new services coverage ≥ 80%
- Review uncovered lines (should be minimal)
Build Verification
- Clean build:
rm -rf dist && pnpm build - Verify no TypeScript errors
- Check bundle size (should be ≤ 5% increase)
- Verify tree-shaking working (check bundle analysis)
Runtime Verification
- Start dev server:
pnpm dev - Verify no startup errors
- Check all CRON jobs scheduled correctly
- Test tracking endpoints manually
- Test query endpoints manually
- Test admin endpoints manually
- Verify queue jobs processing
- Check logs for warnings/errors
Documentation Updates
- Update architecture docs (if exists)
- Update developer guide (if needed)
- Add migration notes to CHANGELOG
- Update README (if service structure explained)
Performance Testing
- Benchmark tracking endpoint latency (should be ≤ 50ms)
- Benchmark query endpoint latency (should be unchanged)
- Check memory usage (should be ≤ 5% increase)
- Verify Redis connection pooling working
Final Sign-off
- Code review by team lead
- QA testing pass
- Merge to main branch
- Deploy to staging
- Monitor for errors (24 hours)
- Deploy to production
Rollback Plan (If Issues Found)
Emergency Rollback Steps
- Identify issue and severity
- Revert merge commit:
git revert <commit-hash> - Deploy revert to production
- Document issue in ticket
- Fix in separate branch
- Re-test thoroughly before re-deploying
Known Rollback Triggers
- Critical: Tracking events lost (data integrity)
- Critical: CRON jobs failing (aggregation stopped)
- High: API endpoints returning 500 errors
- High: Test coverage drops below 70%
- Medium: Performance regression > 20%
- Low: Linting warnings
Success Metrics
After completion, verify:
- Line Count: All files ≤ 400 lines (target: ≤ 350 avg)
- Test Coverage: ≥ 80% for all new services
- API Compatibility: 100% (no breaking changes)
- Build Time: ≤ 5% increase
- Response Time: ≤ 5% increase
- Memory Usage: ≤ 10% increase
- Bundle Size: ≤ 5% increase
- Zero Downtime: No service interruption during deployment
Notes
- Estimated total time: 16-23 hours (2-3 days)
- Can be parallelized across team members
- Phase 1 (ProfileAnalytics) is critical path - do first
- Phases 2-6 can be done in parallel after Phase 1
- Each phase is independently testable
- Rollback possible at any phase boundary
Status: Not Started Last Updated: 2026-01-22