Commit Graph

7 Commits

Author SHA1 Message Date
Дмитрий f5c7c29301 test(schema): add UNIQUE-vid behavioral test + intent-clear placeholder assert
- Add it-block для UNIQUE INDEX idx_supplier_leads_vid_unique:
  две INSERT с одинаковым vid → вторая бросает QueryException
  (прямой behavioral тест webhook-идемпотентности).
- Replace tautological strlen($secret->value) >= 16 на toBe('__SET_ON_DEPLOY__')
  — было проверкой литерала, который мы сами и записали; теперь intent-clear
  assertion того, что seed кладёт placeholder. Реальная strength-валидация
  secret'а — дело deploy-time validator'а, вне scope Plan 2.
- Add uses(DatabaseTransactions::class) — приводит файл к проектному
  pattern (см. WebhookReceiveTest, TenantModelsTest, SetTenantContextTest).
  Без него новый INSERT с vid=999000111 коллидил бы при re-run, т.к.
  Pest.php применяет RefreshDatabase глобально не делает (закомментирован).

Code-review fixes for Plan 2 Task 1.
2026-05-10 18:16:19 +03:00
Дмитрий fb55bfdd1f feat(db): supplier_leads + projects.delivered_today + 2 system_settings (v8.18)
Plan 2/5 Task 1 — слой данных для supplier-webhook flow.

- supplier_leads (SaaS-level, без RLS) — raw payload incoming webhook'ов
- projects.delivered_today — дневной счётчик для проверки daily quota
- system_settings: supplier_webhook_secret + supplier_ip_allowlist

Spec: docs/superpowers/specs/2026-05-10-supplier-integration-design.md §5-§6

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 18:07:31 +03:00
Дмитрий 9cf380f170 feat(db): create supplier_sync_log audit table (SaaS-level, append-only)
Append-only journal AJAX-синхронизаций с поставщиком crm.bp-gr.ru.
Используется для retry, отладки rt-project-* и алертов менеджеру.

- 9 columns: id, supplier_project_id (nullable FK SET NULL),
  action, request_payload (jsonb), response_body (jsonb),
  http_status, error_message, duration_ms, created_at
- 1 CHECK chk_supplier_sync_log_action
  (create/update/delete/disable/session_refresh)
- 3 индекса: supplier_project_id, action, created_at
- REVOKE ALL FROM crm_app_user (DO $$ conditional)
- No RLS (SaaS-level)

Spec: §4.3
Plan: Task 5
Test: 4/4 passed (table, action enum, FK, no RLS).

Schema v8.15 → v8.16. Метрики: 60 таблиц (+1) / 108 индексов (+3).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 13:42:46 +03:00
Дмитрий 7f694f78e0 feat(db): create lead_charges ledger (tenant-scoped RLS, FK to partitioned deals)
Append-only ledger списаний за каждый доставленный лид. Tenant-scoped
с RLS tenant_isolation (ENABLE + FORCE + USING/WITH CHECK).

- 8 columns: id, tenant_id, deal_id, deal_received_at, tier_no,
  price_per_lead_kopecks, charged_at, created_at
- Composite FK lead_charges_deals_fk(deal_id, deal_received_at) →
  deals(id, received_at) DEFERRABLE INITIALLY DEFERRED
  (deals партиционирована — DEFERRABLE для атомарного deal+charge)
- 2 индекса: (tenant_id, charged_at), (deal_id, deal_received_at)
- RLS на (tenant_id = current_setting('app.current_tenant_id')::bigint)
- GRANT SELECT, INSERT для crm_app_user (без UPDATE/DELETE — append-only)

Spec: docs/superpowers/specs/2026-05-10-supplier-integration-design.md §7.4
Plan: docs/superpowers/plans/2026-05-10-supplier-foundation-plan.md Task 4

Test: 3/3 passed (table exists, composite FK to deals, RLS enforces
tenant isolation via testing_rls_user role).

Schema v8.14 → v8.15. Метрики: 59 таблиц (+1) / 105 индексов (+2) /
39 RLS (+1) / функции/триггеры без изменений.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 13:38:17 +03:00
Дмитрий b08e1edb33 feat(db): create pricing_tiers table (7-step volume billing, kopecks integer) 2026-05-10 12:54:02 +03:00
Дмитрий 9b99d81deb feat(db): create supplier_projects table (SaaS-level aggregate, B1/B2/B3 platforms)
Plan 1/5 Task 2 — SaaS-level агрегатная сущность для проектов у поставщиков.
Несколько Лидерра-tenant'ов могут шарить один supplier_project (sharing-model
spec §2.3): для site/call — по domain/phone; для sms — по (sender, keyword)
на B2 или (sender) на B3. RLS НЕ применяется (таблица не tenant-scoped),
defense-in-depth через REVOKE ALL FROM crm_app_user.

Колонки: platform, signal_type, unique_key (TEXT), supplier_external_id,
current_limit, current_workdays/regions (jsonb), sync_status (pending/ok/failed),
last_synced_at, inactive_since (TTL 180 дней), timestamps.

CHECK constraints (chk_supplier_projects_*):
- platform IN (B1, B2, B3)
- signal_type IN (site, call, sms)
- sync_status IN (pending, ok, failed)
- NOT (platform=B1 AND signal_type=sms) — B1 не поддерживает СМС

Indexes: UNIQUE(platform, unique_key); btree на sync_status, inactive_since.

Тесты: 6/6 (table+columns / unique / platform CHECK / sync_status CHECK / no RLS / no privileges).
Schema: v8.12 → v8.13. Метрики: 56→57 таблиц / 98→101 индексов; RLS/функции/триггеры без изменений.
2026-05-10 12:47:25 +03:00
Дмитрий 2ebe000271 feat(db): extend projects for supplier integration (signal_type, identifier, sms_senders, sms_keyword, delivered_in_month, b1/b2/b3 FK placeholders)
Plan 1/5 Task 1. Adds 8 columns + 3 CHECK constraints + 1 composite index
to projects table for supplier integration foundation. Schema bumped
v8.11 to v8.12. Spec: docs/superpowers/specs/2026-05-10-supplier-integration-design.md §2.1.

7/7 Pest tests pass; rollback verified.
2026-05-10 12:40:02 +03:00