138 lines
5.9 KiB
Markdown
138 lines
5.9 KiB
Markdown
# Ulti Backend
|
||
|
||
Backend monolithe Go orchestrant la Ulti Suite — alternative souveraine à Google Suite.
|
||
|
||
## Architecture
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────┐
|
||
│ nginx (reverse proxy unique, port 80) │
|
||
├─────────────────────────────────────────────────────────┤
|
||
│ ultid (Go monolithe) │
|
||
│ ├─ /api/v1/mail — Ultimail (IMAP/SMTP custom) │
|
||
│ ├─ /api/v1/drive — Ultidrive (→ Nextcloud WebDAV) │
|
||
│ ├─ /api/v1/calendar — Agenda (→ Nextcloud CalDAV) │
|
||
│ ├─ /api/v1/contacts — Contacts (→ Nextcloud CardDAV) │
|
||
│ ├─ /api/v1/meet — Ultimeet (→ Jitsi JWT) │
|
||
│ ├─ /api/v1/photos — Ultiphotos (→ Immich API) │
|
||
│ ├─ /api/v1/admin — Administration │
|
||
│ ├─ /api/v1/search — Recherche transversale │
|
||
│ └─ /ws — WebSocket realtime │
|
||
├─────────────────────────────────────────────────────────┤
|
||
│ Services tiers (Docker) │
|
||
│ ├─ PostgreSQL 16 — DB partagée │
|
||
│ ├─ KeyDB — Cache/sessions │
|
||
│ ├─ RustFS — Object storage S3 │
|
||
│ ├─ Authentik — Auth OIDC/SAML │
|
||
│ ├─ Nextcloud (nginx+FPM) — Drive/Cal/Contacts (/cloud) │
|
||
│ ├─ Jitsi — Visioconférence │
|
||
│ └─ Immich — Photos/ML │
|
||
└─────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
## Quick Start
|
||
|
||
```bash
|
||
# 1. Copy environment file
|
||
cp .env.example .env
|
||
# Edit secrets once at the top of .env (POSTGRES_PASSWORD, RUSTFS_SECRET_KEY, etc.)
|
||
# Other variables use {{VAR}} placeholders expanded at launch.
|
||
# Toggle modules with flags:
|
||
# NEXTCLOUD_ENABLED=true|false
|
||
# JITSI_ENABLED=true|false
|
||
# IMMICH_ENABLED=true|false
|
||
|
||
# 2. Start stack (core + modules enabled by flags)
|
||
./deploy/compose-up.sh up -d
|
||
```
|
||
|
||
## Development
|
||
|
||
```bash
|
||
# Run locally (needs PG, KeyDB, RustFS running; loads .env with {{VAR}} expansion)
|
||
go run ./cmd/ultid
|
||
|
||
# Build
|
||
go build -o ultid ./cmd/ultid
|
||
|
||
# Expand .env for external tools (docker, migrate)
|
||
go run ./cmd/envexpand -in .env -out .env.resolved
|
||
source <(grep -v '^#' .env.resolved | sed 's/^/export /')
|
||
|
||
# Run migrations (use expanded ULTID_DB_URL; host may need localhost instead of postgres)
|
||
migrate -path migrations -database "$ULTID_DB_URL" up
|
||
```
|
||
|
||
### Reverse proxy (nginx)
|
||
|
||
Un seul **nginx** expose l’entrée HTTP (`:80`) et route :
|
||
|
||
| Chemin | Service |
|
||
|--------|---------|
|
||
| `/api/*` | ultid |
|
||
| `/ws` | ultid (WebSocket) |
|
||
| `/auth/*` | Authentik |
|
||
| `/meet/*` | Jitsi (si `JITSI_ENABLED=true`) |
|
||
| `/cloud/*` | Nextcloud nginx+FPM (si `NEXTCLOUD_ENABLED=true`) |
|
||
|
||
Nextcloud : FPM + nginx dédié ; ultid appelle `NEXTCLOUD_URL` en interne (`http://nextcloud:80`).
|
||
Caddy retiré : un seul proxy évite la double couche ; TLS plus tard (certbot, Traefik, ou `listen 443` nginx).
|
||
|
||
### Centralized secrets
|
||
|
||
Set passwords and keys **once** in the `Secrets` section at the top of `.env`. Derived values reference them with `{{POSTGRES_PASSWORD}}`, `{{RUSTFS_SECRET_KEY}}`, etc. Expansion runs via:
|
||
|
||
- `./deploy/compose-up.sh` — writes `.env.resolved` for Docker Compose
|
||
- `go run ./cmd/envexpand -in .env -out .env.resolved` — manual export for migrate/scripts
|
||
- `go run ./cmd/ultid` — expands `.env` in-process before reading config
|
||
|
||
Runtime secret files are also supported with `*_FILE` variables (example: `ULTID_OIDC_CLIENT_SECRET_FILE=/run/secrets/oidc_client_secret`).
|
||
|
||
Mail credentials are encrypted at rest with AES-GCM using `MAIL_CREDENTIAL_KEYS` (`key_id:base64key,...`) and `MAIL_ACTIVE_CREDENTIAL_KEY_ID`.
|
||
Secret rotation policy is enforced through:
|
||
|
||
- `SECRET_ROTATION_MAX_AGE`
|
||
- `ULTID_OIDC_CLIENT_SECRET_ROTATED_AT`
|
||
- `MAIL_CREDENTIAL_KEY_ROTATED_AT`
|
||
- `MAIL_WEBHOOK_SHARED_SECRET_ROTATED_AT`
|
||
|
||
## Stack
|
||
|
||
| Component | Technology |
|
||
|-----------|-----------|
|
||
| Backend | Go 1.23+ (chi, pgx, go-imap, go-smtp) |
|
||
| Database | PostgreSQL 16 |
|
||
| Cache | KeyDB (Redis-compatible, multi-threaded) |
|
||
| Object Storage | RustFS (S3-compatible, Apache 2.0) |
|
||
| Auth | Authentik (OIDC/SAML) |
|
||
| Files/Cal/Contacts | Nextcloud headless (WebDAV/CalDAV/CardDAV) |
|
||
| Video | Jitsi Meet (JWT auth) |
|
||
| Photos | Immich (ML classification) |
|
||
| Reverse Proxy | nginx (TLS à ajouter via certbot ou autre) |
|
||
| Search | PostgreSQL tsvector + GIN |
|
||
|
||
## Project Structure
|
||
|
||
```
|
||
├── cmd/ultid/ — Entry point
|
||
├── internal/
|
||
│ ├── api/ — HTTP handlers (mail, admin, drive, calendar, contacts, meet, photos)
|
||
│ ├── mail/ — IMAP sync, SMTP send, rules engine, webhooks
|
||
│ ├── nextcloud/ — WebDAV/CalDAV/CardDAV client
|
||
│ ├── meet/ — Jitsi JWT generation
|
||
│ ├── photos/ — Immich API client
|
||
│ ├── auth/ — OIDC verification
|
||
│ ├── search/ — Full-text search
|
||
│ ├── realtime/ — WebSocket hub
|
||
│ └── config/ — Environment config
|
||
├── migrations/ — SQL migrations
|
||
├── deploy/ — Docker Compose configs
|
||
│ ├── docker-compose.yml — Core stack
|
||
│ ├── nginx/
|
||
│ ├── nextcloud/
|
||
│ ├── jitsi/
|
||
│ └── immich/
|
||
├── Dockerfile — Multi-stage build
|
||
└── .env.example
|
||
```
|