Skip to main content

Interview scheduling

Before this capability, inviting a candidate to interview was a bare status flip on the Application pipeline with no artifact — nobody on the recruiting team could see, from a calendar, when and with whom a gesprek was actually happening. Interview closes that gap: a scheduling record per interview round (an Application can go through several rounds, each its own Interview), synced onto a real calendar.

A one-way projection onto a configured shared calendar

InterviewCalendarService upserts one calendar event per scheduled Interview into a configured shared Nextcloud calendar — a principal/URI pair set once in configuration, kept independent of any other calendar sync (such as leave & absence sync) so interviews and absence can target different calendars.

This sync is one-way, and it is important to understand what that means in practice: the sync derives the event's fields from the Interview record every time it runs. A hand edit made directly on the calendar event — moving the time, changing the location — is overwritten by the next sync, not preserved. Reschedule the Interview itself, not the calendar entry.

  • First sync creates the event and stamps a derived event-id marker back onto the Interview — an inspectable "has this ever reached the calendar" record.
  • Rescheduling (changing scheduledStart/scheduledEnd) updates that same event by its stored id — never a duplicate.
  • A no-op resync writes nothing: running the sync twice with no data change makes zero calendar writes on the second run.
  • Cancelling an Interview removes its calendar event. Completing one leaves the event in place as history — it is not re-synced or deleted.
  • Deleted Interviews are reconciled: the sync also removes any orphaned interview event whose underlying Interview no longer exists in the register, while leaving every other, manually-created calendar event on the same calendar untouched.

AVG boundary

Unlike absence sync (where even the kind of leave is excluded from the calendar), an interview event's whole purpose is telling the panel who and what role — so the event's summary carries the candidate's name and the vacancy title. Everything else Application-sensitive never reaches the render path at all: email, phone, CV file, motivation letter, talent-pool opt-in, and rejection/retention dates are excluded by construction, not filtered after the fact. Interviewers are listed as plain text in the event description, never as calendar attendees — so scheduling one never triggers an automatic invitation email.

Degradation and triggers

An unconfigured instance (interview calendar principal/URI unset) skips cleanly — skipped-no-calendar — never an error:

occ hrmq:interview:sync
occ hrmq:interview:sync --from 2026-07-01

--from bounds which Interviews are pushed; omitted, every scheduled Interview syncs. A guarded "Sync naar agenda" action on an Interview's own detail page triggers a single-Interview sync for an admin or HR caller.

Where it lives

Interview pages nest under the existing Onboarding & ATS menu group — no new top-level menu entry — and an Application's own detail page lists its interview rounds directly, so a round is reachable without a separate navigation path.