Commit Graph
100 Commits
Author SHA1 Message Date
mrhid6 98233b620c docs: fold the mcp task 12 token-form steps into the api keys redesign 2026-09-08 14:12:26 +00:00
mrhid6 2d6b5bd8a3 feat: restrict an api key to tagged servers from the create dialog 2026-09-08 14:12:10 +00:00
mrhid6 ac9cc57e7e feat: rebuild the create key dialog around a scope matrix and a preview 2026-09-08 14:10:37 +00:00
mrhid6 a0641e8ecb feat: summarise key posture above the ledger 2026-09-08 14:09:00 +00:00
mrhid6 67ac029354 feat: redesign the api key list as a ledger with lifetime bars 2026-09-08 14:07:56 +00:00
mrhid6 a0b5565a63 docs: explain why GET /api/mcp deliberately answers 405 in stateless mode 2026-09-08 14:07:54 +00:00
mrhid6 aedc388535 refactor: split the api keys panel into ledger, chips, lifetime and dialog 2026-09-08 14:06:02 +00:00
mrhid6 5e4c8afdd1 feat: model an api key's remaining lifetime as a single value 2026-09-08 14:03:49 +00:00
mrhid6 0166b17299 feat: serve the mcp endpoint behind the licence feature 2026-09-08 13:57:21 +00:00
mrhid6 674236bb76 feat: audit mcp tool calls and guard against fleet-wide fan-out 2026-09-08 13:50:28 +00:00
mrhid6 5943d98681 feat: add the mcp tool registry and its scope gates 2026-09-08 13:50:01 +00:00
mrhid6 7ea8e2fff0 fix: close out-of-scope server access in vulns, packages, run logs, and key revoke 2026-09-08 13:48:11 +00:00
mrhid6 f87986b4f7 feat: enforce token tag restrictions at the server resolution chokepoints 2026-09-08 13:43:38 +00:00
mrhid6 2481974b3a feat: carry the token tag restriction on the session 2026-09-08 13:37:05 +00:00
mrhid6 f9df426e6c feat: allow an API token to be restricted to servers by tag 2026-09-08 13:34:58 +00:00
mrhid6 e8e41f197a build: temporarily replace vantage-shared with local checkout 2026-09-08 13:31:56 +00:00
mrhid6 1f2b56ea29 Revert "chore: pick up the mcp licence feature from vantage-shared"
This reverts commit a2fe478c82.
2026-09-08 13:31:20 +00:00
mrhid6 8234bdf9f3 feat: add the mcp scope resource 2026-09-08 13:29:41 +00:00
mrhid6 a2fe478c82 chore: pick up the mcp licence feature from vantage-shared 2026-09-08 13:28:25 +00:00
mrhid6 a2eee958f0 docs: implementation plan for the mcp server, and creation tools in the spec 2026-09-08 13:24:03 +00:00
mrhid6 998e1c419d docs: design spec for the MCP server feature 2026-09-08 13:12:57 +00:00
mrhid6 d92ca7591f Rephrased secrets page
Chart Release / chart (push) Successful in 18s
Server Deploy / deploy (push) Successful in 1m3s
2026-09-08 10:25:01 +00:00
mrhid6 11a81e714f chore: Bump chart
Server Deploy / deploy (push) Successful in 14s
Chart Release / chart (push) Successful in 15s
2026-09-08 09:22:30 +00:00
mrhid6 c946a23afc fix: Fixed chart values
Server Deploy / deploy (push) Successful in 11s
Chart Release / chart (push) Successful in 14s
2026-09-08 09:21:38 +00:00
mrhid6 262795bf2e fix: Fixed ci workflow
Chart Release / chart (push) Successful in 19s
Server Deploy / deploy (push) Successful in 1m18s
2026-09-08 09:19:11 +00:00
mrhid6 3164f5ca22 fix: Fixed ci workflow
Chart Release / chart (push) Successful in 25s
Server Deploy / deploy (push) Failing after 1m9s
2026-09-08 09:16:44 +00:00
mrhid6 574057811f chore: remove go.work
Chart Release / chart (push) Successful in 18s
Server Deploy / deploy (push) Canceled after 42s
2026-09-08 09:10:48 +00:00
mrhid6 e0cc3988fc refactor: move vantagectl to vantage-ctl
vantagectl/ becomes the root of gitea.hostxtra.co.uk/vantage/vantage-ctl.
The command keeps the name vantagectl; only the repository and the image
path change, to vantage/vantage-ctl.

