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

126 lines
4.6 KiB
Markdown

# 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단계: 문제 테이블 식별
```python
# 문제가 되는 테이블들 확인
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단계: 데이터베이스 정리 스크립트 실행
```bash
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 서비스 재시작
```bash
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. 향후 개발 가이드라인
```python
# 권장하지 않음
pharmacy_info = Table('pharmacy_info',
Column('user_id', Integer, ForeignKey('users.id')) # ❌
)
# 권장 방법
pharmacy_info = Table('pharmacy_info',
Column('headscale_user_id', Integer) # ✅ 단순 참조, 제약조건 없음
)
```
### 4. 데이터베이스 백업 중요성
- 모든 스키마 변경 전 백업 생성 필수
- 백업 파일명에 타임스탬프 포함으로 버전 관리
- 롤백 절차 사전 준비
## 🔧 복구 방법 (필요시)
만약 문제가 재발하거나 백업에서 복원해야 할 경우:
```bash
# 백업에서 복원
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 클라이언트 연결 복구*