fix(schema): 입금자명 길이 제한 50자 → 15자로 조정

근거:
- SMS 입금자명: 한글 7자 제한 (은행 시스템)
- 사용자 수동 입력: 15자로 충분한 여유
- 매칭 로직: 앞 7자만 사용

변경사항:
- CHECK (length(depositor_name) <= 50) → 15
- 데이터 복원 시 truncate: 50자 → 15자
- SCHEMA_MIGRATION_GUIDE.md 업데이트
- MIGRATION_SUMMARY.md 업데이트

로컬 테스트 결과:
-  15자 이하: 정상 입력
  - 숫자 15자: "123456789012345" ✓
  - 한글 15자: "홍길동아버지어머니할머님고모고" ✓
-  16자 이상: 거부됨
  - 숫자 16자: "1234567890123456" ✗ (CHECK 제약조건)
  - 한글 16자: "홍길동아버지어머니할머님고모고모" ✗ (CHECK 제약조건)

실용성:
- SMS 7자 보장 + 사용자 입력 여유
- 불필요한 긴 이름 방지
- 매칭 로직과 완벽 호환

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
kappa
2026-01-19 16:02:18 +09:00
parent 04dcb57fae
commit 4a0499890a
3 changed files with 16 additions and 16 deletions

View File

@@ -13,7 +13,7 @@ Database migration to add critical data integrity constraints and audit logging
| Component | Change | Impact | | Component | Change | Impact |
|-----------|--------|--------| |-----------|--------|--------|
| `user_deposits.balance` | Add CHECK (balance >= 0) | Prevents negative balances | | `user_deposits.balance` | Add CHECK (balance >= 0) | Prevents negative balances |
| `deposit_transactions.depositor_name` | Add CHECK (length <= 50) | Enforces name length limit | | `deposit_transactions.depositor_name` | Add CHECK (length <= 15) | Enforces name length limit |
| `audit_logs` | New table | Tracks all critical operations | | `audit_logs` | New table | Tracks all critical operations |
### Risk Assessment ### Risk Assessment
@@ -50,7 +50,7 @@ telegram-bot-workers/
- [ ] Read `SCHEMA_MIGRATION_GUIDE.md` completely - [ ] Read `SCHEMA_MIGRATION_GUIDE.md` completely
- [ ] Backup production database - [ ] Backup production database
- [ ] Check for negative balances in production - [ ] Check for negative balances in production
- [ ] Check for long depositor names (> 50 chars) in production - [ ] Check for long depositor names (> 15 chars) in production
- [ ] Verify rollback script is accessible - [ ] Verify rollback script is accessible
- [ ] Schedule deployment window (< 5 min) - [ ] Schedule deployment window (< 5 min)
- [ ] Notify stakeholders (optional) - [ ] Notify stakeholders (optional)
@@ -209,18 +209,18 @@ balance INTEGER NOT NULL DEFAULT 0 CHECK (balance >= 0)
CHECK constraint failed: balance >= 0 CHECK constraint failed: balance >= 0
``` ```
### Depositor Name Length <= 50 (deposit_transactions) ### Depositor Name Length <= 15 (deposit_transactions)
**Why**: Bank SMS truncates names at 7 chars, but we allow 50 for edge cases **Why**: Bank SMS truncates names at 7 chars, but we allow 15 for flexibility
**Implementation**: **Implementation**:
```sql ```sql
depositor_name TEXT CHECK (length(depositor_name) <= 50) depositor_name TEXT CHECK (length(depositor_name) <= 15)
``` ```
**Effect**: Names longer than 50 chars will be rejected: **Effect**: Names longer than 50 chars will be rejected:
``` ```
CHECK constraint failed: length(depositor_name) <= 50 CHECK constraint failed: length(depositor_name) <= 15
``` ```
--- ---
@@ -282,7 +282,7 @@ wrangler d1 execute telegram-conversations \
# Check for long names # Check for long names
wrangler d1 execute telegram-conversations \ wrangler d1 execute telegram-conversations \
--command "SELECT id, depositor_name, length(depositor_name) as len --command "SELECT id, depositor_name, length(depositor_name) as len
FROM deposit_transactions WHERE length(depositor_name) > 50" FROM deposit_transactions WHERE length(depositor_name) > 15"
``` ```
3. **Prepare Backup** 3. **Prepare Backup**

View File

