| name | xianwen-db-ops |
| description | Database operations for Xianwen Online: Neon PostgreSQL queries, migrations, data cleanup, player data deletion, and schema management. Use when user needs database operations, migration fixes, data cleanup, or says '清空資料庫', '刪除玩家', 'migration'. |
Xianwen Database Operations
Database management workflow for Neon PostgreSQL, extracted from 50+ database operation sessions.
Database Connection
- Provider: Neon (managed PostgreSQL)
- Region: ap-southeast-1 (Singapore)
- Connection: Via pooler with SSL required
- ORM: SQLx (Rust, compile-time checked queries)
Migration Management
Location
server/migrations/ — Currently 136+ migration files
Creating New Migrations
Migration Best Practices
- Always use
IF NOT EXISTS / IF EXISTS for safety
- Add columns as nullable first, then backfill, then add constraints
- Never drop columns in production without a deprecation period
- Use
ON CONFLICT for upsert operations
Common Migration Issues
| Issue | Solution |
|---|
| Column already exists | Use ALTER TABLE ... ADD COLUMN IF NOT EXISTS |
| ON CONFLICT without unique constraint | Add unique/exclusion constraint first |
| Migration applied but data missing | Write separate data migration SQL |
| Production schema out of sync | SSH to server, check applied migrations |
Common Operations
Delete Player Data
DELETE FROM player_inventory WHERE character_id IN (SELECT id FROM characters WHERE user_id = '<user_id>');
DELETE FROM player_techniques WHERE character_id IN (SELECT id FROM characters WHERE user_id = '<user_id>');
DELETE FROM player_quests WHERE character_id IN (SELECT id FROM characters WHERE user_id = '<user_id>');
DELETE FROM characters WHERE user_id = '<user_id>';
DELETE FROM users WHERE id = '<user_id>';
Clear All Player Data (Development)
TRUNCATE characters, player_inventory, player_techniques, player_quests,
player_equipment, player_pets, player_achievements CASCADE;
Data Integrity Checks
SELECT * FROM player_techniques WHERE character_id NOT IN (SELECT id FROM characters);
SELECT s.name, COUNT(sm.id) FROM sects s LEFT JOIN sect_members sm ON s.id = sm.sect_id GROUP BY s.name;
SELECT name, current_location FROM npcs WHERE current_location IS NULL;
SQLx Workflow
After Schema Changes
- Create migration file
- Run
cargo sqlx prepare to update offline query metadata
- Commit the
.sqlx/ directory changes
- Deploy server (migration runs automatically on startup)
Query Patterns
let character = sqlx::query_as!(Character, "SELECT * FROM characters WHERE id = $1", id)
.fetch_optional(&pool)
.await?;
Safety Rules
- NEVER run destructive queries without explicit user confirmation
- ALWAYS use transactions for multi-table operations
- ALWAYS backup before bulk operations (pg_dump)
- NEVER expose connection strings in code — use environment variables
- Check
ON CONFLICT specs match existing unique constraints