Source identity
| Field | Recorded value |
|---|---|
| Source type | GitHub source |
| Original record | Janady13/missionmatch / frontend/src/lib/types.ts |
| Date | Not specified in source |
| Repository | Janady13/missionmatch |
| Revision | 2178e7298d0e5d9af83afa12402fd587f0ba6ed8 |
| Branch | feature/aioe-upgrade |
| Path or archive member | frontend/src/lib/types.ts |
| Original SHA-256 | 765912e56fc69ea69e28496fe64041117d75ad7dca63301b8b2c423e4b80b22e |
| Git blob SHA | 05d61b3eb9994c69c9afa899ca697bb65e1fcd17 |
| Reading-copy SHA-256 | 765912e56fc69ea69e28496fe64041117d75ad7dca63301b8b2c423e4b80b22e |
Recovered source transcript
Download complete source text ↓1,296 lines · 32.8 KB
// TypeScript mirrors of the Go API DTOs (internal/modules/matching). Scores are strings (decimal).
export type Band = 'green' | 'yellow' | 'red'
// ReadinessState is the per category state (a score bucket). MissionStatusCode is the overall mission
// readiness verdict, a distinct code space the backend emits as ready | review | recruiting; the two
// were conflated under one type, which hid review and recruiting and wrongly admitted partial and gap.
export type ReadinessState = 'ready' | 'partial' | 'gap'
export type MissionStatusCode = 'ready' | 'review' | 'recruiting'
export interface ComponentView {
component: string
weight: string
raw: string
weighted: string
rationale: string
}
export interface MatchedSkillView {
required_skill: string
candidate_skill?: string
similarity: string
exact: boolean
matched: boolean
}
export interface MatchResultView {
candidate_id: string
requirement_id: string
total_score: string
band: Band
band_label: string
components: Record<string, string>
explanation: string
gap_summary: string[]
matched_skills: MatchedSkillView[]
trace: ComponentView[]
weight_profile_version: string
}
// One recorded outcome event, the closed loop feedback signal.
export interface OutcomeInput {
module: string
subjectType: string
subjectId: string
requirementId?: string
eventType: string
signalValue: number
reasonCode: string
}
export interface AioeStatus {
outcomesRecorded: number
lastRunAt?: string
lastRunOutcomesSeen?: number
lastRunProfilesMoved?: number
activeProfileVersion: string
adjustmentsThisMonth: number
updaterConfigured: boolean
shadowMode: boolean
pendingCandidateVersion?: string
}
export interface AioeAdjustment {
dimension: string
oldValue: string
newValue: string
producedVersion: number
windowStart: string
windowEnd: string
outcomesUsed: number
rationale: string
createdAt: string
}
export interface TermView {
id: string
alias: string
expansion: string
global: boolean
createdAt: string
}
export interface ReadinessCategory {
name: string
score: string
weight: string
state: ReadinessState
}
export interface MissionReadiness {
status: string
status_code: MissionStatusCode
score: string
band: Band
categories: ReadinessCategory[]
}
export interface BattleCard {
strengths: string[]
gaps: string[]
}
export interface ClearanceIntel {
current: string
status: string
sci_eligible: boolean
ci_poly_eligible: boolean
full_scope_poly: boolean
expired: boolean
investigation_age_months?: number
expires_at?: string
reinvestigation_due_at?: string
recent_classified_support: boolean
provenance: string
provenance_label: string
verified: boolean
verified_at?: string
}
export interface RequirementArea {
area: string
met: boolean
}
export interface RiskArea {
severity: 'warning' | 'info'
message: string
}
export interface ContractReadiness {
areas: RequirementArea[]
risks: RiskArea[]
}
export interface WinImpact {
level: string
level_code: 'high' | 'medium' | 'low'
staffing_strength: string
reasons: string[]
}
export interface NextStep {
action: string
reason: string
}
export interface ScreenView {
match: MatchResultView
mission_readiness: MissionReadiness
battle_card: BattleCard
clearance_intelligence: ClearanceIntel
contract_readiness: ContractReadiness
win_impact: WinImpact
next_steps: NextStep[]
}
export interface CandidateListView {
id: string
full_name: string
clearance_level: string
clearance_status: string
years_experience: number
location?: string
available: boolean
}
export interface RequirementListView {
id: string
title: string
required_level: string
customer_agency?: string
key_personnel: boolean
}
export interface SlateMemberView {
candidate_id: string
rank: number
total_score: string
band: Band
band_label: string
explanation: string
gap_summary: string[]
}
export interface SlateResult {
slate_id: string
requirement_id: string
name: string
members: SlateMemberView[]
}
// slateMATCH list, detail, and proposal readiness views (read from the stored slate, never rescored).
export interface SlateSummaryView {
slate_id: string
name: string
status: string
member_count: number
created_at: string
}
export interface SlateMemberDetailView {
candidate_id: string
full_name: string
rank: number
total_score: string
band: Band
band_label: string
components: Record<string, string>
explanation: string
gap_summary: string[]
decision: 'pending' | 'approved' | 'rejected'
decision_note: string
}
export interface ProposalReadinessView {
slate_id: string
requirement_id: string
total_members: number
approved: number
rejected: number
pending: number
proposal_ready: number
potential: number
recruiting: number
approved_ready: number
readiness_pct: string
status: string
}
export interface SlateDetailView {
slate_id: string
requirement_id: string
requirement_title: string
name: string
status: string
members: SlateMemberDetailView[]
readiness: ProposalReadinessView
}
// missionMATCH "who can support this mission today": read from the persisted screenMATCH evaluation.
export interface SupportView {
candidate_id: string
full_name: string
total_score: string
band: Band
band_label: string
available: boolean
evaluated_at: string
}
// AEDT adverse impact report (the four fifths analysis). Every figure is computed from recorded
// outcomes joined to consented demographics by the compliance role; nothing is fabricated.
export interface ImpactRow {
group: string
considered: number
selected: number
rate: string
impact_ratio: string
flagged: boolean
}
export interface AnalysisSection {
stage: string
total_n: number
unknown_count: number
no_demographics_count: number
by_gender: ImpactRow[]
by_race_ethnicity: ImpactRow[]
intersectional: ImpactRow[]
}
export interface AdverseImpactReport {
generated_at: string
data_from: string
data_to: string
source: string
method: string
selection: AnalysisSection
screening: AnalysisSection
}
// CurationProposalView is one pending WS8 teaching curation proposal awaiting the two step human gate. It
// carries the skill pair by id and the evidence counts only, never any candidate fact. The compliance or
// operator user approves it (the first step, which stages an inert ontology edge), then verifies it (the
// second, distinct step, which activates the edge for future scores). Nothing is ever auto applied.
export interface CurationProposalView {
id: string
kind: string
from_skill_id: string
to_skill_id: string
relation: string
proposed_strength: string
evidence_observations: number
evidence_successes: number
model_version: string
status: string
created_at: string
}
export interface OpportunityFitView {
requirement_id: string
title: string
customer_agency?: string
score: string
band: Band
status: string
}
// ---------- Mission Check (W1) ----------
// The Mission Check advisory recommendation. DO NOT SUBMIT is a derived label on the Red band.
export type MissionRecommendation = 'SUBMIT' | 'REVIEW' | 'DO NOT SUBMIT'
export interface MissionCheckFitRow extends OpportunityFitView {
recommendation: MissionRecommendation
recommendation_reason: string
}
// ParsedCandidate is what the extractor read from the resume, surfaced so the user can review and Save it.
export interface ParsedCandidate {
full_name: string
clearance_level: string
clearance_poly: string
clearance_status: string
years_experience: number
location: string
skills: string[]
certifications: string[]
customer_experience: string[]
}
// ParsedRequirement is what the JD parsed to, so the Mode B requirement panel reflects what was scored.
export interface ParsedRequirement {
title: string
required_level: string
customer_agency: string
key_personnel: boolean
}
// Mode A: the resume scored against every open opportunity, ranked.
export interface MissionCheckModeAResult {
rows: MissionCheckFitRow[]
candidate: ParsedCandidate
assumptions: string[]
data_categories: string[]
}
// Mode B: the resume scored against one pasted job description. view is the exact ScreenView /screen returns.
export interface MissionCheckModeBResult {
view: ScreenView
recommendation: MissionRecommendation
recommendation_reason: string
candidate: ParsedCandidate
requirement: ParsedRequirement
assumptions: string[]
data_categories: string[]
}
// SaveCandidateRequest is the reviewed, structured candidate the user chose to persist from a result.
// Clearance fields are DB codes; clearance is a self reported indicator the user confirmed, not verified.
export interface SaveCandidateRequest {
full_name: string
clearance_level: string
clearance_poly: string
clearance_status: string
years_experience: number
location: string
remote: boolean
relocatable: boolean
available: boolean
skills: string[]
certifications: string[]
customer_experience: string[]
}
export interface RankedCandidateView {
candidate_id: string
full_name: string
clearance_level: string
clearance_status: string
years_experience: number
location?: string
available: boolean
score: string
band: Band
status: string
}
// ---- SAM.gov Contract Opportunities (cached federal opportunity feed) ----
export interface SamPOC {
type?: string
fullName?: string
title?: string
email?: string
phone?: string
fax?: string
}
export interface SamOpportunity {
notice_id: string
title: string
solicitation_number: string
department: string
sub_agency: string
full_agency_path: string
naics_code: string
psc_code: string
set_aside_code: string
set_aside: string
type: string
posted_date: string
response_deadline: string
active: boolean
place_of_performance: { city: string; state: string; zip: string }
ui_link: string
description_url: string
resource_links: string[]
point_of_contact: SamPOC[]
source: string
synced_at: string
}
export interface OpportunityFilters {
naics?: string[]
set_aside?: string[]
state?: string[]
department?: string[]
sub_agency?: string[]
q?: string
active_only?: boolean
limit?: number
}
// ---- USASpending federal awards (incumbent intel + Galapagos past performance) ----
export interface FederalAward {
award_uid: string
award_id: string
recipient_name: string
recipient_uei: string
award_amount: string
awarding_agency: string
awarding_sub_agency: string
pop_start_date: string
pop_end_date: string
naics_code: string
naics_description: string
description: string
is_galapagos: boolean
source: string
synced_at: string
}
// ---- BLS OEWS regional wage baseline ----
export interface WageArea {
area: string
area_name: string
annual_mean: string
annual_median: string
}
export interface WageBaseline {
occupation_code: string
occupation_title: string
role: string
year: string
areas: WageArea[]
source: string
synced_at: string
}
// ---- External candidate sourcing (People Data Labs) ----
export interface ExternalCandidate {
id: string
full_name: string
email: string
headline: string
location: string
years_experience: number
available: boolean
external_id: string
source: string
clearance: string
created_at: string
}
export interface SourcingLogEntry {
id: string
candidate_id: string
external_id: string
source: string
provider: string
legal_basis: string
collected_at: string
}
// ---- Candidate workforce intelligence (computed, never hardcoded) ----
export interface IntelClearance {
level: string
status: string
sci_eligible: boolean
sci_known: boolean
investigation_year?: string
provenance: string
verified: boolean
available: boolean
}
export interface IntelReadiness {
score: string
band: Band
status: string
}
export interface IntelProposal {
value: string // YES or REVIEW
reason: string
}
export interface IntelWinImpact {
level: string // HIGH, MEDIUM, LOW
basis: string
}
export interface IntelBestFit {
requirement_id: string
name: string
customer_agency?: string
score: string
band: Band
}
export interface CandidateIntelligence {
id: string
full_name: string
source: string // seed or external
headline?: string
years_experience: number
location?: string
available: boolean
clearance: IntelClearance
mission_readiness: IntelReadiness
proposal_ready: IntelProposal
win_impact: IntelWinImpact
best_fit: IntelBestFit
labor_category_coverage: string[]
}
// ---- Workforce Command Center ----
export interface CCBanner {
total_cleared_workforce: number
available_candidates: number
proposal_ready_candidates: number
active_requirements: number
staffing_gaps: number
high_risk_opportunities: number
}
export interface CCDriver { key: string; label: string; pct: string; state: ReadinessState; weight: string }
export interface CCMissionReadiness {
score: string
band: Band
status: string
drivers: CCDriver[]
availability_req_coverage: string
flags: string[]
}
export interface CCOpportunity {
opportunity_id: string
name: string
customer_agency?: string
solicitation_number?: string
due_date?: string
value: string | null
readiness_score: string
total_requirements: number
covered_requirements: number
headcount_needed: number
headcount_covered: number
key_personnel_open: number
staffing_risk: string
staffing_risk_code: 'high' | 'medium' | 'low'
}
export interface CCGap {
labor_category: string
required_level: string
required_level_label: string
unmet: number
blocks_key_personnel: boolean
impacted_opportunities: string[]
value_at_risk: string | null
priced_opportunities: number
unpriced_opportunities: number
total_opportunities: number
value_representative: boolean
value_basis: string
impact_modeled_pct: string
impact_modeled_label: string
headline: string
recommendation: string
}
export interface CCLevelCount { level: string; label: string; total: number; available: number }
export interface CCPolyCount { poly: string; label: string; total: number; available: number }
export interface CCExpiryAlert {
candidate_id: string
full_name: string
clearance_level: string
days_until_expiry: number
severity: 'critical' | 'warning' | 'info'
}
export interface CCClearanceIntel {
inventory_by_level: CCLevelCount[]
inventory_by_poly: CCPolyCount[]
availability_windows: { now: number; d30: number; d60: number; d90: number }
expiring: {
expired: number
due_30: number
due_60: number
due_90: number
reinvestigation_overdue: number
alerts: CCExpiryAlert[]
}
}
export interface CCLcatCoverage { labor_category: string; filled: number; demanded: number; coverage: string; color: Band }
export interface CCOppRef { opportunity_id: string; name: string }
export interface CCProposalReadiness {
ready: number
at_risk: number
key_personnel_missing: number
labor_categories_missing: number
ready_opportunities: CCOppRef[]
at_risk_opportunities: CCOppRef[]
key_personnel_missing_opportunities: CCOppRef[]
labor_categories_missing_opportunities: CCOppRef[]
}
export interface CCWinCandidate {
candidate_id: string
full_name: string
clearance_level: string
poly: string
years_experience: number
}
export interface CCHeatMetro { metro: string; total: number; available: number; cleared: number }
export interface CCRecommendation {
severity: 'high' | 'medium' | 'low'
message: string
action_target: string
related_ids: string[]
source_ref: string
}
export interface CCLaunch { product: string; action: string; label: string; route: string }
// CCUpcomingOpportunity is one planning stage forecast surfaced beside the current readiness. It never
// changes the current numbers. available_cleared_in_state is a real bench count; the comparable
// requirement coverage is the engine backed eligibility of the org's similar requirements; fit_note
// states honestly that a bare forecast has no precise match score.
export interface CCUpcomingOpportunity {
record_id: string
title: string
agency: string
naics?: string
place_of_performance?: string
state?: string
set_aside?: string
estimated_value: string | null
estimated_award_date?: string
incumbent_name?: string
planning_note: string
available_cleared_in_state: number
comparable_requirements: number
comparable_covered: number
fit_note: string
adoptable: boolean
}
// CCIncumbentRef is one incumbent and award context row from the contract award feed.
export interface CCIncumbentRef {
record_id: string
incumbent: string
incumbent_uei?: string
agency: string
naics?: string
value: string | null
value_source?: string
award_date?: string
source: string
}
// AdoptForecastInput turns a forecast into a real requirement the engine scores.
export interface AdoptForecastInput {
required_level: string
required_poly: string
required_years: number
key_personnel: boolean
skills: string[]
}
export interface AdoptForecastResult {
requirement_id: string
title: string
}
// ---- AI Brain (the closed Registry, grounded mission brain) ----
// AskRequest is the free text question the Ask panel sends. The intent and args fields exist on the
// backend contract but the panel never sets them; a plain question is routed by the brain itself.
export interface AskRequest {
question: string
intent?: string
args?: Record<string, unknown>
}
// AskAnswer is a grounded answer. path names the retrieval route the brain took (closed answer, tool,
// retrieval, or graph walk). faithful states whether the answer stayed inside its cited evidence, and
// citations lists the grounding rows. fallback_reason is present only when the brain stepped down a route.
export interface AskAnswer {
answer: string
path: 'cag' | 'tag' | 'rag' | 'graph'
rationale_source: string
citations: string[]
faithful: boolean
evidence_count: number
fallback_reason?: string
}
export interface CommandCenterView {
as_of: string
organization_id: string
generated_at: string
meta: { empty: boolean; notes: string[] }
banner: CCBanner
mission_readiness: CCMissionReadiness
active_opportunities: CCOpportunity[]
staffing_gaps: CCGap[]
clearance_intelligence: CCClearanceIntel
labor_category_coverage: CCLcatCoverage[]
proposal_readiness: CCProposalReadiness
win_impact: { high_impact_count: number; top: CCWinCandidate[] }
heat_map: CCHeatMetro[]
upcoming_opportunities: CCUpcomingOpportunity[]
incumbent_landscape: CCIncumbentRef[]
ai_recommendations: CCRecommendation[]
action_center: {
suggested_requirement_id: string | null
suggested_opportunity_id: string | null
open_opportunities_without_slate: number
requirements_unscreened: number
launch: CCLaunch[]
}
executive_cards: CCExecutiveCard[]
}
export interface CCExecutiveCard {
key: string
title: string
value: string
detail: string
state: string
no_data: boolean
data_note?: string
}
// ---------------------------------------------------------------------------
// recruitMATCH. Mirrors internal/modules/recruitmatch. Counts are integers and
// every percentage is a decimal string, so convert with num() at render time.
// The backend deliberately emits no color: color is presentation and lives here.
// ---------------------------------------------------------------------------
export interface RMHeadline {
active_jobs: number
identified: number
screened: number
submitted: number
approved: number
on_bench: number
}
// Pct is this stage as a share of identified. The backend guarantees the sequence
// is non increasing, so a stage can never render wider than the one before it.
export interface RMFunnelStage {
key: string
label: string
count: number
pct: string
}
// Decisions count slate MEMBERSHIPS, not people, which is why they sit apart from
// the funnel. approve_rate excludes pending members from its denominator.
export interface RMDecisions {
approved: number
rejected: number
pending: number
total: number
approve_rate: string
}
export interface RMBandMix {
green: number
yellow: number
red: number
total: number
}
export interface RMClearanceRow {
code: string
label: string
count: number
pct: string
}
export interface RMTopJob {
requirement_id: string
title: string
customer_agency?: string
required_level: string
submitted: number
}
export interface RMRecruiterRow {
user_id: string
full_name: string
screened: number
decided: number
approved: number
}
// EmptyPanel names a panel the product intends to show and the feed it still needs.
export interface RMEmptyPanel {
key: string
title: string
reason: string
}
export interface RMView {
as_of: string
organization_id: string
generated_at: string
headline: RMHeadline
funnel: RMFunnelStage[]
decisions: RMDecisions
band_mix: RMBandMix
clearance: RMClearanceRow[]
top_jobs: RMTopJob[]
recruiters: RMRecruiterRow[]
empty_panels: RMEmptyPanel[]
}
// Mirrors internal/modules/alerts. Every field crosses the wire as a string.
// Populated by the scheduled alert-sweep job, so this feed has data before a
// recruiter has done anything in the product.
export interface Alert {
id: string
alert_type: string
severity: string
subject_type?: string
subject_id: string
title: string
detail?: string
status: string
created_at: string
updated_at: string
}
// Mirrors internal/modules/staffing RecommendationView, trimmed to what the panel renders.
// rationale_source is 'deterministic' when the model could not be reached or its prose failed
// the faithfulness check, so the UI can always say whether a human is reading generated text.
export interface RecommendationView {
id: string
requirement_id: string
candidate_id: string
action: string
rank: number
confidence: string
rationale: string
rationale_source: string
status: string
created_at: string
}
export interface ProactiveResponse {
recommendations: RecommendationView[]
limit: number
offset: number
}
// Mirrors internal/modules/org. Branding is per organization so the application white labels for every
// client. logo_etag changes with the bytes, so it is a safe cache buster in an image URL.
export interface OrgBranding {
organization_id: string
name: string
display_name: string
has_logo: boolean
logo_etag?: string
logo_updated_at?: string
}
// ---------------------------------------------------------------------------
// recruiting: clients and contacts. Mirrors internal/modules/recruiting.
// updated_at is both a display value and the optimistic concurrency token; it
// must be sent back on every update or the write is refused.
// ---------------------------------------------------------------------------
export interface RClient {
id: string
name: string
uei?: string
industry?: string
website?: string
status: string
notes?: string
contact_count: number
owner_user_id?: string
owner_name?: string
owner_since?: string
created_at: string
updated_at: string
}
export interface RContact {
id: string
client_id: string
full_name: string
title?: string
email?: string
phone?: string
is_hiring_manager: boolean
is_primary: boolean
status: string
created_at: string
updated_at: string
}
export interface RClientDetail extends RClient {
contacts: RContact[]
}
export interface RClientList {
clients: RClient[]
limit: number
offset: number
total: number
}
// Requisitions. Money arrives as a decimal string, never a number, because a JSON number is a float64
// and a bill rate multiplied downstream must be exactly the rate that was agreed.
export type RRequisition = {
id: string
client_id?: string
client_name?: string
hiring_manager_id?: string
hiring_manager_name?: string
owner_user_id?: string
owner_name?: string
requirement_id?: string
title: string
description?: string
labor_category?: string
openings: number
priority: string
employment_type: string
status: string
required_level: string
required_poly: string
work_location?: string
remote_allowed: boolean
bill_rate_min?: string
bill_rate_max?: string
pay_rate_min?: string
pay_rate_max?: string
salary_min?: string
salary_max?: string
opened_at: string
target_fill_date?: string
closed_at?: string
on_hold_since?: string
// Three clocks. age is the wall clock a client sees, working removes time spent on hold, held is the
// difference, shown so neither number has to be taken on trust.
age_days: number
working_days: number
held_days: number
// Negative means the target has passed. Absent means no target was set, which is not the same as zero.
days_to_target?: number
created_at: string
updated_at: string
}
export type RRequisitionEvent = {
id: string
from_status?: string
to_status: string
days_in_from: number
note?: string
actor_user_id?: string
actor_user_name?: string
occurred_at: string
}
export type RRequisitionDetail = RRequisition & { events: RRequisitionEvent[] }
export type RRequisitionList = {
requisitions: RRequisition[]
limit: number
offset: number
total: number
}
// Pipeline. The funnel counts high water marks, so it is monotone by construction; the board columns
// count who is at each stage right now. Those are different questions with deliberately different answers.
export type RApplication = {
id: string
requisition_id: string
requisition_title?: string
client_name?: string
candidate_id: string
candidate_name: string
clearance_level: string
available: boolean
stage: string
stage_label: string
furthest_stage: string
furthest_stage_label: string
disposition_code?: string
disposition_reason?: string
owner_user_id?: string
owner_name?: string
source_first_touch?: string
source_last_touch?: string
stage_changed_at: string
days_in_stage: number
created_at: string
updated_at: string
}
export type RStageEvent = {
id: string
from_stage?: string
from_stage_label?: string
to_stage: string
to_stage_label: string
days_in_from: number
reason?: string
disposition_code?: string
actor_user_id?: string
actor_name?: string
occurred_at: string
}
export type RApplicationDetail = RApplication & { events: RStageEvent[] }
export type RFunnelStage = { stage: string; label: string; count: number; pct: string }
export type RConversion = { from: string; to: string; from_label: string; to_label: string; rate: string }
export type RDisposition = { code: string; stage: string; count: number; pct: string }
export type RStageColumn = { stage: string; label: string; count: number; applications: RApplication[] }
export type RPipelineBoard = {
requisition_id: string
requisition_title: string
openings: number
placed: number
seats_left: number
total: number
active: number
columns: RStageColumn[]
funnel: RFunnelStage[]
conversion: RConversion[]
dispositions: RDisposition[]
}
export type RDispositionOption = { code: string; outcome: string; label: string }
export type RDispositionCatalog = { dispositions: RDispositionOption[]; stages: RFunnelStage[] }
export type RApplicationList = {
applications: RApplication[]
limit: number
offset: number
total: number
}
// Assignments. Money is a decimal string, never a JSON number, because a rate that round tripped
// through a float64 would not reconcile with an invoice.
export type RMargin = { gross_per_hour?: string; margin_pct?: string; fee?: string }
export type RGuarantee = { days: number; ends_on?: string; days_remaining?: number; breached: boolean }
export type RInterview = {
id: string
application_id: string
candidate_name?: string
round: number
kind: string
scheduled_at?: string
completed_at?: string
outcome: string
interviewer?: string
notes?: string
created_at: string
updated_at: string
}
export type ROffer = {
id: string
application_id: string
candidate_name?: string
status: string
employment_type: string
bill_rate?: string
pay_rate?: string
salary?: string
fee_pct?: string
margin: RMargin
extended_at: string
responded_at?: string
expires_at?: string
decline_reason?: string
next_statuses: string[]
created_at: string
updated_at: string
}
export type RPlacement = {
id: string
application_id: string
offer_id?: string
candidate_id?: string
candidate_name?: string
requisition_id?: string
requisition_title?: string
client_name?: string
status: string
employment_type: string
start_date: string
end_date?: string
bill_rate?: string
pay_rate?: string
salary?: string
fee_amount?: string
margin: RMargin
guarantee: RGuarantee
live: boolean
created_at: string
updated_at: string
}
export type RAssignment = {
application_id: string
candidate_name: string
stage: string
stage_label: string
interviews: RInterview[]
offers: ROffer[]
placements: RPlacement[]
}
export type RPlacementList = { placements: RPlacement[]; limit: number; offset: number; total: number }
// Recruiter activity. auto_captured is output only: the log input type has no such field, so a caller
// cannot claim their manual entry was recorded by the platform.
export type RActivity = {
id: string
actor_user_id?: string
actor_name?: string
kind: string
direction: string
outcome: string
candidate_id?: string
candidate_name?: string
contact_id?: string
requisition_id?: string
requisition_title?: string
application_id?: string
body?: string
auto_captured: boolean
occurred_at: string
created_at: string
}
export type RActivityList = { activities: RActivity[]; limit: number; offset: number; total: number }
export type RRecruiterEffort = {
user_id?: string
name: string
logged: number
connects: number
// Absent rather than "0.00" when nothing was logged, because a zero rate on no attempts claims a
// failure that did not happen.
connect_rate?: string
captured: number
}
export type RActivitySummary = {
since: string
total_logged: number
total_connects: number
total_captured: number
connect_rate?: string
recruiters: RRecruiterEffort[]
by_kind: { kind: string; count: number }[]
}
// Tasks. Buckets are computed in the organization's timezone, so "today" is the working day rather
// than a UTC day. An evening task due today does not read as due tomorrow.
export type RTask = {
id: string
title: string
detail?: string
status: string
priority: string
assigned_to?: string
assignee_name?: string
due_at?: string
completed_at?: string
bucket: 'overdue' | 'today' | 'soon' | 'later' | 'none'
// Negative when overdue. Absent when there is no due date, which is not the same as zero.
due_in_days?: number
candidate_id?: string
candidate_name?: string
requisition_id?: string
requisition_title?: string
application_id?: string
contact_id?: string
created_at: string
updated_at: string
}
export type RTaskQueue = {
time_zone: string
overdue: number
today: number
soon: number
later: number
no_due_date: number
unassigned: number
tasks: RTask[]
}
export type RTaskList = { tasks: RTask[]; limit: number; offset: number; total: number }
// Analytics. Time to fill keeps still-open requisitions in the calculation as right-censored
// observations, so the median is not biased low by excluding everything that has not filled yet.
export type RSurvivalPoint = { days: string; at_risk: number; filled: number; surviving: string }
export type RTimeToFill = {
cohort: number
filled: number
still_open: number
// The figure every other tool shows, computed over filled orders only. Biased low.
naive_median_days?: string
// The corrected figure. Absent when fewer than half the cohort has filled, which is the honest answer.
median_days?: string
median_reached: boolean
curve: RSurvivalPoint[]
}
export type RFillRate = {
filled: number
closed_unfilled: number
cancelled: number
still_open: number
rate_of_resolved?: string
rate_of_decided?: string
suppressed: boolean
}
export type RAgingBucket = { label: string; min_days: number; max_days: number; count: number }
export type RSourceEffect = { source: string; applications: number; placed: number; rate?: string; suppressed: boolean }
export type RPlacementSummary = {
live: number
started: number
ended: number
fell_off: number
guarantee_breaches: number
contract_gross_per_hour?: string
direct_hire_fees?: string
}
export type RAnalytics = {
since: string
time_zone: string
time_to_offer: RTimeToFill
time_to_start: RTimeToFill
worked_time_to_start: RTimeToFill
fill_rate: RFillRate
aging: RAgingBucket[]
oldest_open_days: number
funnel: RFunnelStage[]
conversion: RConversion[]
sources: RSourceEffect[]
recruiters: RRecruiterEffort[]
placements: RPlacementSummary
}
// Reporting. Periods are bucketed in the organization's timezone, and fiscal_quarter is the US FEDERAL
// fiscal quarter, which begins 1 October.
export type RPeriodRow = {
start: string
label: string
opened: number
filled: number
submissions: number
placements: number
activities: number
connects: number
connect_rate?: string
}
export type RReport = {
period: string
since: string
time_zone: string
rows: RPeriodRow[]
totals: RPeriodRow
}