Skip to main content

Use Cases and How Models Interact

Below, each use case shows:

  • which models are touched
  • the status transitions that occur
  • side effects (notifications, billing triggers, etc.)

1.0 End-to-End Happy Path

Scenario

McDonald's Orchard needs 3 Service Crew workers for a shift next Tuesday (9am–6pm, $12/hr). The Job already exists on the platform. The employer adds a new Shift, talent apply, workers are selected, they complete the shift, and get paid.

Step-by-step

Step 1 — Employer adds a Shift to an existing Job

Actor: Org::UserProfile (employer)

Models touched: Gig::Shift

  1. Employer selects an existing Gig::Job ("Service Crew at McDonald's Orchard, $12/hr")
  2. Employer enters: starts_at, ends_at, headcount = 3
  3. System creates Gig::Shift with status draft
  4. If employer's location requires approval → status becomes pending_approval
  5. If no approval required → status becomes open
  6. Listings::Job is updated to reflect the new open shift

Step 2 — Talent applies to the Shift

Actor: Talent::Profile (talent)

Models touched: Gig::Application

  1. Talent browses marketplace, finds the Job via Listings::Job, and selects a Shift
  2. System checks: talent is not suspended, has no time overlap with existing Assignments
  3. System creates Gig::Application with status pending
  4. System recalculates rankings for all pending Applications on this Shift

Step 3 — Employer accepts applicants

Actor: Org::UserProfile (employer)

Models touched: Gig::Application

  1. Employer views ranked applicant list for the Shift
  2. Employer accepts 3 applicants (up to headcount)
  3. For each accepted applicant: Gig::Application.statusaccepted
  4. Each accepted talent receives a notification: "You've been selected for Tuesday's shift"
  5. Remaining applicants stay in pending — they may still be selected if an accepted talent declines

Step 4 — Talent confirms acceptance

Actor: Talent::Profile (talent)

Models touched: Gig::Application, Gig::Assignment

  1. Talent opens the notification and confirms: "Yes, I will work this shift"
  2. Gig::Application.statusconfirmed
  3. System creates Gig::Assignment with status confirmed, linking the talent to the Shift
  4. System checks for time overlaps with the talent's other Applications → conflicting Applications auto-rejected
  5. Shift's filled count increases (e.g., 1/3 → 2/3)

If the talent does not confirm within the deadline, Gig::Application.statusexpired, and the employer can select the next ranked applicant.

Step 5 — Shift becomes active

Actor: System (time-based trigger)

Models touched: Gig::Shift

  1. When Gig::Shift.starts_at is reached, Gig::Shift.statusactive
  2. System begins no-show monitoring for all confirmed Assignments on this Shift

Step 6 — Talent clocks in

Actor: Talent::Profile (talent) + Org::UserProfile (employer)

Models touched: Gig::QrCode, Gig::Assignment

  1. Employer generates a clock-in Gig::QrCode for the Shift (one QR for all workers)
  2. QR code has an expiry (configurable, e.g., 15 minutes)
  3. Talent scans the QR code
  4. System records actual_clock_in timestamp (immutable)
  5. Gig::Assignment.statusclocked_in

Step 7 — Talent clocks out

Actor: Talent::Profile (talent) + Org::UserProfile (employer)

Models touched: Gig::QrCode, Gig::Assignment

  1. Employer generates a clock-out Gig::QrCode for the Shift
  2. Employer fills in the initial time confirmation form: billable_clock_in, billable_clock_out, billable_break_minutes
  3. Talent scans the clock-out QR code
  4. System records actual_clock_out timestamp (immutable)
  5. billable_* fields are set from the employer's form (defaults to actual times if employer skips the form)
  6. Gig::Assignment.statusclocked_out

Step 8 — Settlement window and verification

Actor: System + Org::UserProfile (employer, optional)

Models touched: Gig::Assignment, Gig::AssignmentAdjustment, Gig::Payment

  1. The settlement window opens (from clock-out until 9:00am the next day)
  2. Employer may adjust billable times during this window — each change creates an immutable Gig::AssignmentAdjustment record
  3. At 9:00am the next day (or earlier if employer explicitly locks):
    • Gig::Assignment.billable_locked_at is set
    • Gig::Assignment.statusverified
  4. System calculates wage: billable_hours × hourly_rate = gross_wage
  5. System creates Gig::Payment with status pending and the calculated wage
  6. System triggers Billing domain to consume gig credits from the employer's entitlement lots

Step 9 — Shift completes

Actor: System

Models touched: Gig::Shift

  1. When all Assignments for the Shift reach a terminal state (verified, cancelled, or no_show):
    • Gig::Shift.statuscompleted
  2. The Job remains active — employer can add new Shifts at any time

