feat: add collaborative interview scheduling
Add candidate decisions, co-interviewer accounts, scheduled interview inbox and calendar views, candidate-safe meeting links, shared documents, and private live notes backed by RabbitMQ. Extend the disposable integration environment to validate PostgreSQL migrations, seeded users, interview lifecycle behavior, and RabbitMQ fanout. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
parent
fd06fbbb5d
commit
75e3c73a61
35 changed files with 3621 additions and 58 deletions
60
backend/migrations/00006_next_stage_interviews.sql
Normal file
60
backend/migrations/00006_next_stage_interviews.sql
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
-- +goose Up
|
||||
ALTER TABLE users
|
||||
ADD COLUMN display_name VARCHAR(200) NOT NULL DEFAULT '';
|
||||
|
||||
UPDATE users
|
||||
SET display_name = split_part(email, '@', 1)
|
||||
WHERE display_name = '';
|
||||
|
||||
ALTER TABLE invitations
|
||||
ADD COLUMN outcome VARCHAR(32) NOT NULL DEFAULT 'pending'
|
||||
CHECK (outcome IN ('pending', 'passed', 'failed'));
|
||||
|
||||
CREATE TABLE scheduled_interviews (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
job_id BIGINT NOT NULL REFERENCES job_postings(id) ON DELETE CASCADE,
|
||||
invitation_id BIGINT NOT NULL UNIQUE REFERENCES invitations(id) ON DELETE RESTRICT,
|
||||
participant_id BIGINT NOT NULL REFERENCES participants(id) ON DELETE RESTRICT,
|
||||
creator_id BIGINT NOT NULL REFERENCES users(id) ON DELETE RESTRICT,
|
||||
starts_at TIMESTAMPTZ NOT NULL,
|
||||
location VARCHAR(500) NOT NULL,
|
||||
candidate_token VARCHAR(64) NOT NULL UNIQUE,
|
||||
shared_document TEXT NOT NULL DEFAULT '',
|
||||
status VARCHAR(32) NOT NULL DEFAULT 'scheduled'
|
||||
CHECK (status IN ('scheduled', 'started', 'completed', 'cancelled')),
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE INDEX scheduled_interviews_job_id_idx ON scheduled_interviews(job_id);
|
||||
CREATE INDEX scheduled_interviews_participant_id_idx ON scheduled_interviews(participant_id);
|
||||
|
||||
CREATE TABLE interview_attendees (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
interview_id BIGINT NOT NULL REFERENCES scheduled_interviews(id) ON DELETE CASCADE,
|
||||
user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
status VARCHAR(32) NOT NULL DEFAULT 'invited'
|
||||
CHECK (status IN ('invited', 'accepted', 'declined')),
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
UNIQUE (interview_id, user_id)
|
||||
);
|
||||
|
||||
CREATE INDEX interview_attendees_user_id_idx ON interview_attendees(user_id);
|
||||
|
||||
CREATE TABLE interview_notes (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
interview_id BIGINT NOT NULL REFERENCES scheduled_interviews(id) ON DELETE CASCADE,
|
||||
author_id BIGINT NOT NULL REFERENCES users(id) ON DELETE RESTRICT,
|
||||
body TEXT NOT NULL,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE INDEX interview_notes_interview_id_idx ON interview_notes(interview_id);
|
||||
|
||||
-- +goose Down
|
||||
DROP TABLE IF EXISTS interview_notes;
|
||||
DROP TABLE IF EXISTS interview_attendees;
|
||||
DROP TABLE IF EXISTS scheduled_interviews;
|
||||
ALTER TABLE invitations DROP COLUMN outcome;
|
||||
ALTER TABLE users DROP COLUMN display_name;
|
||||
Loading…
Add table
Add a link
Reference in a new issue