feat(chat): журнал разговоров переезжает с Jivo на свой чат
jivo_chat_id -> chat_id + добавлены source/user_id/ip (спека 2026-07-13-own-chat-widget-design §5). Историческая миграция создания таблицы не тронута. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -56,7 +56,7 @@ class ProcessJivoMessageJob implements ShouldQueue
|
||||
// Память разговора — ДО записи текущего сообщения (иначе оно попадёт в историю).
|
||||
// Служебные хвосты «👉 Показать на портале: …» из прошлых ответов LLM не нужны.
|
||||
$history = BotDialog::query()
|
||||
->where('jivo_chat_id', $this->chatId)
|
||||
->where('chat_id', $this->chatId)
|
||||
->orderByDesc('id')
|
||||
->limit(self::HISTORY_LIMIT)
|
||||
->get(['direction', 'message'])
|
||||
@@ -69,7 +69,7 @@ class ProcessJivoMessageJob implements ShouldQueue
|
||||
->all();
|
||||
|
||||
BotDialog::create([
|
||||
'jivo_chat_id' => $this->chatId,
|
||||
'chat_id' => $this->chatId,
|
||||
'direction' => 'in',
|
||||
'message' => $this->text,
|
||||
'created_at' => now(),
|
||||
@@ -85,7 +85,7 @@ class ProcessJivoMessageJob implements ShouldQueue
|
||||
app(JivoBotClient::class)->sendMessage($this->chatId, $this->clientId, $answer->text);
|
||||
|
||||
BotDialog::create([
|
||||
'jivo_chat_id' => $this->chatId,
|
||||
'chat_id' => $this->chatId,
|
||||
'direction' => 'out',
|
||||
'message' => $answer->text,
|
||||
'matched_chunks' => $answer->matchedChunkIds,
|
||||
@@ -99,7 +99,7 @@ class ProcessJivoMessageJob implements ShouldQueue
|
||||
private function awaitsContact(): bool
|
||||
{
|
||||
$lastOut = BotDialog::query()
|
||||
->where('jivo_chat_id', $this->chatId)
|
||||
->where('chat_id', $this->chatId)
|
||||
->where('direction', 'out')
|
||||
->latest('id')
|
||||
->value('message');
|
||||
@@ -124,7 +124,7 @@ class ProcessJivoMessageJob implements ShouldQueue
|
||||
}
|
||||
|
||||
$rows = BotDialog::query()
|
||||
->where('jivo_chat_id', $this->chatId)
|
||||
->where('chat_id', $this->chatId)
|
||||
->orderByDesc('id')
|
||||
->limit(8)
|
||||
->get(['direction', 'message'])
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
/**
|
||||
* Свой чат вместо Jivo (спека 2026-07-13-own-chat-widget-design §5).
|
||||
* Журнал диалогов перестаёт быть журналом Jivo: номер разговора теперь наш,
|
||||
* добавляем откуда пришёл (portal/landing), кто клиент (если вошёл) и адрес.
|
||||
* На проде таблицы нет (бот там не стоит) — переименование безопасно.
|
||||
*/
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
DB::statement('ALTER TABLE bot_dialogs RENAME COLUMN jivo_chat_id TO chat_id');
|
||||
DB::statement("ALTER TABLE bot_dialogs ADD COLUMN IF NOT EXISTS source VARCHAR(16) NOT NULL DEFAULT 'portal'");
|
||||
DB::statement('ALTER TABLE bot_dialogs ADD COLUMN IF NOT EXISTS user_id BIGINT');
|
||||
DB::statement('ALTER TABLE bot_dialogs ADD COLUMN IF NOT EXISTS ip VARCHAR(45)');
|
||||
// Опрос окошка: «дай реплики этого разговора после id N».
|
||||
DB::statement('CREATE INDEX IF NOT EXISTS idx_bot_dialogs_chat_seq ON bot_dialogs (chat_id, id)');
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
DB::statement('DROP INDEX IF EXISTS idx_bot_dialogs_chat_seq');
|
||||
DB::statement('ALTER TABLE bot_dialogs DROP COLUMN IF EXISTS ip');
|
||||
DB::statement('ALTER TABLE bot_dialogs DROP COLUMN IF EXISTS user_id');
|
||||
DB::statement('ALTER TABLE bot_dialogs DROP COLUMN IF EXISTS source');
|
||||
DB::statement('ALTER TABLE bot_dialogs RENAME COLUMN chat_id TO jivo_chat_id');
|
||||
}
|
||||
};
|
||||
@@ -9,13 +9,13 @@ uses(RefreshDatabase::class);
|
||||
|
||||
it('bot_dialogs принимает запись входа и выхода', function () {
|
||||
DB::table('bot_dialogs')->insert([
|
||||
'jivo_chat_id' => 'chat-1',
|
||||
'chat_id' => 'chat-1',
|
||||
'direction' => 'in',
|
||||
'message' => 'что такое проект?',
|
||||
'created_at' => now(),
|
||||
]);
|
||||
DB::table('bot_dialogs')->insert([
|
||||
'jivo_chat_id' => 'chat-1',
|
||||
'chat_id' => 'chat-1',
|
||||
'direction' => 'out',
|
||||
'message' => 'Проект — это…',
|
||||
'matched_chunks' => json_encode([1, 2]),
|
||||
@@ -24,5 +24,19 @@ it('bot_dialogs принимает запись входа и выхода', fun
|
||||
'created_at' => now(),
|
||||
]);
|
||||
|
||||
expect(DB::table('bot_dialogs')->where('jivo_chat_id', 'chat-1')->count())->toBe(2);
|
||||
expect(DB::table('bot_dialogs')->where('chat_id', 'chat-1')->count())->toBe(2);
|
||||
});
|
||||
|
||||
it('журнал разговоров хранит номер разговора, откуда пришёл и кто клиент', function () {
|
||||
$columns = DB::select("
|
||||
SELECT column_name FROM information_schema.columns
|
||||
WHERE table_name = 'bot_dialogs'
|
||||
");
|
||||
$names = array_map(fn ($c) => $c->column_name, $columns);
|
||||
|
||||
expect($names)->toContain('chat_id')
|
||||
->and($names)->toContain('source')
|
||||
->and($names)->toContain('user_id')
|
||||
->and($names)->toContain('ip')
|
||||
->and($names)->not->toContain('jivo_chat_id');
|
||||
});
|
||||
|
||||
@@ -33,7 +33,7 @@ it('наша часть тракта (без сети) укладывается
|
||||
$latencies = [];
|
||||
for ($i = 0; $i < 10; $i++) {
|
||||
(new ProcessJivoMessageJob("chat-{$i}", 'c', 'что такое проект?'))->handle();
|
||||
$latencies[] = (int) BotDialog::where('jivo_chat_id', "chat-{$i}")
|
||||
$latencies[] = (int) BotDialog::where('chat_id', "chat-{$i}")
|
||||
->where('direction', 'out')->value('latency_ms');
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user