Chapter 22: Sharing Reports
Overview
melisai share turns a JSON report into a single URL you can drop into Slack, an incident channel, or a Jira ticket. The recipient opens the link in any modern browser and sees the diagnosis rendered — no melisai install, no JSON viewer, no agents.
There are two URL shapes. The CLI picks the short one by default and falls back to the long one when the backend is unreachable, so the same command works on internet-connected hosts and on airgapped servers.
Live demo: https://melisai.dev/r/uJOzZUjb
Two URL Shapes
| Mode | URL shape | When it fires | Storage |
|---|---|---|---|
| Short link | https://melisai.dev/r/Xa9bC3kp |
Default. CLI POSTs to melisai.dev/api/r |
Backend keeps gzip blob in SQLite |
| Fragment fallback | https://melisai.dev/r#H4sIAAAA… |
Upload failed (network/timeout/5xx), or --offline |
None — the URL is the payload |
Both URLs decode to exactly the same view: meta block (hostname/kernel/profile/duration), the 0-100 health score, USE metric bars, anomalies list, recommendations with copy-paste commands.
What's in the Payload
melisai share does not upload the full report. It extracts the Summary plus a minimum metadata header:
{
"v": 1,
"meta": {
"hostname": "prod-rtb-01",
"kernel": "6.8.0-90-generic",
"cpus": 32,
"memory_gb": 128,
"profile": "standard",
"duration": "30s",
"timestamp": "2026-05-25T10:00:00Z",
"tool_version": "0.6.0"
},
"summary": {
"health_score": 68,
"anomalies": [ /* 0..N anomaly records */ ],
"resources": { /* USE metric per resource */ },
"recommendations":[ /* 0..N recommendations */ ]
}
}
The viewer page at melisai.dev/r/ only knows how to render v: 1. Bumps to the schema must keep older clients working — older code falls back to a clear "unsupported payload version" message instead of crashing.
The wire encoding is base64url(gzip(json)). Typical encoded sizes:
| Profile | JSON | gzip+base64url |
|---|---|---|
quick, healthy server |
~10 KB | ~1.5 KB |
standard, loaded server with 15 anomalies + 10 recs |
~25 KB | ~3–5 KB |
deep with stack traces / histograms |
~80–150 KB | summary still ~5–10 KB (stacks and histograms are not shipped via share) |
Privacy
The payload carries identifying data: hostname, kernel version, anomaly evidence strings ("TCPRcvQDrop=1.2k/s observed across 3 interfaces"), recommendation evidence. Treat the URL with the same care as the JSON report itself.
If a hostname is sensitive, scrub it in the report before sharing — jq '.metadata.hostname = "redacted"' report.json | melisai share -.
CLI Flags
melisai share [flags] <report.json>
--api-url string short-link backend (default https://melisai.dev/api/r)
--base-url string viewer prefix for fragment fallback (default https://melisai.dev/r)
--offline skip the backend and emit a fragment URL straight away
--timeout duration upload budget before falling back (default 10s)
Use - instead of a path to read the report from stdin: melisai collect ... -o - | melisai share -.
Self-Hosting the Backend
The backend is the melisai-share-api binary, also in this repo:
go build ./cmd/melisai-share-api
./melisai-share-api \
--addr=:8080 \
--db=/var/lib/melisai-share-api/store.db \
--public-base=https://share.example.com/r \
--max-body-bytes=1048576 \
--retention=2160h \
--cleanup-interval=1h
The viewer is static HTML+JS — copy apps/melisai-site/public/r/index.html (in the hetzner-k8s-infra repo) behind any nginx that proxies /api/r to the binary above. There is no auth on POST; protect uploads with rate limiting and a firewall.
HTTP Contract
The backend exposes three endpoints. Anything else returns 404.
| Method | Path | Body | Response |
|---|---|---|---|
POST |
/api/r |
gzip bytes (must start with 0x1f 0x8b), ≤ 1 MB |
201 {"code":"Xa9bC3kp","url":"https://…/r/Xa9bC3kp"} |
GET |
/api/r/{code} |
— | 200 raw gzip bytes (application/octet-stream, Cache-Control: public, max-age=300) |
GET |
/healthz |
— | 200 {"status":"ok","count":N} |
The viewer fetches /api/r/{code} with cache: 'no-store' so retention sweeps and takedowns aren't masked by browser cache.
Security Notes
- Code space. 8 base62 characters = 62⁸ ≈ 2.18 × 10¹⁴ slots, generated by
crypto/randwith rejection sampling. Codes are unguessable; there is no enumeration risk. - Body cap. The backend rejects > 1 MB and anything not starting with the gzip magic header (
0x1f 0x8b). - Rate limit. The reference nginx config caps writes at 20/min per real client IP. Adjust to taste.
- Schema validation. The viewer page rejects payloads whose
vdoesn't matchSUPPORTED_VERSION. - XSS. Every payload field is rendered via
textContent. The viewer page never feeds untrusted data toinnerHTML,eval,Function, orsetTimeout(string).
Source Files
| File | Lines | Purpose |
|---|---|---|
internal/share/share.go |
~140 | Payload schema, Encode/Decode, BuildURL |
internal/share/client.go |
~75 | HTTP client used by the CLI for short-link upload |
cmd/melisai/share.go |
~100 | Cobra subcommand, fragment fallback wiring |
internal/shareapi/codec.go |
~70 | 8-char base62 code generator, ValidCode |
internal/shareapi/store.go |
~120 | SQLite store (open/put/get/count/delete-older-than) |
internal/shareapi/handlers.go |
~190 | POST/GET/healthz handlers, body cap, collision retry |
cmd/melisai-share-api/main.go |
~165 | Binary entry point, retention loop, graceful shutdown |
