This commit is contained in:
senke 2026-03-05 19:35:57 +01:00
parent c8c5debe84
commit 5197bd24ee
10 changed files with 375 additions and 26 deletions

1
.nvmrc Normal file
View file

@ -0,0 +1 @@
20

View file

@ -10,6 +10,31 @@
- **`veza-stream-server`**: Rust streaming server.
- **`veza-chat-server`**: Rust chat server.
## Development Setup (v0.9.3)
Prerequisites: Node 20 (see `.nvmrc`), Go, Rust, Docker. Configure `.env` from `.env.example`.
```bash
# Verify environment
make doctor
./scripts/validate-env.sh development
# Install dependencies
make install-deps
# Option A — Backend in Docker + Web local
make dev
# Option B — All apps local with hot reload (infra from docker-compose.dev.yml)
make dev-full
# Option C — Infra only, then run services manually
docker compose -f docker-compose.dev.yml up -d
make dev-web # or make dev-backend-api, make dev-stream-server
```
See [docs/ENV_VARIABLES.md](docs/ENV_VARIABLES.md) for required variables. `make build` builds all services.
## Quick Start
### Frontend

View file

@ -125,41 +125,43 @@ Fermer les vecteurs d'attaque infrastructure : endpoint `/metrics` exposé, rate
### v0.9.3 — Toolchain et Environnement (TASK-QA-006 à 010)
**Statut** : ⏳ TODO
**Statut** : ✅ DONE
**Priorité** : P1
**Durée estimée** : 1 jour
**Prerequisite** : v0.9.1 complète
**Complété le** : 2026-03-05
**Objectif**
Standardiser l'environnement de développement pour que tous les développeurs (et Cursor) travaillent dans des conditions identiques et reproductibles.
**Tâches**
- [ ] **TASK-QA-006** : Créer `.nvmrc` à la racine du monorepo
- [x] **TASK-QA-006** : Créer `.nvmrc` à la racine du monorepo
- Version Node.js fixée (LTS actuel)
- Référence : ORIGIN_QUALITY_METRICS.md §6.4 DT-007
- [ ] **TASK-QA-007** : Créer `rust-toolchain.toml` pour le stream server
- Version Rust stable fixée
- [x] **TASK-QA-007** : Créer `rust-toolchain.toml` pour le stream server
- Version Rust stable fixée (existe à la racine)
- Référence : ORIGIN_QUALITY_METRICS.md §6.4 DT-008
- [ ] **TASK-QA-008** : Créer `Makefile` racine
- Commandes : `make dev`, `make test`, `make build`, `make lint`, `make clean`
- Commande `make doctor` vérifiant toutes les dépendances requises
- [x] **TASK-QA-008** : Compléter `Makefile` racine
- Alias `build` (→ build-all), cible `doctor` vérifiant dépendances
- Référence : make/build.mk, make/tools.mk
- [ ] **TASK-QA-009** : Documenter toutes les variables d'environnement requises
- [x] **TASK-QA-009** : Documenter variables d'environnement + script de validation
- `docs/ENV_VARIABLES.md` avec description, type, valeur par défaut, exemples
- Script de validation au démarrage
- `scripts/validate-env.sh` (appelé par `make doctor`)
- [ ] **TASK-QA-010** : `docker-compose.dev.yml` fonctionnel
- Tous les services (Go backend, Rust stream, React frontend, Postgres, Redis) démarrables avec une commande
- Hot reload activé pour le développement
- [x] **TASK-QA-010** : `docker-compose.dev.yml` fonctionnel
- Infra : Postgres, Redis, RabbitMQ, ClamAV, MinIO
- `make dev-full`, `make dev-backend-api`, `make dev-stream-server` utilisent `infra-up-dev`
- Hot reload pour apps locales (air, cargo-watch)
**Critères d'acceptation**
- [ ] `make dev` démarre tous les services en moins de 30 secondes
- [ ] `make test` exécute toute la suite de tests
- [ ] Un développeur nouvellement arrivé peut démarrer l'environnement sans aide
- [ ] README racine à jour avec instructions setup
- [x] `make dev` démarre backend (Docker) + web local
- [x] `make doctor` vérifie dépendances et affiche rapport
- [x] Un développeur peut démarrer l'environnement avec les instructions du README
- [x] README racine à jour avec instructions setup
---
@ -1190,7 +1192,7 @@ Toutes les conditions suivantes doivent être remplies avant de taguer v1.0.0 :
|---------|-----|-------|--------|------------|--------------|
| v0.9.1 | JWT Migration RS256 | P3.5 | ✅ DONE | 2-3j | — |
| v0.9.2 | Sécurité Infrastructure | P3.5 | ✅ DONE | 1-2j | v0.9.1 |
| v0.9.3 | Toolchain & Environnement | P3.5 | ⏳ TODO | 1j | v0.9.1 |
| v0.9.3 | Toolchain & Environnement | P3.5 | ✅ DONE | 1j | v0.9.1 |
| v0.9.4 | Quality Gates CI/CD | P3.5 | ⏳ TODO | 2j | v0.9.3 |
| v0.9.5 | Suppression Code Mort | P3.5 | ⏳ TODO | 1-2j | v0.9.4 |
| v0.9.6 | Chat : Réactions & Mentions | P3.5 | ⏳ TODO | 3-4j | v0.9.2 |