chart-release.yml's render checks are repointed at the new image. The
chart itself has no default backup.image and fails loudly without one, so
an existing cluster keeps working until someone changes the value.

go.work stays, now with a single use ./server entry: without it a go.work
further up the developer's filesystem is picked up instead.
2026-09-08 09:07:14 +00:00
mrhid6 44d9036440 refactor: move the agent and its installer to vantage-agent
agent/ becomes the root of gitea.hostxtra.co.uk/vantage/vantage-agent,
with installer/ alongside it, and agent-release.yml goes with them.

Releases now come from that repository, so the six places this server
generates or reads a release URL are repointed: both install scripts,
both update scripts, and the latest-version lookup in dispatch.go. The
agent/v* tag prefix is unchanged — those scripts grep for it.

Agents built before this move have the old mrhid6/vantage path compiled
into their self-update and will 404 on the push-button update. The
remedy is the /update one-liner, which this server generates and which
therefore has to ship first.
2026-09-08 09:00:22 +00:00
mrhid6 1c6d9e8495 refactor: move proto/ to vantage-shared
vantage.proto documents the hand-written types in shared/grpc/pb, and
nothing compiles it. Keeping it in a different repository from the Go
types it describes meant the one rule holding them together — add the
message to both in the same commit — could not be followed at all.

server's rebuild trigger loses proto/, which it only carried as
insurance against exactly that split.
2026-09-08 08:44:47 +00:00
mrhid6 f9dec9b230 refactor: move the public host out to vantage-site and vantage-docs
site/ and sitesvc/ become web/ and server/ in vantage-site; docsite/
becomes the root of vantage-docs. Their images move with them, to
vantage/vantage-site/{web,server} and vantage/vantage-docs.

Nothing here imported any of them, and sitesvc turned out to read no
database at all, so both cuts are clean. docker-compose.site.yml is
deleted rather than emptied: every service it held now ships with the
repository that builds it, and deploy/docker/docker-compose.yml is once
again exactly a self-hosted install.

Corrects four comments that named sitesvc for work it no longer does.
2026-09-08 08:41:11 +00:00
mrhid6 872699c38c refactor: move Vantage HQ out to the vantage-admin repository
admin/ and adminsite/ are extracted with their history to
gitea.hostxtra.co.uk/vantage/vantage-admin, where they are named server/
and web/ for what they are rather than for the services they run. Their
images move with them, to vantage/vantage-admin/{server,web}.

Nothing here imported them, so the cut is clean: the only coupling was
always at runtime, through admin writing into the control plane's
database. The parts of that contract this side enforces are unchanged and
still documented here — hq-sourced users, POST /license answering 409
cloud_managed, and FREE_INSTANCE_REAP_AFTER needing to match.

LICENSE_SIGNING_KEY now appears in no compose file in this repository.
Keeping it out used to be a rule someone had to remember; it is the
repository boundary now.

docker-compose.site.yml loses both services and gains a note on how the
host composes the three files together.
2026-09-08 08:13:55 +00:00
mrhid6 eb32d367c8 feat: Removed comments in workflow 2026-09-08 07:47:42 +00:00
mrhid6 a134f8443a fix: download vantage-shared before asking the module cache where it is
go list -m -f '{{.Dir}}' reports an empty Dir and exits 0 for a module that
is not in the cache, so on a cold runner swag was handed an empty --dir and
failed several steps later with 'dir:  does not exist'. Download first, and
fail loudly if the path is still not there.
2026-09-08 07:47:00 +00:00
mrhid6 ee1f9f3b32 refactor: consume vantage-shared as an external private module
shared/ is extracted to gitea.hostxtra.co.uk/vantage/vantage-shared and
pinned at v0.1.0 by server, agent, admin, sitesvc and vantagectl. The
replace directives and the ./shared entry in go.work are gone.

Every Go build now needs a credential for the private module: CI writes a
netrc per job from REGISTRY_USER + RELEASE_TOKEN and sets GOPRIVATE, and
the four Go Dockerfiles take it as a BuildKit secret rather than a build
arg, which would survive in the builder layer's history. RELEASE_TOKEN
needs read access to the vantage org.