Step 10 — Payment disbursement

Actor: System + Finance team

Models touched: Gig::Payment

  1. System generates bank instruction file including all pending Payments
  2. Gig::Payment.statusprocessing
  3. Finance uploads the file to the bank for GIRO disbursement
  4. Once confirmed: Gig::Payment.statuspaid

2.0 Posting a New Job (First Time)

Scenario

A new client (Subway) wants to post their first gig job. No Gig::Job exists yet.

Steps

  1. Employer enters Job details: title, description, requirements, hourly rate, location
  2. System creates Gig::Job with status active
  3. System snapshots the role via Org::JobRoleVersion (if job roles are configured)
  4. Employer adds a Shift to the Job (same as Step 1 in 1.0)

Business rules:

  • A Job must belong to exactly one Org::Company
  • Job title, description, and hourly rate are required
  • The same Job is reused for all future Shifts — employer does not need to re-enter details

2.1 Posting a Shift with Approval Required

Scenario

An NTUC outlet requires HQ approval before shifts are published.

Steps

  1. Location manager creates a Shift under an existing Job
  2. System creates Gig::Shift with status pending_approval
  3. Approver (HQ or area manager) is notified
  4. Approver reviews and approves → Gig::Shift.statusopen
  5. Or approver rejects → Gig::Shift.statuscancelled

Business rules:

  • Approval requirement is a per-location configuration
  • The Shift is not visible on the marketplace until approved
  • The approver hierarchy depends on Org::UserProfile role/permission design (open question)

3.0 Auto-Selection

Scenario

An employer posted a Shift needing 2 workers. 5 talent applied but the employer hasn't selected anyone. The auto-select deadline arrives.

Preconditions

  • Auto-selection is enabled for this location (per-location configuration)
  • Shift has pending Applications with rankings

Steps

  1. Auto-select deadline arrives (AM shifts: 9am previous day, PM shifts: 5pm previous day)
  2. System retrieves all pending Applications for the Shift, ordered by talent_rank ascending (rank 1 = best)
  3. System selects the top N applicants (where N = headcount - current_filled_count)
  4. For each selected Application:
    • Gig::Application.statusaccepted
    • Talent is notified: "You've been auto-selected"
  5. Talent must still confirm (same as Step 4 in 1.0) — auto-selection does not skip the confirmation step
  6. Remaining unselected Applications: Gig::Application.statusrejected

Business rules:

  • Auto-selection only selects talent who have not been suspended and have no time overlaps
  • If the top-ranked talent has a conflict, the system skips to the next ranked talent
  • If there are fewer applicants than headcount, the system selects all available applicants

4.0 Talent Cancels Application Before Selection

Scenario

A talent applied to a shift but changed their mind before the employer made a selection.

Steps

  1. Talent requests cancellation of their pending Application
  2. Gig::Application.statuswithdrawn
  3. Shift's applicant count decreases
  4. System recalculates rankings for remaining applicants

Business rules:

  • No penalty, no document required
  • Available at any time while Application is in pending status
  • Cancellation reason is optional

4.1 Talent Cancels Assignment (>48 Hours Before Shift)

Scenario

A talent was confirmed for a Tuesday shift but cancels on Saturday (>48 hours before).

Steps

  1. Talent requests cancellation of their confirmed Assignment
  2. Talent provides a mandatory cancellation reason (via Taxonomy::GigStatusReason)
  3. Gig::Assignment.statuscancelled
  4. The corresponding Gig::Application.statuscancelled
  5. Shift's filled count decreases (e.g., 3/3 → 2/3)
  6. If Shift is still open and before cutoff, new talent can apply to fill the position
  7. Employer is notified: "A confirmed worker has cancelled"

Business rules:

  • No penalty — cancellation is outside the 48-hour window
  • No supporting document required
  • Cancellation reason is mandatory

4.2 Talent Cancels Assignment (3–48 Hours Before Shift)

Scenario

A talent was confirmed for a Tuesday 9am shift but cancels on Monday at 2pm (~19 hours before).

Steps

1–7: Same as 4.1

  1. System evaluates the talent's suspension history:
    • 1st offense: Warning notification sent. Incident recorded. No suspension.
    • 2nd offense: Pending suspension created. Talent has 24 hours to submit appeal with supporting document.
    • 3rd offense: Pending suspension created (30 days). Same 24-hour appeal window.
    • 4th+ offense: Pending suspension created (90 days). Same 24-hour appeal window.

Business rules:

  • Cancellation reason is mandatory
  • Supporting document is recommended but not required in this window
  • Talent enters progressive suspension discipline (see Suspension use cases 7.0–7.2)

