Every export is framework-neutral. The same call behaves identically on VORP and on RSG, because all framework access goes through the built-in bridge.
Conventions
Server exports are called asexports.dd_pinboard:Name(...) from any server script. They take the board’s locationKey, which is the key of the entry in Config.boardLocations, not the numeric database id.
A board row is created on first open or by SeedBoard. Until then, state and id lookups return nil, clearing returns false, and viewer lookup returns an empty list. SeedBoard can create the row for a configured location.
The client and NUI net events (dd_pinboard:sv:*, dd_pinboard:cl:*) are internal to the resource, re-validated on every call, and not a supported API. Build on the exports below.
Server exports
GetBoardIdForLocation
Resolves a config key to theid in dd_pinboard_boards. Use it when you need to join against the pinboard tables yourself.
GetBoardState
Loads the full board as the resource itself sees it: the board row, every card with its payload decoded from JSON, and every thread.payload is the card’s content and is owned by the board UI: a note holds its formatted text, a photo holds url, a drawing holds its strokes. Treat it as opaque unless you know the current UI format.
This reads the board from the database on every call, so it is not something to run in a loop. Read it when a menu opens or a job is evaluated, not per frame.
ClearBoard
Removes every card and thread on the board, and immediately pushes the empty state to everyone who has it open. The board row, its background and its stored view remain. This is what the/pinboard_clear command calls.
SeedBoard
Replace the contents of a configured board with a preset fromconfig/showcase.lua. This creates the board row if necessary and sends the resulting state to current viewers, clearing card reservations and their undo history.
false with an error key and leave existing content intact. The counts describe the preset’s cards and threads.
Fixed backgrounds override the preset’s background; bounds, image hosts and content caps still apply. Validation temporarily counts old and new content together, so a nearly full board may reject a preset. Do not automatically clear it on failure if its content must be retained.
GetBoardViewers
Read the current viewers, ordered by arrival, without exposing the internal presence state.src is the player’s server id. name is the display name used on the board; with Config.anonymizeCollaborators it is a translated visitor alias rather than the character name. This list includes readers as well as editors and does not indicate who currently holds a card.
Database schema
Three tables are created on start withCREATE TABLE IF NOT EXISTS, so the bootstrap is safe to run on every restart. Threads reference cards, and cards reference boards, with ON DELETE CASCADE all the way down: deleting a board row removes its cards and threads, deleting a card removes the threads attached to it.
location_key is unique, so there is exactly one board per config key. The payload column uses the JSON type and needs MySQL 5.7.8+ or MariaDB 10.2.7+.
Card reservations and viewer presence are held in memory, not in the database. A resource restart clears them. There is no board-wide editing lock. Undo history belongs to the client session and is not persisted.
Moving or renaming a board
The configkey is the board’s identity. To rename a location without losing its content, update the row instead of the config alone:
key in Config.boardLocations to match. Changing only the config creates a fresh empty board under the new key on first open.