# Best practices

Чек-лист для consumer'ов Ordinis API.

## Идентификация записей

1. **Используй `businessKey`, не UUID.** UUID — внутренний идентификатор
   записи и **меняется** при создании новой версии (через update).
   `businessKey` стабилен через всю жизнь записи.

2. **Не делай FK на копию справочника.** Если копируешь данные к себе для
   snapshot — храни `business_key VARCHAR` как key, не `id UUID` либо
   `internal_id`. Это устойчиво к updates.

## Авторизация

3. **Кэшируй access token с TTL = `expires_in - 30s`.** Не делай новый
   token request на каждый API call — Keycloak rate limits + латентность.

4. **Refresh JWT перед TTL.** Не дожидайся 401 — большинство Keycloak SDK
   рефрешат автоматически.

5. **Не храни `client_secret` в коде / git.** Vault либо secret manager.

## Чтение

6. **Кэшируй per `(dictionary, lang)`.** Inline в коде — `staleTime` /
   TTL. См. [Caching](caching.md).

7. **Используй `?lang=` параметр** для flatten i18n полей если UI на одном
   языке. Без `lang` ответ возвращает `{ru-RU: "...", en-US: "..."}`
   объект — лишний размер payload + проще баг.

8. **Не запрашивай history endpoint** на hot path. История нужна только
   admin UI / audit. Список + by-key endpoints достаточны для типичного
   consumer.

## Запись (admin only)

9. **Не пиши массовых update'ов** через одиночные API calls. Ordinis
   оптимизирован под редкие записи и частые чтения. Для bulk import
   используй `POST /admin/bundle/import` (через bundle Maven module).

10. **Bulk close через `_bulk-close`** endpoint, не loop одиночных POST.
    Per-record transactions, classification (skipped vs error vs closed),
    меньше latency.

11. **Bulk export CSV** через `_export?format=csv` для extracting filtered
    данные в legacy системы.

## Обработка событий

12. **Idempotency** — события at-least-once, могут прийти дважды. Используй
    `(dictionary, businessKey, txTime, version)` либо `deliveryId` (для webhooks)
    как dedup key.

13. **Async обработка** — отвечай webhook'у `202 Accepted` сразу, обрабатывай
    в background. Жёсткий timeout 10s.

14. **HMAC verify первым** — до парсинга JSON. Защита от spoofed events.

15. **Stale cache на 5xx / timeout** — отдавай старые данные с warn'ом, не
    падай каскадно.

## Производительность

16. **Parallel-fetch related dictionaries** при cascading select:

    ```ts
    const [spacecrafts, satTypes, instruments] = await Promise.all([
      fetch('/api/v1/spacecraft/records?lang=ru'),
      fetch('/api/v1/satellite_type/records?lang=ru'),
      fetch('/api/v1/instrument/records?lang=ru'),
    ])
    ```

    Не последовательные `await`, не N+1 loops.

17. **Cascading filters в memory** — после loading dictionaries фильтруй
    клиент-side вместо новых API calls:

    ```ts
    const allowedFormats = formats.filter(f =>
      instrument.data.supportedFormatCodes.includes(f.businessKey))
    ```

18. **Не делай polling в tight loop** — используй webhooks либо Kafka events
    для realtime invalidation. Polling каждые 5 мин — OK, каждые 10 сек — нет.

## Error handling

19. **Don't retry 4xx (кроме 401 и 429).** Permanent errors требуют code
    fix, не retry.

20. **Exponential backoff на 5xx / timeout.** Base 0.5s, multiplier 2,
    jitter 0-0.5s, max 5 attempts. См. [Errors](errors.md).

21. **Сохраняй `traceId`** при эскалации в Ordinis team. Без traceId
    investigation в Tempo занимает в 10x дольше.

## Bundle versioning

22. **Forward compatibility** — допускай новые поля в API responses которые
    ты не знаешь. Не fail on unknown fields. Schema validation у consumer'а
    должна быть `additionalProperties: true` (либо аналог).

23. **Подписывайся на `nsi.dictionary.changed` events** для новых
    справочников — они появляются с минор-bump bundle.

24. **Monitor schema versions** в `GET /dictionaries` response — если
    `schemaVersion` поменялся, проверь твой mapping не сломался.

## Безопасность

25. **HTTPS обязателен** — webhook URLs тоже только https. SSRF guard
    блокирует http:// и private CIDR.

26. **Не log access tokens** в plaintext. Большинство logging frameworks
    имеют redaction patterns для `Authorization` header.

27. **Rotate `client_secret`** регулярно. Раз в квартал — minimum, раз
    в месяц — recommended для production. Coordinate с Ordinis team
    при rotation.

## Коммуникация с командой

28. **Прежде чем bulk import** > 1000 records — talk to Ordinis team. У
    нас есть staging environment + bulk-import endpoint без rate limits.

29. **Запрашивай новый scope / role** через `zimin.an@nstart.space`
    либо issue с label `keycloak-role-request`.

30. **При проблеме**: воспроизведи на staging, скопируй traceId, открой
    issue. Скриншоты UI ошибок помогают.

## Тестирование

31. **Mock Ordinis в unit tests** — не завись от availability staging
    cluster. Нашa OpenAPI spec accurate, генерируй mock client.

32. **Integration tests против staging** — не prod. Staging данные — тестовые,
    можно create/close без последствий.

33. **Load tests на staging** в low-traffic окно. Координируй с Ordinis
    team — мы можем включить дополнительные replicas для вашего теста.

## Reference: bundle cuod

См. [Bundle cuod](bundle-cuod.md) — список 40 справочников, их связи,
типичные operations.

## Дальше

- [События](events.md) — push-обновления
- [Caching](caching.md) — стратегии кэша
- [Errors](errors.md) — обработка ошибок
