# 🏭 Инфраструктура

## Docker Compose (локальная разработка)

### Сервисы

```yaml
services:
  backend:     # Spring Boot (Java 17), порт 8080
  frontend:    # Apache httpd:alpine, порт 80
  db:          # PostgreSQL alpine3.23, порт 5432
```

### Сеть

Все сервисы работают в Docker-сети `proxy` (external). Перед первым запуском:

```bash
docker network create proxy
```

### Переменные окружения

Файл `.env` в корне проекта:

```env
POSTGRES_USER=myuser
POSTGRES_PASSWORD=replace-with-local-password
POSTGRES_DB=app_db
JWT_SECRET=replace-with-random-jwt-secret-minimum-32-bytes
JWT_ACCESS_TOKEN_TTL=15m
JWT_REFRESH_TOKEN_TTL=7d
```

`POSTGRES_PASSWORD` обязателен для `docker compose up`: пароль не хранится в `compose.yaml`. `JWT_SECRET` должен быть случайным секретом длиной минимум 32 байта. В продакшене секреты задаются через Kubernetes Secret, а не через коммитимые файлы.

Локальный `backend/tenants.json` тоже не коммитится. Для ручного запуска backend вне Docker можно взять `backend/tenants.example.json`, создать рядом `tenants.json` и подставить локальный пароль.

### Dockerfile (Backend)

Backend собирается через multi-stage сборку Maven:
1. Этап сборки: `maven:3.9-eclipse-temurin-17` → `mvn package`
2. Этап запуска: `eclipse-temurin:17-jre-alpine` → `java -jar app.jar`

### Dockerfile (Frontend)

```dockerfile
FROM httpd:alpine
COPY . /usr/local/apache2/htdocs/
RUN chown -R www-data:www-data /usr/local/apache2/htdocs/
```

---

## Kubernetes (продакшн)

### Расположение конфигурации

Файлы Kubernetes манифестов: `../k8s/`

### Ключевые ресурсы

| Ресурс | Тип | Описание |
|--------|-----|----------|
| `backend` | Deployment | Spring Boot приложение |
| `frontend` | Deployment | Apache httpd |
| `tenants-config` | ConfigMap | JSON-список тенантов |

### JWT настройки

`app-config` задаёт TTL access/refresh-токенов и признак Secure-cookie:

- `JWT_ACCESS_TOKEN_TTL=15m`
- `JWT_REFRESH_TOKEN_TTL=7d`
- `JWT_REFRESH_COOKIE_SECURE=true`

`app-secret` задаёт `JWT_SECRET`. Его нельзя логировать или хранить в публичных артефактах как реальный продакшн-секрет.

### ConfigMap для тенантов

ConfigMap `tenants-config` монтируется в под backend по пути `/config/tenants.json`.

При добавлении тенанта через API:
1. `DatabaseController` обновляет in-memory DataSource
2. `ConfigMapUpdater` обновляет ConfigMap через Kubernetes API
3. `TenantConfigWatcher` на остальных подах подхватывает изменения (каждые 30 сек)

### Обновление backend

```bash
kubectl rollout restart deployment backend -n magistr
```

---

## Caddy (реверс-прокси)

**Расположение:** `../caddy-proxy/` для локальной разработки, в продакшене - отдельный сервис

В продакшене Caddy обрабатывает входящий трафик для `*.zuev.company`:
- Автоматическое получение TLS-сертификатов (Let's Encrypt)
- Маршрутизация `/api/*` → backend:8080
- Маршрутизация статики → frontend:80

---

## CI/CD (Gitea Actions)

### Пайплайн сборки Docker-образов

Расположение: `.gitea/workflows/docker-build.yaml`

Основные шаги:
1. Checkout кода
2. Login в Docker Registry
3. Build + Push образов (`backend`, `frontend`)
4. Генерация меток через `docker/metadata-action`

---

## Мониторинг (SigNoz + OpenTelemetry)

### Архитектура мониторинга

```mermaid
graph LR
    Backend["Spring Boot"] -->|OTLP gRPC| Collector["OTel Collector"]
    Frontend["JS (otel.js)"] -->|OTLP HTTP| Collector
    Collector --> SigNoz["SigNoz"]
    
    Collector -->|"Метрики PostgreSQL"| PgExporter["pg_exporter"]
```

### Интеграция Backend

Backend отправляет через OpenTelemetry:
- **Логи** — через Logback + OTLP exporter
- **Трейсы** — автоинструментация Spring Boot
- **Метрики** — JVM метрики, HTTP метрики

Tenant ID добавляется в:
- MDC (логи): `MDC.put("tenant.id", tenant)`
- Span атрибуты: `Span.current().setAttribute("tenant.id", tenant)`

### Интеграция Frontend

Файл `admin/js/otel.js` — клиентская телеметрия:
- Метрики производительности страниц
- Трейсы пользовательских действий

### Дашборды SigNoz

- JVM Dashboard (Heap, GC, Threads)
- PostgreSQL Dashboard (Connections, Queries)
- HTTP Dashboard (Requests, Latency, Errors)
