# 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 ```