admin, sitesvc and vantagectl now build from their own directory; only
server still needs the repository root, for default_steps/. The rebuild
triggers in server-deploy.yml lose their shared/ patterns, since a
service now moves when its own go.mod pin does.
2026-09-08 07:42:58 +00:00
mrhid6 5326639918 fix: declare grpc dependency in shared go.mod
The workspace supplied it; a standalone build of the module could not
resolve google.golang.org/grpc at all.
2026-09-08 07:36:13 +00:00
mrhid6 3bf80a117b refactor: rename shared module to gitea.hostxtra.co.uk/vantage/vantage-shared 2026-09-08 07:34:53 +00:00
mrhid6 189a8fa963 feat: Move grpc pbs to shared 2026-09-07 15:50:25 +00:00
mrhid6 7b13944c24 fix: Build the vantagectl image on its release tag, not on every push to main
vantagectl is a released tool, not a running service. An operator restoring a
database should be able to name the version they ran, and ":latest, rebuilt
whenever main moved" cannot be named after the fact.

The image now builds in vantagectl-release.yml on a vantagectl/v* tag, tagged
with that version as well as latest, with VERSION passed through so the binary
inside reports the tag rather than "dev". server-deploy.yml no longer builds
it and is back to seven images.

The cost is that a shared/ fix reaches the image only at the next release
rather than the next push to main. That is the intended trade and is written
down in CLAUDE.md next to the trigger table.
2026-09-07 15:11:39 +00:00
mrhid6 e7384d334a feat: Add vantagectl, the control plane backup and restore CLI
Vantage encrypts SSH private keys, vault secrets, SSO client secrets and
console credentials with KEY_ENCRYPTION_KEY. That key is in no backup and is
not recoverable, so restoring a database without it produces a control plane
whose every secret is permanently unreadable.

vantagectl dumps and restores a whole database and stamps a SHA-256
fingerprint of the key into every archive, so a restore refuses rather than
producing that database. The key itself is never written.

- shared/cryptobox: AES-GCM extracted so the server and the CLI share one
  implementation rather than a copy that can drift
- shared/backup: manifest, tar+gzip archive with per-member checksums
  verified before the first write, dump, restore, verify
- vantagectl: its own module, so cobra stays out of the server, admin and
  sitesvc module graphs
- container image, tagged release workflow, CI rebuild trigger
- optional Helm CronJob, off by default
- operator documentation, reconciled with the existing backups page
2026-09-07 14:52:13 +00:00
mrhid6 be299845ca fix: document inspect and --confirm-db's actual behaviour 2026-09-07 14:45:37 +00:00
mrhid6 d83061786c fix: validate manifest collection names and route archive accessors through safeJoin 2026-09-07 14:45:37 +00:00
mrhid6 b28a2263bb fix: read KEY_ENCRYPTION_KEY in archive-only verify; never leave a partial archive 2026-09-07 14:45:36 +00:00
mrhid6 b6f45390c4 fix: correct verify's ciphertext field map against the models 2026-09-07 14:45:36 +00:00
mrhid6 2e4bc687d4 fix: replay index specs verbatim instead of reconstructing them 2026-09-07 14:45:36 +00:00
mrhid6 d328d3aaca docs: Reconcile backups and backup-and-restore pages
backups.md kept its store-level table and danger note but now points to
vantagectl as the supported path, with mongodump/mongorestore demoted to
an explicit fallback and a warning that a plain dump records no key
fingerprint. backup-and-restore.md links back for the store-level
overview.
2026-09-07 14:32:31 +00:00
mrhid6 89cc524f3f docs: Document backup and restore
The page leads with KEY_ENCRYPTION_KEY rather than mentioning it in a
note, because holding a good database dump and no key is the way this goes
wrong.
2026-09-07 14:29:03 +00:00
mrhid6 f0f2600bed feat: Add an optional scheduled backup CronJob to the chart
Off by default: a backup with nowhere durable to land is a false sense of
safety and the chart cannot know where that is. NOTES.txt says so when it
is off.

No restore manifest ships: a restore must never be something a helm
upgrade can trigger.
2026-09-07 14:17:42 +00:00
mrhid6 884fd189fb fix: Report the real reason verify falls back to archive-only checks
resolveGlobals can fail for two distinct reasons — no MongoDB URI, or no
resolvable database name — and verify.go was printing a hardcoded
no-URI note regardless of which one occurred, misleading an operator
whose URI was fine but whose database name could not be resolved.
2026-09-07 14:11:58 +00:00
mrhid6 e08cc2f928 feat: Build and publish vantagectl
The scratch runtime stage copies an explicit /tmp: restore extracts an
archive there before verifying it, and a scratch image has none.

