fix(billing-v2): supplier_lead_deliveries migration prod-compatible — pgsql_supplier connection + explicit GRANTs + drop-index no-op
This commit is contained in:
@@ -16,11 +16,14 @@ return new class extends Migration
|
||||
if ($sql === false) {
|
||||
throw new RuntimeException('Migration SQL file not found.');
|
||||
}
|
||||
DB::unprepared($sql);
|
||||
// Prod: crm_app_user (default pgsql) не имеет CREATE на schema public.
|
||||
// Используем pgsql_supplier (crm_supplier_worker, BYPASSRLS, имеет CREATE).
|
||||
// На dev pgsql_supplier тоже = postgres superuser → работает идентично.
|
||||
DB::connection('pgsql_supplier')->unprepared($sql);
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
DB::unprepared('DROP TABLE IF EXISTS supplier_lead_deliveries CASCADE;');
|
||||
DB::connection('pgsql_supplier')->unprepared('DROP TABLE IF EXISTS supplier_lead_deliveries CASCADE;');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,21 +1,31 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* No-op миграция-маркер (Billing v2 Spec B): телефонный дедуп удалён,
|
||||
* индекс deals_duplicate_of_id_idx становится неиспользуемым (колонка
|
||||
* deals.duplicate_of_id оставлена спящей — drop отдельной DBA-задачей,
|
||||
* mirrors Spec A balance_leads two-phase).
|
||||
*
|
||||
* Почему миграция no-op: индекс владельца crm_migrator, DROP требует прав
|
||||
* owner; .env не имеет crm_migrator credentials, а pgsql_supplier
|
||||
* (crm_supplier_worker) не владеет индексами на partitioned deals. Запуск
|
||||
* DROP отложен — выполняется напрямую psql под postgres-superuser отдельно.
|
||||
* Эта миграция только маркер «обработано», чтобы migrate --force не падал.
|
||||
*
|
||||
* На dev (postgres-superuser) индекс уже отсутствует из schema.sql v8.34,
|
||||
* поэтому ничего не делаем — тоже корректно.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
$sql = file_get_contents(base_path('../db/migrations/2026_05_23_201_drop_deals_duplicate_of_id_index.sql'));
|
||||
if ($sql === false) {
|
||||
throw new RuntimeException('Migration SQL file not found.');
|
||||
}
|
||||
DB::unprepared($sql);
|
||||
// Intentionally empty.
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
// No-op: index has been deemed unused (telephone dedup removed). Recreation is unnecessary.
|
||||
// No-op: recreation is unnecessary (concept removed).
|
||||
}
|
||||
};
|
||||
|
||||
@@ -16,3 +16,23 @@ CREATE TABLE supplier_lead_deliveries (
|
||||
ALTER TABLE supplier_lead_deliveries ENABLE ROW LEVEL SECURITY;
|
||||
CREATE POLICY tenant_isolation ON supplier_lead_deliveries
|
||||
USING (tenant_id = current_setting('app.current_tenant_id')::bigint);
|
||||
|
||||
-- Явные GRANT'ы для 4 ролей: на prod таблица создаётся crm_supplier_worker
|
||||
-- (default privileges от postgres-superuser не наследуются на чужие creator-role).
|
||||
-- Mirror webhook_dedup_keys grant pattern. DO block — idempotent + dev-safe
|
||||
-- (на dev ролей нет → silent skip).
|
||||
DO $$
|
||||
BEGIN
|
||||
IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'crm_app_user') THEN
|
||||
GRANT SELECT, INSERT, UPDATE, DELETE ON supplier_lead_deliveries TO crm_app_user;
|
||||
END IF;
|
||||
IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'crm_admin_user') THEN
|
||||
GRANT SELECT, INSERT, UPDATE, DELETE ON supplier_lead_deliveries TO crm_admin_user;
|
||||
END IF;
|
||||
IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'crm_supplier_worker') THEN
|
||||
GRANT SELECT, INSERT, UPDATE, DELETE ON supplier_lead_deliveries TO crm_supplier_worker;
|
||||
END IF;
|
||||
IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'crm_migrator') THEN
|
||||
GRANT ALL PRIVILEGES ON supplier_lead_deliveries TO crm_migrator;
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
@@ -2062,6 +2062,26 @@ ALTER TABLE supplier_lead_deliveries ENABLE ROW LEVEL SECURITY;
|
||||
CREATE POLICY tenant_isolation ON supplier_lead_deliveries
|
||||
USING (tenant_id = current_setting('app.current_tenant_id')::bigint);
|
||||
|
||||
-- Явные GRANT'ы для 4 ролей (mirror webhook_dedup_keys): на prod таблица
|
||||
-- создаётся crm_supplier_worker, default privileges не наследуются от
|
||||
-- postgres-superuser на чужие creator-role. DO block — idempotent + dev-safe
|
||||
-- (на dev ролей нет → silent skip).
|
||||
DO $$
|
||||
BEGIN
|
||||
IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'crm_app_user') THEN
|
||||
GRANT SELECT, INSERT, UPDATE, DELETE ON supplier_lead_deliveries TO crm_app_user;
|
||||
END IF;
|
||||
IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'crm_admin_user') THEN
|
||||
GRANT SELECT, INSERT, UPDATE, DELETE ON supplier_lead_deliveries TO crm_admin_user;
|
||||
END IF;
|
||||
IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'crm_supplier_worker') THEN
|
||||
GRANT SELECT, INSERT, UPDATE, DELETE ON supplier_lead_deliveries TO crm_supplier_worker;
|
||||
END IF;
|
||||
IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'crm_migrator') THEN
|
||||
GRANT ALL PRIVILEGES ON supplier_lead_deliveries TO crm_migrator;
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
|
||||
-- =============================================================================
|
||||
-- 7. БИЛЛИНГ (SAAS-уровень)
|
||||
|
||||
Reference in New Issue
Block a user