Some checks failed
Deploy Trade-In / build-backend (push) Blocked by required conditions
Deploy Trade-In / deploy (push) Blocked by required conditions
Deploy Trade-In / changes (push) Successful in 11s
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / test (push) Has been cancelled
Co-authored-by: bot-backend <bot-backend@gendsgn.local> Co-committed-by: bot-backend <bot-backend@gendsgn.local>
59 lines
3.3 KiB
PL/PgSQL
59 lines
3.3 KiB
PL/PgSQL
-- Migration 185: account_quota_overrides — персональные месячные лимиты оценок
|
||
--
|
||
-- WHY:
|
||
-- Бонусные попытки для платящих пилотов раздавались хаком через SQL-runbook:
|
||
-- `UPDATE account_estimate_usage SET used = used - N` (negative used). Для user2
|
||
-- (Брусника) это дало used=-35 при глобальном limit=15 → GET /quota отдавал
|
||
-- {limit:15, used:-35, remaining:50} → фронт (EstimateForm.tsx) рендерил абсурд
|
||
-- «Осталось 50 из 15». Правильное решение — персональный лимит, а не отрицательный
|
||
-- счётчик использования.
|
||
--
|
||
-- WHAT:
|
||
-- 1. Таблица account_quota_overrides(username PK, monthly_limit, note, updated_at) —
|
||
-- per-user override глобального settings.estimate_quota_limit. Читается через
|
||
-- app.services.account_quota.user_limit().
|
||
-- 2. Seed: user2 (Брусника) → monthly_limit=50, пилотный грант 2026-07-13.
|
||
-- 3. Сброс хака: account_estimate_usage.used < 0 → 0 (для user2, единственного
|
||
-- затронутого аккаунта). После этой миграции user2: limit=50, used=0,
|
||
-- remaining=50 — корректно вместо «50 из 15».
|
||
--
|
||
-- IDEMPOTENCY:
|
||
-- CREATE TABLE IF NOT EXISTS + INSERT ... ON CONFLICT DO UPDATE (upsert, безопасен
|
||
-- при повторном применении) + UPDATE ... WHERE used < 0 (после первого прогона
|
||
-- used=0, условие больше не матчит — безопасный no-op при ре-apply).
|
||
--
|
||
-- Dependencies: 076_account_estimate_quota.sql (account_estimate_usage).
|
||
|
||
BEGIN;
|
||
|
||
CREATE TABLE IF NOT EXISTS account_quota_overrides (
|
||
username text PRIMARY KEY,
|
||
monthly_limit integer NOT NULL,
|
||
note text,
|
||
updated_at timestamptz NOT NULL DEFAULT now()
|
||
);
|
||
|
||
COMMENT ON TABLE account_quota_overrides IS
|
||
'Персональный override месячного лимита оценок trade-in (вместо глобального '
|
||
'settings.estimate_quota_limit). Читается app.services.account_quota.user_limit().';
|
||
|
||
COMMENT ON COLUMN account_quota_overrides.monthly_limit IS
|
||
'Персональный лимит успешных оценок в календарный месяц для username.';
|
||
|
||
COMMENT ON COLUMN account_quota_overrides.note IS
|
||
'Причина override (grant / pilot / manual bump) — для аудита ручных изменений.';
|
||
|
||
INSERT INTO account_quota_overrides (username, monthly_limit, note)
|
||
VALUES ('user2', 50, 'Брусника — пилот, грант 2026-07-13')
|
||
ON CONFLICT (username) DO UPDATE SET
|
||
monthly_limit = EXCLUDED.monthly_limit,
|
||
note = EXCLUDED.note,
|
||
updated_at = now();
|
||
|
||
-- Сбрасываем прежний хак бонусных попыток (negative used), который ломал /quota:
|
||
-- limit=15, used=-35 → remaining=50 → фронт рендерил «Осталось 50 из 15».
|
||
UPDATE account_estimate_usage
|
||
SET used = 0, updated_at = now()
|
||
WHERE username = 'user2' AND used < 0;
|
||
|
||
COMMIT;
|