shared/ now fans out to four Go images rather than three.
2026-09-07 14:09:00 +00:00
mrhid6 3ce963b0cd feat: Add the vantagectl restore and verify subcommands
--force requires a typed database name on a terminal and --confirm-db
without one, so a copy-pasted restore command carries its intended target
and cannot destroy a different database.

Also silences cobra's own error print (root.go) so a failure is reported
once by main.go instead of twice, and pins the Changed()-based env
fallback in resolveGlobals with a test for an explicitly empty --db.
2026-09-07 14:04:25 +00:00
mrhid6 461a79277d feat: Add the vantagectl backup and inspect subcommands
Progress output goes to stderr so --out - stays a clean pipe into restic,
age or aws s3 cp. Archive names carry no colon, because these get copied
onto Windows shares.
2026-09-07 13:57:04 +00:00
mrhid6 d9f7fa6993 feat: Add the vantagectl module and its cobra root
Its own module rather than a package under shared, so cobra and pflag stay
out of the module graphs of server, admin and sitesvc, which never use
them.
2026-09-07 13:45:20 +00:00
mrhid6 060fa64339 feat: Add backup verify with a live decrypt probe
A fingerprint comparison proves two archives agree about a key. Only
opening real ciphertext from the target proves the key in hand reads the
data, which is the question an operator actually has.
2026-09-07 11:26:34 +00:00
mrhid6 30d83c4c32 feat: Add the backup restore
Every refusal happens before the first write: format, checksums, key
policy, then target inspection. A unique index that will not build aborts,
because the unique indexes here are tenant-isolation properties rather
than optimisations.
2026-09-07 11:23:27 +00:00
mrhid6 a918b1bdc1 feat: Add the backup dump
Collections are enumerated live rather than from a list, so a collection
added later is backed up with no code change. Documents are written as the
raw BSON the driver returned, so Decimal128, ObjectId, DateTime and binary
subtypes survive byte for byte.
2026-09-07 11:16:38 +00:00
mrhid6 66b1a041ba feat: Add the backup archive writer and reader
Open extracts and verifies every member against the manifest before the
reader is usable, so a corrupt archive is refused before a restore writes
its first document rather than halfway through.
2026-09-07 11:10:17 +00:00
mrhid6 d55ed2b19a feat: Add the backup archive manifest
KeyFingerprint is a pointer so an archive that recorded no key is a state
restore can report, not a default it silently treats as a match.
2026-09-07 11:08:02 +00:00
mrhid6 8135c8d781 feat: Add key fingerprinting for backup archives
Fingerprint hashes the raw key bytes rather than the hex string, so the
same key written in different cases fingerprints identically.
2026-09-07 11:03:48 +00:00
mrhid6 577b060b8a feat: Extract AES-GCM into shared/cryptobox
services/crypto.go keeps its function names and its KEY_ENCRYPTION_KEY
lookup and delegates the cipher, so vantagectl's verify probe can decrypt
with the same implementation rather than a second copy.
2026-09-07 10:55:54 +00:00
mrhid6 1028a2e43a docs: Add the backup-restore implementation plan
Thirteen tasks, each ending in a testable deliverable and a commit.

Also drops --log-level from the spec: the tool's whole output is what it is
telling the operator, and a level that could hide a key warning is worth not
having.
2026-09-07 10:30:56 +00:00
mrhid6 eba93a812e docs: Correct Dockerfile location and specify the verify probe
vantagectl/Dockerfile follows the repo's per-module convention rather than
living under deploy/docker.

verify's live check needs AES-GCM open, so the cipher primitives move to
shared/cryptobox and services/crypto.go delegates, rather than a second
copy of the cipher existing in another module.
2026-09-07 10:10:04 +00:00
mrhid6 83b7256b60 docs: Design for control plane backup and restore
Standalone vantagectl CLI (cobra, own module) that dumps and restores a
whole Vantage MongoDB database, stamping a sha256 fingerprint of
KEY_ENCRYPTION_KEY into the manifest so a restore cannot silently produce
a database whose secrets are unreadable.

