> 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/inventory/developers/architecture.md).

# Architecture

## Architecture

#### The one rule

**The client never decides anything.** The NUI is a view and an input device. It proposes moves; the server validates, commits and broadcasts the result.

A move the client believes in but the server refuses simply does not happen, and the interface corrects itself from the server's answer rather than from its own optimism.

#### The transaction engine

Every mutation — a drag, a purchase, a craft, a trade, a pickup, a death drop — goes through the engine in `server/core/transaction.lua`.

```
propose  →  VALIDATE  →  commit  →  ledger  →  broadcast
```

`VALIDATE` is where every rule lives. Weight, slots, pinning, bag nesting, evidence, licences, carry limits — all of them are checked in one place, on one code path.

{% hint style="info" %}
This is the single most important design decision in the resource. A rule added to `VALIDATE` holds everywhere at once. A rule added at a call site holds only there, and the next feature that moves items will quietly bypass it — which is exactly how inventories grow dupes.
{% endhint %}

Concretely, five rules were moved into `VALIDATE` after being found missing somewhere: evidence, bound items, pinning, carrying a placeable, and carrying a craft result. Each had a path around it before.

#### Versioned containers

Every container carries a `version`, and every commit bumps it. A move carries the version the player's screen was showing; if the container has changed since, the move is refused as `stale_version` and the player is handed the current contents instead of a silently different outcome. Two commits never touch one container at the same time: each locks every container it touches, in a fixed order, for the length of the commit.

This is what keeps two players moving items in a shared stash from overwriting each other.

#### Layout

```
shared/config.lua          all settings
data/items.lua             item definitions
data/recipes.lua           crafting recipes

client/                    NUI bridge, markers, targets, mirrors
server/
  core/transaction.lua     the engine — every mutation
  types/*.lua              container behaviours: stash, wear, placeable, …
  api/*.lua                exports and self-tests
  admin.lua                the admin panel's dispatcher
compat/
  qb-inventory/            name proxy
  ox_inventory/            name proxy
ui/                        built NUI (Vue 3 + Vite + Pinia)
web/                       NUI source
```

#### The framework bridge

Player data — identity, job, money, needs — is asked of `aty_lib`, not of QBCore or ESX: `client/framework.lua` on the client, `Utils` / `modules` on the server, and every other file gets the same answer whatever the server runs. Two deliberate exceptions: Qbox, which the bridge does not know by name, is asked through `qbx_core` directly (see Compatibility), and the qb compatibility layer and the migration tool talk to `qb-core` by name, because that is their job.

That is why standalone mode is not a special case with its own code path — it is one more answer the bridge can give.

#### The NUI

Vue 3 with Pinia, built by Vite into `ui/`. The same built artifact serves the game and the demo on the website; a mock layer stands in for the server when it detects it is running in a plain browser.

{% hint style="warning" %}
NUI messages sent to a page that has not mounted yet are **dropped, not queued**. If you are pushing state to the interface on connect, have the interface ask for it instead — that race is real and it presents as an inexplicably empty panel.
{% endhint %}
