mattermost-push-proxy-router/AGENTS.md
Felipe M. 8789af2997
feat: include Go runtime and process metrics on /metrics
Register prometheus Go and process collectors alongside the router
metrics so /metrics exposes standard go_* and process_* series.
2026-07-27 08:39:11 +02:00

105 lines
3.6 KiB
Markdown

# 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 stock `mattermost-push-proxy`
- Official prefixes (e.g. `apple_rn`, `android_rn`) → HPNS relay
## Tech Stack
- **Backend**: Go 1.26+ (`github.com/BurntSushi/toml` for 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
```bash
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 routing
- `device_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`:
```toml
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/