WBS-9 진행: API 에러 수정 및 DB 스키마 정규화
- snapshot_admin_store_v1.py: summarize_workspace에서 account_snapshot의 captured_at 사용 (updated_at 대신) - account_snapshot 테이블: 올바른 스키마 재정의 (ordinal PK, row_json, 핵심필드, updated_at) - settings 테이블: 올바른 스키마 재정의 (ordinal PK, key, value_json, note, updated_at) - initialize_snapshot_admin_db.py: XLSX에서 settings, account_snapshot을 올바른 스키마로 로드 - load_from_xlsx_correct.py: account_snapshot을 특별 처리해서 스키마 보존 - /api/settings/save: 정상 작동 (200 응답) - build_ui_state: load_collection_dashboard_state 예외 처리 추가 (진행 중) 데이터 현황: - kis_data_collection.db: 1 테이블 (data_feed), 25행 - snapshot_admin.db: 27 테이블, 7,501행 * settings: 32행 (올바른 스키마) * account_snapshot: 44행 (올바른 스키마) 남은 작업: - /api/state 크래시 원인 진단 및 수정 - /api/export 데이터 검증 - 웹 UI 개선 (백오피스 수준) - T+20 모니터링 활성화 - CI/CD 백업 기능 Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
account_snapshot 테이블 스키마 수정
|
||||
last_updated -> updated_at
|
||||
"""
|
||||
|
||||
import sqlite3
|
||||
from pathlib import Path
|
||||
|
||||
def fix_account_snapshot_schema():
|
||||
"""account_snapshot 테이블 스키마 수정"""
|
||||
|
||||
db_path = Path('src/quant_engine/snapshot_admin.db')
|
||||
conn = sqlite3.connect(db_path)
|
||||
conn.row_factory = sqlite3.Row
|
||||
cursor = conn.cursor()
|
||||
|
||||
# 현재 컬럼 확인
|
||||
cursor.execute("PRAGMA table_info(account_snapshot)")
|
||||
current_cols = {col[1]: col[2] for col in cursor.fetchall()}
|
||||
print(f"현재 컬럼: {list(current_cols.keys())}")
|
||||
|
||||
# 데이터 백업
|
||||
cursor.execute("SELECT * FROM account_snapshot LIMIT 1")
|
||||
sample = cursor.fetchone()
|
||||
print(f"\n샘플 행 컬럼: {sample.keys() if sample else 'NO DATA'}")
|
||||
|
||||
# account_snapshot 데이터 백업
|
||||
cursor.execute("SELECT * FROM account_snapshot")
|
||||
backup = cursor.fetchall()
|
||||
print(f"백업 행 수: {len(backup)}")
|
||||
|
||||
# 기존 테이블 삭제
|
||||
cursor.execute("DROP TABLE IF EXISTS account_snapshot")
|
||||
|
||||
# 올바른 스키마로 생성
|
||||
cursor.execute("""
|
||||
CREATE TABLE account_snapshot (
|
||||
ordinal INTEGER NOT NULL,
|
||||
row_json TEXT NOT NULL,
|
||||
captured_at TEXT NOT NULL DEFAULT '',
|
||||
account TEXT NOT NULL DEFAULT '',
|
||||
account_type TEXT NOT NULL DEFAULT '',
|
||||
ticker TEXT NOT NULL DEFAULT '',
|
||||
name TEXT NOT NULL DEFAULT '',
|
||||
parse_status TEXT NOT NULL DEFAULT '',
|
||||
user_confirmed TEXT NOT NULL DEFAULT '',
|
||||
updated_at TEXT NOT NULL
|
||||
)
|
||||
""")
|
||||
|
||||
cursor.execute("CREATE INDEX IF NOT EXISTS idx_account_snapshot_captured_at ON account_snapshot(captured_at)")
|
||||
cursor.execute("CREATE INDEX IF NOT EXISTS idx_account_snapshot_ticker ON account_snapshot(ticker)")
|
||||
|
||||
print("\n새 스키마 생성:")
|
||||
print(" ordinal INTEGER NOT NULL")
|
||||
print(" row_json TEXT NOT NULL")
|
||||
print(" captured_at TEXT NOT NULL DEFAULT ''")
|
||||
print(" account TEXT NOT NULL DEFAULT ''")
|
||||
print(" account_type TEXT NOT NULL DEFAULT ''")
|
||||
print(" ticker TEXT NOT NULL DEFAULT ''")
|
||||
print(" name TEXT NOT NULL DEFAULT ''")
|
||||
print(" parse_status TEXT NOT NULL DEFAULT ''")
|
||||
print(" user_confirmed TEXT NOT NULL DEFAULT ''")
|
||||
print(" updated_at TEXT NOT NULL")
|
||||
|
||||
# 데이터 복원
|
||||
if backup:
|
||||
print(f"\n데이터 복원 중: {len(backup)}개 행")
|
||||
|
||||
for row_dict in backup:
|
||||
# row_dict는 sqlite3.Row 타입
|
||||
values = []
|
||||
for col_name in [
|
||||
'ordinal', 'row_json', 'captured_at', 'account', 'account_type',
|
||||
'ticker', 'name', 'parse_status', 'user_confirmed'
|
||||
]:
|
||||
if col_name in row_dict.keys():
|
||||
values.append(row_dict[col_name])
|
||||
else:
|
||||
values.append(None)
|
||||
|
||||
# updated_at: last_updated 또는 captured_at 사용
|
||||
if 'last_updated' in row_dict.keys() and row_dict['last_updated']:
|
||||
values.append(str(row_dict['last_updated']))
|
||||
elif 'captured_at' in row_dict.keys() and row_dict['captured_at']:
|
||||
values.append(str(row_dict['captured_at']))
|
||||
else:
|
||||
values.append('')
|
||||
|
||||
cursor.execute("""
|
||||
INSERT INTO account_snapshot (
|
||||
ordinal, row_json, captured_at, account, account_type, ticker, name,
|
||||
parse_status, user_confirmed, updated_at
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""", values)
|
||||
|
||||
conn.commit()
|
||||
print(f"[OK] {len(backup)}개 행 복원")
|
||||
else:
|
||||
conn.commit()
|
||||
print("[OK] 테이블 생성 (데이터 없음)")
|
||||
|
||||
# 검증
|
||||
cursor.execute("SELECT COUNT(*) FROM account_snapshot")
|
||||
count = cursor.fetchone()[0]
|
||||
print(f"\n검증: {count}개 행")
|
||||
|
||||
cursor.execute("PRAGMA table_info(account_snapshot)")
|
||||
new_cols = {col[1]: col[2] for col in cursor.fetchall()}
|
||||
print(f"새 컬럼: {list(new_cols.keys())}")
|
||||
|
||||
conn.close()
|
||||
|
||||
print("\n[OK] account_snapshot 테이블 스키마 수정 완료")
|
||||
|
||||
if __name__ == "__main__":
|
||||
fix_account_snapshot_schema()
|
||||
Reference in New Issue
Block a user