Register prometheus Go and process collectors alongside the router metrics so /metrics exposes standard go_* and process_* series.
3.6 KiB
AGENTS.md - Mattermost Push Proxy Router
Project Summary
Stateless Go HTTP router that sits in front of Mattermost push notification backends. It implements the /api/v1/send_push and /api/v1/ack protocol used by Mattermost servers, routing traffic by mobile client platform prefix.
Problem It Solves
Mattermost exposes a single server-wide PushNotificationServer URL. On mixed deployments (official mobile app + custom client like Bubbles), one proxy cannot serve both: official apps need HPNS keys, custom apps need their own APNs key/topic. This router forwards:
- Custom prefixes (e.g.
apple_bubbles) → your stockmattermost-push-proxy - Official prefixes (e.g.
apple_rn,android_rn) → HPNS relay
Tech Stack
- Backend: Go 1.26+ (
github.com/BurntSushi/tomlfor config) - Protocol: Mattermost push proxy API (
POST /api/v1/send_push,POST /api/v1/ack) - Deployment: Single binary, Docker, GoReleaser
Project Structure
main.go — CLI entry point
server.go — HTTP server and route handlers
router.go — Platform extraction from push payloads
proxy.go — Upstream forwarding
config.go — Environment-based configuration
Makefile — Build/test/lint targets
Build & Run
make build
CONFIG_FILE=config/router.toml ./mattermost-push-proxy-router
make test
Default port: 8066 (from config listen, overridable via PORT).
Routing Logic
Device IDs are registered as platform:token (e.g. apple_bubbles:<hex>). The Mattermost server splits this into JSON fields before POSTing to the push service:
platform→ prefix used for routingdevice_id→ bare APNs/FCM token
The router reads platform (with -vN version suffix stripped) and matches it against configured routes.
Configuration
Routes are defined in a TOML file referenced by CONFIG_FILE:
listen = ":8066"
[[routes]]
prefixes = ["apple_bubbles"]
url = "http://bubbles-proxy:8067"
[[routes]]
prefixes = ["apple_rn", "android_rn"]
url = "https://push.mattermost.com"
| Variable | Description |
|---|---|
CONFIG_FILE |
Path to router TOML config (required) |
PORT |
Override listen port |
REQUEST_TIMEOUT_SEC |
Upstream HTTP timeout |
Architecture
Mattermost server
└─ PushNotificationServer
└─ [this router :8066]
├─ apple_bubbles:* → custom mattermost-push-proxy (:8067)
└─ apple_rn:* / android_rn:* → HPNS (push.mattermost.com)
Key Conventions
- Config via TOML file (
CONFIG_FILE); HTTP/API handling uses stdlib only - Responses follow push-proxy shape:
{"status":"OK"},{"status":"FAIL","error":"..."} - Unknown platforms return
FAIL(same as stock proxy dropping unmatched types)
Metrics
Prometheus metrics are exposed at GET /metrics:
| Metric | Labels | Description |
|---|---|---|
router_requests_total |
path, platform |
Requests routed to a backend |
router_routing_errors_total |
reason |
Requests rejected before forwarding (read_body, invalid_json, missing_platform, unknown_platform) |
router_upstream_requests_total |
platform, outcome |
Upstream responses (success, fail, error) |
router_upstream_duration_seconds |
platform |
Upstream request latency histogram |
Standard Go runtime and process metrics (go_*, process_*) are included automatically.
Related Docs
- Design spec:
spec.md - Official push proxy: https://github.com/mattermost/mattermost-push-proxy
- Mattermost push service docs: https://developers.mattermost.com/contribute/more-info/mobile/push-notifications/service/