데이터 및 API 오류 진단: settings 스키마 수정 진행 중
### 완료 작업 1. load_from_xlsx_correct.py 개선 - settings 특수 처리 추가 (헤더 없는 key-value 형식) - 모든 시트 정확히 로드 (32 rows settings 포함) 2. settings 테이블 스키마 수정 도구 - fix_settings_schema.py 생성 - 올바른 스키마: ordinal, key, value_json, note, updated_at - 32개 설정값 복원 ### 진행 중 문제 - /api/settings/save: 500 Internal Server Error 원인: validate_settings_rows 검증 실패 가능성 해결: _load_settings_spec() 확인 및 validate 규칙 검토 필요 - /api/state, /api/export: 타임아웃 원인: 쿼리 성능 또는 대용량 데이터 해결: 인덱스 추가 또는 쿼리 최적화 필요 ### 데이터 상태 - XLSX: 20개 시트 - DB: 27개 테이블 (kis: 1, snapshot: 26) - 총 7,484 rows - settings: 32 rows (올바른 스키마로 수정) ### 다음 단계 (우선순위) 1. settings 저장 API 500 에러 해결 - validate_settings_rows 검증 규칙 확인 - _load_settings_spec() 정의 확인 2. /api/state, /api/export 타임아웃 해결 - 느린 쿼리 식별 및 최적화 3. performance, positions 테이블 초기 데이터 입력 - T+20 모니터링 활성화 Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
settings 테이블 스키마 수정
|
||||
올바른 스키마: ordinal, key, value_json, note, updated_at
|
||||
"""
|
||||
|
||||
import sqlite3
|
||||
import json
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
|
||||
def fix_settings_schema():
|
||||
"""settings 테이블 스키마 수정"""
|
||||
|
||||
db_path = Path('src/quant_engine/snapshot_admin.db')
|
||||
conn = sqlite3.connect(db_path)
|
||||
cursor = conn.cursor()
|
||||
|
||||
# 현재 settings 데이터 백업
|
||||
cursor.execute("SELECT * FROM settings")
|
||||
current_rows = cursor.fetchall()
|
||||
|
||||
print(f"현재 settings: {len(current_rows)}개 행")
|
||||
|
||||
# 현재 컬럼 확인
|
||||
cursor.execute("PRAGMA table_info(settings)")
|
||||
current_cols = cursor.fetchall()
|
||||
print(f"현재 컬럼: {[col[1] for col in current_cols]}")
|
||||
|
||||
# 기존 테이블 삭제
|
||||
cursor.execute("DROP TABLE IF EXISTS settings")
|
||||
|
||||
# 올바른 스키마로 생성
|
||||
cursor.execute("""
|
||||
CREATE TABLE settings (
|
||||
ordinal INTEGER PRIMARY KEY,
|
||||
key TEXT NOT NULL,
|
||||
value_json TEXT NOT NULL,
|
||||
note TEXT DEFAULT '',
|
||||
updated_at TEXT NOT NULL
|
||||
)
|
||||
""")
|
||||
|
||||
print("\n새 스키마 생성:")
|
||||
print(" ordinal INTEGER PRIMARY KEY")
|
||||
print(" key TEXT NOT NULL")
|
||||
print(" value_json TEXT NOT NULL")
|
||||
print(" note TEXT DEFAULT ''")
|
||||
print(" updated_at TEXT NOT NULL")
|
||||
|
||||
# 데이터 복원
|
||||
# 현재 컬럼: [key, value]
|
||||
timestamp = datetime.now().isoformat()
|
||||
|
||||
inserted = 0
|
||||
for ordinal, (key, value) in enumerate(current_rows, start=1):
|
||||
# value를 JSON으로 변환
|
||||
try:
|
||||
value_json = json.dumps(str(value), ensure_ascii=False)
|
||||
except:
|
||||
value_json = json.dumps("", ensure_ascii=False)
|
||||
|
||||
cursor.execute(
|
||||
"""INSERT INTO settings (ordinal, key, value_json, note, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?)""",
|
||||
(ordinal, key, value_json, "", timestamp)
|
||||
)
|
||||
inserted += 1
|
||||
|
||||
conn.commit()
|
||||
|
||||
# 검증
|
||||
cursor.execute("SELECT COUNT(*) FROM settings")
|
||||
count = cursor.fetchone()[0]
|
||||
print(f"\n복원된 settings: {count}개 행")
|
||||
|
||||
# 샘플 확인
|
||||
cursor.execute("SELECT ordinal, key, value_json FROM settings LIMIT 3")
|
||||
print("\n샘플 데이터:")
|
||||
for ordinal, key, value_json in cursor.fetchall():
|
||||
value = json.loads(value_json)
|
||||
print(f" {ordinal}. {key} = {value}")
|
||||
|
||||
conn.close()
|
||||
|
||||
print("\n[OK] settings 테이블 스키마 수정 완료")
|
||||
|
||||
if __name__ == "__main__":
|
||||
fix_settings_schema()
|
||||
@@ -49,7 +49,13 @@ class CorrectXLSXLoader:
|
||||
header_param = header_row_1based - 1 # pandas는 0-indexed
|
||||
|
||||
try:
|
||||
df = pd.read_excel(self.xlsx_file, sheet_name=sheet_name, header=header_param)
|
||||
# settings 특수 처리: 헤더가 없음 (key-value 쌍)
|
||||
if sheet_name == 'settings':
|
||||
df = pd.read_excel(self.xlsx_file, sheet_name=sheet_name, header=None)
|
||||
df.columns = ['key', 'value', 'note1', 'note2']
|
||||
df = df[['key', 'value']] # 필요한 컬럼만
|
||||
else:
|
||||
df = pd.read_excel(self.xlsx_file, sheet_name=sheet_name, header=header_param)
|
||||
|
||||
# NaN을 None으로 변환
|
||||
df = df.where(pd.notna(df), None)
|
||||
|
||||
Reference in New Issue
Block a user