Ограничение sms.ru — не более 8 SMS за 10 минут ПО АККУНТУ суммарно, на любые
номера (антибомбинг; превышение → отказ с кодами 231/232). Таймеры first/second/
paid стартуют в одну и ту же секунду, поэтому счётчик нужно читать
последовательно, иначе каждый процесс видит «свободно 8» и вместе они
превышают лимит.
- sms_rate_limit.py: acquire_send_lock/release_send_lock на pg_advisory_lock,
lock_timeout 120с; докстринг, описание настроек и текст алерта приведены к
правилу «8 суммарно по аккаунту» (страховка «N на номер» остаётся).
- first/second/paid: блокировка берётся сразу после получения списка групп и
снимается перед выходом; если блокировку взять не удалось — прогон
пропускается (лучше пропуск, чем блокировка аккаунта), следующая попытка по
таймеру.
- Настройки: sms_limit_account_10min=8 (основное правило), окно 600с;
sms_limit_per_number_10min=8 остаётся второй страховкой.
Проверено на клоне боевой базы (sms_rl_test), реальный sms.ru не вызывался:
- 2 процесса × 20 попыток одновременно → ровно 8 отправок (4+4), далее
«аккаунт: уже 8 SMS за 600с (лимит 8)»; в БД 8 строк с sms_id в окне;
- блокировка: держатель 6с → попытка с таймаутом 2с = False (2.0с), с
таймаутом 20с = True (2.7с);
- E2E сц.3 (боевой профиль per_number=0/account=8/win=600): 8 ушло, 3
придержано; сц.1 (per-number=8) — регресс пройден.
Full edge-fn sync clobbered a live hotfix: repo request-otp only wrote
otp_code_hash, but login_otps.otp_code is NOT NULL, so every request
failed with 'Failed to generate OTP' and no PIN email was sent. Restore
writing otp_code (n8n send_pin trigger emails it; verify still uses hash).
confirm-delivery-choice blocked any order_groups with delivery_status
other than 'pending_confirmation', so orders in manual handling
(manual_confirmation_required) showed the client a form but rejected the
save. Allow booking for manual_confirmation_required so clients can pick
date+time until the order is assigned/paid. Surface 'paid_storage' and
'driver_assigned' states to the client view instead of a dead form.
- mapOrderGroupRowToDeliveryGroup dropped called/called_at/called_comment
fields (they were selected but never mapped) so the panel always read
'not called' and freshly saved calls appeared to vanish.
- CalledPanel: one-tap 'Звонили' marks called with now; app-styled
date/time dropdowns (CallDateTime) default to current moment for fast
entry; comment edit form pre-filled.
- OrderDetailPanel: forward real onRefreshOrder (was a silent no-op) so
the card refreshes from DB after a save.
- add fetchOrderGroupById (single .eq(id).single() query)
- useOrderGroups gains groupId mode: fetches one group, not full 2.6MB list
- GroupDetailPage passes groupId — fixes 30-40s card open on slow connections
- staff hook called /functions/v1/subscribe-push which does not exist on the
server (functions are named push-subscribe/push-unsubscribe and are keyed by
phone_normalized for the CLIENT flow only; push_subscriptions has no user_id)
- keep local browser PushManager subscription; drop broken server round-trips
- client PushSubscriptionBanner flow untouched (uses correct endpoint)
- remove postgres_changes .channel().subscribe() from useNotifications
- notifications now load via REST on mount and refresh on tab focus
- eliminates WS retry hangs (30-40s stalls) from dead realtime container;
web-push (Push API) is unaffected and works independently
- new src/utils/pwaCacheCleanup.js: deletes all construction-delivery-* caches
except current v115 on every app load; runs in page context so it works even
for users still on old SW
- wire into main.jsx startup
- fixes 3GB cache bloat / 30-40s hangs for users whose SW hasn't updated
- activate: delete ALL caches except current STATIC/RUNTIME (was keeping every
previous construction-delivery-* cache forever → 3GB storage, 30-40s caches.match)
- fetch: only cache same-origin static assets (js/css/img/fonts); API/data and
cross-origin requests go straight to network, never cached
- bump to v115