FeaturesEvery page in the console leads to the same decision chain
20 console pages, menus narrowed by role — but one shared ruleset and one shared audit chain. There is no second execution path.
Why it is 20
The operator rail has 10 nav entries and the admin rail has 12; the overview and the approval inbox — 2 of them — hang on both. Deduplicated, that is 20.
The product’s own documentation is one short: the admin rail’s online schema change has the short nav label "change", identical to the operator rail’s change ticket — deduplicate by short label and the two collapse into one.
So every page below is listed under its full name.
The overview and the approval inbox hang on both rails; their cards live in this column and are not repeated in the next one.
- Who it is for
- The landing page for any signed-in user. Signing in used to drop you straight into the terminal — making the one place that can change real data the default page.
- What it solves
- Without it, "how many tickets am I waiting on, how many wait on me, which approval-free window is open" means checking four places.
Constraints you would not guess
- The gateway status card shows global figures to everyone. It returns 0 when the stats query fails — "never blocked anything" and "the stats are broken" are the same number on screen.
- Two of the cards take only the first 5 rows of page one and then filter, so "0 waiting on me" may just mean none on this page.
- Who it is for
- The main surface for the on-call DBA or operator investigating or patching data by hand: instance on the left, SQL in the middle, decision context on the right.
- What it solves
- Without it, everyone needs a production account and a local client — and judgement, approval, masking and auditing simply do not exist.
Constraints you would not guess
- A result set is capped at the first 200 rows, hard-coded in the gateway and not configurable. Getting everything means going through data export.
- A single statement times out after 30 seconds by default, so a half-hour stored procedure cannot finish here — which is exactly why the background execution page exists.
- Who it is for
- For whoever was stopped by a gate in the terminal and got a ticket number: come back here to see whether it was approved, then press execute.
- What it solves
- Because approval does not execute, without this page a change simply hangs until somebody notices it never took effect (ADR 0010).
Constraints you would not guess
- A ticket executes exactly once, and the claim happens before execution and is not released on failure: when a connection drops mid-statement, whether the command ran is genuinely unknown.
- An approved but unexecuted ticket never expires; the timeout sweep only touches the ones still awaiting signature — ADR 0010 records this as a known debt rather than an overlooked one.
- Who it is for
- The page an approver comes back to all day. It hangs on both rails, because an approver is not necessarily a platform administrator.
- What it solves
- Without it, blocked commands get approved over chat, and the approver never sees the target environment, the risk level, the rule that was hit or the full SQL.
Constraints you would not guess
- The chain is parallel and settled by any single approval, not a multi-level sign-off: everyone in the approver pool gets their own node, and one approval settles the whole ticket.
- The name ticked on the chain is not necessarily the person who signed. The interface stamps the lowest-numbered pending node; the real signer is in the operator field of the audit record.
- Who it is for
- For whoever needs a batch of SQL to reach an environment properly: raise a release, come back to see how far it got and who signed.
- What it solves
- The background section of ADR 0005 puts it best: the audit chain can prove who ran a statement, not whether it was reviewed before it ran.
Constraints you would not guess
- Whether you may raise a ticket at all is decided by a dedicated capability dimension, per tier, before the statement itself is judged.
- DML and DDL may not share a ticket; a declaration that disagrees with the contents is refused on the spot and told which statement and which verb. The classification is counter-intuitive: SELECT counts as DML, GRANT and REVOKE count as DDL.
- Who it is for
- The DBA or release owner who has to run a migration or bootstrap script of a few hundred to a few tens of thousands of statements against a target database.
- What it solves
- Without it, a large script can only be sourced locally in one go: no per-statement grading, and no guarantee that the bytes reviewed are the bytes that run.
Constraints you would not guess
- Scanning requires a target instance first, and if the instance or its tier cannot be resolved the scan is refused outright — scanning against an empty tier matches no dictionary row at all, so every statement comes back reported as safe.
- The same script grades differently against the rehearsal environment and against production: it is judged by the target instance’s own tier, not by a fixed scan baseline (ADR 0014).
- Who it is for
- Anyone who needs a whole result set out of the system: reconciliation, migration, a regulatory request. The gateway runs it in the background and hands back an encrypted archive.
- What it solves
- Without it, "get me a dump" in practice means a DBA writing a file out on a jump host and dropping it into a chat app: no size limit, no masking, no approval.
Constraints you would not guess
- By default an export does not go through approval — it is masked row by row and simply runs. Only a task with "include raw sensitive values" ticked stops and opens a high-risk approval ticket, and a worker runs it once approved.
- "Read-only" is not "allowed to export": any verdict that is not allow is refused, needs-approval included. This was a real vulnerability fix — a role explicitly denied read access could once pull a whole table out through the export page.
- Only a single read-only query is accepted; INTO OUTFILE and DUMPFILE are blocked explicitly and separately — they keep SELECT as the leading verb, so a verb allowlist cannot see them.
Background execution
/async-jobs- Who it is for
- The DBA running a month-end stored procedure, a bulk DML, a long-transaction DDL. You can close the page after submitting.
- What it solves
- A procedure that takes 30 to 60 minutes will always hit the 30 second statement timeout in the terminal; a client that bypasses the gateway loses judgement, auditing and masking entirely.
Constraints you would not guess
- It returns no result set. Drop a SELECT in and all you get is "0 rows affected" — this page is background execution, not background querying.
- There is no cancel. Nobody can cancel, administrators included. The backend has no abort endpoint, and the frontend writes a line explaining that rather than offering a button that does nothing.
Execution window (the shuttle)
/exec-windows- Who it is for
- For whoever has to run dozens of changes back to back on a given night: request a time range plus one specific database in advance.
- What it solves
- Straight from the background of ADR 0015: dozens of DDL statements waking the approver all night; or loosening the rules in advance and forgetting to tighten them — which is worse than having no approval at all.
Constraints you would not guess
- A window only lowers needs-approval to allow. Deny stays deny, and the risk level is not lowered either — lowering it would make this DROP look like an ordinary query in the audit log. It also does not relax MFA: that is judged independently from the tier’s own flag, whatever the verdict.
- Creating and editing both go through approval, and nothing is allowed through while it waits; deleting does not. An edit sends it back to pending and voids the old approval on the spot.
- The window list has no menu gate and is not narrowed per user: any signed-in user sees every window — where an approval-free door is and when it opens should not be knowledge reserved for administrators.
- Who it is for
- Operators, DBAs and developers with the terminal menu, for "which instance and database is the table I need to change on".
- What it solves
- Without it, searching column names across instances means asking every table on every production instance for its columns.
Constraints you would not guess
- The data is a local cached copy, not the live database — and that sync is off by default. Unless you turn it on in settings this page stays empty forever.
- The sensitive-column markers on this page are computed in the frontend by applying the masking rules; the backend field does not carry them — the moment the two definitions diverge, what is marked and what is actually masked become two different lists.
This column lists 10 cards — the overview and approval inbox in this nav are the same route as on the operator rail, and their cards are in the column above.
Database configuration
/connections- Who it is for
- For the platform administrator onboarding a new cluster, or changing how tightly an environment is governed. It is the single source of everything.
- What it solves
- Without it, you insert rows with plaintext passwords by hand and guarantee for yourself that the environment resolves to a tier that actually exists.
Constraints you would not guess
- Tiers carry the rules; an environment only decides which instances belong to it, and a tier can carry several environments. So "add a Hong Kong production cluster" means creating an environment under the production tier — fully governed the moment it exists.
- Tags decide who can touch an instance, and a user-level tag set replaces the role-level one entirely rather than being unioned with it. An empty role tag set means unrestricted, not "not configured". If the authorization cannot be read, the answer is deny.
- A new tier must clone its rules from an existing one; there is no "empty tier" option. Both rule lookups read "not found" as allow, so an empty tier would go live the moment an instance points at it.
- Who it is for
- For the DBA facing "a two hundred million row table needs an index, and it has replicas hanging off it".
- What it solves
- ADR 0011 lays out the cost of native DDL as a table: no throttling, no pausing, no aborting once it starts; 3 hours on the primary means 3 hours of replica lag; and MDL pile-ups.
Constraints you would not guess
- MySQL only, and only two actions: add an index and drop an index. The ADR even talks you out of it: if your table is not large and replica lag does not matter, native DDL is the better choice.
- This page does not check tag authorization, does not look at tiers, and does not go through approval — it only asks whether you are a platform administrator. The read endpoints do not even require that: any signed-in user can read them.
- The preflight reports all 14 blocking conditions in one pass. Whether replica-lag throttling can be installed depends on the target instance: if the primary cannot report its replicas, or replication is broken, or the heartbeat cannot reach them, the migration runs anyway — unthrottled.
High-risk rules
/risk-rules- Who it is for
- For the platform administrator deciding things like "should we block TRUNCATE on the rehearsal environment too". The page is a dictionary of command against tier.
- What it solves
- Without it, "which words count as dangerous in which environment" is either hard-coded and shipped with releases, or scattered across a few people’s memories.
Constraints you would not guess
- High-risk does not mean forbidden. The three settings really mean: high and medium both route to approval, and off falls back to the capability matrix. Only two things actually deny — the capability matrix saying deny, and a gate that cannot be read.
- The dictionary scans the structure left after string literals are blanked out, not the raw text — a script containing nothing but INSERT statements was once graded as a high-risk DELETE because a permission string read system:menu:delete.
SQL standards review
/sql-review- Who it is for
- For the DBA or standards owner deciding whether "a table must have a primary key" should be promoted to blocking a release.
- What it solves
- Without it these standards live only in a few Word documents, review is done by eye, and the developer who got blocked cannot tell company policy from one platform’s taste.
Constraints you would not guess
- Standards review takes no part in execution decisions. It has exactly two call sites in the whole backend: the review stage of the pipeline, and the manual self-check on this page; the judgement engine references it zero times — the service comment says it outright, this channel never decides whether a command may run.
- Of the 87 built-in rules, 55 block a release, 16 record and let it through, and 16 are advice. The platform severity and the standards class are deliberately two separate columns — an operator downgrading a rule to a warning does not amend the company standard.
- A dialect that cannot be recognized is not silently downgraded, it errors out — PolarDB for PostgreSQL was once given the MySQL standard because its tag contains polardb, and not one finding was real.
- Who it is for
- For the platform administrator registering phone numbers and national id numbers as sensitive columns before go-live.
- What it solves
- The core argument of ADR 0009: anything that asks the frontend to do the masking is sending the raw value to the browser in full and then politely asking it not to show it.
Constraints you would not guess
- It governs exactly one thing: masking rules keyed by table name plus column name. The second panel on the page, temporary grants, is a shell — the interface renders it as not yet wired up.
- Rules are global: no instance dimension, no environment dimension, no database dimension. A rule on one column takes effect on identically named tables across every engine; an empty table name means all tables.
- This gate stops casual sight, not exfiltration: the matching is a deliberately over-eager heuristic, and it openly admits a subquery that renames the column gets past it. The real boundary is not granting access to the table.
Roles and permissions
/permissions- Who it is for
- For the platform administrator loosening or tightening one notch for one role on one tier. Someone holding the permissions menu who is not an administrator gets read-only.
- What it solves
- Without it, permissions exist only in four tables and can only be changed in the database directly — and the change leaves no trace on the audit chain.
Constraints you would not guess
- The capability matrix has 8 dimensions: Read data / Write data / Schema change / Grants & accounts / Connect instance / Approve tickets / Explain plan / Raise a release. 6 of them take part in per-statement decisions — nothing in the decision layer reads Connect instance and Approve tickets.
- The three settings are allow, needs-approval and deny, and any value that cannot be recognized is read as deny. That was a real fix: a mapping returned the zero value for an unknown key — the most permissive one — so a cell that said deny was in fact allowing.
Pipeline configuration
/pipelines- Who it is for
- For the platform administrator defining what a release has to pass through. Reading needs the pipeline menu; writing needs administrator on top.
- What it solves
- Without it you are inserting into two tables by hand, and the set of stage types is closed: an unknown type is either skipped, or crashes the runner.
Constraints you would not guess
- Seven stage types, none of them mandatory, but you cannot have none. Having no execution stage is legal: review plus approval, then hand it to a DBA, is a real workflow. Zero stages is illegal — it would report success having done nothing.
- The on-failure action is only abort or continue, and the execution stage is forced to abort: continuing after a failure means the later verification and notification stages announce a change that never happened as a success.
- Who it is for
- For the platform administrator handling joiners, leavers, a lost authenticator, a temporary suspension.
- What it solves
- Without it you are writing to three tables directly, and privileged changes like password resets, role changes and deactivations never reach the hash chain.
Constraints you would not guess
- The authentication model is local passwords plus TOTP only: no LDAP and no SSO. An invitation only creates a row with no password, while sign-in only admits active accounts — so the invited person cannot get in on their own.
- What an administrator cannot do: see anyone else’s TOTP secret; set a login password for a service account; deactivate themselves; deactivate the last administrator.
- Who it is for
- Auditors, DBA leads and administrators doing cross-person review and chain verification; everyone else holding the audit menu sees only their own rows.
- What it solves
- Without it you are querying the table directly, and nothing anywhere can recompute the hash chain — verification exists only on this page.
Constraints you would not guess
- It records the full command text and no result sets. And not only commands: successful and failed sign-ins, administrators changing roles, users and settings, release submissions and manual releases, exports, and simulated execution.
- Verification covers content being altered and rows being pulled out of the middle of the chain; it does not cover the tail being truncated wholesale — that needs the tail anchored outside the gateway. The payload also has several versions and historical rows are never recomputed (ADR 0019).
- Audit rows have no delete or edit entry point and no retention cleanup; today they are kept forever. Anyone with direct database access can of course still change a row — the value of the chain is that the change is detectable.
- Who it is for
- For the platform administrator. Reading needs the settings menu; every write needs administrator on top.
- What it solves
- Changing these values in the database directly never reaches the audit chain — and the blast radius of several of them goes far beyond "one switch".
Constraints you would not guess
- The largest blast radii: idle lock is a real sign-out when it fires, not a screen lock; turning on mandatory MFA keeps everyone not yet enrolled out of production entirely; turning on metadata sync means this gateway logs into every one of your production instances on a schedule.
- Dropdowns store the key, not the translated label — storing the label once meant that anyone who had switched language and pressed save silently loosened the approval timeout into auto-escalate and changed the session lifetime to 8 hours, with nothing on screen saying so.
- Saving is two-phase and all-or-nothing: every value is computed to its final form before a single one is written, then they are written together. The screen offers one save button, and a half-applied set could be the half that turns a gate off.
A project is not a page
There is no project page in the console. It exists only in a modal on the database configuration page — the only place a project can be created, renamed or deleted.
Its place is nailed down by the code itself: an organizational dimension, not a security boundary. The decision layer never looks at the project id. Stacking a project that can restrict access on top of that gives you two overlapping scope mechanisms, and the wrong one shows up as something visible that should not have been.
Ownership attaches to a database, not an instance — attaching it to instances would force people to split instances along project lines. Unowned is a legal state, not a blank to fill in.
Running in the background is a mechanism with one page
Background SQL jobs have exactly one entry point, the background execution page: the terminal has no "send to background" button, and neither does the script library or the change ticket page.
But running in the background as a mechanism spans three places: data export has its own worker pool; the execution stage of change tickets and of pipeline configuration share a single per-step execution limit; and one slider in system settings governs both.
The three queues are independent, and a restart treats them differently: background execution and export are failed outright, while in the release queue the queued ones are requeued, the running ones are failed, and the ones awaiting confirmation are left alone.