Phase 2 scaffold: mitra online status & pairing logic

Add mitra online/offline status with heartbeat-based auto-offline,
customer-mitra pairing via Valkey pub/sub blast, session management,
and control center dashboard with real-time stats.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-05 23:17:49 +08:00
parent a7a2a32d27
commit d668112edd
44 changed files with 2800 additions and 80 deletions

View File

@@ -64,6 +64,84 @@ const migrate = async () => {
ON CONFLICT (key) DO NOTHING
`
// --- Phase 2: Mitra Online Status & Pairing ---
await sql`
CREATE TABLE IF NOT EXISTS mitra_online_status (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
mitra_id UUID NOT NULL UNIQUE REFERENCES mitras(id),
is_online BOOLEAN NOT NULL DEFAULT FALSE,
last_online_at TIMESTAMPTZ,
last_offline_at TIMESTAMPTZ,
last_heartbeat_at TIMESTAMPTZ,
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
)
`
await sql`
CREATE TABLE IF NOT EXISTS mitra_online_logs (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
mitra_id UUID NOT NULL REFERENCES mitras(id),
status VARCHAR(10) NOT NULL,
timestamp TIMESTAMPTZ NOT NULL DEFAULT NOW()
)
`
await sql`
CREATE INDEX IF NOT EXISTS idx_mitra_online_logs_mitra_id
ON mitra_online_logs (mitra_id)
`
await sql`
CREATE TABLE IF NOT EXISTS chat_sessions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
customer_id UUID NOT NULL REFERENCES customers(id),
mitra_id UUID REFERENCES mitras(id),
status VARCHAR(30) NOT NULL DEFAULT 'searching',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
paired_at TIMESTAMPTZ,
ended_at TIMESTAMPTZ,
ended_by VARCHAR(20)
)
`
await sql`
CREATE INDEX IF NOT EXISTS idx_chat_sessions_customer_id
ON chat_sessions (customer_id)
`
await sql`
CREATE INDEX IF NOT EXISTS idx_chat_sessions_mitra_id
ON chat_sessions (mitra_id)
`
await sql`
CREATE INDEX IF NOT EXISTS idx_chat_sessions_status
ON chat_sessions (status)
`
await sql`
CREATE TABLE IF NOT EXISTS chat_request_notifications (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
session_id UUID NOT NULL REFERENCES chat_sessions(id),
mitra_id UUID NOT NULL REFERENCES mitras(id),
notified_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
response VARCHAR(20),
responded_at TIMESTAMPTZ
)
`
await sql`
CREATE INDEX IF NOT EXISTS idx_chat_request_notifications_session_id
ON chat_request_notifications (session_id)
`
await sql`
INSERT INTO app_config (key, value)
VALUES ('max_customers_per_mitra', '{"value": 3}')
ON CONFLICT (key) DO NOTHING
`
console.log('Migration complete.')
await sql.end()
}