apps/recallassess/recallassess-api/src/api/admin/email/services/email-engagement.service.ts
Persists per-participant email engagement metrics for analytics.
Properties |
|
Methods |
|
constructor(prisma: BNestPrismaService)
|
||||||
|
Parameters :
|
| Async incrementEmailsSent |
incrementEmailsSent(participantId: number, periodStart: Date, periodEnd: Date)
|
|
Increment emails_sent for the given participant and reporting period (creates row if missing).
Returns :
Promise<EmailEngagementMetrics>
|
| Private logEmailsSentSnapshot | ||||||
logEmailsSentSnapshot(row: EmailEngagementMetrics)
|
||||||
|
Parameters :
Returns :
EmailEngagementMetrics
|
| Async mergeEngagementMetrics | |||||||||||||||
mergeEngagementMetrics(participantId: number, periodStart: Date, periodEnd: Date, patch: Prisma.EmailEngagementMetricsUpdateInput)
|
|||||||||||||||
|
Merge partial engagement counters / rates for a period.
Parameters :
Returns :
Promise<EmailEngagementMetrics>
|
| Async updateEngagementById | |||||||||
updateEngagementById(id: number, data: Prisma.EmailEngagementMetricsUpdateInput)
|
|||||||||
|
Updates an engagement row by primary key (e.g. after batch reconciliation). BUG-020:
Parameters :
Returns :
Promise<EmailEngagementMetrics | null>
|
| Private Async upsertEngagementMetrics | |||||||||||||||
upsertEngagementMetrics(participantId: number, periodStart: Date, periodEnd: Date, update: Prisma.EmailEngagementMetricsUpdateInput)
|
|||||||||||||||
|
Parameters :
Returns :
Promise<EmailEngagementMetrics>
|
| Private Readonly logger |
Type : unknown
|
Default value : new Logger(EmailEngagementService.name)
|
import { BNestPrismaService } from "@bish-nest/core/services/database/prisma/prisma.service";
import { Injectable, Logger } from "@nestjs/common";
import type { EmailEngagementMetrics, Prisma } from "@prisma/client";
/**
* Persists per-participant email engagement metrics for analytics.
*/
@Injectable()
export class EmailEngagementService {
private readonly logger = new Logger(EmailEngagementService.name);
constructor(private readonly prisma: BNestPrismaService) {}
/**
* Increment emails_sent for the given participant and reporting period (creates row if missing).
*/
async incrementEmailsSent(
participantId: number,
periodStart: Date,
periodEnd: Date,
): Promise<EmailEngagementMetrics> {
return this.upsertEngagementMetrics(participantId, periodStart, periodEnd, {
emails_sent: { increment: 1 },
});
}
/**
* Merge partial engagement counters / rates for a period.
*/
async mergeEngagementMetrics(
participantId: number,
periodStart: Date,
periodEnd: Date,
patch: Prisma.EmailEngagementMetricsUpdateInput,
): Promise<EmailEngagementMetrics> {
return this.upsertEngagementMetrics(participantId, periodStart, periodEnd, patch);
}
private async upsertEngagementMetrics(
participantId: number,
periodStart: Date,
periodEnd: Date,
update: Prisma.EmailEngagementMetricsUpdateInput,
): Promise<EmailEngagementMetrics> {
const createdDefaults: Prisma.EmailEngagementMetricsCreateInput = {
participant_id: participantId,
period_start: periodStart,
period_end: periodEnd,
emails_sent: 0,
emails_opened: 0,
emails_clicked: 0,
emails_converted: 0,
};
const row = await this.prisma.client.emailEngagementMetrics.upsert({
where: {
participant_id_period_start_period_end: {
participant_id: participantId,
period_start: periodStart,
period_end: periodEnd,
},
},
create: createdDefaults,
update,
});
return this.logEmailsSentSnapshot(row);
}
/**
* Updates an engagement row by primary key (e.g. after batch reconciliation).
*
* BUG-020: `updated` may be null if middleware / client extensions alter the result — never read
* `updated.emails_sent` without checking.
*/
async updateEngagementById(
id: number,
data: Prisma.EmailEngagementMetricsUpdateInput,
): Promise<EmailEngagementMetrics | null> {
const updated = await this.prisma.client.emailEngagementMetrics.update({
where: { id },
data,
});
if (updated == null) {
this.logger.warn(
`Email engagement update returned null for id=${id}; skipping analytics that read emails_sent.`,
);
return null;
}
return this.logEmailsSentSnapshot(updated);
}
private logEmailsSentSnapshot(row: EmailEngagementMetrics): EmailEngagementMetrics {
const sent = row.emails_sent;
this.logger.debug(`Engagement metrics id=${row.id} participant_id=${row.participant_id} emails_sent=${sent}`);
return row;
}
}