The key itself never enters the archive.
2026-09-07 10:07:50 +00:00
mrhid6 9d17f539b5 fix: Fixed card header margin 2026-09-07 08:36:18 +00:00
mrhid6 28f746c7e2 feat: Compact vitals 2026-09-07 08:26:07 +00:00
mrhid6 9d218cb19f feat: Reduce server vitials panel height 2026-09-07 08:14:47 +00:00
mrhid6 f9ef9c4929 fix: Fixed mobile scroll bar 2026-09-07 08:02:09 +00:00
mrhid6 049e005873 feat: Updated monitor chart 2026-08-25 15:02:04 +00:00
mrhid6 c440b59b93 feat: Updated affected components on status page incidents 2026-08-25 14:56:50 +00:00
mrhid6 3e4865884c feat: Updated plans and catalogue pages 2026-08-25 14:35:47 +00:00
mrhid6 270d55e6a6 feat: Updated status page title 2026-08-25 14:11:21 +00:00
mrhid6 7a0a1953f6 fix: Fixed api url on web 2026-08-25 13:53:59 +00:00
mrhid6 3e4ccc9720 feat: Added more debug logging 2026-08-25 13:26:23 +00:00
mrhid6 e5947489e4 fix: Fixed status page published switch 2026-08-25 13:26:10 +00:00
mrhid6 0a7a10aeed feat: Added status pages to license page 2026-08-25 13:10:28 +00:00
mrhid6 28b813ba64 feat: sell status pages as a per-instance licence feature 2026-08-25 09:25:05 +00:00
mrhid6 68160dc681 docs: correct the status page URL for self-hosted, trim to what ships
- The status page URL was given only as `<instance>.vantage.<tld>`, which a
  self-hosted install does not serve. Both deployments are now described.
- The banner is documented as one notice: the editor exposes no level picker
  and the view renders every level identically.
- `pending` added to the component states, which a monitor with no result yet
  renders.
- Delete page documented alongside un-publish.
- `TRUSTED_PROXIES` names the LAN case: with the RFC1918 default, a client on a
  private range reaching the server directly is itself trusted and can spoof
  `X-Forwarded-For` — and now `X-Forwarded-Host`. Narrow it to the proxy.
- CLAUDE.md: scopes are nine resources, not eight; `status-pages` added to the
  REST route table; the host-resolution rules recorded under Status pages.
2026-08-25 09:05:06 +00:00
mrhid6 32e7420d89 fix: wire status page and incident delete, stop promising a name we do not publish
- The display-name placeholder showed the monitor's own name, reading as "leave
  this blank and we will use it". The server deliberately does the opposite: a
  blank `display_name` publishes the raw monitor id, because publishing an
  internal name has to be a decision. The placeholder now says "Public name
  (required)" and Save is refused until every component has one, so nobody adds
  five monitors and discovers five UUIDs on their public page. The server
  fallback is unchanged.
- `deleteStatusPage` and `deleteStatusIncident` existed in the api client and
  were wired to nothing, and the page address is immutable — delete was the
  only correction for a typo and there was no way to reach it. The editor
  header gains a typed-confirmation Delete page, and each incident row a
  confirmed delete, both on the existing ConfirmDialog.
- The create modal's address hint had lost its em dash and read as a broken
  sentence.
2026-08-25 09:05:06 +00:00
mrhid6 7e1d67dba4 fix: file live outages as active, refuse "operational" over zero components
- A derived monitor outage with no `resolved_at` went to `History`, so an
  ongoing disruption was listed under "Past incidents" while the component pill
  beside it read Down. Unresolved now goes to `ActiveIncidents`.
- `overallState` returned `up` when nothing was counted: "all systems
  operational" claimed from no evidence at all. A page with no components now
  reports `no_data`, which the view already renders as "Status unknown".
- `EnsureStatusPageIndexes` returned on the first failure, so a transient
  failure on the `status_pages` index left `status_incidents` with no unique
  `(instance_id, incident_id)` index — a correctness property, not a scan
  optimisation. All three are attempted and the failures joined.
2026-08-25 09:04:54 +00:00
mrhid6 da1dc90ac5 fix: resolve the public status page's tenant from a trusted X-Forwarded-Host
The SSR fetch set `Host` to the visitor's hostname. `Host` is a forbidden
header name and undici discards it silently, so the Go server saw
`server:8080`, `hostSlug` returned "", `InstanceFromHost` returned false and
every public status page 404'd on every deployment. The feature did not work.

