Skip to main content

Pipeline System

Pipelines are Kanban-style boards for managing recruitment workflows. Each pipeline belongs to a company and an owner, contains jobs via PipelineItem records, and tracks candidates through status stages.

Pipeline Structure

Core Enums

EnumValues
PipelineTypeACTIVE, PRIVATE, ARCHIVED
ShareableTypeSHARABLE, NOT_SHARABLE
PipelineItemStatusNEW, IN_PROGRESS, IN_FOCUS, PENDING_FEEDBACK, CLOSED, FEATURE_REQUEST
CandidateStatusNEW, IN_REVIEW, INTERVIEW, APPROVED, REJECTED, WITHDRAWN

Candidate Status Flow

Candidates move through these stages on the pipeline board:

warning

Withdrawals can happen from any active stage. When a candidate withdraws, the status changes to WITHDRAWN and a withdrawal reason is persisted.

Pipeline Item Status Transitions

Pipeline items (jobs within a pipeline) follow their own status lifecycle. Some transitions require a reason field:

FromAllowed TargetsReason Required?
NEWIN_PROGRESS, IN_FOCUS, PENDING_FEEDBACK, CLOSED, FEATURE_REQUESTPENDING_FEEDBACK and CLOSED require reason
IN_PROGRESSNEW, IN_FOCUS, PENDING_FEEDBACK, CLOSEDPENDING_FEEDBACK and CLOSED require reason
IN_FOCUSIN_PROGRESS, PENDING_FEEDBACK, CLOSEDPENDING_FEEDBACK and CLOSED require reason
PENDING_FEEDBACKIN_PROGRESS, IN_FOCUS, CLOSEDCLOSED requires reason
CLOSEDNEW, IN_PROGRESS, FEATURE_REQUESTAll require reason
FEATURE_REQUESTNEW, IN_PROGRESS, CLOSEDCLOSED requires reason

Scoring Configuration

Each pipeline can have a PipelineScoringConfig that controls how AI match scores are weighted:

WeightDefaultPurpose
skillWeight0.40Skill-based matching
semanticWeight0.35Semantic similarity
contextWeight0.25Contextual relevance

The innerWeights JSON field allows fine-grained sub-weight tuning.

Key GraphQL Operations

Pipeline CRUD

# Create pipeline with scoring config
mutation {
createPipeline(input: {
name: "Q1 Engineering Hires"
description: "Backend and frontend roles"
companyId: "company-uuid"
pipelineType: ACTIVE
shareableType: SHARABLE
scoringConfig: {
skillWeight: 0.45
semanticWeight: 0.30
contextWeight: 0.25
}
}) { id name pipelineType }
}

# List pipelines for current user
query {
pipelines {
id name pipelineType
owner { firstName lastName }
pipelineItems { id job { title } status }
}
}

Pipeline Items (Jobs)

# Add job to pipeline
mutation {
createPipelineItem(input: {
pipelineId: "pipeline-uuid"
jobId: "job-uuid"
}) { id status }
}

# Update pipeline item status
mutation {
updatePipelineItem(input: {
id: "item-uuid"
status: IN_PROGRESS
}) { id status }
}

Candidate Management

# Add talent as candidate to a job
mutation {
addTalentAsCandidate(addTalentAsCandidateInput: {
talentId: "talent-uuid"
jobId: "job-uuid"
cvId: "cv-uuid"
}) { id status }
}

# Self-apply as candidate
mutation {
applyAsCandidate(applyAsCandidateInput: {
jobId: "job-uuid"
motivation: "Excited about this role"
}) { id status }
}

# Update candidate status
mutation {
updateCandidate(updateCandidateInput: {
id: "candidate-uuid"
status: INTERVIEW
}) { id status }
}
info

applyAsCandidate prevents duplicate applications per user/job. It auto-provisions a talent pool entry and generates default motivation text when not supplied.

Pipeline Sharing

Pipelines support four sharing mechanisms:

TypeModelPermission Levels
User sharePipelineUserShareVIEW, EDIT, MANAGE
Company sharePipelineCompanyShareVIEW, EDIT, MANAGE
External sharePipelineExternalShareVIEW only (token-based)
Collaborator shareCollaboratorPipelineShareVIEW, EDIT, MANAGE

Access Control Matrix

RoleCreateReadUpdateDeleteShareManage Items
Pipeline OwnerYYYYYY
Company AdminYYYYYY
Company MemberYY---Y
Shared (MANAGE)-YY-YY
Shared (EDIT)-YY--Y
Shared (VIEW)-Y----
External Token-Y----
# Share pipeline with user
mutation {
createPipelineUserShare(input: {
pipelineId: "pipeline-uuid"
userId: "user-uuid"
permissionLevel: EDIT
}) { id permissionLevel }
}

# External share (token-based, with expiry)
mutation {
createPipelineExternalShare(input: {
pipelineId: "pipeline-uuid"
email: "partner@example.com"
expirationHours: 168
}) { id token expiresAt }
}

Authorization

The PipelineAuthorizationService provides centralized access checks:

  • canAccessPipeline(userId, pipelineId) -- read access (returns boolean)
  • hasWriteAccess(userId, pipelineId) -- write access (returns boolean)
  • getAccessiblePipelineIds(userId) -- all pipelines the user can see

Access is resolved by checking, in order: ownership, company admin/member status, user/company shares, and collaborator relationships (only ACTIVE collaborators).