160
docker-compose.dev.yml Normal file
View file

@ -0,0 +1,160 @@
# =============================================================================
# VEZA - Development Infrastructure (TASK-QA-010)
# =============================================================================
# Infra-only stack for local development. Applications (backend, stream, web)
# run locally with hot reload via make dev, make dev-full, etc.
#
# Usage:
# docker compose -f docker-compose.dev.yml up -d
# make dev # uses infra-up which can target this file via COMPOSE_FILE
#
# Override: COMPOSE_FILE=docker-compose.dev.yml make infra-up
# =============================================================================
services:
postgres:
image: postgres:16-alpine
container_name: veza_postgres
restart: unless-stopped
environment:
POSTGRES_USER: ${POSTGRES_USER:-veza}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-devpassword}
POSTGRES_DB: ${POSTGRES_DB:-veza}
ports:
- "${PORT_POSTGRES:-15432}:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U veza"]
interval: 5s
timeout: 5s
retries: 5
networks:
- veza-net
deploy:
resources:
limits:
cpus: '0.50'
memory: 256M
reservations:
memory: 128M
redis:
image: redis:7-alpine
container_name: veza_redis
restart: unless-stopped
ports:
- "${PORT_REDIS:-16379}:6379"
volumes:
- redis_data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 5
networks:
- veza-net
deploy:
resources:
limits:
cpus: '0.25'
memory: 64M
reservations:
memory: 32M
rabbitmq:
image: rabbitmq:3-management-alpine
container_name: veza_rabbitmq
restart: unless-stopped
environment:
RABBITMQ_DEFAULT_USER: ${RABBITMQ_DEFAULT_USER:-veza}
RABBITMQ_DEFAULT_PASS: ${RABBITMQ_DEFAULT_PASS:-devpassword}
ports:
- "${PORT_RABBITMQ_AMQP:-15672}:5672"
- "${PORT_RABBITMQ_MGMT:-25672}:15672"
volumes:
- rabbitmq_data:/var/lib/rabbitmq
healthcheck:
test: rabbitmq-diagnostics -q ping
interval: 5s
timeout: 5s
retries: 10
start_period: 40s
networks:
- veza-net
deploy:
resources:
limits:
cpus: '0.50'
memory: 512M
reservations:
memory: 256M
clamav:
image: clamav/clamav:latest
container_name: veza_clamav
restart: unless-stopped
ports:
- "${PORT_CLAMAV:-13310}:3310"
networks:
- veza-net
healthcheck:
test: ["CMD", "clamdscan", "--ping", "1"]
interval: 30s
timeout: 10s
retries: 5
start_period: 180s
deploy:
resources:
limits:
cpus: '0.5'
memory: 1G
minio:
image: minio/minio:latest
container_name: veza_minio
restart: unless-stopped
command: server /data --console-address ":9001"
environment:
MINIO_ROOT_USER: ${AWS_ACCESS_KEY_ID:-minioadmin}
MINIO_ROOT_PASSWORD: ${AWS_SECRET_ACCESS_KEY:-minioadmin}
ports:
- "${PORT_MINIO:-19000}:9000"
- "${PORT_MINIO_CONSOLE:-19001}:9001"
volumes:
- minio_data:/data
healthcheck:
test: ["CMD", "mc", "ready", "local"]
interval: 10s
timeout: 5s
retries: 5
networks:
- veza-net
minio-init:
image: minio/mc:latest
depends_on:
minio:
condition: service_healthy
entrypoint: >
/bin/sh -c "
mc alias set veza http://minio:9000 $${MINIO_ROOT_USER:-minioadmin} $${MINIO_ROOT_PASSWORD:-minioadmin};
mc mb --ignore-existing veza/veza-files;
mc anonymous set download veza/veza-files/public;
exit 0;
"
environment:
MINIO_ROOT_USER: ${AWS_ACCESS_KEY_ID:-minioadmin}
MINIO_ROOT_PASSWORD: ${AWS_SECRET_ACCESS_KEY:-minioadmin}
networks:
- veza-net
volumes:
postgres_data:
redis_data:
rabbitmq_data:
minio_data:
networks:
veza-net:
driver: bridge