@@ -13,7 +13,7 @@ This migration adds critical data integrity constraints and audit logging capabi
| Change | Purpose | Risk Level | | Change | Purpose | Risk Level |
|--------|---------|------------| |--------|---------|------------|
| `user_deposits.balance` CHECK constraint | Prevent negative balances | Medium | | `user_deposits.balance` CHECK constraint | Prevent negative balances | Medium |
| `deposit_transactions.depositor_name` length limit | Enforce 50 character max | Low | | `deposit_transactions.depositor_name` length limit | Enforce 15 character max | Low |
| `audit_logs` table | Track all important operations | None (new table) | | `audit_logs` table | Track all important operations | None (new table) |
--- ---
@@ -46,20 +46,20 @@ INSERT INTO user_deposits (user_id, balance) VALUES (999999, -1000);
### 2. Depositor Name Length (`deposit_transactions`) ### 2. Depositor Name Length (`deposit_transactions`)
**Goal**: Limit `depositor_name` to 50 characters max **Goal**: Limit `depositor_name` to 15 characters max
**Implementation**: **Implementation**:
```sql ```sql
CREATE TABLE deposit_transactions ( CREATE TABLE deposit_transactions (
... ...
depositor_name TEXT CHECK (length(depositor_name) <= 50), depositor_name TEXT CHECK (length(depositor_name) <= 15),
... ...
); );
``` ```
**Impact**: **Impact**:
- ✅ Prevents excessively long names - ✅ Prevents excessively long names
- 📏 Truncates existing names >50 chars (logs truncated records) - 📏 Truncates existing names >15 chars (logs truncated records)
- 🔧 Requires table recreation (SQLite limitation) - 🔧 Requires table recreation (SQLite limitation)
**Verification**: **Verification**:
@@ -137,7 +137,7 @@ wrangler d1 execute telegram-conversations \
# Check for long depositor names (will be truncated) # Check for long depositor names (will be truncated)
wrangler d1 execute telegram-conversations \ wrangler d1 execute telegram-conversations \
--command "SELECT id, depositor_name, length(depositor_name) as len FROM deposit_transactions WHERE length(depositor_name) > 50" --command "SELECT id, depositor_name, length(depositor_name) as len FROM deposit_transactions WHERE length(depositor_name) > 15"
``` ```
### 3. Notify Users (if downtime expected) ### 3. Notify Users (if downtime expected)
@@ -496,7 +496,7 @@ wrangler d1 execute telegram-conversations \
After migration, verify: After migration, verify:
- [ ] All user_deposits records have `balance >= 0` - [ ] All user_deposits records have `balance >= 0`
- [ ] All deposit_transactions have `depositor_name` length <= 50 - [ ] All deposit_transactions have `depositor_name` length <= 15
- [ ] audit_logs table exists with correct schema - [ ] audit_logs table exists with correct schema
- [ ] All indexes recreated successfully - [ ] All indexes recreated successfully
- [ ] Record counts match pre-migration - [ ] Record counts match pre-migration

View File

@@ -59,7 +59,7 @@ CREATE TABLE deposit_transactions (
type TEXT NOT NULL CHECK(type IN ('deposit', 'withdrawal', 'refund')), type TEXT NOT NULL CHECK(type IN ('deposit', 'withdrawal', 'refund')),
amount INTEGER NOT NULL, amount INTEGER NOT NULL,
status TEXT NOT NULL DEFAULT 'pending' CHECK(status IN ('pending', 'confirmed', 'rejected', 'cancelled')), status TEXT NOT NULL DEFAULT 'pending' CHECK(status IN ('pending', 'confirmed', 'rejected', 'cancelled')),
depositor_name TEXT CHECK (length(depositor_name) <= 50), depositor_name TEXT CHECK (length(depositor_name) <= 15),
description TEXT, description TEXT,
confirmed_at DATETIME, confirmed_at DATETIME,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP, created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
@@ -78,7 +78,7 @@ SELECT
status, status,
CASE CASE
WHEN depositor_name IS NULL THEN NULL WHEN depositor_name IS NULL THEN NULL
WHEN length(depositor_name) > 50 THEN substr(depositor_name, 1, 50) WHEN length(depositor_name) > 15 THEN substr(depositor_name, 1, 15)
ELSE depositor_name ELSE depositor_name
END as depositor_name, END as depositor_name,
description, description,
@@ -89,7 +89,7 @@ FROM deposit_transactions_backup;
-- 2.5 Log truncated records (if any) -- 2.5 Log truncated records (if any)
SELECT 'TRUNCATED DEPOSITOR NAME:' as warning, id, depositor_name, length(depositor_name) as original_length SELECT 'TRUNCATED DEPOSITOR NAME:' as warning, id, depositor_name, length(depositor_name) as original_length
FROM deposit_transactions_backup FROM deposit_transactions_backup
WHERE depositor_name IS NOT NULL AND length(depositor_name) > 50; WHERE depositor_name IS NOT NULL AND length(depositor_name) > 15;
-- 2.6 Drop backup table -- 2.6 Drop backup table
DROP TABLE deposit_transactions_backup; DROP TABLE deposit_transactions_backup;