> ## Documentation Index
> Fetch the complete documentation index at: https://internal.mechzie.in/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Job Lifecycle

> Job state machine, status transitions, dispatch system, and cancellation rules

## Overview

A job in MechZie follows a strict state machine from creation to payment. Understanding these states is critical for building the correct UI flows.

## State Machine

```mermaid theme={null}
stateDiagram-v2
    [*] --> pending: Customer creates job
    pending --> dispatching: System starts dispatch
    pending --> cancelled: Customer cancels (free)

    dispatching --> accepted: Mechanic accepts
    dispatching --> no_mechanic_found: All tiers exhausted
    dispatching --> cancelled: Customer cancels (free)

    accepted --> en_route: Mechanic starts driving
    accepted --> cancelled: Either cancels (free)

    en_route --> arrived: Mechanic arrives
    en_route --> cancelled: Either cancels (₹50 fee)

    arrived --> in_progress: Mechanic starts work
    arrived --> cancelled: Either cancels (₹50 fee)

    in_progress --> completed: Mechanic finishes
    in_progress --> cancelled: Either cancels (₹50 fee)

    completed --> paid: Payment captured (webhook)
```

## Status Reference

| Status              | Who triggers      | Description                       | UI State                        |
| ------------------- | ----------------- | --------------------------------- | ------------------------------- |
| `pending`           | System            | Job created, about to dispatch    | "Finding a mechanic..."         |
| `dispatching`       | System            | Actively searching for mechanics  | "Searching nearby mechanics..." |
| `accepted`          | Mechanic          | A mechanic accepted the job       | Show mechanic info              |
| `en_route`          | Mechanic          | Mechanic is driving to location   | Show map + ETA                  |
| `arrived`           | Mechanic          | Mechanic has arrived              | "Mechanic has arrived"          |
| `in_progress`       | Mechanic          | Work has started                  | Show live line items            |
| `completed`         | Mechanic          | Work finished, final price set    | Show payment screen             |
| `paid`              | System (webhook)  | Payment captured successfully     | Show receipt                    |
| `cancelled`         | Customer/Mechanic | Job cancelled                     | Show cancellation               |
| `no_mechanic_found` | System            | No mechanic available in any tier | "No mechanics available"        |

## Creating a Job

```bash theme={null}
curl -X POST https://mechzie-api-production.run.app/api/v1/jobs \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "service_category_id": "uuid-of-category",
    "pickup_address": "MG Road, Bangalore, Karnataka",
    "pickup_lat": 12.9716,
    "pickup_lng": 77.5946,
    "vehicle_id": "uuid-of-vehicle",
    "description": "Engine not starting, battery might be dead",
    "photo_urls": ["https://s3.../photo1.jpg"]
  }'
```

**Required fields:** `service_category_id`, `pickup_address`, `pickup_lat`, `pickup_lng`
**Optional fields:** `vehicle_id`, `description`, `photo_urls`

<Warning>
  If the customer has **unpaid cancellation fees**, job creation returns **402 PAYMENT\_REQUIRED**. The customer must pay the fee first via `POST /payments/create-order`.
</Warning>

## Dispatch System

After job creation, the system automatically dispatches to nearby mechanics in expanding tiers:

| Tier | Search Radius | Timeout    | Max Mechanics Contacted |
| ---- | ------------- | ---------- | ----------------------- |
| 1    | 3 km          | 30 seconds | 20                      |
| 2    | 7 km          | 30 seconds | 20                      |
| 3    | 15 km         | 45 seconds | 30                      |

**How it works:**

1. System finds available, verified mechanics within Tier 1 radius
2. Sends `job:offer` Socket.io event to each mechanic
3. First mechanic to call `POST /jobs/{id}/accept` wins (others get `job:taken`)
4. If no one accepts within the timeout, expands to Tier 2, then Tier 3
5. If all tiers exhaust → status becomes `no_mechanic_found`

<Note>
  The customer sees the job status change from `pending` → `dispatching` almost immediately. They receive `job:status` events via Socket.io as the state changes. Show a loading/searching animation during `dispatching`.
</Note>

