feat: add realistic interview data and scheduling logic to seed script#107
feat: add realistic interview data and scheduling logic to seed script#107
Conversation
|
🚅 Deployed to the reqcore-pr-107 environment in applirank
|
📝 WalkthroughWalkthroughA seeding script enhancement that introduces comprehensive interview data generation. The update adds a date utility function, interview metadata type, and extensive interview dataset, then integrates a new interview creation phase into the existing seed pipeline that resolves applications and populates interview records with scheduling details. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
📝 Coding Plan
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@server/scripts/seed.ts`:
- Around line 1132-1153: The interview fixtures use iv.daysOffset values (e.g.,
-16, -18, -20) that can make interviews older than their parent application or
even the candidate; fix by clamping parent createdAt timestamps against the
earliest interview per seed key: when building interviews (look at
iv.daysOffset, scheduledAt, candidateRespondedAt, invitationSentAt, createdAt,
updatedAt in the db.insert(schema.interview) block) compute the minimum
iv.daysOffset for that applicationId/seed group and ensure the application's
createdAt (and candidate/application history createdAt) equals at least
daysAgo(Math.abs(minOffset) + X) (X = safety gap like 1–4 days) or reduce the
negative iv.daysOffset values so interviews never precede their parent;
implement this clamp where the application is inserted (use applicationId and
its createdAt computation and the daysAgo helper) so the seeded timeline remains
monotonic.
- Around line 1126-1130: The missing applicationId indicates broken fixture
mapping; instead of warning and continuing, fail fast so the seed run stops and
the dataset issue is obvious: in the block using
applicationMap.get(`${iv.jobIndex}-${iv.candidateIndex}`) (where applicationId
and iv are defined) replace the console.warn + continue behavior with an
explicit failure (throw a descriptive Error or call process.exit(1) with an
error message) that includes the jobIndex and candidateIndex to make the bad
mapping easy to find.
- Around line 103-109: The current dateWithOffset function builds timestamps
using local system timezone (new Date() + setHours), causing inconsistent
scheduledAt values; update dateWithOffset to accept an IANA timezone string
(e.g., timezone param used by interviews) and construct the datetime in that
zone using a timezone-aware API (either Luxon: DateTime.fromObject({ year,
month, day, hour, minute }, { zone }) then toJSDate(), or Temporal: build a
Temporal.PlainDate from today in the target zone, combine with time into a
Temporal.PlainDateTime and convert to Temporal.ZonedDateTime and
toInstant().toString()/toDate()); replace the local setDate/setHours approach in
dateWithOffset to produce a timezone-correct Date for scheduledAt. Ensure
callers of dateWithOffset (where scheduledAt is set) provide the interview IANA
timezone.
| /** Create a date offset from today with a specific time. Positive = future, negative = past. */ | ||
| function dateWithOffset(daysOffset: number, hour: number, minute: number = 0): Date { | ||
| const d = new Date() | ||
| d.setDate(d.getDate() + daysOffset) | ||
| d.setHours(hour, minute, 0, 0) | ||
| return d | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
In JavaScript/TypeScript, does Date#setHours use the host machine's local timezone, and what is the recommended way to construct a wall-clock time for a specific IANA timezone such as Europe/Berlin?
💡 Result:
Yes. Date#setHours is a local-time setter: it interprets/updates the hour using the host environment’s current local time zone (and DST rules), not an arbitrary IANA zone like Europe/Berlin. This is why it can yield different results on machines in different time zones. [1], [2]
Recommended: use Temporal for “wall-clock time in an IANA zone”
If you want “2026-03-12 09:00 in Europe/Berlin” as a real zoned date-time (handling DST gaps/ambiguity), construct a Temporal.PlainDateTime and convert it to a Temporal.ZonedDateTime:
const pdt = new Temporal.PlainDateTime(2026, 3, 12, 9, 0);
const zdt = pdt.toZonedDateTime({ timeZone: "Europe/Berlin", disambiguation: "compatible" });Temporal.ZonedDateTime is designed for IANA time zones and provides explicit control for DST ambiguity/gaps via disambiguation. [3], [4]
If you must return a legacy Date
A JS Date can only represent an instant (UTC timestamp), not “9am Berlin time” by itself. If you need a Date that corresponds to that Berlin wall-clock time, use a time-zone-aware library (e.g., Luxon) to compute the correct instant:
import { DateTime } from "luxon";
const dt = DateTime.fromObject(
{ year: 2026, month: 3, day: 12, hour: 9, minute: 0 },
{ zone: "Europe/Berlin" }
);
const date: Date = dt.toJSDate();(Luxon’s fromObject is the flexible “from components” constructor; the zone determines the correct offset/DST.) [5]
Sources: MDN Date/local vs UTC methods [1], ECMA-262 LocalTime usage in setHours algorithm [2], MDN Temporal toZonedDateTime and ZonedDateTime behavior/options [3], [4], Luxon API docs [5].
Make dateWithOffset timezone-aware.
new Date() + setHours() uses the host machine's local timezone, so this seed will produce different wall-clock scheduledAt values on a UTC box than on a developer laptop. Because each interview already carries an IANA timezone, build the timestamp in that zone instead of relying on local-time setters. For legacy Date objects, use a timezone-aware library like Luxon; for modern code, use Temporal.ZonedDateTime.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@server/scripts/seed.ts` around lines 103 - 109, The current dateWithOffset
function builds timestamps using local system timezone (new Date() + setHours),
causing inconsistent scheduledAt values; update dateWithOffset to accept an IANA
timezone string (e.g., timezone param used by interviews) and construct the
datetime in that zone using a timezone-aware API (either Luxon:
DateTime.fromObject({ year, month, day, hour, minute }, { zone }) then
toJSDate(), or Temporal: build a Temporal.PlainDate from today in the target
zone, combine with time into a Temporal.PlainDateTime and convert to
Temporal.ZonedDateTime and toInstant().toString()/toDate()); replace the local
setDate/setHours approach in dateWithOffset to produce a timezone-correct Date
for scheduledAt. Ensure callers of dateWithOffset (where scheduledAt is set)
provide the interview IANA timezone.
| const applicationId = applicationMap.get(`${iv.jobIndex}-${iv.candidateIndex}`) | ||
| if (!applicationId) { | ||
| console.warn(`⚠️ Skipping interview "${iv.title}" — no application found for job ${iv.jobIndex}, candidate ${iv.candidateIndex}`) | ||
| continue | ||
| } |
There was a problem hiding this comment.
Fail fast on broken interview mappings.
A missing applicationId here means the fixture data is out of sync. Warning and continuing leaves the demo org partially populated, and rerunning will still skip the org later, so the broken dataset persists.
Suggested fix
const applicationId = applicationMap.get(`${iv.jobIndex}-${iv.candidateIndex}`)
if (!applicationId) {
- console.warn(`⚠️ Skipping interview "${iv.title}" — no application found for job ${iv.jobIndex}, candidate ${iv.candidateIndex}`)
- continue
+ throw new Error(`Missing application for interview "${iv.title}" (job ${iv.jobIndex}, candidate ${iv.candidateIndex})`)
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const applicationId = applicationMap.get(`${iv.jobIndex}-${iv.candidateIndex}`) | |
| if (!applicationId) { | |
| console.warn(`⚠️ Skipping interview "${iv.title}" — no application found for job ${iv.jobIndex}, candidate ${iv.candidateIndex}`) | |
| continue | |
| } | |
| const applicationId = applicationMap.get(`${iv.jobIndex}-${iv.candidateIndex}`) | |
| if (!applicationId) { | |
| throw new Error(`Missing application for interview "${iv.title}" (job ${iv.jobIndex}, candidate ${iv.candidateIndex})`) | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@server/scripts/seed.ts` around lines 1126 - 1130, The missing applicationId
indicates broken fixture mapping; instead of warning and continuing, fail fast
so the seed run stops and the dataset issue is obvious: in the block using
applicationMap.get(`${iv.jobIndex}-${iv.candidateIndex}`) (where applicationId
and iv are defined) replace the console.warn + continue behavior with an
explicit failure (throw a descriptive Error or call process.exit(1) with an
error message) that includes the jobIndex and candidateIndex to make the bad
mapping easy to find.
| const scheduledAt = dateWithOffset(iv.daysOffset, iv.hour, iv.minute ?? 0) | ||
| const responded = iv.candidateResponse !== 'pending' | ||
|
|
||
| await db.insert(schema.interview).values({ | ||
| id: id(), | ||
| organizationId: orgId, | ||
| applicationId, | ||
| title: iv.title, | ||
| type: iv.type, | ||
| status: iv.status, | ||
| scheduledAt, | ||
| duration: iv.duration, | ||
| location: iv.location, | ||
| notes: iv.notes, | ||
| interviewers: iv.interviewers, | ||
| createdById: userId, | ||
| candidateResponse: iv.candidateResponse, | ||
| candidateRespondedAt: responded ? daysAgo(Math.abs(iv.daysOffset) + 2) : null, | ||
| invitationSentAt: responded ? daysAgo(Math.abs(iv.daysOffset) + 3) : null, | ||
| timezone: iv.timezone, | ||
| createdAt: daysAgo(Math.abs(iv.daysOffset) + 4), | ||
| updatedAt: daysAgo(Math.abs(iv.daysOffset) + 1), |
There was a problem hiding this comment.
These backdated interviews can precede their application history.
The application phase above only backdates rows 1-15 days, but this fixture includes interviews at -16, -18, and -20 days. Those records will always sort earlier than their owning application, and some can even predate candidate creation, which makes the seeded timeline impossible. Please clamp parent createdAt values against the earliest interview for each seed key, or reduce the interview backdating so the timeline stays monotonic.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@server/scripts/seed.ts` around lines 1132 - 1153, The interview fixtures use
iv.daysOffset values (e.g., -16, -18, -20) that can make interviews older than
their parent application or even the candidate; fix by clamping parent createdAt
timestamps against the earliest interview per seed key: when building interviews
(look at iv.daysOffset, scheduledAt, candidateRespondedAt, invitationSentAt,
createdAt, updatedAt in the db.insert(schema.interview) block) compute the
minimum iv.daysOffset for that applicationId/seed group and ensure the
application's createdAt (and candidate/application history createdAt) equals at
least daysAgo(Math.abs(minOffset) + X) (X = safety gap like 1–4 days) or reduce
the negative iv.daysOffset values so interviews never precede their parent;
implement this clamp where the application is inserted (use applicationId and
its createdAt computation and the daysAgo helper) so the seeded timeline remains
monotonic.
Summary
Type of change
Validation
DCO
Signed-off-by) viagit commit -sSummary by CodeRabbit
New Features
Chores