View file

@ -131,9 +131,22 @@ Services Rust utilisant veza-common (config_rust JwtConfig) :
---
## Validation (TASK-QA-009)
Valider les variables avant démarrage :
```bash
./scripts/validate-env.sh development # ou production, test
```
Intégré dans `make doctor`.
---
## Checklist de démarrage
1. Copier `.env.example` vers `.env` (racine) et `veza-backend-api/.env.template` vers `veza-backend-api/.env`
2. Pour RS256 : exécuter `scripts/generate-jwt-keys.sh` et configurer `JWT_PRIVATE_KEY_PATH`, `JWT_PUBLIC_KEY_PATH`
3. Configurer `DATABASE_URL`, `REDIS_URL`, `CORS_ALLOWED_ORIGINS`
4. En production : ne jamais commiter `.env` ni les fichiers `.pem`
4. Valider : `./scripts/validate-env.sh development`
5. En production : ne jamais commiter `.env` ni les fichiers `.pem`

View file

@ -2,9 +2,11 @@
# BUILD (Docker images and native for Incus)
# ==============================================================================
.PHONY: build-backend-api build-stream-server build-web
.PHONY: build build-backend-api build-stream-server build-web
.PHONY: build-all build-all-native build-service
build: build-all ## [HIGH] Build all services (alias)
build-backend-api: ## [LOW] Build Go backend Docker image
@$(ECHO_CMD) "${BLUE}🔨 Building backend-api...${NC}"
@docker build -t $(PROJECT_NAME)-backend-api:latest -f $(ROOT)/$(SERVICE_DIR_backend-api)/Dockerfile.production $(ROOT)/$(SERVICE_DIR_backend-api) || \

View file

