Gig::AssignmentAdjustment
Purpose
An AssignmentAdjustment is an immutable audit record created each time an employer or admin changes the billable times on a Gig::Assignment. It captures what changed, the old and new values, who made the change, and why.
AssignmentAdjustment is a domain concept, not just an infrastructure audit log. It exists because the business process has specific rules: employers can adjust billable times during the settlement window (from clock-out until 9am the next day), and each adjustment must be traceable for dispute resolution.
Common scenarios that produce adjustment records:
- Employer corrects break time from 30 to 60 minutes after clock-out
- Employer adjusts clock-in from 9:02am to 9:00am because the worker started before the QR was generated
- Ops enters an adjustment on behalf of the employer based on a WhatsApp message
When a talent asks "Why am I paid less?" or an employer says "I sent you a WhatsApp to update the timings", the adjustment history provides the complete answer.
Model Context
| Context | Details |
|---|---|
| Entity | Gig::AssignmentAdjustment (child of Assignment, append-only) |
| Layer | Operations — Audit |
| Upstream dependencies | Gig::Assignment (the assignment whose billable times were changed) |
| Downstream dependents | None — this is a terminal record. Read by the Assignment detail view for audit display. |
State Machine
AssignmentAdjustment has no state machine. Records are immutable — once created, they are never updated or deleted. They are append-only event records.
Use Cases
| ID | Use Case | Trigger | Actor |
|---|---|---|---|
| UC-1 | Record an employer adjustment | Employer changes billable times during settlement | System (on behalf of Employer) |
| UC-2 | Record an admin adjustment | Admin changes billable times on behalf of employer | System (on behalf of Admin) |
| UC-3 | View adjustment history for an assignment | Employer or admin reviewing changes | Employer or Admin |
UC-1: Record an employer adjustment
| Field | Details |
|---|---|
| Actor | System (triggered by employer action on Assignment UC-8) |
| Trigger | Employer modifies billable times during settlement window |
Preconditions:
Gig::Assignmentexists andstatus: clocked_outbillable_locked_atis NULL (settlement window open)
System Behavior:
- Employer changes one or more
billable_*fields on the Assignment (see Assignment UC-8) - System creates an AssignmentAdjustment record with:
gig_assignment_id: the assignmentchanges: JSON capturing each changed field with old and new valuesreason: employer-provided reason (mandatory)adjusted_by_type:Org::UserProfileadjusted_by_id: the employer's profile IDcreated_at: current timestamp
Business Rules:
- The AssignmentAdjustment is created in the same transaction as the Assignment update — they are atomic
- The
changesJSON uses a consistent format:{
"field_name": {
"was": "old_value",
"now": "new_value"
}
} - Example — employer adjusts break time and clock-in:
{
"billable_break_minutes": {
"was": 30,
"now": 60
},
"billable_clock_in": {
"was": "2026-04-08T09:02:00",
"now": "2026-04-08T09:00:00"
}
} - If multiple fields change in one save, they are captured in a single adjustment record
- Reason is mandatory
Postconditions:
- Immutable AssignmentAdjustment record exists
- Cannot be edited or deleted
UC-2: Record an admin adjustment
| Field | Details |
|---|---|
| Actor | System (triggered by admin action on Assignment UC-9) |
| Trigger | Admin modifies billable times on behalf of employer |
Preconditions:
Gig::Assignmentexists- For non-admin:
billable_locked_atis NULL. For admin: can override even after lock.
System Behavior:
- Admin changes
billable_*fields (see Assignment UC-9) - System creates an AssignmentAdjustment record with:
adjusted_by_type:Identities::Adminadjusted_by_id: the admin's IDreason: e.g., "Per employer WhatsApp request"
- All other fields same as UC-1
Business Rules:
- Admin adjustments follow the same audit rules as employer adjustments
- Admin CAN adjust after
billable_locked_atis set — this is the only way to change verified times - When admin adjusts a verified Assignment, the
Gig::Paymentmay need to be recalculated (open question — see Payment spec)
Postconditions:
- Same as UC-1
UC-3: View adjustment history for an assignment
| Field | Details |
|---|---|
| Actor | Org::UserProfile or Identities::Admin |
| Trigger | Reviewing changes to billable times |
Preconditions:
- Assignment exists
System Behavior:
- System retrieves all AssignmentAdjustment records for the Assignment, ordered by
created_atascending - Displays a chronological timeline:
- Timestamp
- Who made the change (employer name or admin name)
- What changed (rendered from
changesJSON) - Why (reason text)
Business Rules:
- All adjustments are visible to both employers and admins
- The timeline starts with the initial billable values (set at clock-out) and shows each subsequent change
Postconditions:
- Read-only operation
Invariants
- AssignmentAdjustment records are immutable — once created, they cannot be updated or deleted
- Every change to
billable_*fields on an Assignment MUST create an AssignmentAdjustment record — no silent changes changesJSON must contain at least one field withwasandnowvaluesreasonis mandatory — every adjustment must have an explanationadjusted_by_typeandadjusted_by_idare mandatory — every adjustment must be attributable to a person- Created in the same database transaction as the Assignment update
Model Interactions
| Related Model | Relationship | Interaction |
|---|---|---|
Gig::Assignment | AssignmentAdjustment belongs_to Assignment | Each adjustment references the assignment whose billable times were changed. |
Org::UserProfile | Polymorphic adjusted_by | Tracks which employer made the adjustment. |
Identities::Admin | Polymorphic adjusted_by | Tracks which admin made the adjustment (when ops acts on behalf of employer). |
Schema Gaps
The gig_assignment_adjustments table is new — it does not exist in the current DBML. The schema is defined in jodapp-api/docs/db/gig.dbml.