- `web/` now forwards the visitor's host as `X-Forwarded-Host`, and their
  address on `X-Forwarded-For` — without the latter gin sees a request from the
  Next pod with no XFF and every visitor of every page shares one 120/min
  bucket, tripped by exactly the traffic an outage produces.
- `publicStatusInstance` honours `X-Forwarded-Host` only when `c.RemoteIP()` is
  in `TRUSTED_PROXIES`. It is a tenant selector, so an untrusted peer must not
  be able to name one; `RemoteIP()` rather than `ClientIP()` because the latter
  is reconstructed from the very headers being judged. `TrustedProxies()` moves
  from main.go into the api package so the variable keeps one parser.
- A host naming no slug on a non-cloud deployment resolves the sole instance,
  the way bootstrap does. A self-hosted install at vantage.acme.com or an IP
  has no slug and could never serve a status page; more than one instance is a
  404 rather than a guess, and an unknown-but-well-formed slug stays a 404.
- `InstanceFromHost` gains an explicit-host variant rather than a second copy
  of the slug rules, and now caches negative lookups: an unknown host cost a
  Mongo query per anonymous request, which is also a timing oracle separating
  "no such instance" from "instance exists, page does not".
- The handler's `@Router` annotation is dropped. openapi.json declares one
  server of `/api`, so it published `/api/public/status/{pageId}` — a path that
  does not exist. The real address is described in prose instead.
2026-08-25 09:04:47 +00:00
mrhid6 72c9492223 docs: status pages 2026-08-25 08:44:38 +00:00
mrhid6 fa67d839cd fix: status page editor error handling, maintenance validation and UTC display 2026-08-25 08:40:05 +00:00
mrhid6 1452928b75 feat: status page authoring UI 2026-08-25 08:32:43 +00:00
mrhid6 bf10023f35 fix: empty slices rather than null on the unavailable status snapshot 2026-08-24 19:42:16 +00:00
mrhid6 f4f41e400b feat: public status page 2026-08-24 14:53:42 +00:00
mrhid6 3abbdc41d6 feat: status page authoring API
Adds owner|admin routes under /api/status-pages for authoring status pages
and their incidents/maintenance windows, gated by the status_pages licence
feature. Adds the "status" token scope resource and the ten route-scope
entries, and regenerates the committed OpenAPI document.

Also types ErrPageInvalid as a sentinel for status page/incident validation
failures (previously bare errors), so statusPageError maps them to 400
instead of 500, and createStatusIncident/updateStatusIncident route through
the shared error mapper rather than hand-rolling a 400 for any service error.
2026-08-24 14:43:17 +00:00
mrhid6 6ba54f690c fix: default TRUSTED_PROXIES in shipped deployments and route /public/ through ingress 2026-08-24 14:35:29 +00:00
mrhid6 a3c6b2a305 feat: public status page endpoint with per-address rate limit 2026-08-24 14:29:24 +00:00
mrhid6 21a2d077d8 feat: cached public status snapshot with licence gate 2026-08-24 14:24:07 +00:00
mrhid6 6263c7e16f fix: clear resolved_at when reopening a status incident via appended update 2026-08-24 14:21:26 +00:00
mrhid6 161835802d feat: authored status incidents and maintenance windows 2026-08-24 14:18:06 +00:00
mrhid6 6f998ff506 feat: status page CRUD and cache invalidation 2026-08-24 14:15:25 +00:00
mrhid6 d192589790 fix: maintenance repaint no longer zeroes no_data uptime; strengthen redaction test 2026-08-24 14:12:38 +00:00
mrhid6 21c2bb2646 feat: public status snapshot assembly and redaction boundary 2026-08-24 14:07:10 +00:00
mrhid6 9c0bbd13dd feat: status page id validation and cache key 2026-08-24 14:02:46 +00:00
mrhid6 1c15961309 feat: status page schema, licence feature and indexes 2026-08-24 14:00:00 +00:00
mrhid6 383b763a66 docs: attach approved status page mockup to the implementation plan 2026-08-24 13:52:07 +00:00
mrhid6 3e99a9df33 docs: public status pages implementation plan 2026-08-24 13:42:44 +00:00
mrhid6 f1b6f90345 docs: public status pages design spec 2026-08-24 13:32:24 +00:00
mrhid6 2a660697c5 docs: Updated troubleshotting doc 2026-08-24 12:50:44 +00:00