diff --git a/packages/api-gateway/bin/report.ts b/packages/api-gateway/bin/report.ts index 42e6d41c8..8f8442bab 100644 --- a/packages/api-gateway/bin/report.ts +++ b/packages/api-gateway/bin/report.ts @@ -16,6 +16,7 @@ import { AnalyticsActivity, AnalyticsStoreInterface, Period, + PeriodKeyGeneratorInterface, StatisticsMeasure, StatisticsStoreInterface, } from '@standardnotes/analytics' @@ -24,6 +25,7 @@ const requestReport = async ( analyticsStore: AnalyticsStoreInterface, statisticsStore: StatisticsStoreInterface, domainEventPublisher: DomainEventPublisherInterface, + periodKeyGenerator: PeriodKeyGeneratorInterface, ): Promise => { const analyticsOverTime = [] @@ -103,6 +105,24 @@ const requestReport = async ( } } + const periodKeys = periodKeyGenerator.getDiscretePeriodKeys(Period.Last7Days) + const registerToActivityRetention = new Map>() + for (let i = 0; i < periodKeys.length; i++) { + const retentionOverDays = new Map() + for (let j = 0; j < periodKeys.length - i; j++) { + const dailyRetention = await analyticsStore.calculateActivitiesRetention({ + firstActivity: AnalyticsActivity.Register, + firstActivityPeriodKey: periodKeys[i], + secondActivity: AnalyticsActivity.GeneralActivity, + secondActivityPeriodKey: periodKeys[i + j], + }) + + retentionOverDays.set(periodKeys[i + j], dailyRetention) + } + + registerToActivityRetention.set(periodKeys[i], retentionOverDays) + } + const event: DailyAnalyticsReportGeneratedEvent = { type: 'DAILY_ANALYTICS_REPORT_GENERATED', createdAt: new Date(), @@ -120,6 +140,13 @@ const requestReport = async ( activityStatistics: yesterdayActivityStatistics, activityStatisticsOverTime: analyticsOverTime, statisticMeasures, + retentionStatistics: [ + { + firstActivity: AnalyticsActivity.Register, + secondActivity: AnalyticsActivity.GeneralActivity, + retention: registerToActivityRetention, + }, + ], }, } @@ -138,8 +165,9 @@ void container.load().then((container) => { const analyticsStore: AnalyticsStoreInterface = container.get(TYPES.AnalyticsStore) const statisticsStore: StatisticsStoreInterface = container.get(TYPES.StatisticsStore) const domainEventPublisher: DomainEventPublisherInterface = container.get(TYPES.DomainEventPublisher) + const periodKeyGenerator: PeriodKeyGeneratorInterface = container.get(TYPES.PeriodKeyGenerator) - Promise.resolve(requestReport(analyticsStore, statisticsStore, domainEventPublisher)) + Promise.resolve(requestReport(analyticsStore, statisticsStore, domainEventPublisher, periodKeyGenerator)) .then(() => { logger.info('Usage report generation complete') diff --git a/packages/api-gateway/src/Bootstrap/Container.ts b/packages/api-gateway/src/Bootstrap/Container.ts index 64f4530dd..19849acbc 100644 --- a/packages/api-gateway/src/Bootstrap/Container.ts +++ b/packages/api-gateway/src/Bootstrap/Container.ts @@ -6,6 +6,7 @@ import * as AWS from 'aws-sdk' import { AnalyticsStoreInterface, PeriodKeyGenerator, + PeriodKeyGeneratorInterface, RedisAnalyticsStore, RedisStatisticsStore, StatisticsStoreInterface, @@ -91,13 +92,13 @@ export class ContainerConfigLoader { // Services container.bind(TYPES.HTTPService).to(HttpService) - const periodKeyGenerator = new PeriodKeyGenerator() + container.bind(TYPES.PeriodKeyGenerator).toConstantValue(new PeriodKeyGenerator()) container .bind(TYPES.AnalyticsStore) - .toConstantValue(new RedisAnalyticsStore(periodKeyGenerator, container.get(TYPES.Redis))) + .toConstantValue(new RedisAnalyticsStore(container.get(TYPES.PeriodKeyGenerator), container.get(TYPES.Redis))) container .bind(TYPES.StatisticsStore) - .toConstantValue(new RedisStatisticsStore(periodKeyGenerator, container.get(TYPES.Redis))) + .toConstantValue(new RedisStatisticsStore(container.get(TYPES.PeriodKeyGenerator), container.get(TYPES.Redis))) container.bind(TYPES.CrossServiceTokenCache).to(RedisCrossServiceTokenCache) container.bind(TYPES.Timer).toConstantValue(new Timer()) diff --git a/packages/api-gateway/src/Bootstrap/Types.ts b/packages/api-gateway/src/Bootstrap/Types.ts index d7dbb994e..448bbabf1 100644 --- a/packages/api-gateway/src/Bootstrap/Types.ts +++ b/packages/api-gateway/src/Bootstrap/Types.ts @@ -26,6 +26,7 @@ const TYPES = { StatisticsStore: Symbol.for('StatisticsStore'), DomainEventPublisher: Symbol.for('DomainEventPublisher'), Timer: Symbol.for('Timer'), + PeriodKeyGenerator: Symbol.for('PeriodKeyGenerator'), } export default TYPES diff --git a/packages/domain-events/src/Domain/Event/DailyAnalyticsReportGeneratedEventPayload.ts b/packages/domain-events/src/Domain/Event/DailyAnalyticsReportGeneratedEventPayload.ts index a22b164e9..6faa74663 100644 --- a/packages/domain-events/src/Domain/Event/DailyAnalyticsReportGeneratedEventPayload.ts +++ b/packages/domain-events/src/Domain/Event/DailyAnalyticsReportGeneratedEventPayload.ts @@ -28,4 +28,9 @@ export interface DailyAnalyticsReportGeneratedEventPayload { totalCount: number }> outOfSyncIncidents: number + retentionStatistics: Array<{ + firstActivity: string + secondActivity: string + retention: Map> + }> }