-- Settings that an administrator can change without a redeploy, and the flag -- that takes an account out of use without deleting it. -- -- Three of the server's tunables were environment variables, which meant -- changing how long an incident waits before it is paged again required editing -- a chart, merging it, and waiting for a reconcile. They are behaviour, not -- infrastructure, and the difference is who needs to change them and how often. -- -- What stays in the environment: the ntfy URL and token, the database DSN, the -- listen address and the public URL. Those are where the server is plugged in -- rather than how it behaves, they are needed before the database is open, and -- two of them are credentials. -- -- Key/value rather than a column per setting. A settings table with one row and -- a column per knob needs a migration for every new knob, and #6 and #7 will -- both add some. The cost is that values are text and the accessor has to say -- what type it wanted; settings.go does that in one place. -- -- No rows are seeded here: a migration cannot read the environment. The server -- inserts each key from its own configuration at startup, once, so an install -- that upgrades keeps exactly the behaviour it had. See SeedSettings. CREATE TABLE settings ( key TEXT PRIMARY KEY, value TEXT NOT NULL, updated_at BIGINT NOT NULL DEFAULT FLOOR(EXTRACT(EPOCH FROM now()))::bigint ); -- Disabling an account rather than deleting it: the person has left, or the -- credential is suspect, and their incidents, acknowledgements and timeline -- entries must stay exactly where they are. Deleting a user nulls their -- acknowledged_by and assigned_to, which quietly rewrites history. -- -- A disabled user cannot sign in and their API keys stop working, but they are -- still a name the timeline can show and still a member of their teams. ALTER TABLE users ADD COLUMN disabled_at BIGINT;