gendesign/tradein-mvp/backend/data/sql/185_account_quota_overrides.sql
bot-backend d530602fbd
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
fix(tradein/quota): per-user quota override + no-burn on empty estimate (#2517)
Co-authored-by: bot-backend <bot-backend@gendsgn.local>
Co-committed-by: bot-backend <bot-backend@gendsgn.local>
2026-07-13 20:18:42 +00:00

59 lines
3.3 KiB
PL/PgSQL
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

-- 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;