> For the complete documentation index, see [llms.txt](https://docs.rainmad.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.rainmad.com/resources/jobs-v-legal-multiplayer-job-pack/configuration.md).

# Configuration

Configuration is split across three layers:

* **`shared/main_config.lua`** — global, server-wide settings (framework, money, daily featured, level system, admins, locale strings).
* **`shared/ui_config.lua`** — UI defaults and web locale strings sent to the tablet UI.
* **`shared/jobs/<jobId>.lua`** — per-job content (reward, dialog, taskbar, blips, vehicle, locations).

## Framework

```lua
Config.framework = {
    name = "auto",          -- "esx" | "qb" | "auto" (auto-detects)
    targetScript = "ox_target", -- "ox_target" | "qb-target" | "qtarget"
    useOxNotify = true,     -- send notifications via ox_notify
    debug = false,          -- enable verbose debug + zone outlines
}
```

## Money

```lua
Config.moneyOptions = {
    moneyName = "money",
    moneyIsItem = false,
}
```

## Daily Featured Job

```lua
Config.dailyFeaturedJob = {
    enabled = true,
    bonusMultiplier = 1.25, -- 1.25 = +25% payout on the featured job
    rotationHour = 24,      -- UTC hour to rotate (24 = 00:00 UTC)
}
```

The featured job is **deterministic** — picked from a sorted, alphabetical pool seeded by the UTC date, so all players see the same featured job and a server restart never changes it within the same day.

## Vehicle Cleanup

```lua
Config.vehicleCleanup = {
    enabled = false,
    abandonTimeoutMs = 180000,  -- 3 min: how long until an abandoned vehicle despawns
    distanceThreshold = 100.0,  -- meters: distance from owner before considered abandoned
    checkIntervalMs = 30000,    -- 30 sec: server thread interval
}
```

## General

```lua
Config.general = {
    nearbyPlayersDistance = 5.0, -- crew invite range
    inviteExpireTime = 60,       -- seconds before a crew invite expires
    sqlSaveInterval = 10,        -- minutes between periodic progress flushes
    jobCompleteAutoEnd = 30,     -- seconds before the complete modal auto-closes if leader idle

    level = {
        perLevelExpAmount = 1000, -- account-level XP per level
        maxLevel = 30,
    },
    jobLevel = {
        perLevelExpAmount = 1000, -- per-job XP per level
        maxLevel = 10,
        bonusPerLevel = 0.02,     -- +2% money bonus per per-job level
    },
    jobCenter = {
        pedModel = "s_m_y_uscg_01",
        coords = vector4(-268.823, -956.624, 30.223, 204.099),
    },
}
```

## Admins

```lua
Config.admins = {
    identifiers = {
        ["license:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"] = true,
        -- ["steam:110000100000000"] = true,
    },
}
```

Listed identifiers gain access to the in-game admin panel (KPIs, charts, per-job stats, job config, lobby view, and the job editor).

## Bucket Retention

```lua
Config.bucketRetentionDays = 90 -- delete payout buckets older than N days, 0 = never
```

## Per-job Configuration (Shared Structure)

Every job in `shared/jobs/` follows the same skeleton. Example from `shared/jobs/cleaner.lua`:

```lua
Config.jobs.cleaner = {
    disabled = false,
    reward = {
        money = { min = 900, max = 1400 },
        exp = 110,
    },
    webConfig = {
        name = "Cleaner",
        beginnerFriendly = true,
        description = "Keep the city pristine — collect waste and sanitize public areas.",
        reqLevel = 1,             -- account level required to start
        players = "1-2",          -- recommended crew size (string, display only)
        duration = "20 min",      -- average duration (string, display only)
        objectives = { "Mop, wipe and sweep", "Pressure-wash the dirt", "Clear zones" },
        image = "./images/cleaner.png",
    },
    timeBonus = {
        time = 20,                -- complete under N minutes for a bonus
        multiplier = 1.25,        -- +25% reward
        perPlayerReduction = 2,   -- subtract N minutes per extra crew member
    },
    npc = {                       -- dispatcher NPC at the depot
        model = "s_m_m_autoshop_01",
        coords = vector4(-292.370, -985.516, 30.080, 299.325),
    },
    vehicle = {                   -- work vehicle the leader spawns
        model = "bison",
        leaderOnly = true,
        vehicleSpawnCoords = {
            vector4(-297.940, -990.581, 30.583, 342.457),
            vector4(-301.425, -989.447, 30.583, 339.084),
        },
    },
    locations = { ... },          -- job-specific work locations
}
```
