> For the complete documentation index, see [llms.txt](https://atiysus-organization.gitbook.io/aty-scripts/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://atiysus-organization.gitbook.io/aty-scripts/weapon-editor/guide/moderation.md).

# Moderation

## Moderation

Player-made designs can be reviewed before they are usable. It is **off by default**.

```lua
Config.Moderation = { enabled = false }
```

{% hint style="warning" %}
Only turn this on if someone is actually going to review the queue. With nobody reviewing, every design a player makes sits in `pending` forever and simply never appears in game — which players read as "the feature is broken", not "it is awaiting review".

With moderation off, a saved design is approved immediately and usable at once.
{% endhint %}

### The queue

```
/gunsmithadmin  →  Moderation queue
```

Needs the `mod` scope. Each entry can be:

| Action      | Result                                                   |
| ----------- | -------------------------------------------------------- |
| **Approve** | The design becomes usable                                |
| **Reject**  | The design is refused, with a reason shown to its author |
| **Revoke**  | An already-approved design is withdrawn                  |

Every decision is written to `aty_gunsmith_audit`, and fires the `moderation` webhook if one is set.

A design's status is one of `draft`, `pending`, `approved`, `rejected`, `revoked`.

### Who may review

```lua
Config.Hooks.canModerate = function(src) return Perms.has(src, 'mod') end
```

The default is the `mod` scope, which resolves through your framework's own permission system — QBCore `HasPermission`, ESX group, or ACE. Replace the hook to use your own rule.

### Automatic rejection

`skinValidator` runs on every design before it reaches the queue:

```lua
Config.Hooks.skinValidator = function(def)
    -- return false, 'reason' to reject
    return true, nil
end
```

This is the place for banned imagery, a word filter, or a rule about which layer types your server allows. It runs server-side, on the definition, so it sees exactly what will be drawn.

### Queue limit

```lua
Config.Lanes.baked = { enabled = true, autoApprove = false, queueLimit = 200 }
```

Once the queue reaches `queueLimit`, further submissions are refused with *"the moderation queue is full"* rather than being silently dropped. That number is the signal that nobody is reviewing.

### Rate limiting

Independent of moderation, `Config.RateLimit.skinsPerMinute` (6 by default) caps how fast one player can save designs. It is there to stop the queue being flooded by one person.

### Supply limits

A design record can carry a `supply` — `NULL` for unlimited, or a number for a mint limit. Once `minted` reaches it, further attempts are refused with *"this skin is sold out"*. This is the hook for limited-run or event skins, driven through the `mintSkin` export.

### Exports and events

```lua
exports.aty_gunsmith:createSkin(author, def)
exports.aty_gunsmith:setSkinStatus(skinId, status, reason)
exports.aty_gunsmith:mintSkin(skinId, owner)
```

```lua
AddEventHandler('aty_gunsmith:skinModerated', function(data) end)
AddEventHandler('aty_gunsmith:skinApplied',   function(data) end)  -- { serial, skinId, lane }
```

### See also

* Skin Studio
* Permissions
