# Architecture Messenger is a self-hosted monolith: a single Go binary serves the REST API, WebSocket hub, media files and the built frontend. PostgreSQL is the only stateful dependency; attachments live on local disk behind an S3-like interface. ## Component diagram ```mermaid flowchart LR subgraph Browser[Browser / PWA] UI[React + Vite + Tailwind] SW[Service Worker
offline cache + Web Push] end subgraph Server[Go binary - single process] HTTP[REST API /api/v1] WS[WebSocket hub
in-memory] MEDIA[Media service
thumbnails] PUSH[Push notifier
VAPID] end subgraph Data PG[(PostgreSQL 17)] DISK[(local disk
S3-like Storage)] end UI -->|REST + WS| HTTP UI --> WS SW -->|Web Push| PUSH HTTP --> PG WS --> PG PUSH --> PG MEDIA --> DISK HTTP --> MEDIA WS -.->|presence check| PUSH ``` ## Request flow for a message ```mermaid sequenceDiagram participant A as Alice (PWA) participant API as API participant PG as PostgreSQL participant WS as WS hub participant B as Bob (PWA) A->>API: POST /conversations/{id}/messages API->>PG: INSERT message API->>WS: publish message.created WS-->>A: message.created (echo) WS-->>B: message.created API->>PUSH: notify offline members PUSH-->>B: Web Push (if offline) API-->>A: 201 message ``` ## Key decisions (see docs/adr) | Area | Decision | Rationale | |---|---|---| | Shape | Monolith, one container | Family scale; trivial deploy; no fake microservices | | Realtime | In-memory WS hub | Presence and delivery in one process; pg LISTEN/NOTIFY is the scaling path | | Search | ILIKE substring | No extension dependency; instant at family scale; pg_trgm noted as upgrade | | Media | S3-like Storage interface | Swap local disk for MinIO without touching handlers | | Auth | JWT access + rotated refresh in httpOnly cookies | No token in JS; rotation limits replay | | Crypto | TLS in transit; E2EE via libsignal on roadmap | Never hand-roll crypto | ## Deployment docker-compose runs: api, postgres, victoriametrics, grafana. See `deploy/` for compose + Grafana dashboard provisioning. - **Metrics**: `GET /metrics` (Prometheus format), scraped by VictoriaMetrics - **Grafana**: http://localhost:3000, dashboard «Messenger» auto-provisioned - **Push**: optional; requires VAPID keys (`go run ./cmd/keygen`)