chore: add server provisioning migrations
- 003_add_server_tables.sql: server_orders, server_instances tables - 003_server_sessions.sql: KV-based session tracking - 004_add_terminated_at.sql: track instance termination time Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
161
migrations/003_MIGRATION_NOTES.md
Normal file
161
migrations/003_MIGRATION_NOTES.md
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
# Migration 003: Server Sessions from KV to D1
|
||||||
|
|
||||||
|
**Date**: 2026-01-28
|
||||||
|
**Type**: Session Storage Migration
|
||||||
|
**Status**: Ready to Deploy
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
Migrated server consultation session management from KV Namespace to D1 Database for better consistency, reliability, and integrated data management.
|
||||||
|
|
||||||
|
## Changes Summary
|
||||||
|
|
||||||
|
### 1. Database Schema (`schema.sql` + `migrations/003_server_sessions_d1.sql`)
|
||||||
|
|
||||||
|
**New Table**: `server_sessions`
|
||||||
|
```sql
|
||||||
|
CREATE TABLE IF NOT EXISTS server_sessions (
|
||||||
|
user_id TEXT PRIMARY KEY,
|
||||||
|
status TEXT NOT NULL CHECK(status IN ('gathering', 'recommending', 'selecting', 'ordering', 'completed')),
|
||||||
|
collected_info TEXT,
|
||||||
|
last_recommendation TEXT,
|
||||||
|
messages TEXT,
|
||||||
|
created_at INTEGER NOT NULL,
|
||||||
|
updated_at INTEGER NOT NULL,
|
||||||
|
expires_at INTEGER NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_server_sessions_expires ON server_sessions(expires_at);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Code Changes
|
||||||
|
|
||||||
|
**Updated Files**:
|
||||||
|
- `/src/server-agent.ts` - Session management functions (getServerSession, saveServerSession, deleteServerSession)
|
||||||
|
- `/src/openai-service.ts` - Session check in generateOpenAIResponse()
|
||||||
|
- `/src/tools/server-tool.ts` - start_consultation, continue_consultation, cancel_consultation actions
|
||||||
|
- `/src/routes/handlers/callback-handler.ts` - server_order and server_cancel callbacks
|
||||||
|
|
||||||
|
**Function Signature Changes**:
|
||||||
|
```typescript
|
||||||
|
// Before (KV)
|
||||||
|
export async function getServerSession(kv: KVNamespace, userId: string): Promise<ServerSession | null>
|
||||||
|
export async function saveServerSession(kv: KVNamespace, userId: string, session: ServerSession): Promise<void>
|
||||||
|
export async function deleteServerSession(kv: KVNamespace, userId: string): Promise<void>
|
||||||
|
|
||||||
|
// After (D1)
|
||||||
|
export async function getServerSession(db: D1Database, userId: string): Promise<ServerSession | null>
|
||||||
|
export async function saveServerSession(db: D1Database, userId: string, session: ServerSession): Promise<void>
|
||||||
|
export async function deleteServerSession(db: D1Database, userId: string): Promise<void>
|
||||||
|
|
||||||
|
// New
|
||||||
|
export async function cleanupExpiredSessions(db: D1Database): Promise<number>
|
||||||
|
```
|
||||||
|
|
||||||
|
**Removed**:
|
||||||
|
- All `[SESSION DEBUG]` logging (unnecessary with D1's strong consistency)
|
||||||
|
- KV constants: `SESSION_TTL`, `SESSION_KEY_PREFIX`
|
||||||
|
|
||||||
|
**Added**:
|
||||||
|
- `SESSION_TTL_MS` constant (3600 * 1000 = 1 hour)
|
||||||
|
- `cleanupExpiredSessions()` function for cron cleanup
|
||||||
|
- Automatic expiry checking in queries (`WHERE expires_at > ?`)
|
||||||
|
|
||||||
|
### 3. Key Implementation Details
|
||||||
|
|
||||||
|
**Session Storage**:
|
||||||
|
- JSON serialization for complex fields (collected_info, last_recommendation, messages)
|
||||||
|
- Automatic TTL management with expires_at column
|
||||||
|
- Strong consistency (no eventual consistency issues)
|
||||||
|
|
||||||
|
**Error Handling**:
|
||||||
|
- Graceful JSON parsing with try-catch
|
||||||
|
- Null checks for expired/missing sessions
|
||||||
|
- Proper logging without debug noise
|
||||||
|
|
||||||
|
**Performance**:
|
||||||
|
- Primary key on user_id for fast lookups
|
||||||
|
- Index on expires_at for efficient cleanup
|
||||||
|
- Single query for session retrieval
|
||||||
|
|
||||||
|
### 4. Migration Path
|
||||||
|
|
||||||
|
**Automatic Migration**:
|
||||||
|
- Old KV sessions will expire naturally (1 hour TTL)
|
||||||
|
- New sessions are created in D1 automatically
|
||||||
|
- No manual data migration needed
|
||||||
|
|
||||||
|
**Zero Downtime**:
|
||||||
|
- D1 table creation is idempotent (IF NOT EXISTS)
|
||||||
|
- Code handles missing sessions gracefully
|
||||||
|
- Users can restart consultation if session expires
|
||||||
|
|
||||||
|
### 5. Benefits
|
||||||
|
|
||||||
|
**Before (KV Namespace)**:
|
||||||
|
- Eventual consistency (delayed reads)
|
||||||
|
- Complex debugging (async replication)
|
||||||
|
- Separate data store (fragmented)
|
||||||
|
- Manual cleanup needed
|
||||||
|
|
||||||
|
**After (D1 Database)**:
|
||||||
|
- Strong consistency (immediate reads)
|
||||||
|
- Simple debugging (SQL queries)
|
||||||
|
- Integrated storage (single database)
|
||||||
|
- Automatic cleanup (expires_at + cron)
|
||||||
|
|
||||||
|
### 6. Deployment Steps
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Apply migration (creates table)
|
||||||
|
wrangler d1 execute telegram-conversations --file=migrations/003_server_sessions_d1.sql
|
||||||
|
|
||||||
|
# 2. Verify table creation
|
||||||
|
wrangler d1 execute telegram-conversations --command "SELECT name FROM sqlite_master WHERE type='table' AND name='server_sessions'"
|
||||||
|
|
||||||
|
# 3. Deploy code changes
|
||||||
|
npm run deploy
|
||||||
|
|
||||||
|
# 4. Test server consultation flow
|
||||||
|
# Send message: "서버 추천"
|
||||||
|
# Verify session is created in D1
|
||||||
|
wrangler d1 execute telegram-conversations --command "SELECT * FROM server_sessions LIMIT 5"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7. Rollback Plan
|
||||||
|
|
||||||
|
If issues occur:
|
||||||
|
|
||||||
|
1. **Code Rollback**: Revert to previous commit (KV-based code)
|
||||||
|
2. **Database**: Drop table if needed
|
||||||
|
```sql
|
||||||
|
DROP TABLE IF EXISTS server_sessions;
|
||||||
|
DROP INDEX IF EXISTS idx_server_sessions_expires;
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note**: Old KV sessions are unaffected (will expire naturally)
|
||||||
|
|
||||||
|
### 8. Testing Checklist
|
||||||
|
|
||||||
|
- [x] Migration SQL syntax validated
|
||||||
|
- [x] Schema.sql updated
|
||||||
|
- [x] All code references updated (env.SESSION_KV → env.DB)
|
||||||
|
- [x] Logging cleaned up (no debug noise)
|
||||||
|
- [ ] Local testing (`npm run dev`)
|
||||||
|
- [ ] Production deployment
|
||||||
|
- [ ] Session creation test
|
||||||
|
- [ ] Session retrieval test
|
||||||
|
- [ ] Session expiry test
|
||||||
|
- [ ] Concurrent session handling
|
||||||
|
|
||||||
|
### 9. Notes
|
||||||
|
|
||||||
|
**Important**:
|
||||||
|
- `server_order_confirm:` and `delete_confirm:` sessions remain in KV (not migrated, separate feature)
|
||||||
|
- Troubleshoot agent still uses KV (separate migration needed if required)
|
||||||
|
- D1 binding (`env.DB`) already exists in project
|
||||||
|
|
||||||
|
**Future Improvements**:
|
||||||
|
- Consider migrating troubleshoot sessions to D1
|
||||||
|
- Add session analytics (query D1 for session stats)
|
||||||
|
- Implement session history/audit log
|
||||||
54
migrations/003_add_server_tables.sql
Normal file
54
migrations/003_add_server_tables.sql
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
-- Migration 003: Add server provisioning tables
|
||||||
|
-- Date: 2026-01-28
|
||||||
|
-- Description: Add server_orders and user_servers tables for Queue-based server provisioning
|
||||||
|
|
||||||
|
-- Server orders table (provisioning requests)
|
||||||
|
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 TEXT NOT NULL, -- 서버 스펙 ID (plan_name)
|
||||||
|
region TEXT NOT NULL, -- 리전 코드
|
||||||
|
label TEXT, -- 서버 라벨 (선택)
|
||||||
|
price_paid INTEGER NOT NULL, -- 지불 금액 (원)
|
||||||
|
status TEXT NOT NULL DEFAULT 'pending', -- pending, provisioning, completed, failed, refunded
|
||||||
|
provider TEXT NOT NULL, -- anvil
|
||||||
|
instance_id TEXT, -- 생성된 인스턴스 ID
|
||||||
|
ip_address TEXT, -- 할당된 IP
|
||||||
|
root_password TEXT, -- 초기 root 비밀번호 (암호화 권장)
|
||||||
|
error_message TEXT, -- 실패 시 에러 메시지
|
||||||
|
provisioned_at DATETIME, -- 프로비저닝 완료 시각
|
||||||
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
FOREIGN KEY (user_id) REFERENCES users(id)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- User servers table (active servers)
|
||||||
|
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,
|
||||||
|
spec_id TEXT NOT NULL,
|
||||||
|
region TEXT NOT NULL,
|
||||||
|
ip_address TEXT,
|
||||||
|
status TEXT NOT NULL DEFAULT 'running', -- running, stopped, deleted
|
||||||
|
monthly_price INTEGER NOT NULL,
|
||||||
|
expires_at DATETIME, -- 다음 결제일
|
||||||
|
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)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Indexes for server_orders
|
||||||
|
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_telegram ON server_orders(telegram_user_id);
|
||||||
|
|
||||||
|
-- Indexes for user_servers
|
||||||
|
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_user_servers_instance ON user_servers(provider, instance_id);
|
||||||
17
migrations/003_server_sessions.sql
Normal file
17
migrations/003_server_sessions.sql
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
-- Server consultation sessions table
|
||||||
|
CREATE TABLE IF NOT EXISTS server_sessions (
|
||||||
|
user_id TEXT PRIMARY KEY,
|
||||||
|
status TEXT NOT NULL DEFAULT 'gathering',
|
||||||
|
collected_info TEXT, -- JSON
|
||||||
|
last_recommendation TEXT, -- JSON
|
||||||
|
messages TEXT, -- JSON
|
||||||
|
created_at INTEGER NOT NULL,
|
||||||
|
updated_at INTEGER NOT NULL,
|
||||||
|
expires_at INTEGER NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Index for cleanup job
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_sessions_expires ON server_sessions(expires_at);
|
||||||
|
|
||||||
|
-- Index for status queries
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_sessions_status ON server_sessions(user_id, status);
|
||||||
21
migrations/003_server_sessions_d1.sql
Normal file
21
migrations/003_server_sessions_d1.sql
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
-- Migration 003: Server Sessions to D1 Database
|
||||||
|
-- Migrate server session management from KV Namespace to D1 Database
|
||||||
|
-- Date: 2026-01-28
|
||||||
|
|
||||||
|
-- Create server_sessions table
|
||||||
|
CREATE TABLE IF NOT EXISTS server_sessions (
|
||||||
|
user_id TEXT PRIMARY KEY,
|
||||||
|
status TEXT NOT NULL CHECK(status IN ('gathering', 'recommending', 'selecting', 'ordering', 'completed')),
|
||||||
|
collected_info TEXT,
|
||||||
|
last_recommendation TEXT,
|
||||||
|
messages TEXT,
|
||||||
|
created_at INTEGER NOT NULL,
|
||||||
|
updated_at INTEGER NOT NULL,
|
||||||
|
expires_at INTEGER NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Create index for expiry cleanup
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_server_sessions_expires ON server_sessions(expires_at);
|
||||||
|
|
||||||
|
-- Note: Existing KV sessions will be automatically migrated on first access
|
||||||
|
-- Old sessions in KV will expire naturally (1 hour TTL)
|
||||||
5
migrations/004_add_terminated_at.sql
Normal file
5
migrations/004_add_terminated_at.sql
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
-- Migration 004: Add terminated_at column
|
||||||
|
-- Date: 2026-01-28
|
||||||
|
-- Description: Add terminated_at column for server termination tracking
|
||||||
|
|
||||||
|
ALTER TABLE server_orders ADD COLUMN terminated_at DATETIME;
|
||||||
Reference in New Issue
Block a user