47 lines
2.9 KiB
Markdown
47 lines
2.9 KiB
Markdown
# Спецификация: конфигурация и стартовая инициализация (единица 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" } }
|
||
```
|