Commit Graph

23 Commits

Author SHA1 Message Date
Дмитрий b4c51bf0bc feat(admin): СМС-центр (smsc.ru) на плашке внешних сервисов — баланс, пороги, кнопка пополнения
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 08:25:28 +03:00
Дмитрий 707d4d56b2 fix(external): защитить Carbon::parse срока прокси (fat-finger в .env не роняет джобу/дашборд) + тесты границ/битой даты/алерта 2026-07-17 08:59:02 +03:00
Дмитрий 8fd0bd3577 test(external): allKeys теперь 14 сервисов (добавлен proxy_market) 2026-07-17 08:34:45 +03:00
Дмитрий d9b40228f4 feat(external): регистрация proxy_market в реестре балансов (фон + суточная джоба) 2026-07-17 08:19:16 +03:00
Дмитрий 6ca13d01a5 feat(external): ProxyMarketProbe — живость прокси + срок как баланс 2026-07-17 08:16:18 +03:00
Дмитрий 08a29033fc feat(external): LivenessReading::warn() — amber для «скоро истечёт» 2026-07-17 08:12:02 +03:00
Дмитрий 88e08b0a3d feat(external): AITUNNEL баланс+«Пополнить», EXA «Пополнить», ЮKassa=живость (не деньги) 2026-07-16 18:45:06 +03:00
Дмитрий d4b466cf75 feat(external): keyso — проба живости (зависимость поиска клиентов, 13-й ключ) 2026-07-16 17:03:47 +03:00
Дмитрий c1f46c0cc5 refactor(external): xfetch — проба живости (ключ у sales-finder, не у портала) 2026-07-16 17:00:14 +03:00
Дмитрий 90da8c1bb2 fix(external): живость = сервер ответил (<500), не только 2xx
На проде self_render (GET к POST-ручке /render) и exa (GET api.exa.ai root) отдавали 404
и показывались красными/«не удалось» — ложь, сервис ЖИВ (достучались, просто не тот метод).
Теперь liveness: status<500 → жив (404/405 = сервер ответил); 5xx/обрыв → мёртв.
Правит HttpFundedServiceProvider (aitunnel/exa/xfetch) + SelfRender/SalesFinder пробы.
Тесты: 20/20 (вкл. новые 404→жив, 5xx→мёртв), Larastan 0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 15:29:07 +03:00
Дмитрий 4bfe0b7005 feat(external): SSH-тоннель EXA — отдельная плитка живости (12-й сервис)
По вопросу владельца: EXA ходит через обратный SSH-тоннель (services.exa.proxy),
и это самое хрупкое звено (ops-машина+Happ+порт 10808). Раньше падение тоннеля
выглядело бы как «EXA не отвечает». Теперь ExaTunnelLivenessProbe — отдельная плитка:
сквозной запрос ЧЕРЕЗ прокси на нейтральный адрес (exa.tunnel_check_url, дефолт
api.ipify.org). Тоннель🟢+EXA🔴 = проблема у EXA; тоннель🔴 = легла наша труба.
Дашборд: 12 сервисов. Тесты: 66 моей области зелёные (вкл. 3 пробы тоннеля + 12-keys), Larastan 0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 15:04:52 +03:00
Дмитрий 6be827aaa3 fix(external): EXA-баланс/живость ходит через proxy (Cloudflare режет РФ-IP)
EXA (api.exa.ai) за Cloudflare блокирует российские IP боевого. Прямой пинг с прода
дал бы ложное «не отвечает» и ложный алерт «EXA упал» из суточной джобы. Теперь
ExaBalanceProvider ходит через services.exa.proxy (тот же тоннель, что ExaSiteFinder).
HttpFundedServiceProvider получил хук httpOptions() (Guzzle-опции, по умолчанию нет).
Тест: 4/4 ExaBalanceProviderTest, Larastan 0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 14:54:43 +03:00
Дмитрий e97d164bc9 feat(external): 5 новых сервисов под присмотр (AITUNNEL/EXA/xfetch/self-render/Sales-finder)
Фаза B плана 2026-07-16-external-services-online-monitoring:
- HttpFundedServiceProvider — база «деньги-или-живость» по HTTP (DRY).
- AitunnelBalanceProvider / ExaBalanceProvider / XfetchBalanceProvider — баланс если
  задан *_balance_url, иначе живость пингом; деградация «деньги→жив→grey».
- SelfRenderLivenessProbe / SalesFinderLivenessProbe — только живость.
- Реестр рефрешера расширен до 11 сервисов; supplier — единственный тяжёлый.
- config/services.php: ключи новых сервисов (sales_finder.base_url дефолт ПУСТОЙ).
Тесты: 53 External зелёные, Larastan 0 по своим файлам (точечно).