4.3 Talent Cancels Assignment (0–3 Hours Before Shift) — Urgent Cancellation

Scenario

A talent was confirmed for a 9am shift and cancels at 7:30am (1.5 hours before).

Steps

  1. Talent requests cancellation
  2. System requires: cancellation reason + supporting document (e.g., MC)
  3. If no document provided → cancellation is blocked
  4. If document provided:
    • Steps 3–7 from 4.1 apply
    • Step 8 from 4.2 applies (progressive suspension discipline)

Business rules:

  • Supporting document is mandatory for urgent cancellations
  • Cancellation is blocked if the talent cannot provide a document
  • After shift start time, cancellation is blocked entirely — the talent is treated as a no-show

5.0 Employer Cancels a Shift

Scenario

An employer posted a Shift for Tuesday but no longer needs the manpower.

Steps

  1. Employer requests cancellation of the Shift
  2. Employer provides a mandatory cancellation reason (via Taxonomy::GigStatusReason)
  3. All pending and accepted Applications on the Shift → cancelled
  4. All confirmed Assignments on the Shift → cancelled
  5. Gig::Shift.statuscancelled
  6. Affected talent are notified: "The shift you were confirmed for has been cancelled"

Billing impact (if Assignments existed):

If any Assignments were in confirmed status (talent had already confirmed), the employer's gig credits are deducted based on how late the cancellation is:

WindowCredit deduction
>48 hours before shiftNo deduction
24–48 hoursProgressive deduction (low)
12–24 hoursProgressive deduction (moderate)
3–12 hoursProgressive deduction (high)
0–3 hoursProgressive deduction (very high)
After shift startFull shift value consumed

Specific deduction percentages are a configuration decision (see open questions in Overview).


5.1 Employer Rejects a Specific Assignment

Scenario

An employer selected 3 workers for a shift but decides to remove one specific worker before the shift starts.

Steps

  1. Employer selects the Assignment to reject
  2. Employer provides a mandatory rejection reason (via Taxonomy::GigStatusReason)
  3. Gig::Assignment.statuscancelled
  4. The corresponding Gig::Application.statusrejected
  5. Shift's filled count decreases
  6. Talent is notified: "You have been removed from this shift"
  7. If Shift is still open, new talent can apply

Billing impact:

Same progressive credit deduction as 5.0, based on timing of the rejection relative to shift start.

Business rules:

  • Rejection reason is mandatory (addresses the legacy data quality issue where 93% of rejections had no reason)
  • If the Assignment is clocked_in (talent is already working), the employer can still reject but payment for hours worked is an open question (see Gig::Payment model spec)

6.0 No-Show Detection

Scenario

A talent was confirmed for a 9am shift but does not clock in.

Steps

  1. Gig::Shift transitions to active at starts_at (9:00am)
  2. System monitors all confirmed Assignments for clock-in activity
  3. After a configured no-show window (e.g., shift ends + grace period):
    • Gig::Assignment.statusno_show
  4. No Gig::Payment is created for this Assignment
  5. The talent enters the progressive suspension discipline (same as 4.2 step 8)
  6. Employer is notified: "Worker did not show up for the shift"

Business rules:

  • No-show detection is system-triggered (not manual)
  • The no-show window is configurable (legacy used 24 hours after shift end; this may be shortened)
  • A no-show counts as an offense in the progressive suspension policy

6.1 Shift Expiration — No Applicants

Scenario

An employer posted a Shift but no talent applied before the cutoff time.

Steps

  1. Cutoff time arrives (configured hours before shift start)
  2. Gig::Shift.statusexpired
  3. No Applications or Assignments exist, so no notifications needed

6.2 Shift Expiration — No Selection

Scenario

5 talent applied to a Shift but the employer never selected anyone and auto-selection is disabled.

Steps

  1. Cutoff time arrives
  2. All pending Applications → expired
  3. Gig::Shift.statusexpired
  4. Talent are notified: "The shift you applied for has expired"

7.0 Suspension — Warning (1st Offense)

Scenario

A talent cancels an Assignment within 48 hours of shift start for the first time.

Steps

  1. Cancellation processed (per 4.2)
  2. System checks talent's suspension history: no prior incidents
  3. System creates an incident record (warning)
  4. Talent receives a notification: "This is a warning — repeated late cancellations or no-shows will result in suspension"
  5. No restrictions applied — talent can continue to apply and work normally

7.1 Suspension — Pending with Appeal Window (2nd+ Offense)

Scenario

A talent cancels an Assignment within 48 hours for the second time. They have a valid MC.

