4a385b1df7
3 production-tightening после 7-фичного пакета v1.55. (1) HMAC + per-token rate-limit для webhook receive endpoint: - WebhookReceiveController::receive: tenant lookup → rate-limit → HMAC → payload validation. - HMAC: опциональный X-Webhook-Signature: sha256=<hex> через hash_hmac + hash_equals (constant-time). Backward-compat: header missing → 202. - Per-token rate-limit: RateLimiter с decay 60 сек. Лимит из system_settings.webhook_rate_limit_rps × 60. На превышении 429 + Retry-After. Hit ставится ДО валидации payload — иначе обходимо 422. - Pest +5: HMAC valid/invalid 401/missing 202; rate-limit 60+1=429; ключ изолирован per-token. (2) Реальный fetch system_settings в AdminSystemView: - onMounted → adminApi.listSystemSettings() → splice replace. - На fetch-error → fallback на mock + warning v-alert. - Кнопка «Обновить» — ручной reload. - Vitest +3: mount fetch / reload / error fallback. (3) Реальный CSV-export для bulk-actions DealsView: - applyBulkExport → CSV через Blob+a[download]. - 8 колонок, ; разделитель, \r\n, BOM через String.fromCharCode(0xFEFF) (литеральный U+FEFF блокируется ESLint no-irregular-whitespace). - Filename deals_export_YYYY-MM-DD.csv. - Empty selection → toast без download. - Vitest +2: spy createObjectURL+anchor.click; empty без blob. PHPStan baseline регенерирован. Регресс: lint+type-check+format ✅; vitest 242/242 за 15.82 сек (+4); vite build 903 ms; Pint+PHPStan passed; Pest 141/141 за 17.8 сек (+5, 627 assertions). Реестр v1.55→v1.56, CLAUDE.md v1.46→v1.47. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>