Sign-in flow
The dashboard sends you to Discord with the identify and guilds scopes. Discord returns a code, the API exchanges it for tokens, and your user row is created or updated. Tokens are encrypted with AES-256-GCM before storage.
The browser receives one cookie, lyx_session. It is HttpOnly, SameSite=Lax, Secure in production, and signed with HMAC-SHA256. It contains your user ID and an expiry, nothing else.
Which servers appear
The API asks Discord for your guild list, keeps guilds where you are the owner or have Manage Server, then intersects that with the guilds the bot is actually in. If you lose Manage Server, the server disappears on the next check.
Opening a server page directly still runs the same check server-side. A guild ID in the URL is not authorization.
Saving
Each tab saves its own module. The API validates the values, writes them to Postgres, records an audit entry and returns the hydrated settings. The bot reads the same row, so changes apply without a restart.
If validation fails, nothing is written and the error is shown in the toast.
Signing out
Sign out clears the cookie. The Discord tokens stay encrypted in the database so a new sign-in can reuse the row; they are replaced on the next OAuth exchange.