[CL-HOTELSYNC-REVENUE-VALIDATE] Валидация totalRevenue в hotel-sync webhook #858

Merged
andrei merged 2 commits from feature/claude-hotelsync-revenue-validate into master 2026-06-24 15:30:02 +00:00
Owner

Что сделано

Добавлена валидация PMS-поля data.totalRevenue в webhook POST /api/hotel-sync/webhook (event revenue.daily) перед записью в финансовую колонку propertyObject.annualRevenue. Гард Number.isFinite() && >= 0; невалидное значение → warn-лог + skip.

Зачем

Соседнее поле rate клампится в [0,1] (PIX-1235), а totalRevenue писалось напрямую без проверки. Malformed PMS-payload (NaN/Infinity/negative) попадал в annualRevenue, которое питает yield-проекции инвесторам → искажение фин-расчётов. Найдено в мега-аудите (rate-limit/validation coverage). Эндпоинт M2M (x-api-key + HMAC-SHA256), severity LOW.

План тестирования

  • Регресс-тест api/src/routes/__tests__/hotel-sync.test.ts: valid 125000 → пишет; negative/NaN/Infinity → skip. RED до фикса, GREEN после.
  • vitest 13/13 в файле, 189/189 integration (pre-push). tsc clean, eslint clean.

Где могу ошибаться

  • Нет верхнего bound (только finite+non-negative).
  • Skip вместо 400: M2M-источник, warn-лог фиксирует инцидент.
## Что сделано Добавлена валидация PMS-поля `data.totalRevenue` в webhook `POST /api/hotel-sync/webhook` (event `revenue.daily`) перед записью в финансовую колонку `propertyObject.annualRevenue`. Гард `Number.isFinite() && >= 0`; невалидное значение → warn-лог + skip. ## Зачем Соседнее поле `rate` клампится в [0,1] (PIX-1235), а `totalRevenue` писалось напрямую без проверки. Malformed PMS-payload (NaN/Infinity/negative) попадал в `annualRevenue`, которое питает yield-проекции инвесторам → искажение фин-расчётов. Найдено в мега-аудите (rate-limit/validation coverage). Эндпоинт M2M (x-api-key + HMAC-SHA256), severity LOW. ## План тестирования - Регресс-тест `api/src/routes/__tests__/hotel-sync.test.ts`: valid 125000 → пишет; negative/NaN/Infinity → skip. RED до фикса, GREEN после. - vitest 13/13 в файле, 189/189 integration (pre-push). tsc clean, eslint clean. ## Где могу ошибаться - Нет верхнего bound (только finite+non-negative). - Skip вместо 400: M2M-источник, warn-лог фиксирует инцидент.
[CL-HOTELSYNC-REVENUE-VALIDATE] fix(hotel-sync): валидация totalRevenue перед записью в annualRevenue
Some checks failed
CI / App (pull_request) Failing after 2m35s
React Doctor / React Doctor / App (pull_request) Failing after 47h6m2s
PR Janitor / janitor (pull_request) Failing after 47h6m10s
CI / Secrets Scan (pull_request) Failing after 47h7m3s
CI / Prisma Migrate Gate (pull_request) Failing after 47h6m50s
CI / Python SDK (pull_request) Failing after 47h7m29s
CI / Contracts (pull_request) Failing after 47h9m21s
CI / API (pull_request) Failing after 47h11m31s
CI / Telegram Mini App (pull_request) Failing after 47h12m12s
9be3650638
Webhook revenue.daily писал PMS-поле data.totalRevenue напрямую в
финансовую колонку propertyObject.annualRevenue без проверки. Соседнее
поле rate клампится в [0,1] (PIX-1235), а totalRevenue — нет: malformed
PMS-payload (NaN/Infinity/negative) портил yield-проекции инвесторам.

Фикс: гард Number.isFinite && >= 0 перед persist, иначе warn-лог и skip
(зеркало паттерна PIX-1235). Регрессионный тест на valid/negative/NaN/
Infinity. Эндпоинт M2M (x-api-key + HMAC), severity LOW, но касается
financial-display поля.
Merge branch 'master' into feature/claude-hotelsync-revenue-validate
Some checks failed
PR Janitor / janitor (pull_request) Failing after 46h2m25s
CI / Prisma Migrate Gate (pull_request) Failing after 46h2m43s
CI / Secrets Scan (pull_request) Failing after 46h2m45s
CI / Contracts (pull_request) Failing after 46h4m55s
CI / Python SDK (pull_request) Failing after 46h3m11s
CI / App (pull_request) Failing after 46h4m57s
CI / API (pull_request) Failing after 46h4m59s
CI / Telegram Mini App (pull_request) Failing after 46h9m34s
633e2af72f
andrei merged commit 2c46abdeff into master 2026-06-24 15:30:02 +00:00
andrei deleted branch feature/claude-hotelsync-revenue-validate 2026-06-24 15:30:03 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
europa-tech-srl/europatech!858
No description provided.