diff --git a/app/database/migrations/2026_07_09_190000_create_supplier_order_checks.php b/app/database/migrations/2026_07_09_190000_create_supplier_order_checks.php index dd67ba51..f4cbacbe 100644 --- a/app/database/migrations/2026_07_09_190000_create_supplier_order_checks.php +++ b/app/database/migrations/2026_07_09_190000_create_supplier_order_checks.php @@ -3,32 +3,61 @@ declare(strict_types=1); use Illuminate\Database\Migrations\Migration; -use Illuminate\Database\Schema\Blueprint; -use Illuminate\Support\Facades\Schema; +use Illuminate\Support\Facades\DB; +/** + * supplier_order_checks — история итоговой проверки заказа у поставщика. + * + * VerifySupplierOrderJob после ночного прогона робота перечитывает живой кабинет + * поставщика и сверяет каждую нашу строку с формулой; результат + * (ok / mismatch / unable_to_verify + список расхождений) пишется сюда одной строкой. + * + * Системная таблица (как supplier_sync_runs / supplier_deferred_sync) — без RLS/ + * tenant_id, пишет supplier-flow джоб под crm_supplier_worker (BYPASSRLS), читает SaaS-admin. + * Создаётся через pgsql_supplier + инлайн-GRANT (guard IF EXISTS) — на проде миграции + * катит crm_migrator, поэтому дефолтные привилегии crm_supplier_worker не наследуются. + * + * Spec: docs/superpowers/specs/2026-07-09-supplier-order-verification-and-deadline-watch-design.md §6. + */ return new class extends Migration { public function up(): void { - Schema::create('supplier_order_checks', function (Blueprint $table): void { - $table->bigIncrements('id'); - $table->timestampTz('checked_at'); - $table->unsignedBigInteger('sync_run_id')->nullable(); - $table->integer('intended_rows')->default(0); - $table->integer('live_rows')->default(0); - $table->integer('mismatch_count')->default(0); - // ok | mismatch | unable_to_verify - $table->string('status', 32); - $table->jsonb('details')->nullable(); - $table->timestampTz('created_at')->useCurrent(); + $supplier = DB::connection('pgsql_supplier'); - $table->index('checked_at'); - $table->index('status'); - }); + $supplier->statement(<<<'SQL' + CREATE TABLE IF NOT EXISTS supplier_order_checks ( + id BIGSERIAL PRIMARY KEY, + checked_at TIMESTAMPTZ NOT NULL, + sync_run_id BIGINT, + intended_rows INTEGER NOT NULL DEFAULT 0, + live_rows INTEGER NOT NULL DEFAULT 0, + mismatch_count INTEGER NOT NULL DEFAULT 0, + status VARCHAR(32) NOT NULL + CHECK (status IN ('ok','mismatch','unable_to_verify')), + details JSONB, + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() + ) + SQL); + $supplier->statement('CREATE INDEX IF NOT EXISTS idx_supplier_order_checks_checked ON supplier_order_checks (checked_at DESC)'); + $supplier->statement('CREATE INDEX IF NOT EXISTS idx_supplier_order_checks_status ON supplier_order_checks (status)'); + + foreach (['crm_supplier_worker'] as $role) { + $supplier->statement(<<statement('DROP TABLE IF EXISTS supplier_order_checks CASCADE'); } }; diff --git a/docs/observer/STATUS.md b/docs/observer/STATUS.md index 29c08b98..9d7e9259 100644 --- a/docs/observer/STATUS.md +++ b/docs/observer/STATUS.md @@ -1,6 +1,6 @@ # Brain Status (auto-generated) -Last updated: 2026-07-10T01:43:47.562Z +Last updated: 2026-07-10T01:58:51.729Z | Контролёр | Состояние | Детали | |---|---|---| @@ -112,8 +112,8 @@ Episodes since last run: 542 / threshold: 10 | PID | Имя | CPU-время | Возраст | |---|---|---|---| -| 11216 | MsMpEng | 2.69ч | NaNч | -| 10400 | Code | 1.98ч | NaNч | +| 11216 | MsMpEng | 2.76ч | 0.0ч | +| 10400 | Code | 2.00ч | 0.0ч | ⚠️ Проверь, не «осиротевшие» ли это процессы от завершённых Claude-сессий.