project-nomad/docs/homelab/architecture.md
2026-03-13 17:41:23 +00:00

219 lines
8.3 KiB
Markdown

# Project N.O.M.A.D. — Homelab Edition: Architecture
## System Overview
Project N.O.M.A.D. Homelab Edition is a container-native knowledge platform designed for NAS and homelab environments. The architecture prioritizes reliability, minimal resource usage, and compatibility with storage-backed systems.
## Container Stack
```
┌─────────────────────────────────────────────────────────────────┐
│ Docker Host / NAS │
│ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ nomad-internal network │ │
│ │ │ │
│ │ ┌──────────────┐ ┌──────────────┐ ┌─────────────┐ │ │
│ │ │ nomad-nginx │ │ nomad-app │ │nomad-worker │ │ │
│ │ │ (Nginx) ├───►│ (AdonisJS) │ │ (Queue Jobs)│ │ │
│ │ │ :80/:443 │ │ :8080 │ │ │ │ │
│ │ └──────────────┘ └──────┬───────┘ └──────┬──────┘ │ │
│ │ │ │ │ │
│ │ ┌──────▼───────┐ ┌──────▼──────┐ │ │
│ │ │nomad-database│ │ nomad-cache │ │ │
│ │ │ (MySQL 8.0) │ │ (Redis 7) │ │ │
│ │ │ :3306 │ │ :6379 │ │ │
│ │ └──────────────┘ └─────────────┘ │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │
│ Volumes: │
│ ├── nomad-db-data (Docker volume - local SSD) │
│ ├── NOMAD_DATA_DIR/storage (bind mount - NAS share) │
│ ├── NOMAD_DATA_DIR/redis (bind mount) │
│ └── NOMAD_DATA_DIR/logs/nginx (bind mount) │
└─────────────────────────────────────────────────────────────────┘
```
## Service Roles
### nomad-app (Application Server)
- **Technology:** Node.js 22 + AdonisJS 6
- **Role:** Serves the web UI (React/Inertia), handles API requests, manages content
- **Port:** 8080
- **Dependencies:** nomad-database, nomad-cache
### nomad-worker (Background Worker)
- **Technology:** Same image as nomad-app
- **Role:** Processes background jobs — content downloads, AI model downloads, embeddings, benchmarks
- **Queues:** downloads, model-downloads, benchmarks, embeddings
- **Dependencies:** nomad-database, nomad-cache
### nomad-database (Database)
- **Technology:** MySQL 8.0
- **Role:** Persistent storage for services, content metadata, chat sessions, benchmarks, settings
- **Storage:** Docker named volume (optimized for I/O)
### nomad-cache (Cache / Queue Broker)
- **Technology:** Redis 7 Alpine
- **Role:** BullMQ job queues, session cache, real-time event transport
- **Config:** AOF persistence, 256MB max memory with LRU eviction
### nomad-nginx (Reverse Proxy)
- **Technology:** Nginx Alpine
- **Role:** TLS termination, request routing, static asset caching, WebSocket proxy
- **Ports:** 80 (HTTP), 443 (HTTPS)
## Data Flow
### Content Download Pipeline
```
User Request
nomad-app (API) ──► nomad-cache (Redis Queue)
nomad-worker
Downloads content
/app/storage/
(NAS bind mount)
```
### AI Chat Pipeline
```
User Message
nomad-app ──► Ollama (AI Model)
│ │
│ ▼
│ Response + RAG context
│ │
▼ ▼
nomad-database (Chat History)
```
### Real-Time Updates
```
nomad-worker ──► nomad-cache (Redis Pub/Sub)
nomad-app (Transmit SSE)
Browser (EventSource)
```
## Storage Architecture
### Design Principles
1. **Database on local volume** — Docker named volume for high-IOPS MySQL operations
2. **Content on NAS share** — Bind mount to NAS storage for large files (ZIM, maps, PDFs)
3. **Logs rotated automatically** — Nginx logs on bind mount, easily accessible
### Storage Tiers
| Tier | Type | Use Case | I/O Profile |
|------|------|----------|-------------|
| **Hot** | Docker named volume | MySQL database | High IOPS, small writes |
| **Warm** | Bind mount (SSD/cache) | Redis, temp files | Medium IOPS |
| **Cold** | Bind mount (NAS array) | Content library, backups | Sequential reads, large files |
### NAS Compatibility
| Platform | Storage Path | Notes |
|----------|-------------|-------|
| **Unraid** | `/mnt/user/appdata/project-nomad` | Uses cache drive for DB |
| **TrueNAS SCALE** | `/mnt/pool/apps/project-nomad` | ZFS dataset recommended |
| **Linux** | `/opt/project-nomad` | Standard filesystem |
| **Synology** | `/volume1/docker/project-nomad` | Btrfs volume |
## Network Architecture
### Internal Network
All services communicate over the `nomad-internal` bridge network. Only the following ports are exposed to the host:
| Port | Service | Purpose |
|------|---------|---------|
| 80 | nomad-nginx | HTTP (configurable) |
| 443 | nomad-nginx | HTTPS (configurable) |
| 8080 | nomad-app | Direct app access (optional) |
### Reverse Proxy Compatibility
The stack works behind external reverse proxies:
```
Internet/LAN
┌───────────────────┐
│ External Proxy │ Nginx Proxy Manager / Traefik / Caddy
│ (TLS termination) │
└─────────┬─────────┘
┌─────────────────────┐
│ nomad-nginx (:80) │ OR directly to nomad-app (:8080)
└─────────┬───────────┘
┌─────────────────────┐
│ nomad-app (:8080) │
└─────────────────────┘
```
When using an external reverse proxy, you can disable `nomad-nginx`:
```yaml
# In docker-compose.yml override
services:
nomad-nginx:
profiles: ["proxy"] # Only starts with --profile proxy
```
## Resource Requirements
### Minimum (8 GB RAM system)
| Service | RAM | CPU |
|---------|-----|-----|
| nomad-app | 256 MB | 0.25 cores |
| nomad-worker | 256 MB | 0.1 cores |
| nomad-database | 256 MB | 0.25 cores |
| nomad-cache | 64 MB | 0.05 cores |
| nomad-nginx | 16 MB | 0.01 cores |
| **Total** | **~850 MB** | **~0.66 cores** |
### Recommended (32 GB RAM system)
| Service | RAM | CPU |
|---------|-----|-----|
| nomad-app | 1 GB | 1 core |
| nomad-worker | 2 GB | 1 core |
| nomad-database | 1 GB | 0.5 cores |
| nomad-cache | 256 MB | 0.1 cores |
| nomad-nginx | 32 MB | 0.05 cores |
| **Total** | **~3.3 GB** | **~2.65 cores** |
## Security Model
- No authentication by default (network-level access control recommended)
- All inter-service communication on private Docker network
- Database and Redis not exposed to host by default
- Docker socket mounted read-only where possible
- Agent communication via shared secret (Bearer token)