# Спецификация: конфигурация и стартовая инициализация (единица 1) ## Назначение Чтение `appsettings.json`, валидация при старте (tech-requirements 4.2), тест подключения к БД; идемпотентная синхронизация атлетов из конфига с `src.athlete` (upsert по хэшу ключа). ## Конфигурация | Параметр | Тип | Валидация | |---|---|---| | `Api.Key` | string | непустой; уникальный среди `Api.Athletes[].apiKey` | | `Api.Athletes` | list | каждый `{name, apiKey}`: оба поля непусты; дубликаты `apiKey` — фатально | | `Db.ConnectionString` | string | непустой; тест подключения при старте — фатально при неудаче | Ошибка любой проверки: запись в лог (`Log.Logger`, уровень Error) + stderr, код возврата процесса 1. ## Логика 1. Загрузить и провалидировать конфиг (порядок: `Api.Key` → `Api.Athletes` → `Db.ConnectionString`). 2. Тест подключения к БД (репозиторий `MigrationRepository` или прямой запрос `SELECT 1` через Kit.Helpers). 3. Для каждого атлета из `Api.Athletes`: - `hash = SHA256(apiKey)` (hex, lower-case — тот же формат, что пишет m08 при создании атлета); - `athlete_select` по `p_api_key_hash = hash`; - если не найден — `athlete_insert(p_name, p_api_key_hash)`; - если найден и имя отличается — `athlete_update` (имя из конфига — источник); - 🛡 `is_blocked` конфигом не переопределяется — источник блокировки только БД. ## Тесты | # | Проверка | Ожидание | |---|---|---| | 1 | Пустой `Api.Key` | код возврата 1, ошибка в лог/stderr | | 2 | Дубликат `apiKey` среди `Api.Athletes` | код возврата 1 | | 3 | Недоступная БД (`Db.ConnectionString` → неверный порт) | код возврата 1 | | 4 | Первый старт: атлет конфига отсутствует в БД | создан `src.athlete` с SHA-256-хэшем ключа | | 5 | Повторный старт (идемпотентность) | дублей атлетов нет | | 6 | Переименование атлета в конфиге | имя в БД обновлено, id сохранён | ## Пример конфига ```json { "Api": { "Key": "owner-key", "Athletes": [ { "name": "Иван", "apiKey": "ivan-key-1" } ] }, "Db": { "ConnectionString": "Host=127.0.0.1;Port=5433;Database=watchbody;Username=postgres;Password=watchbody" } } ```