SQLDesk

Administration

Everything an administrator does, and where to look when something is wrong.

Users and groups

Groups carry permission. A user in the admin group can do everything; the default group is what everyone else starts in. Data sources are attached to groups, so adding somebody to a group is how they get access to data.

Users can be disabled rather than deleted, which keeps their queries and dashboards intact and attributed.

The Admin pages

Admin in the top row, for anyone with super_admin. Each page says what it is for in a line or two under its tabs, so you are not guessing which of seven holds the number you want.

Overview
Where the headroom is going: Postgres connections, Redis memory, how many workers are busy, how deep the queues are. Also who has run the most queries in the last hour and how much of that came from cache. The place to start when the instance feels slow and you do not yet know why.
System Status
The server's report on itself — version, uptime, when the query manager last made a pass, queue depths, table sizes. The figures to quote when something has to be escalated.
RQ Status
The job queues themselves, worker by worker. A queue growing while workers sit idle means the jobs are going somewhere nobody is listening.
Storage Status
What is being held and what happens to it when: cached query results, uploaded files, and how much of its quota each organisation has left. Both clean-ups can be started from here rather than waiting for their slot. See What happens to uploaded files.
Running Queries
Everything the workers have in flight, who asked for it, against which data source and for how long. A scheduled refresh shows as the scheduler rather than a person, because nobody is waiting for it. Any of them can be stopped from here, and stopping one is recorded.
Streaming Queries
Every Kafka topic being consumed, the rate events are arriving at, and — the column it exists for — why a quiet one is quiet. Paused, broken and genuinely empty look identical on a chart and are three different problems. The row budget and the events-per-second ceiling are set here. Shown when streams are on.
Outdated Queries
Scheduled queries whose next run is already overdue. A handful is ordinary; a long list means the workers are not keeping up with the schedules people have set.
MCP
Who has connected over MCP, what they asked for, and every refused attempt — never the question somebody put to their client and never the SQL that came back. Shown when MCP is on. See MCP.

Settings is its own menu in the top row rather than a gear on the right, and it holds different things for different people: an administrator sees data sources, users, groups, alert destinations and the organisation's settings; everybody else sees their snippets and their own account.

Permissions an administrator hands out

Some things are neither for everybody nor only for administrators. The person who knows what a table is for is rarely the person who runs the cluster, so these are granted to a group, under Settings → Groups, and anyone in that group has them.

PermissionWhat it allowsOffered when
manage_catalogDescribe tables and columns, agree or deny proposed measures, export the semantic layer. Puts Catalog in the top row.MCP is on
use_streamsStart a stream and watch it. Starting one takes a slot; watching somebody else's running stream needs no permission at all.Streams are on
manage_streamsChoose which of a cluster's topics may be queried, and how much of each is kept. Puts Streaming Data Sources beside Data Sources in Settings.Streams are on
manage_live_dashboardsMake a dashboard live, so the server refreshes it for everyone looking.Always
keep_uploadsStop an uploaded file expiring, so it stays until somebody deletes it.Files expire at all
use_mcpConnect a client over MCP, and see what yours has been doing under My MCP.MCP is on
send_dashboardsSubscribe people to a dashboard on a schedule, and send one to Slack.Rendering is on

A permission this install cannot honour is not offered at all, rather than granted and inert. With streams switched off in the chart there is no streams permission to give anybody, and with MCP off there is no catalog permission — because a permission that does nothing is worse than no permission.

What happens to uploaded files

An uploaded file is the only copy there is. A query result can be fetched from the warehouse again; a CSV somebody dragged in six months ago and has since deleted from their laptop cannot be re-created by anybody. So the policy is deliberately cautious, and nothing is ever deleted without a warning somebody could have acted on.

  1. Three days unqueried: unloaded. The file stops being registered with DuckDB, so queries on that data source no longer pay to infer its schema. The file is untouched and the next query that names it brings it back. Nobody is told, because nothing was lost.
  2. Six days: its uploader is emailed — one message, however many of their files are due, each with its size, whether it has ever been queried, and a button that keeps it.
  3. Seven days: deleted, but only files that were warned about. If mail was not working, nothing is deleted; the warning is retried instead. A file whose uploader has no address is never deleted on a timer at all — an administrator removes it from the Storage page, having looked at it.

Keeping a file is a permission (Keep uploaded files) an administrator grants to a group, from the email, the Storage page, or the data source's own page. A kept file stays until somebody deletes it.

The quota is a ceiling on everything uploaded, 5 GB by default. An upload past it is refused with the figures in the message, including how many files nothing has queried in a month — removing those is almost always the answer.

Turn any of it off with SQLDESK_UPLOAD_LIFETIME_DAYS=0, SQLDESK_UPLOAD_UNLOAD_AFTER_DAYS=0 or SQLDESK_UPLOAD_QUOTA_MB=0. The reason the default is not "keep everything" is that keeping everything is what SQLDesk did until 0.7, and on a development machine it filled the disk and took Postgres with it.

Keeping it healthy

Settings worth knowing

SettingWhy
SQLDESK_SECRET_KEYEncrypts data source credentials. Rotating it makes them unreadable.
SQLDESK_HOSTThe address in emails and alerts. Wrong, and every link points at localhost.
SQLDESK_FEATURE_AITurns MCP on. Off by default.
Mail settingsWithout them, alerts and invitations silently do nothing.
Public URLsCan be disabled instance-wide if shared links are not acceptable.
SQLDESK_UPLOAD_QUOTA_MBA ceiling on uploaded files, 5 GB by default. 0 removes it, and removing it is how a disk fills.
SQLDESK_UPLOAD_LIFETIME_DAYSHow long an uploaded file is kept, 7 by default. 0 keeps everything forever.
SQLDESK_STREAM_ROW_BUDGETRows of raw events kept per stream, 5 million by default. The window follows from this and the rate.
SQLDESK_STREAM_EVENTS_PER_SECONDEvents a second stored from one stream, 5,000 by default. Past it they are sampled and every chart says so. 0 removes the ceiling, which is how a worker becomes the slowest part of a cluster.
SQLDESK_STREAM_ACTIVE_MINUTESHow long after somebody last looked a stream keeps consuming, 15 by default. 0 turns streams off entirely.

Streams, operationally

What a stream costs is different in kind from everything else here: a query costs when somebody runs it, and a stream costs continuously. So the two numbers worth knowing are the row budget (how much disk a stream may take) and the events-per-second ceiling (how much work it may make a worker do). Past the ceiling events are sampled rather than queued — an unbounded queue in front of a slow writer is the crash, not the protection against it.

A stream holds a worker while it is consuming, so give streams a queue of their own (SQLDESK_STREAM_QUEUE is not a setting yet — the jobs go on streams, and a worker whose QUEUES names it is what keeps a consumer out of the way of the queries people are waiting for). One worker per active stream, and only while somebody is watching: see a stream is a window.

Raw events live in a DuckDB file per stream, under the same volume as uploaded files — so the uploads volume is what fills if a budget is set too high. The per-minute rollups live in Postgres, because they are small by construction and are the part that has to survive a restart.