Job Application
This example demonstrates a job application workflow with submissions, reviews, interviews, and hiring decisions.
Application Lifecycle
flow
machine: @application
scenario: submission
given:
@applicant is registered
job posting is active
on :submit from @applicant (api)
? all required fields are filled
application moves to #pending
$submitted_at becomes now
emit :new_application to @recruiter
? missing required fields
emit :validation_error to @applicant
with $missing_fields
expect:
= application is in #pending
scenario: initial screening
given:
application is in #pending
@recruiter is assigned
on :screen from @recruiter (api)
? qualifications match requirements
application moves to #screened
emit :screening_passed to @applicant
? qualifications do not match
application moves to #rejected
emit :application_rejected to @applicant
with:
| reason | "Qualifications do not match requirements" |
expect:
= application has been screened
scenario: interview process
given:
application is in #screened
on :schedule_interview from @recruiter (api)
application moves to #interview_scheduled
$interview_date becomes $scheduled_date
emit :interview_invitation to @applicant
with:
| date | $interview_date |
| location | $interview_location |
on :interview_completed from @interviewer with:
| field | value | validation |
| score | $score | required, number, between 1 and 10 |
| notes | $notes | optional, string |
application moves to #interview_completed
$interview_score becomes $score
$interview_notes becomes $notes
? $interview_score >= 8
emit :strong_candidate_alert to @hiring_manager
expect:
= interview has been completed
scenario: hiring decision
given:
application is in #interview_completed
$interview_score: number is 8
on :approve from @hiring_manager (api)
? $interview_score >= 7
application moves to #offer_pending
emit :prepare_offer to @hr
emit :approval_notification to @applicant
? $interview_score < 7
application moves to #rejected
emit :application_rejected to @applicant
on :offer_sent from @hr
application moves to #offer_extended
$offer_expires_at becomes now + 7 days
emit :offer_details to @applicant
with:
| salary | $offered_salary |
| benefits | $benefits_package |
| deadline | $offer_expires_at |
expect:
= offer process has started
scenario: offer response
given:
application is in #offer_extended
on :accept_offer from @applicant (api)
? offer has not expired
application moves to #hired
emit :offer_accepted to @hr
emit :welcome_package to @applicant
emit :onboarding_request to @onboarding
? offer has expired
emit :offer_expired_error to @applicant
on :decline_offer from @applicant (api)
application moves to #offer_declined
$decline_reason becomes $reason
emit :offer_declined to @hr
emit :feedback_request to @applicant
on :negotiate from @applicant (api)
application moves to #negotiating
emit :negotiation_request to @hr
with:
| requested_salary | $requested_salary |
| notes | $negotiation_notes |
on :counter_offer from @hr
emit :counter_offer_details to @applicant
with:
| salary | $counter_salary |
| benefits | $counter_benefits |
expect:
= offer response has been processed
scenario: expiration handling
on :check_expired_applications
triggered: every day at 00:00
for each application in #pending
? $submitted_at older than 30 days
application moves to #expired
emit :application_expired to @applicant
for each application in #offer_extended
? $offer_expires_at has passed
application moves to #offer_expired
emit :offer_expired to @applicant
emit :offer_expired to @hrState Diagram
Lane Diagram
Testing Scenarios
Successful Hire
flow
scenario: successful hire path
given:
@applicant is registered
job posting is active
on :submit from @applicant (api)
application moves to #pending
on :screen from @recruiter (api)
application moves to #screened
on :schedule_interview from @recruiter (api)
application moves to #interview_scheduled
on :interview_completed from @interviewer
$interview_score becomes 9
application moves to #interview_completed
on :approve from @hiring_manager (api)
application moves to #offer_pending
on :offer_sent from @hr
application moves to #offer_extended
on :accept_offer from @applicant (api)
application moves to #hired
expect:
= application is in #hired
= @applicant received :welcome_packageRejection at Screening
flow
scenario: rejected at screening
given:
@applicant is registered
qualifications do not match
on :submit from @applicant (api)
application moves to #pending
on :screen from @recruiter (api)
application moves to #rejected
expect:
= application is in #rejected
= @applicant received :application_rejectedOffer Negotiation
flow
scenario: salary negotiation
given:
application is in #offer_extended
$offered_salary is 80000
on :negotiate from @applicant (api)
$requested_salary becomes 90000
application moves to #negotiating
on :counter_offer from @hr
$counter_salary becomes 85000
on :accept_offer from @applicant (api)
application moves to #hired
expect:
= application is in #hired