# Los Santos RP — server notes

Everything here was written for this server. No ESX, no QBCore, no downloaded
resources: `cfx-server-data` is not used at all, and the bundled `chat` and
`monitor` resources are not started.

## Layout

    /opt/fivem/server        FXServer artefacts (build 25770, the recommended one)
    /opt/fivem/data          server-data root; run FXServer with this as cwd
      server.cfg             main config
      secrets.cfg            licence key + DB credentials, mode 600
      resources/[rp]/        our resources
    /opt/fivem/bin           supervise.sh (keep-alive), rcon (console pipe)
    /opt/fivem/logs          server.log, rotated at 200MB
    /opt/fivem/etc/schema.sql  the database schema

## Resources

| resource      | what it is |
|---------------|------------|
| `rp_db`       | MariaDB client speaking the MySQL wire protocol directly over a TCP socket — handshake, `mysql_native_password`, text result sets, connection pool, transactions. No npm packages. Lua front end in `lib/db.lua`. |
| `rp_core`     | Config, shared validation, appearance model, scrypt password hashing, the player registry, and the client/server request bridge. |
| `rp_session`  | Connection gate (bans, capacity), accounts, characters, spawn. Every decision is made here; the client can only ask. |
| `rp_loading`  | Loading screen: procedural night-city flyover on canvas, progress bound to the game's real load events, ambience synthesised with the Web Audio API. |
| `rp_ui`       | Sign in / register, character creation with a live ped preview, spawn picker. Scripted cameras live in `client/camera.lua`. |
| `rp_selftest` | Checks the account/character data path on every boot and proves it survived the restart. |
| `rp_dbtest`   | Driver test suite. Not started by default; `ensure rp_dbtest` to run it. |

## The look

The interface is the paperwork side of a life in Los Santos: every screen is a
sheet from the city's Office of Vital Records, lying on a dark desk while the
game runs on behind it. Paper is the only surface we draw; the game is the room
the desk is in. That is why the NUI body stays transparent and the sheets are
opaque - an opaque sheet stays legible over a bright daylight city, where a dark
glass panel would not.

`html/tokens.css` is shared verbatim by `rp_ui` and `rp_loading` and holds the
whole system. Three typographic voices, and the rule between them is literal:

| voice | face | what it is |
|-------|------|------------|
| preprinted | Archivo, expanded, caps | what the form was printed with: headings, field captions, buttons |
| typed | IBM Plex Mono | what somebody entered on it: values, serials, names, user input |
| prose | IBM Plex Sans | the plain-English notes in the margin: blurbs and hints |

Three inks, each with exactly one job and never used decoratively: `--canary`
(municipal form yellow) is what is selected right now, `--stamp` (oxblood) is
filed / refused / destroyed, `--verdi` (municipal teal) is checked and valid.

The one loud thing is the rubber stamp, and it only ever marks a real change of
state: the file opened, the application approved, the placement issued. It is
masked with SVG turbulence so the ink lands unevenly, and the paper on the desk
takes the hit with it.

Fonts are bundled, never fetched: a NUI page has no guaranteed internet. Any
glyph used in `content:` must exist in the shipped latin subset, which is why
the validation tick is drawn from borders rather than U+2713.

Screens can be looked at without launching the game: `python3 /opt/preview/build.py`
stubs the NUI bridge, pushes each screen into a representative state, and writes
standalone pages to `/opt/preview/out` for headless Chrome to shoot.

## Operating it

    service fivem start|stop|restart|status
    rcon <command>            # e.g. rcon refresh, rcon status
    tail -f /opt/fivem/logs/server.log

`supervise.sh` restarts FXServer if it dies, backing off from 5s up to 5min so
a server that cannot start (bad key, database down) does not hammer Cfx. It
also holds a FIFO open on the server's stdin — FXServer quits the moment stdin
reaches EOF, and that FIFO is what `rcon` writes to.

## Starting on boot

There is no systemd in this container. The platform runs a login shell as PID 1,
which sources `/etc/profile.d/redl-autostart.sh`, which starts everything marked
in `/etc/redl/enabled`. Both `mariadb` and `fivem` are marked, and `/etc/init.d/fivem`
waits for MariaDB to answer before starting the server.

## Database

MariaDB, database `rp`, application user `rp@127.0.0.1` with only
SELECT/INSERT/UPDATE/DELETE. Passwords are scrypt with a per-password salt and
the cost parameters stored in the hash. Tables: `accounts`, `auth_attempts`,
`characters`, `transactions`, `inventory`, `vehicles`.

Every query goes through `DB.Query`/`DB.Insert`/... with `?` parameters.
`CLIENT_MULTI_STATEMENTS` is deliberately not negotiated, so even a failure of
the escaper could not turn a parameter into a second statement.

## Not yet built

The pre-spawn experience and the framework underneath it are done. Gameplay on
top of it — chat, HUD, inventory, jobs, vehicles, policing, medical — is not.
`characters`, `transactions`, `inventory` and `vehicles` already have their
tables and the money API in `rp_core/server/player.lua` is journalled and ready.
