-- Telegram Bot Rolling Summary Schema -- D1 Database for Cloudflare Workers -- 사용자 테이블 CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY AUTOINCREMENT, telegram_id TEXT UNIQUE NOT NULL, username TEXT, first_name TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ); -- 메시지 버퍼 (요약 전 임시 저장) CREATE TABLE IF NOT EXISTS message_buffer ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL, chat_id TEXT NOT NULL, role TEXT NOT NULL CHECK(role IN ('user', 'bot')), message TEXT NOT NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (user_id) REFERENCES users(id) ); -- 요약 저장 테이블 (슬라이딩 윈도우: 최대 3개만 유지) CREATE TABLE IF NOT EXISTS summaries ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL, chat_id TEXT NOT NULL, generation INTEGER NOT NULL DEFAULT 1, summary TEXT NOT NULL, message_count INTEGER NOT NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (user_id) REFERENCES users(id) ); -- 도메인 소유권 테이블 CREATE TABLE IF NOT EXISTS user_domains ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL, domain TEXT UNIQUE NOT NULL, verified INTEGER DEFAULT 0, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (user_id) REFERENCES users(id) ); -- 예치금 계정 테이블 CREATE TABLE IF NOT EXISTS user_deposits ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL UNIQUE, balance INTEGER NOT NULL DEFAULT 0, version INTEGER NOT NULL DEFAULT 1, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (user_id) REFERENCES users(id) ); -- 은행 입금 알림 테이블 (SMS → 메일 → 파싱) CREATE TABLE IF NOT EXISTS bank_notifications ( id INTEGER PRIMARY KEY AUTOINCREMENT, bank_name TEXT, depositor_name TEXT NOT NULL, depositor_name_prefix TEXT, amount INTEGER NOT NULL, balance_after INTEGER, transaction_time DATETIME, raw_message TEXT, matched_transaction_id INTEGER, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (matched_transaction_id) REFERENCES deposit_transactions(id) ); -- 예치금 거래 내역 테이블 CREATE TABLE IF NOT EXISTS deposit_transactions ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL, type TEXT NOT NULL CHECK(type IN ('deposit', 'withdrawal', 'refund')), amount INTEGER NOT NULL, status TEXT NOT NULL DEFAULT 'pending' CHECK(status IN ('pending', 'confirmed', 'rejected', 'cancelled')), depositor_name TEXT, depositor_name_prefix TEXT, description TEXT, confirmed_at DATETIME, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (user_id) REFERENCES users(id) ); -- 서버 주문 테이블 CREATE TABLE IF NOT EXISTS server_orders ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL, telegram_user_id TEXT NOT NULL, spec_id INTEGER NOT NULL, region TEXT NOT NULL, label TEXT, price_paid INTEGER NOT NULL, status TEXT NOT NULL DEFAULT 'pending' CHECK(status IN ('pending', 'provisioning', 'active', 'failed', 'cancelled', 'terminated')), provider TEXT NOT NULL CHECK(provider IN ('linode', 'vultr', 'anvil')), provider_instance_id TEXT, ip_address TEXT, root_password TEXT, error_message TEXT, provisioned_at DATETIME, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP, idempotency_key TEXT UNIQUE, FOREIGN KEY (user_id) REFERENCES users(id) ); -- 사용자 서버 테이블 (활성 서버 관리) CREATE TABLE IF NOT EXISTS user_servers ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL, order_id INTEGER NOT NULL UNIQUE, provider TEXT NOT NULL, instance_id TEXT NOT NULL, label TEXT, ip_address TEXT, region TEXT, spec_label TEXT, monthly_price INTEGER, status TEXT NOT NULL DEFAULT 'active' CHECK(status IN ('active', 'stopped', 'terminated')), created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (user_id) REFERENCES users(id), FOREIGN KEY (order_id) REFERENCES server_orders(id) ); -- 서버 관리 세션 테이블 CREATE TABLE IF NOT EXISTS server_sessions ( user_id TEXT PRIMARY KEY, status TEXT NOT NULL DEFAULT 'idle', collected_info TEXT NOT NULL DEFAULT '{}', messages TEXT NOT NULL DEFAULT '[]', created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL, expires_at INTEGER NOT NULL ); -- 인덱스 CREATE INDEX IF NOT EXISTS idx_user_domains_user ON user_domains(user_id); CREATE INDEX IF NOT EXISTS idx_user_domains_domain ON user_domains(domain); CREATE INDEX IF NOT EXISTS idx_deposits_user ON user_deposits(user_id); CREATE INDEX IF NOT EXISTS idx_deposits_user_version ON user_deposits(user_id, version); CREATE INDEX IF NOT EXISTS idx_transactions_user ON deposit_transactions(user_id); CREATE INDEX IF NOT EXISTS idx_transactions_status ON deposit_transactions(status, created_at DESC); CREATE INDEX IF NOT EXISTS idx_transactions_prefix_pending ON deposit_transactions(status, type, depositor_name_prefix, amount, created_at) WHERE status = 'pending' AND type = 'deposit'; CREATE INDEX IF NOT EXISTS idx_bank_notifications_prefix_unmatched ON bank_notifications(depositor_name_prefix, amount, created_at DESC) WHERE matched_transaction_id IS NULL; CREATE INDEX IF NOT EXISTS idx_buffer_user ON message_buffer(user_id); CREATE INDEX IF NOT EXISTS idx_buffer_chat ON message_buffer(user_id, chat_id); CREATE INDEX IF NOT EXISTS idx_summary_user ON summaries(user_id, chat_id); CREATE INDEX IF NOT EXISTS idx_summary_latest ON summaries(user_id, chat_id, generation DESC); CREATE INDEX IF NOT EXISTS idx_users_telegram ON users(telegram_id); CREATE INDEX IF NOT EXISTS idx_server_orders_user ON server_orders(user_id); CREATE INDEX IF NOT EXISTS idx_server_orders_status ON server_orders(status); CREATE INDEX IF NOT EXISTS idx_server_orders_idempotency ON server_orders(idempotency_key) WHERE idempotency_key IS NOT NULL; CREATE INDEX IF NOT EXISTS idx_user_servers_user ON user_servers(user_id); CREATE INDEX IF NOT EXISTS idx_user_servers_status ON user_servers(status); CREATE INDEX IF NOT EXISTS idx_server_sessions_expires ON server_sessions(expires_at);