Steps

  1. Cancellation processed (per 4.2)
  2. System checks talent's suspension history: 1 prior incident (warning)
  3. System creates a pending suspension (7-day) with a 24-hour appeal window
  4. Talent is notified: "Your account is pending suspension. Submit a supporting document within 24 hours to appeal."
  5. During the 24-hour window:
    • Talent cannot apply to new shifts
    • Existing confirmed Assignments are preserved
    • Talent can still work their confirmed shifts
  6. Talent submits MC via in-app document upload
  7. Appeal is routed to ops for review

7.2 Suspension — Appeal Review

Scenario

Ops reviews a pending suspension appeal.

Steps — Approved

  1. Ops reviews the supporting document
  2. Ops approves the appeal
  3. Pending suspension is cleared
  4. Talent regains full access — can apply to new shifts
  5. The incident is recorded but does not count toward escalation

Steps — Rejected

  1. Ops reviews the supporting document
  2. Ops rejects the appeal
  3. Suspension takes effect immediately:
    • Talent cannot apply to new shifts
    • Assignments within the suspension period are cancelled
    • Assignments scheduled after the suspension ends are preserved
  4. Suspension lifts automatically when the period expires (7 / 30 / 90 days)

Steps — No Appeal Submitted

  1. 24-hour appeal window expires with no document submitted
  2. Suspension takes effect automatically (same as rejection above)

8.0 Employer Adjusts Billable Times After Clock-Out

Scenario

An employer filled in the clock-out form at 6pm with incorrect break time. At 8am the next morning, they want to correct it.

Steps

  1. Employer navigates to the Assignment (status: clocked_out)
  2. Employer modifies billable_break_minutes from 30 → 60 and provides a reason
  3. System creates an immutable Gig::AssignmentAdjustment record:
    • field_changed: break_minutes
    • old_value: 30
    • new_value: 60
    • reason: "Worker took a 1-hour break, not 30 minutes"
    • adjusted_by: Org::UserProfile#456
  4. Gig::Assignment.billable_break_minutes updated from 30 → 60
  5. The adjustment is visible in the audit trail for this Assignment

Business rules:

  • Adjustments are only allowed while Gig::Assignment.status = clocked_out (before verification deadline)
  • Each adjustment creates an immutable audit record — the billable_* fields on Assignment are the current fact, the adjustments are the event history
  • After billable_locked_at is set (verification), no further adjustments are allowed unless overridden by an admin

8.1 Admin Adjusts Billable Times on Behalf of Employer

Scenario

An employer sends a WhatsApp message to ops at 8:30am asking to change a worker's clock-in time. Ops enters the adjustment on their behalf.

Steps

  1. Admin navigates to the Assignment
  2. Admin modifies billable_clock_in and provides a reason: "Per employer WhatsApp request"
  3. System creates a Gig::AssignmentAdjustment record with adjusted_by = Identities::Admin
  4. Assignment updated

Business rules:

  • Same as 8.0, but adjusted_by references an admin instead of an employer
  • The reason field captures the communication channel ("Per employer WhatsApp request") for audit

9.0 Time Overlap Auto-Rejection

Scenario

A talent confirms a Tuesday 9am–6pm shift. They had also applied to another Tuesday 10am–4pm shift.

Steps

  1. Talent confirms Assignment for Shift A (9am–6pm)
  2. System scans all other pending Applications for this talent
  3. System detects overlap: Shift B (10am–4pm) overlaps with Shift A
  4. Gig::Application for Shift B → rejected (reason: time overlap)
  5. Talent is notified: "Your application for [Shift B] was automatically withdrawn due to a scheduling conflict"

Business rules:

  • Overlap detection runs when an Assignment is created (Application confirmed)
  • Only pending and accepted Applications are checked — confirmed Assignments are not cancelled (first-confirmed wins)
  • Overlap is determined by comparing starts_at / ends_at of the shifts

10.0 External Integration — Shift Created from UKG

Scenario

A shift is created in UKG (external workforce management system) and needs to appear in Jod.

Steps

  1. Integration layer receives shift data from UKG via API or webhook
  2. System maps the external shift to a Gig::Job (by role and location match) or creates a new one
  3. System creates a Gig::Shift with:
    • starts_at, ends_at, headcount from external data
    • source = 'ukg' and source_id referencing the external shift ID
  4. Shift follows the normal flow from open onward

Business rules:

  • Externally sourced shifts cannot be cancelled from Jod — they must be cancelled in the source system
  • Selection and attendance data is synced back to the external system when assignments are confirmed / clocked in / clocked out
  • The integration layer is designed to support multiple providers (not UKG-specific in the domain model)