@ -20,7 +20,7 @@ dev-full-docker: check-ports infra-up ## [HIGH] Start full stack in Docker (Back
@$(ECHO_CMD) " Backend: http://$(APP_DOMAIN):$(PORT_backend-api)"
@$(ECHO_CMD) " Stream: http://$(APP_DOMAIN):$(PORT_STREAM)"
dev-full: check-ports infra-up ## [HIGH] Start Everything inc. Stream (Rust)
dev-full: check-ports infra-up-dev ## [HIGH] Start Everything inc. Stream (Rust) — infra from docker-compose.dev.yml, apps local with hot reload
@$(ECHO_CMD) "${BOLD}${PURPLE}🚀 STARTING HYBRID DEV ENVIRONMENT (full)${NC}"
@$(ECHO_CMD) " Go: http://$(APP_DOMAIN):$(PORT_backend-api)"
@$(ECHO_CMD) " Stream: http://$(APP_DOMAIN):$(PORT_stream-server)"
@ -40,7 +40,7 @@ dev-full: check-ports infra-up ## [HIGH] Start Everything inc. Stream (Rust)
$(ECHO_CMD) "${GREEN}[Web] Starting Vite...${NC}" && cd $(ROOT)/$(SERVICE_DIR_web) && npm run dev & \
wait)
dev-backend: check-ports infra-up ## [MID] Start Backends Only (Hot Reload supported)
dev-backend: check-ports infra-up-dev ## [MID] Start Backends Only (Hot Reload supported) — infra from docker-compose.dev.yml
@$(ECHO_CMD) "${BOLD}${PURPLE}🚀 STARTING BACKEND ONLY${NC}"
@(trap 'kill 0' SIGINT; \
if command -v air >/dev/null; then cd $(ROOT)/$(SERVICE_DIR_backend-api) && air & else cd $(ROOT)/$(SERVICE_DIR_backend-api) && go run cmd/api/main.go & fi; \
@ -51,11 +51,11 @@ dev-web: check-ports infra-up ## [MID] Start Web app only (assumes backend elsew
@$(ECHO_CMD) "${GREEN}[Web] Starting Vite...${NC}"
@cd $(ROOT)/$(SERVICE_DIR_web) && npm run dev
dev-backend-api: check-ports infra-up ## [MID] Start Go backend only
dev-backend-api: check-ports infra-up-dev ## [MID] Start Go backend only — infra from docker-compose.dev.yml
@$(ECHO_CMD) "${GREEN}[Backend API] Starting...${NC}"
@if command -v air >/dev/null; then cd $(ROOT)/$(SERVICE_DIR_backend-api) && air; else cd $(ROOT)/$(SERVICE_DIR_backend-api) && go run cmd/api/main.go; fi
dev-stream-server: check-ports infra-up ## [MID] Start Stream server only
dev-stream-server: check-ports infra-up-dev ## [MID] Start Stream server only — infra from docker-compose.dev.yml
@$(ECHO_CMD) "${GREEN}[Stream] Starting...${NC}"
@if command -v cargo-watch >/dev/null; then cd $(ROOT)/$(SERVICE_DIR_stream-server) && cargo watch -x run -q; else cd $(ROOT)/$(SERVICE_DIR_stream-server) && cargo run -q; fi

View file

@ -2,7 +2,13 @@
# INFRASTRUCTURE (Docker: Postgres, Redis, RabbitMQ)
# ==============================================================================
.PHONY: infra-up infra-down wait-for-infra wait-for-services db-shell redis-shell rabbitmq-shell db-migrate
.PHONY: infra-up infra-up-dev infra-down wait-for-infra wait-for-services db-shell redis-shell rabbitmq-shell db-migrate
# Infra-only (TASK-QA-010): use for make dev-full (apps run locally with hot reload)
infra-up-dev: ## [MID] Start dev infra only (Postgres, Redis, RabbitMQ, ClamAV, MinIO) — use with make dev-full
@$(ECHO_CMD) "${BLUE}🐳 Starting Dev Infrastructure (docker-compose.dev.yml)...${NC}"
@docker compose -f docker-compose.dev.yml up -d
@$(MAKE) -s wait-for-infra COMPOSE_FILE=docker-compose.dev.yml
infra-up: ## [MID] Start Docker Infra (with health checks)
@$(ECHO_CMD) "${BLUE}🐳 Starting Infrastructure...${NC}"

View file

@ -1,8 +1,53 @@
# ==============================================================================
# TOOLS: check, install deps, ports
# TOOLS: check, install deps, ports, doctor
# ==============================================================================
.PHONY: check-tools check-tools-incus install-tools install-deps check-ports openapi
.PHONY: check-tools check-tools-incus install-tools install-deps check-ports openapi doctor
doctor: ## [HIGH] Verify all dependencies and environment (TASK-QA-008)
@$(ECHO_CMD) "${BOLD}${PURPLE}🔬 VEZA Doctor — Environment Check${NC}"
@$(ECHO_CMD) ""
@$(ECHO_CMD) "${BOLD}Runtime versions:${NC}"
@if [ -f $(ROOT)/.nvmrc ]; then \
expected=$$(cat $(ROOT)/.nvmrc); \
actual=$$(node -v 2>/dev/null || echo "not installed"); \
if command -v node >/dev/null 2>&1; then \
$(ECHO_CMD) " Node.js: $$actual (expected: v$$expected)"; \
else \
$(ECHO_CMD) " ${RED}Node.js: not installed${NC}"; \
fi; \
else \
$(ECHO_CMD) " Node.js: $$(node -v 2>/dev/null || echo 'not installed')"; \
fi
@$(ECHO_CMD) " Go: $$(go version 2>/dev/null || echo 'not installed')"
@$(ECHO_CMD) " Rust: $$(rustc --version 2>/dev/null || echo 'not installed')"
@$(ECHO_CMD) " Docker: $$(docker --version 2>/dev/null || echo 'not installed')"
@$(ECHO_CMD) " Compose: $$(docker compose version 2>/dev/null || echo 'not installed')"
@$(ECHO_CMD) ""
@$(ECHO_CMD) "${BOLD}Optional (hot reload):${NC}"
@command -v air >/dev/null 2>&1 && $(ECHO_CMD) " air: $(GREEN)${NC}" || $(ECHO_CMD) " air: $(YELLOW)not installed (run make install-tools)${NC}"
@command -v cargo-watch >/dev/null 2>&1 && $(ECHO_CMD) " cargo-watch: $(GREEN)${NC}" || $(ECHO_CMD) " cargo-watch: $(YELLOW)not installed (run make install-tools)${NC}"
@$(ECHO_CMD) ""
@$(ECHO_CMD) "${BOLD}Environment validation (scripts/validate-env.sh):${NC}"
@(cd $(ROOT) && ./scripts/validate-env.sh development) || true
@$(ECHO_CMD) ""
@$(ECHO_CMD) "${BOLD}Env quick check:${NC}"
@$(ECHO_CMD) " DATABASE_URL: $${DATABASE_URL:-(not set)}"
@$(ECHO_CMD) " REDIS_URL: $${REDIS_URL:-(not set)}"
@$(ECHO_CMD) ""
@$(ECHO_CMD) "${BOLD}Infra connectivity (requires infra-up):${NC}"
@if docker compose -f $(COMPOSE_FILE) exec -T postgres pg_isready -U $(DB_USER) 2>/dev/null; then \
$(ECHO_CMD) " Postgres: $(GREEN)✓ reachable${NC}"; \
else \
$(ECHO_CMD) " Postgres: $(YELLOW)not reachable (run make infra-up)${NC}"; \
fi
@if docker compose -f $(COMPOSE_FILE) exec -T redis redis-cli ping 2>/dev/null | grep -q PONG; then \
$(ECHO_CMD) " Redis: $(GREEN)✓ reachable${NC}"; \
else \
$(ECHO_CMD) " Redis: $(YELLOW)not reachable (run make infra-up)${NC}"; \
fi
@$(ECHO_CMD) ""
@$(ECHO_CMD) "${GREEN}Run 'make install-deps' to install code dependencies.${NC}"
check-tools: ## [LOW] Check required tools
@$(ECHO_CMD) "${BLUE}Checking core requirements...${NC}"

95
scripts/validate-env.sh Executable file
View file

@ -0,0 +1,95 @@
#!/bin/bash
# =============================================================================
# Environment Variables Validation Script (TASK-QA-009)
# =============================================================================
# Validates required environment variables for Veza development.
# See docs/ENV_VARIABLES.md for full reference.
#
# Usage:
# ./scripts/validate-env.sh [environment]
# environment: development (default), production, test
#
# Can be run before make dev or integrated in make doctor.
# =============================================================================
set -e
ENVIRONMENT=${1:-development}
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$ROOT"
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
check_var() {
local var_name=$1
local required=$2
local value="${!var_name}"
if [ -z "$value" ]; then
if [ "$required" = "required" ]; then
echo -e " ${RED}${var_name} (required, not set)${NC}"
return 1
else
echo -e " ${YELLOW}${var_name} (optional, not set)${NC}"
return 0
fi
else
echo -e " ${GREEN}${var_name}${NC}"
return 0
fi
}
echo ""
echo "🔍 Environment validation (${ENVIRONMENT})"
echo " Ref: docs/ENV_VARIABLES.md"
echo ""
ERRORS=0
# Load .env if present (optional)
if [ -f .env ]; then
set -a
source .env
set +a
fi
echo "Required variables:"
check_var "DATABASE_URL" "required" || ERRORS=$((ERRORS + 1))
check_var "REDIS_URL" "required" || ERRORS=$((ERRORS + 1))
# JWT: either RS256 keys OR JWT_SECRET (dev fallback)
JWT_PRIVATE=$(printenv JWT_PRIVATE_KEY_PATH 2>/dev/null || true)
JWT_PUBLIC=$(printenv JWT_PUBLIC_KEY_PATH 2>/dev/null || true)
JWT_SECRET=$(printenv JWT_SECRET 2>/dev/null || true)
if [ -n "$JWT_PRIVATE" ] && [ -n "$JWT_PUBLIC" ]; then
echo -e " ${GREEN}✓ JWT (RS256: keys configured)${NC}"
elif [ -n "$JWT_SECRET" ] && [ ${#JWT_SECRET} -ge 32 ]; then
echo -e " ${GREEN}✓ JWT (HS256 fallback, min 32 chars)${NC}"
else
echo -e " ${RED}✗ JWT_PRIVATE_KEY_PATH + JWT_PUBLIC_KEY_PATH, or JWT_SECRET (min 32 chars)${NC}"
ERRORS=$((ERRORS + 1))
fi
echo ""
echo "Optional (development):"
check_var "CORS_ALLOWED_ORIGINS" "optional"
check_var "FRONTEND_URL" "optional"
if [ "$ENVIRONMENT" = "production" ]; then
echo ""
echo "Production-specific:"
check_var "CORS_ALLOWED_ORIGINS" "required" || ERRORS=$((ERRORS + 1))
fi
echo ""
if [ $ERRORS -eq 0 ]; then
echo -e "${GREEN}✓ Validation passed.${NC}"
exit 0
else
echo -e "${RED}✗ Validation failed ($ERRORS error(s)).${NC}"
echo " See docs/ENV_VARIABLES.md and .env.example"
exit 1
fi