What is stored
One SQLite file, WAL, single writer connection (which removes SQLITE_BUSY entirely rather
than retrying around it). Five tables exist today; a sixth is designed but not built.
| Table | Row means | Written by |
|---|---|---|
| roles | one role: a soul plus its tool set | OAuth seeding · roles.create |
| users | one allowlisted person | OAuth first sign-in · nxmaster useradd · MCP users.* |
| sessions | one live browser sign-in | OAuth callback · deleted on sign-out |
| chat_sessions | one conversation, owned by one user | POST /ui/sessions |
| messages | one turn inside a conversation | POST /ui/chat, and the run that answers it |
| customers | one CRM account | customers.create |
| bot_tokens | one bot's MCP credential (planned) | botadd |
Relationship
users 1 ──< chat_sessions 1 ──< messages
│
└──< sessions (browser sign-ins)
└──< bot_tokens (planned: one bot per user)
messages.session_key is the chat_sessions.id — the column predates the table and is kept
verbatim, so a query on it still reads as a thread id. Ownership is not denormalised onto
messages: a thread belongs to a user, and a message belongs to a thread.
Rendered from nx-master/data-model/index.md · OKF bundle · regenerate with npm run render