added media fixes, search, push updates, pwa, metrics. preparing release 1.0
CI / Go (build + vet + test) (push) Canceled after 0s
CI / Web (build + lint) (push) Canceled after 0s

This commit is contained in:
vantablackTea
2026-09-27 23:26:15 +03:00
parent 855a62755c
commit 6fc6d977bf
59 changed files with 6823 additions and 113 deletions
+80 -57
View File
@@ -1,84 +1,91 @@
# Messenger
Self-hosted messenger for family and friends. Built from scratch: Go backend,
React PWA frontend, PostgreSQL, WebRTC calls. Deployed on a home-lab mini PC.
React PWA frontend, PostgreSQL. Deployed on a home-lab mini PC.
> **Status:** Phase 1 — auth (JWT + refresh in httpOnly cookies, argon2id),
> contacts, direct-message chats, real-time delivery over WebSocket
> (messages, typing, presence, read receipts). Backend is complete and tested;
> the frontend still shows the Phase 0 status screen.
> **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)
internal/api/ HTTP handlers: auth, users, contacts, conversations, messages
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, structured logging
web/ React + TypeScript + Vite frontend (PWA-ready)
deploy/ docker-compose and operational config
docs/ architecture, ADR, OpenAPI
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 (Phase 1)
## 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}` — create/find DM |
| GET | `/api/v1/conversations/{id}/messages` | History, keyset `?before=` |
| POST | `/api/v1/conversations/{id}/messages` | `{body, temp_id}` — send |
| GET | `/ws` | WebSocket (auth via cookie) |
| 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`.
WebSocket event types: `message.created`, `typing`, `presence`, `read`,
`reaction.added/removed`, `member.added/removed`, `conversation.added/removed`.
## Prerequisites
- Go 1.27+
- Node.js 22+
- Go 1.27+, Node.js 22+, PostgreSQL
- Docker + Docker Compose (for deployment)
## Local development
Requires a local PostgreSQL (e.g. `sudo -u postgres psql -c "CREATE ROLE messenger LOGIN PASSWORD 'messenger';"` and
`sudo -u postgres psql -c "CREATE DATABASE messenger OWNER messenger;"`).
```bash
# Backend (migrations run automatically on start)
cd server
go run ./cmd/api # listen on :8080
# 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;"
# Frontend (separate terminal)
# backend (migrations run automatically on start)
cd server
go run ./cmd/api # :8080
# frontend (separate terminal)
cd web
npm install
npm run dev # Vite on :5173, proxies /api -> :8080
npm run dev # :5173, proxies /api and /ws -> :8080
```
The frontend calls `/api/v1/ping` on load and renders the server response.
## Useful endpoints
| Endpoint | Purpose |
|--------------|----------------------------------|
| `/healthz` | Liveness probe |
| `/readyz` | Readiness probe |
| `/api/v1/ping` | Round-trip check (JSON) |
Optional: demo data → `cd server && go run ./cmd/seed`
(users papa/mama/syn/doch, password `password123`, group «Семья»).
## Deployment (Docker Compose)
@@ -88,19 +95,35 @@ cd deploy
docker compose up -d --build
```
The API container is a single static binary that also serves the built
frontend (`/app/web`). PostgreSQL runs alongside with a healthcheck.
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** — skeleton, CI, Docker ✅
- **Phase 1** — auth (JWT + refresh in httpOnly cookie, argon2id), contacts, DMs, WebSocket delivery, receipts, typing ✅ (backend)
- Phase 1.5 — frontend: auth screens, chat UI, realtime client (PWA)
- Phase 2 — groups, reactions, media upload + thumbnails (S3-like storage interface)
- Phase 3 — search (pg_trgm), Web Push (VAPID), PWA offline
- Phase 4 — P2P WebRTC calls via our WebSocket signalling + coturn TURN fallback
- Phase 5 — metrics (Prometheus + VictoriaMetrics + Grafana), docs, hardening
- **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
Proprietary for now; open-sourcing at v1.0.
Proprietary for now; open-sourcing at a future major version.