headscale-tailscale-replace.../TROUBLESHOOTING_DATABASE_FOREIGN_KEY.md
시골약사 ca61a89739 🏥 Add complete FARMQ Admin Flask application
## Features
- 한국어 Flask 관리 인터페이스 with Bootstrap 5
- Headscale과 분리된 독립 데이터베이스 구조
- 약국 관리 시스템 (pharmacy management)
- 머신 모니터링 및 상태 관리
- 실시간 대시보드 with 통계 및 알림
- Headscale 사용자명과 약국명 분리 관리

## Database Architecture
- 별도 FARMQ SQLite DB (farmq.sqlite)
- Headscale DB와 외래키 충돌 방지
- 느슨한 결합 설계 (ID 참조만 사용)

## UI Components
- 반응형 대시보드 with 실시간 통계
- 약국별 머신 상태 모니터링
- 한국어 지역화 및 사용자 친화적 인터페이스
- 머신 온라인/오프라인 상태 표시 (24시간 타임아웃)

## API Endpoints
- `/api/sync/machines` - Headscale 머신 동기화
- `/api/sync/users` - Headscale 사용자 동기화
- `/api/pharmacy/<id>/update` - 약국 정보 업데이트
- 대시보드 통계 및 알림 API

## Problem Resolution
- Fixed foreign key conflicts preventing Windows client connections
- Resolved machine online status detection with proper timeout handling
- Separated technical Headscale usernames from business pharmacy names

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-09 17:44:56 +09:00

4.6 KiB

Headscale 데이터베이스 외래키 제약조건 문제 해결 기록

🔍 문제 상황

발생한 오류

backend error: handling register with auth key: registering node: failed register(save) node in the database: SQL logic error: foreign key mismatch - "pharmacy_info" referencing "users" (1)

증상

  • Windows Tailscale 클라이언트 연결 시 Google SSO 로그인만 표시됨
  • tailscale up --login-server 명령어 실행 시 위 오류 발생
  • Headscale 컨테이너 로그에서 foreign key mismatch 오류 지속 발생

원인 분석

  1. Flask Admin 앱 개발 과정에서 추가된 커스텀 테이블들이 Headscale 스키마와 충돌

    • pharmacy_info 테이블이 users 테이블을 참조하는 외래키 제약조건 설정
    • machine_specs, monitoring_data 테이블도 유사한 외래키 제약조건 존재
  2. Headscale이 자체 사용자 관리 스키마를 가지고 있어 외부 테이블의 외래키 참조 거부

    • Headscale은 내부적으로 users, machines, nodes 등의 테이블을 관리
    • 외부에서 추가된 테이블이 이들을 참조할 때 스키마 불일치 발생

🛠️ 해결 과정

1단계: 문제 테이블 식별

# 문제가 되는 테이블들 확인
cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name LIKE '%pharmacy%'")
problem_tables = cursor.fetchall()
# 결과: ['pharmacy_info', 'machine_specs', 'monitoring_data']

2단계: 데이터베이스 정리 스크립트 실행

python3 clean-database.py

스크립트 수행 작업:

  1. 백업 생성: db.sqlite.clean_backup.20250909_170759
  2. 외래키 제약조건 비활성화: PRAGMA foreign_keys = OFF
  3. 문제 테이블 제거:
    • DROP TABLE IF EXISTS pharmacy_info
    • DROP TABLE IF EXISTS machine_specs
    • DROP TABLE IF EXISTS monitoring_data
  4. 변경사항 커밋 및 무결성 검사

3단계: Headscale 서비스 재시작

cd /srv/headscale-setup && docker-compose restart headscale

해결 결과

Before (문제 상황):

2025-09-09T17:07:02+09:00 FTL Migration failed: SQL logic error: foreign key mismatch - "pharmacy_info" referencing "users" (1)

After (해결 후):

2025-09-09T17:08:42+09:00 INF Using policy manager version: 2
2025-09-09T17:08:42+09:00 INF Starting Headscale commit=474ea236d0c6d393dbcf7baa98da240ad20c1b66 version=0.26.1
2025-09-09T17:08:46+09:00 INF node has connected, mapSession: 0xc000172600, chan: 0xc000286d90 node=DESKTOP-EMJD1DC node.id=2
2025-09-09T17:08:48+09:00 INF node has connected, mapSession: 0xc00021b680, chan: 0xc000251180 node=0bin-Ubuntu-VM node.id=1

성공 지표:

  • Headscale 정상 시작
  • Windows 클라이언트 (DESKTOP-EMJD1DC) 연결 성공
  • Ubuntu VM 클라이언트 (0bin-Ubuntu-VM) 연결 유지
  • Health check 통과: {"status":"pass"}

📚 교훈 및 베스트 프랙티스

1. Headscale과 커스텀 애플리케이션 분리 원칙

❌ 잘못된 접근: Headscale DB에 직접 외래키 제약조건으로 연결
✅ 올바른 접근: 별도 데이터베이스 또는 느슨한 결합 방식 사용

2. 외래키 제약조건 설계 시 고려사항

  • Headscale 스키마 독립성 유지
  • 별도 데이터베이스 사용 또는 ID 참조만 사용 (외래키 제약조건 없이)
  • 마이그레이션 전 스키마 호환성 검증

3. 향후 개발 가이드라인

# 권장하지 않음
pharmacy_info = Table('pharmacy_info',
    Column('user_id', Integer, ForeignKey('users.id'))  # ❌
)

# 권장 방법
pharmacy_info = Table('pharmacy_info', 
    Column('headscale_user_id', Integer)  # ✅ 단순 참조, 제약조건 없음
)

4. 데이터베이스 백업 중요성

  • 모든 스키마 변경 전 백업 생성 필수
  • 백업 파일명에 타임스탬프 포함으로 버전 관리
  • 롤백 절차 사전 준비

🔧 복구 방법 (필요시)

만약 문제가 재발하거나 백업에서 복원해야 할 경우:

# 백업에서 복원
cp /srv/headscale-setup/data/db.sqlite.clean_backup.20250909_170759 /srv/headscale-setup/data/db.sqlite

# 컨테이너 재시작  
cd /srv/headscale-setup && docker-compose restart headscale

📝 관련 파일들

  • 해결 스크립트: /srv/headscale-setup/clean-database.py
  • 백업 파일: /srv/headscale-setup/data/db.sqlite.clean_backup.20250909_170759
  • Docker Compose: /srv/headscale-setup/docker-compose.yml
  • 로그 위치: docker logs headscale

문제 해결일: 2025-09-09
해결 소요시간: ~30분
영향 범위: Windows/Ubuntu 클라이언트 연결 복구