## Mechanic Actions (State Transitions)

Each transition is a simple POST:

```bash theme={null}
# Accept the job (mechanic)
POST /api/v1/jobs/{id}/accept

# Start driving to customer
POST /api/v1/jobs/{id}/en-route

# Arrived at location
POST /api/v1/jobs/{id}/arrive

# Start working
POST /api/v1/jobs/{id}/start

# Finish the job
POST /api/v1/jobs/{id}/complete

# Decline the job (during dispatch)
POST /api/v1/jobs/{id}/decline
```

All require `Authorization: Bearer ACCESS_TOKEN`. Invalid transitions return **409 INVALID\_TRANSITION**.

## Line Items (Parts & Labor)

Mechanics can add charges during `arrived` or `in_progress` status:

```bash theme={null}
curl -X POST https://mechzie-api-production.run.app/api/v1/jobs/{id}/line-items \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "description": "Spark plug (NGK BKR6E)",
    "quantity": 2,
    "unit_price": 15000,
    "type": "part"
  }'
```

| Field         | Type    | Values                      |
| ------------- | ------- | --------------------------- |
| `description` | string  | Free text                   |
| `quantity`    | integer | 1+                          |
| `unit_price`  | number  | In **paisa** (₹150 = 15000) |
| `type`        | string  | `part`, `labor`, or `other` |

When completed, `final_price = base_price + SUM(quantity × unit_price for all line items)`.

The customer receives a `job:line-item-added` Socket.io event in real-time.

## Cancellation Rules

```bash theme={null}
curl -X PATCH https://mechzie-api-production.run.app/api/v1/jobs/{id}/cancel \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "cancel_reason": "Found alternative help"
  }'
```

### Fee Schedule

| Cancel from status | Fee                  | Who can cancel       |
| ------------------ | -------------------- | -------------------- |
| `pending`          | Free                 | Customer             |
| `dispatching`      | Free                 | Customer             |
| `accepted`         | Free                 | Customer or Mechanic |
| `en_route`         | **₹50** (5000 paisa) | Customer or Mechanic |
| `arrived`          | **₹50** (5000 paisa) | Customer or Mechanic |
| `in_progress`      | **₹50** (5000 paisa) | Customer or Mechanic |

<Warning>
  When a cancellation fee is charged, the customer **cannot create new jobs** until they pay it. Check for outstanding fees: `GET /api/v1/payments/unpaid-fees`.
</Warning>

### Checking Unpaid Fees

```bash theme={null}
GET /api/v1/payments/unpaid-fees
Authorization: Bearer ACCESS_TOKEN
```

**Response:**

```json theme={null}
{
  "hasFees": true,
  "amount": 5000
}
```

## Listing Jobs

```bash theme={null}
GET /api/v1/jobs?page=1&limit=20&status=completed
Authorization: Bearer ACCESS_TOKEN
```

**Response:**

```json theme={null}
{
  "data": [...],
  "page": 1,
  "limit": 20,
  "total": 42
}
```

Filter by status: `pending`, `dispatching`, `accepted`, `en_route`, `arrived`, `in_progress`, `completed`, `paid`, `cancelled`, `no_mechanic_found`.

## Frontend Integration Summary

### Customer App Flow

1. **Create job** → Show searching animation
2. **Listen for `job:status`** → Update UI based on status
3. **On `accepted`** → Show mechanic info, start tracking
4. **`job:join`** → Join job room for location updates
5. **Listen for `location:updated`** → Animate map marker + show ETA
6. **Listen for `job:line-item-added`** → Show added parts/labor
7. **On `completed`** → Show final price, open payment flow
8. **On `paid`** → Show receipt, prompt for rating

### Mechanic App Flow

1. **Listen for `job:offer`** → Show accept/decline dialog (with timer)
2. **On `job:taken`** → Dismiss dialog if another mechanic accepted
3. **Accept** → Navigate to job detail, start sending `location:update`
4. **Transition through states** → `en-route` → `arrive` → `start` → `complete`
5. **Add line items** during `arrived`/`in_progress`
6. **On `paid`** → Show completion, prompt for rating
