Render adoption reports in worker
Deploy / deploy-dev (push) Has been skipped
Deploy / deploy-prod (push) Successful in 1m43s

This commit is contained in:
Corey Blais
2026-06-03 10:55:09 -04:00
parent 52008f5b43
commit 603b4eee4d
6 changed files with 169 additions and 51 deletions
+8 -51
View File
@@ -13,6 +13,7 @@ import Stripe from 'stripe';
import { z } from 'zod';
import { ensureSchema } from './db/schema.js';
import { enqueueAdoptionReportJob, adoptionReportQueueEvents } from './queues/adoptionReportQueue.js';
import { enqueueBirdMilestoneReminderJob, getBirdMilestoneReminderQueueCounts } from './queues/birdMilestoneReminderQueue.js';
import {
consumeMagicLinkToken,
@@ -64,7 +65,6 @@ import {
updateVetVisitForBird,
} from './repositories/birdRepository.js';
import { createIntegrationTokenRecord, listIntegrationTokens, revokeIntegrationToken } from './repositories/integrationTokenRepository.js';
import { renderAdoptionReportPdf } from './reports/adoptionReport.js';
import {
createAuditLogEntry,
createFlockNote,
@@ -150,7 +150,7 @@ const trustProxy = process.env.TRUST_PROXY?.trim() ?? '';
const milestoneRemindersEnabled = (process.env.MILESTONE_REMINDERS_ENABLED ?? 'true').toLowerCase() !== 'false';
const milestoneReminderTimeZone = process.env.MILESTONE_REMINDER_TIME_ZONE?.trim() || 'America/New_York';
const milestoneReminderCheckIntervalMs = 60 * 60 * 1000;
const adoptionReportWeightHistoryDays = 425;
const adoptionReportRenderTimeoutMs = Number(process.env.ADOPTION_REPORT_RENDER_TIMEOUT_MS ?? 45_000);
const photoDeliveryMode = process.env.PHOTO_DELIVERY_MODE === 'redirect' ? 'redirect' : 'proxy';
if (trustProxy) {
@@ -1353,37 +1353,6 @@ const deleteBirdPhotoObjectIfNeeded = async (objectKey: string | null) => {
}
};
const loadBirdReportPhotoBuffer = async (bird: BirdRow) => {
if (!bird.photo_object_key) {
return null;
}
const s3Config = getS3ImageStorageConfig();
if (!s3Config) {
return null;
}
const signedUrl = getSignedS3ObjectUrl({
config: s3Config,
objectKey: bird.photo_object_key,
expiresInSeconds: 5 * 60,
});
const imageResponse = await fetch(signedUrl);
if (!imageResponse.ok) {
return null;
}
const contentType = imageResponse.headers.get('content-type') || bird.photo_content_type || '';
if (!/^image\/(?:png|jpe?g)$/i.test(contentType)) {
return null;
}
return Buffer.from(await imageResponse.arrayBuffer());
};
const getDefaultBirdPhotoAttachment = () => {
const defaultPhotoPath = path.join(process.cwd(), 'assets', 'yoda-default.png');
@@ -3439,27 +3408,15 @@ app.post(
throw new Error('Unable to create bird transfer code.');
}
const [weights, vetVisits, notes, birdPhotoBuffer] = await Promise.all([
listWeightsForBird(sourceBird.id, req.auth!.workspace.id, adoptionReportWeightHistoryDays),
listVetVisitsForBird(sourceBird.id, req.auth!.workspace.id),
listFlockNotes(req.auth!.workspace.id),
loadBirdReportPhotoBuffer(sourceBird),
]);
const birdNotes = notes.filter((note) => note.bird_id === sourceBird.id);
const pdf = await renderAdoptionReportPdf({
bird: sourceBird,
weights,
vetVisits,
notes: birdNotes,
await adoptionReportQueueEvents.waitUntilReady();
const reportJob = await enqueueAdoptionReportJob({
birdId: sourceBird.id,
workspaceId: req.auth!.workspace.id,
transferCode: transferCode.code,
birdPhotoBuffer,
printFriendly: req.query.printFriendly === 'true',
assets: {
logoPath: path.join(process.cwd(), 'assets', 'flockpal-logo.png'),
wordmarkPath: path.join(process.cwd(), 'assets', 'flockpal-text.png'),
defaultBirdPhotoPath: path.join(process.cwd(), 'assets', 'yoda-default.png'),
},
});
const reportResult = await reportJob.waitUntilFinished(adoptionReportQueueEvents, adoptionReportRenderTimeoutMs);
const pdf = Buffer.from(reportResult.pdfBase64, 'base64');
await writeAuditLog(req.auth!, 'bird.adoption_report_created', 'bird', sourceBird.id, sourceBird.name, {
transferCodeId: transferCode.id,