78 lines
2.4 KiB
Markdown
78 lines
2.4 KiB
Markdown
# 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<br/>offline cache + Web Push]
|
||
|
|
end
|
||
|
|
|
||
|
|
subgraph Server[Go binary - single process]
|
||
|
|
HTTP[REST API /api/v1]
|
||
|
|
WS[WebSocket hub<br/>in-memory]
|
||
|
|
MEDIA[Media service<br/>thumbnails]
|
||
|
|
PUSH[Push notifier<br/>VAPID]
|
||
|
|
end
|
||
|
|
|
||
|
|
subgraph Data
|
||
|
|
PG[(PostgreSQL 17)]
|
||
|
|
DISK[(local disk<br/>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`)
|