diff --git a/AGENTS.md b/AGENTS.md index 6bec6ec603..e557183c90 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -136,6 +136,12 @@ The migration generator compares entities against the local database schema. Ens - Subscribers fetch their own data - don't optimize topic payloads for specific consumers - This allows multiple subscribers with different data needs +**Avoid magic numbers for time durations:** +- Use time constants from `src/common/constants.ts` instead of inline calculations +- Available constants: `ONE_MINUTE_IN_SECONDS`, `ONE_HOUR_IN_SECONDS`, `ONE_DAY_IN_SECONDS`, `ONE_WEEK_IN_SECONDS`, `ONE_MONTH_IN_SECONDS`, `ONE_YEAR_IN_SECONDS`, `ONE_HOUR_IN_MINUTES`, `ONE_DAY_IN_MINUTES` +- Example: Use `2 * ONE_DAY_IN_MINUTES` instead of `2 * 24 * 60` +- Add new constants to `src/common/constants.ts` if needed (they are re-exported from `src/common/index.ts`) + ## Best Practices & Lessons Learned **Avoiding Code Duplication:** diff --git a/src/common/constants.ts b/src/common/constants.ts index 29c802c738..1f6b443e5e 100644 --- a/src/common/constants.ts +++ b/src/common/constants.ts @@ -5,6 +5,9 @@ export const ONE_WEEK_IN_SECONDS = ONE_DAY_IN_SECONDS * 7; export const ONE_MONTH_IN_SECONDS = ONE_DAY_IN_SECONDS * 30; export const ONE_YEAR_IN_SECONDS = ONE_DAY_IN_SECONDS * 365; +export const ONE_HOUR_IN_MINUTES = 60; +export const ONE_DAY_IN_MINUTES = ONE_HOUR_IN_MINUTES * 24; + export const THREE_MONTHS_IN_SECONDS = ONE_MONTH_IN_SECONDS * 3; export const MAX_FOLLOWERS_LIMIT = 5_000; diff --git a/src/workers/candidateReviewOpportunitySlack.ts b/src/workers/candidateReviewOpportunitySlack.ts index 704d70c5ef..08606438c3 100644 --- a/src/workers/candidateReviewOpportunitySlack.ts +++ b/src/workers/candidateReviewOpportunitySlack.ts @@ -1,6 +1,6 @@ import { ApplicationScored } from '@dailydotdev/schema'; import { TypedWorker } from './worker'; -import { truncateText, webhooks } from '../common'; +import { ONE_DAY_IN_MINUTES, truncateText, webhooks } from '../common'; import { generateResumeSignedUrl } from '../common/googleCloud'; import { OpportunityMatch } from '../entity/OpportunityMatch'; import { OpportunityJob } from '../entity/opportunities/OpportunityJob'; @@ -13,7 +13,12 @@ const worker: TypedWorker<'gondul.v1.candidate-application-scored'> = { handler: async ({ data }, con): Promise => { if (process.env.NODE_ENV === 'development') return; - const { opportunityId, userId } = data; + const { + opportunityId, + userId, + score: applicationScore, + description, + } = data; const match = await con.getRepository(OpportunityMatch).findOne({ where: { opportunityId, userId }, relations: ['opportunity', 'user'], @@ -42,10 +47,9 @@ const worker: TypedWorker<'gondul.v1.candidate-application-scored'> = { const salary = pref?.salaryExpectation; const cv = pref?.cv; const cvSignedUrl = cv?.blob - ? await generateResumeSignedUrl(cv.blob) + ? await generateResumeSignedUrl(cv.blob, 2 * ONE_DAY_IN_MINUTES) : null; const matchScore = match.description?.matchScore; - const applicationScore = match.applicationRank?.score; await webhooks.recruiterReview.send({ blocks: [ @@ -113,13 +117,13 @@ const worker: TypedWorker<'gondul.v1.candidate-application-scored'> = { text: `*CV:*\n${cvSignedUrl ? `<${cvSignedUrl}|Download CV>` : 'N/A'}`, }, }, - ...(match.applicationRank?.description + ...(description ? [ { type: 'section' as const, text: { type: 'mrkdwn' as const, - text: `*Application Summary:*\n${truncateText(match.applicationRank.description)}`, + text: `*Application Summary:*\n${truncateText(description)}`, }, }, ]