Concepts
Five ideas. Everything in the API is one of them, or a rule about how they move.
Environment
The tenancy boundary. A game has a development, staging and production environment, and nothing crosses between them — not players, not items, not currency. Every row in the data plane carries an environment id, and the database enforces it with row-level security rather than trusting a WHERE clause somebody might forget.
Player
Someone who owns things, identified by a provider and a ticket — Steam, Epic, email, or anonymous while developing. A dedicated server exchanges that ticket for a scoped token; the game client never holds an API key.
Container
A place items live: a stash, a rig, a backpack, a trader's stock. Containers have a layout, fixed when they are created:
- Grid — items have a footprint and coordinates. A rifle is 4×2 and a player packs the stash like luggage. Tarkov-like.
- Slots — a flat run of equal squares addressed by index. A rifle and a bandage take the same room. Rust-like, and what most survival templates already use.
Layout cannot be changed afterwards. containers/ensure is idempotent by owner and kind, so asking for a different layout later returns the original container rather than converting it.
Item instance
One stack, in one container. It carries quantity, position, durability and a property bag that round-trips whatever your template stores per item — attachments, loaded ammo, mods — without either side having to agree on a schema.
Grid width and height travel with the instance rather than being looked up from the catalogue. A rotated rifle is 2×4 where its definition says 4×2, and a UI drawing the definition would overlap its neighbour.
Intent
The API never accepts “here is the player's whole inventory, save it”. Every change is one of five intents:
grant put a new item into a container
move relocate an instance, possibly to another container
consume remove some or all of a stack
split divide a stack in two
merge combine two stacks of the same itemThis is the single most important decision in the design. A state dump plus a retried request duplicates items; an intent plus a retried request does nothing the second time. A batch of intents runs as one database transaction, so a raid extraction moving thirty items is all-or-nothing.
Currency
Held in double-entry accounts. A balance is the sum of its entries, not a number somebody remembered to update, and a deferred constraint trigger refuses any transaction whose entries do not sum to zero. Money can be moved and never conjured.
Next: the HTTP API.