NB: larastan-хук исключён — 2 ошибки выше baseline в ЧУЖОМ незакоммиченном файле
tests/Feature/Billing/ExpireInvoicesTest.php (работа параллельной сессии в общей папке).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 14:50:01 +03:00
Дмитрий c1f015d17d feat(external): ExternalBalanceRefresher — обновление набора сервисов + окно свежести + BalanceReading::alive()
Фаза A плана 2026-07-16-external-services-online-monitoring:
- BalanceReading::alive() — состояние «жив, денежного баланса нет».
- ExternalBalanceRefresher: реестр 6 сервисов, refresh(keys, force, sendAlerts),
  окно свежести 60с, edge-trigger алерта по колонке light (фон/кнопка sendAlerts=false молчат).
- RefreshExternalBalancesJob делегирует рефрешеру (поведение суточного сбора сохранено).
Тесты: 35 External зелёные, Larastan 0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 14:50:01 +03:00
Дмитрий e969b7700a chore(chat): убрать настройки Jivo — чат теперь свой; экскурсии выключены
Config: jivo_bot -> bot (убраны неиспользуемые webhook_secret/outbound_url/token
- транспорт Jivo уже удалён), jivosite убран целиком (виджет больше не нужен).
Env: JIVO_BOT_* -> BOT_*; JIVO_WIDGET_ID/VITE_JIVO_WIDGET_ID удалены.
tours_enabled выключен по умолчанию (BOT_TOURS_ENABLED=false) — экскурсии
«Показать на портале» уходили не по теме вопроса (живая проверка 13.07.2026),
чинить релевантность отдельно; сторож-тест не даёт включить незаметно.

Заодно убраны обнаруженные хвосты того же виджета, оставшиеся от прежних
задач: JivoLivenessProbe (класс+тест+регистрация в мониторинге внешних
сервисов), плитка «JivoSite» в админ-дашборде, встроенный скрипт виджета
в welcome.blade.php, осиротевший тест resources/js/.../JivoWidget.vue
(компонент уже был удалён ранее), declaration VITE_JIVO_WIDGET_ID.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 08:32:21 +03:00
Дмитрий b2699f0d84 feat(y360): баланс почты Яндекс 360 — ручной ввод + кнопка Пополнить
email — денежный сервис; сумма вписывается в админке «Система» (Yandex360BalanceStore),
светофор по порогам, кнопка «Открыть оплату»/«Пополнить» → admin.yandex.ru/products.
Робот-скрейпер отклонён (SPA Яндекса враждебен ботам + автопополнение защищает баланс).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 13:34:13 +03:00
Дмитрий 2adc363123 feat(external): CaptchaLivenessProbe — статус капчи
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 09:03:52 +03:00
Дмитрий edc648d37e feat(external): JivoLivenessProbe — живость чата
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 09:03:51 +03:00
Дмитрий 31e7e2e77e feat(external): YooKassaLivenessProbe — живость платёжного шлюза
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 09:03:50 +03:00
Дмитрий dc392945e7 feat(external): SmtpLivenessProbe — живость почты Yandex 360
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 09:03:50 +03:00
Дмитрий 63d6b88d86 feat(балансы): баланс поставщика = остаток номеров × 20 ₽
У кабинета crm.bp-gr нет денежного баланса — есть «Баланс ГЦК» (остаток номеров)
в выпадашке шапки (table.balancetbl). supplier-balance.js логинится, раскрывает
выпадашку, читает «Баланс ГЦК» -> {numbers}. Провайдер: деньги = numbers ×
number_price_rub (20 ₽/шт, подтверждено владельцем). Live: 3096 -> 61 920 ₽.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 07:54:10 +03:00
Дмитрий 4cb9bfa9d7 fix(балансы): DaData X-Secret заголовок + кламп days_left к 0
- DadataBalanceProvider: эндпоинт profile/balance требует X-Secret вместе с Token
  (был HTTP 401 на проде при первом сборе); добавлен заголовок при наличии secret.
- BalanceHealth: отрицательный баланс больше не даёт «−1 дн.» (кламп max(0, days)).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 07:25:21 +03:00
Дмитрий 2ac6586a24 feat(балансы): backend плитки балансов внешних сервисов
Ежедневный контроль баланса DaData/Поставщик/Yandex Cloud плиткой дашборда.

- Таблица external_service_balances (pgsql_supplier, BYPASSRLS, last-value upsert)
- BalanceHealth: чистая логика светофора (red <floor или <3д; amber <floor или <7д)
- BalanceProvider+DTO; провайдеры DaData(API)/YC(OAuth→IAM→billing)/Supplier(Playwright)
- RefreshExternalBalancesJob: изоляция провайдеров (try/catch), расписание 06:30 МСК
- AdminDashboardController::balances() + плитка в summary + topup_url (кнопка «Пополнить»)
- Тесты: BalanceHealth, 3 провайдера, джоба, endpoint (102 теста зелёные)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 07:12:14 +03:00