# Messenger Self-hosted messenger for family and friends. Built from scratch: Go backend, React PWA frontend, PostgreSQL. Deployed on a home-lab mini PC. > **Status: v1.0.0** — production-ready. Auth, direct chats and groups, > real-time delivery, media, reactions, search, Web Push, PWA offline, > metrics and hardening are all implemented and tested. ## Repository layout ``` server/ Go API cmd/api/ entrypoint (wiring, migrations, graceful shutdown) cmd/keygen/ generate VAPID keys for Web Push cmd/seed/ create demo users and a family group internal/api/ HTTP handlers: auth, users, contacts, conversations, messages, media, search, push internal/auth/ argon2id hashing, JWT access tokens, refresh tokens internal/realtime/ WebSocket hub: events, presence, typing, read receipts internal/media/ S3-like storage + image thumbnails internal/store/ PostgreSQL access (pgx), embedded migrations internal/platform/ config, logging, metrics, rate limiting, version web/ React + TypeScript + Vite PWA (offline, Web Push) deploy/ docker-compose (api, postgres, victoriametrics, grafana) docs/ architecture (mermaid), ADR .github/ CI workflows ``` ## API All endpoints under `/api/v1`. Auth via httpOnly cookies (`messenger_access` = JWT 15 min, `messenger_refresh` = opaque token 30 days, rotated on refresh). | Method | Path | Description | |--------|------|-------------| | POST | `/api/v1/auth/register` | Create account (sets cookies) | | POST | `/api/v1/auth/login` | Sign in (sets cookies) | | POST | `/api/v1/auth/refresh` | Rotate refresh token | | POST | `/api/v1/auth/logout` | Revoke session, clear cookies | | GET | `/api/v1/users/me` | Current user | | GET | `/api/v1/users?q=` | Search users by username/name | | GET | `/api/v1/contacts` | Contact list | | POST | `/api/v1/contacts` | `{user_id}` — add contact | | DELETE | `/api/v1/contacts/{user_id}` | Remove contact | | GET | `/api/v1/conversations` | List chats + unread counts | | POST | `/api/v1/conversations` | `{user_id}` DM or `{type:"group", name, member_ids}` | | GET | `/api/v1/conversations/{id}/members` | List participants + roles | | POST | `/api/v1/conversations/{id}/members` | `{user_id}` — add to group | | DELETE | `/api/v1/conversations/{id}/members/{user_id}` | Remove/leave (owner or self) | | GET | `/api/v1/conversations/{id}/messages` | History, keyset `?before=` | | POST | `/api/v1/conversations/{id}/messages` | `{body, temp_id, media_id?}` — send | | PUT | `/api/v1/conversations/{id}/messages/{msg_id}/reactions` | `{emoji}` — react | | DELETE | `/api/v1/conversations/{id}/messages/{msg_id}/reactions/{emoji}` | Remove reaction | | POST | `/api/v1/media` | Upload file (multipart `file`) | | GET | `/api/v1/media/{id}` | Download file | | GET | `/api/v1/media/{id}/thumb` | Image thumbnail | | GET | `/api/v1/search/messages?q=` | Search user's messages | | POST | `/api/v1/push/subscribe` | Register Web Push subscription | | DELETE | `/api/v1/push/subscribe` | Unregister Web Push subscription | | GET | `/ws` | WebSocket (auth via cookie) | WebSocket event types: `message.created`, `typing`, `presence`, `read`, `reaction.added/removed`, `member.added/removed`, `conversation.added/removed`. ## Prerequisites - Go 1.27+, Node.js 22+, PostgreSQL - Docker + Docker Compose (for deployment) ## Local development ```bash # create the role once (as postgres superuser) sudo -u postgres psql -c "CREATE ROLE messenger LOGIN PASSWORD 'messenger';" sudo -u postgres psql -c "CREATE DATABASE messenger OWNER messenger;" # backend (migrations run automatically on start) cd server go run ./cmd/api # :8080 # frontend (separate terminal) cd web npm install npm run dev # :5173, proxies /api and /ws -> :8080 ``` Optional: demo data → `cd server && go run ./cmd/seed` (users papa/mama/syn/doch, password `password123`, group «Семья»). ## Deployment (Docker Compose) ```bash cp deploy/.env.example deploy/.env # adjust secrets cd deploy docker compose up -d --build ``` Services: `api` (single static binary serving API + frontend), `postgres`, `victoriametrics` (metrics storage), `grafana` (dashboard «Messenger» auto-provisioned at http://localhost:3000). ### Metrics `GET /metrics` exposes Prometheus metrics: HTTP requests by status/path, request latency, WebSocket connections, Go runtime. Scraped by VictoriaMetrics. ### Web Push (optional) ```bash cd server && go run ./cmd/keygen # prints the three VAPID variables ``` Put them in `deploy/.env` (`MESSENGER_VAPID_*`) and in `web/.env` (`VITE_VAPID_PUBLIC_KEY`). Without keys everything works except notifications. ## Architecture & decisions See `docs/architecture.md` (component and sequence diagrams) and `docs/adr/` for the rationale behind: monolith, in-memory WS hub, ILIKE search, S3-like media storage, E2EE roadmap. ## Roadmap - **Phase 0-3** — skeleton → auth/chats → frontend → groups/reactions/media → search/push/PWA ✅ - **Phase 4** — P2P WebRTC calls via our WebSocket signalling + coturn TURN fallback (planned, major feature) - **Phase 5** — metrics, docs, hardening ✅ ## License GPLv3