diff --git a/README.md b/README.md
index acdab77..aa374cb 100644
--- a/README.md
+++ b/README.md
@@ -30,6 +30,8 @@ Built on [RDGames/go-upkeep](https://github.com/RDGames/go-upkeep). Rewritten fo
- **SQLite or Postgres** — SQLite for single-node, Postgres for production
- **Uptime Kuma import** — migrate from Kuma with one command
+> Group monitors roll up child status for display but don't fire their own alerts yet — attach alerts to the children.
+
## Screenshots
@@ -79,10 +81,14 @@ services:
# - UPTOP_ADMIN_KEY=ssh-ed25519 AAAA... you@host
volumes:
- ./data:/data
+ sysctls:
+ - net.ipv4.ping_group_range=0 2147483647
```
First run: set `UPTOP_ADMIN_KEY` to your SSH public key, or attach to the container and add it in the Users tab.
+The `sysctls` line enables unprivileged ICMP inside the container — without it, ping monitors get no response and silently report DOWN.
+
@@ -162,6 +168,19 @@ Set `UPTOP_ENCRYPTION_KEY` to encrypt alert credentials (SMTP passwords, webhook
Without this, credentials are stored as plaintext in the database. uptop warns on startup if unset. To encrypt credentials on an existing install, run `uptop migrate-secrets` with the key set.
+### Data retention
+
+uptop prunes its own history in the background — no external cleanup jobs needed:
+
+| Data | Kept |
+|---|---|
+| Check history | newest 1,000 checks per monitor |
+| State changes (UP/DOWN transitions) | newest 5,000 per monitor |
+| Logs | newest 200 entries |
+| Maintenance windows | 7 days after they end (configurable) |
+
+Sparklines, uptime percentages, and SLA reports are computed from these windows, so very long-horizon stats aren't retained. Export to Prometheus via `/metrics` if you need unlimited history.
+
## Clustering
uptop supports three modes: **leader** (default single node), **follower** (HA failover — takes over if the leader goes down), and **probe** (stateless distributed checks from multiple regions).
diff --git a/docs/config-as-code.md b/docs/config-as-code.md
index 1ce5411..d2d61cd 100644
--- a/docs/config-as-code.md
+++ b/docs/config-as-code.md
@@ -122,7 +122,7 @@ Groups can't nest inside other groups. A group is healthy when all its children
## Alert types
-All 9 providers work in the YAML. The `settings` map is different per type.
+All 10 providers work in the YAML. The `settings` map is different per type.
```yaml
# Discord / Slack / Generic Webhook — just a URL
@@ -149,6 +149,9 @@ All 9 providers work in the YAML. The `settings` map is different per type.
url: https://ntfy.sh
topic: my-alerts
priority: "4"
+ # for protected topics:
+ # username: user
+ # password: pass
# Telegram
- name: Telegram Ops
@@ -178,6 +181,14 @@ All 9 providers work in the YAML. The `settings` map is different per type.
url: https://gotify.example.com
token: app-token
priority: "8"
+
+# Opsgenie
+- name: Opsgenie
+ type: opsgenie
+ settings:
+ api_key: your-api-key
+ priority: P2 # P1–P5, default P3
+ # eu: "true" # use the EU API endpoint
```
## Commands
@@ -224,7 +235,25 @@ Monitors and alerts are matched by **name**. Names must be unique across the ent
Apply is idempotent. Run it twice with the same file, second run changes nothing.
-If something fails mid-apply, just fix the issue and run it again. It picks up where it left off.
+Apply is **not atomic** — items are written one at a time, so an error mid-apply (bad value, lost DB connection, ctrl-C) leaves the items already written in place. That's safe to recover from: apply diffs against the database by name, so fix the issue and run it again — it converges the rest. Just don't run two applies against the same database at once.
+
+## Backups and secrets
+
+`uptop export` writes alert credentials (SMTP passwords, API tokens, webhook URLs) into the YAML in clear text — that's what makes the file restorable. Treat it like a secrets file.
+
+The HTTP export endpoint redacts those same fields **by default**:
+
+```bash
+# secrets show as ***REDACTED*** — fine for sharing or review
+curl -H "X-Uptop-Secret: your-secret" \
+ "http://localhost:8080/api/backup/export"
+
+# full backup you can actually restore from
+curl -H "X-Uptop-Secret: your-secret" \
+ "http://localhost:8080/api/backup/export?redact_secrets=false"
+```
+
+Restoring a redacted export imports the literal string `***REDACTED***` as your credentials. For real backups, pass `redact_secrets=false` or run `uptop export` on the host.
## Typical workflow