Open Administration on a dashboard of what the role can read
Administration used to open on its first section. It opens on a grid of cards now: users, domains, messages waiting in the delivery queue, server memory, and the last 24 hours' received and sent. Each card is there only when the role holds what its number needs -- a count is a query, the metric history a query and a get -- so a helpdesk role that reads accounts and domains sees those two cards and nothing about the server. What the cards count is whatever Stalwart answers for the signed-in account, which scopes a tenant administrator's accounts, domains and queue to the tenancy. The metric history has no tenant in it, and Stalwart's Tenant Administrator role does not hold it, so a tenant's dashboard is users, domains and pending. The history is Enterprise-only and switched off by default. A server that refuses it leaves those cards off; one that records nothing says so rather than showing zeroes. Received and sent add up the queue counters Stalwart's own dashboard uses, filtered with the comparison names the live server accepts (a bare timestamp is unsupportedFilter). The column count follows the number of cards so rows stay even, and falls back by the grid's own width rather than the window's. The server's test for whether an account is offered Administration matches the client's again, now that a count is enough. The mock answers the queue and an hourly history ending in the current hour; MOCK_METRICS=off refuses the history as Community does, a tenant administrator gets the queue, and helpdesk reads domains, as the demo's does. ROADMAP and FEATURES said reporting and queues were out of scope; they say the dashboard reads a handful of numbers and that managing queues, logs and settings stays out. KNOWN-ISSUES records what was settled on the live server and what was only read from source. Fourteen new strings, in all nine catalogues.
This commit is contained in:
@@ -56,6 +56,15 @@ works the same way — and dropped where 0.15 was the whole subject. Support for
|
||||
|
||||
The last two were then tried by hand on the live server the same day and behaved as described. **A password set by an administrator** — written to the account's existing credential, `credentials/<index>/secret` — signs in. **The outranking guard** held: an account with more rights than the viewer's role opens read-only. The guard exists because the source shows Stalwart skipping its grant check when only a password changes and on a delete, and it stays for that reason.
|
||||
|
||||
- **The dashboard's feeds were settled on the live server before the code was written (2026-09-15, 0.16.22 Enterprise, read-only calls from an administrator's session).** The first probes guessed two of these wrong — filtering on `timestamp`, and counting received mail from `message-ingest.*` — and the server and the 0.16.22 source agreed on the answers below:
|
||||
|
||||
- **The metric history filters on comparison names.** `x:Metric/query` accepts `{"timestampIsGreaterThanOrEqual": …, "metric": [names]}`; a bare `timestamp`, `after` or `metric` as a string is `unsupportedFilter`. Sorting on `timestamp` works. At the default interval a day is about 80 records for the six metrics the dashboard reads, and a get takes at most 500.
|
||||
- **Received and sent are `queue.*` counters**, not `message-ingest.*`: `queue.message-queued` for received, and `queue.authenticated-message-queued` + `queue.dsn-queued` + `queue.report-queued` for sent, which is what Stalwart's own dashboard adds up. A Counter holds its interval's count and a zero one is not written; the `*-time` histograms are cumulative, which is why nothing reads them.
|
||||
- **Memory is the `server.memory` Gauge**, in bytes, one per interval. **Counts** come from `/query` with `calculateTotal: true` and `limit: 0`, which returned the whole total for `x:Account` (users only, via `@type`), `x:Domain` and `x:QueuedMessage`.
|
||||
- **`x:Metrics/get` is not the history.** It is the singleton holding the collection settings (Prometheus and OpenTelemetry export, the metrics policy); the history is `x:Metric`.
|
||||
|
||||
**Not confirmed live:** that a tenant administrator's counts are scoped to the tenancy, and that a Community server refuses `x:Metric` as `forbidden`. Both are read from the 0.16.22 source (`query.rs`, `queued_message.rs`, `registry/mod.rs`); the production server has no tenants and is Enterprise, so neither could be tried there without writing. The dashboard's handling of both is covered by tests against the refusal Stalwart's source gives.
|
||||
|
||||
- **A refused password shows the server's reason in English.** Every other refusal from the registry is said in the reader's language: each error type has its own message, and a value one of Stalwart's validators refused — a domain name, an address, an empty field — is recognised by the validator's wording and explained again rather than shown. A password policy is the exception, on purpose. Its rule is the server's to set, so there is nothing to translate it from in advance, and its reason follows a translated sentence rather than being dropped, which would leave "not accepted" with no way to find out why.
|
||||
|
||||
- **Administration is off for a device not marked as your own, and for an installation that says so.** Both are enforced by the server rather than hidden by the menu: such a session is sent no permissions, and the JMAP proxy refuses registry methods beyond the account's own. That is worth stating because the proxy otherwise forwards whatever the browser sends, and before these gates an administrator's console could make any registry call their role allowed. For a session that may not administer, the proxy reads a request body only when it could name a registry method — a `"x:` in the text, or a `\u` escape that could spell one — so ordinary mail traffic is forwarded untouched.
|
||||
|
||||
Reference in New Issue
Block a user