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