추가된 문서:
- SCRIPT_IMPROVEMENT_PLAN.md: 스크립트 개선 계획
- FARMQ_ADMIN_INTEGRATION_ANALYSIS.md: farmq-admin API 분석
- HEADSCALE_AUTO_REGISTER_PLAN.md: 초기 계획
주요 내용:
- Headscale VPN 등록 시 자동 DB 생성
- API 엔드포인트: demo.pharmq.kr, gateway.pharmq.kr
🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
264 lines
8.0 KiB
Markdown
264 lines
8.0 KiB
Markdown
# headscale-quick-install.sh 개선 계획
|
|
|
|
## 목표
|
|
Headscale VPN 등록 시 **farmq.db와 gateway.db에 자동으로 약국 및 관리자 계정 생성**하여
|
|
스크립트 실행만으로 **즉시 프론트엔드 로그인 가능**하게 만들기
|
|
|
|
## 자동 생성 플로우
|
|
|
|
```
|
|
1. Headscale VPN 등록 → VPN IP 부여 (예: 100.64.0.25)
|
|
2. farmq-admin API 호출 → farmq.db에 약국 생성
|
|
- pharmacy_code: P0005 (자동 증가)
|
|
- pharmacy_name: 사용자 입력
|
|
- tailscale_ip: 100.64.0.25 (VPN IP)
|
|
- hira_code: 사용자 입력 (선택)
|
|
- api_port: 8082 (기본값)
|
|
|
|
3. gateway API 호출 → gateway.db에 admin 계정 생성
|
|
- username: p0005 (pharmacy_code 소문자)
|
|
- password: 1234 (기본 비밀번호)
|
|
- email: p0005@pharmq.internal
|
|
- name: {pharmacy_name} 관리자
|
|
- role: admin
|
|
- primary_pharmacy_code: P0005
|
|
- pharmacy_members에도 자동 매핑됨
|
|
|
|
4. 로그인 정보 출력
|
|
```
|
|
|
|
## 추가할 함수들
|
|
|
|
### 1. `collect_pharmacy_info()`
|
|
약국 기본 정보를 사용자로부터 입력받음
|
|
|
|
```bash
|
|
collect_pharmacy_info() {
|
|
echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
echo -e "${WHITE}약국 정보 입력${NC}"
|
|
echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
|
|
# 약국명 입력 (필수)
|
|
while [ -z "$PHARMACY_NAME" ]; do
|
|
read -p "약국명을 입력하세요: " PHARMACY_NAME
|
|
done
|
|
|
|
# 요양기관부호 입력 (선택)
|
|
read -p "요양기관부호 (선택, Enter로 건너뛰기): " HIRA_CODE
|
|
|
|
# 약국 주소 입력 (선택)
|
|
read -p "약국 주소 (선택): " PHARMACY_ADDRESS
|
|
|
|
# 약국장 이름 입력 (선택)
|
|
read -p "약국장 이름 (선택): " OWNER_NAME
|
|
|
|
# 연락처 입력 (선택)
|
|
read -p "약국 연락처 (선택): " PHARMACY_PHONE
|
|
|
|
echo -e "${GREEN}✓ 약국 정보 입력 완료${NC}"
|
|
}
|
|
```
|
|
|
|
### 2. `get_assigned_vpn_ip()`
|
|
Headscale에서 부여받은 VPN IP 가져오기
|
|
|
|
```bash
|
|
get_assigned_vpn_ip() {
|
|
echo -e "${BLUE}VPN IP 확인 중...${NC}"
|
|
|
|
# tailscale status로 IP 추출
|
|
VPN_IP=$(tailscale status --json 2>/dev/null | grep -oP '"TailscaleIPs":\["(\d+\.\d+\.\d+\.\d+)"' | grep -oP '\d+\.\d+\.\d+\.\d+' | head -1)
|
|
|
|
if [ -z "$VPN_IP" ]; then
|
|
echo -e "${RED}✗ VPN IP를 가져올 수 없습니다${NC}"
|
|
return 1
|
|
fi
|
|
|
|
echo -e "${GREEN}✓ VPN IP: $VPN_IP${NC}"
|
|
return 0
|
|
}
|
|
```
|
|
|
|
### 3. `create_pharmacy_via_api()`
|
|
farmq-admin API를 호출하여 약국 생성
|
|
|
|
```bash
|
|
create_pharmacy_via_api() {
|
|
echo -e "${BLUE}약국 등록 중 (farmq.db)...${NC}"
|
|
|
|
# JSON 데이터 구성
|
|
JSON_DATA=$(cat <<EOF
|
|
{
|
|
"pharmacy_name": "$PHARMACY_NAME",
|
|
"vpn_ip": "$VPN_IP",
|
|
"hira_code": "$HIRA_CODE",
|
|
"address": "$PHARMACY_ADDRESS",
|
|
"owner_name": "$OWNER_NAME",
|
|
"phone": "$PHARMACY_PHONE",
|
|
"api_port": 8082
|
|
}
|
|
EOF
|
|
)
|
|
|
|
# API 호출 (외부 도메인)
|
|
RESPONSE=$(curl -s -X POST https://demo.pharmq.kr/api/pharmacy \
|
|
-H "Content-Type: application/json" \
|
|
-d "$JSON_DATA")
|
|
|
|
# pharmacy_code 추출
|
|
PHARMACY_CODE=$(echo "$RESPONSE" | grep -oP '"pharmacy_code":"[^"]*"' | cut -d'"' -f4)
|
|
|
|
if [ -z "$PHARMACY_CODE" ]; then
|
|
echo -e "${RED}✗ 약국 생성 실패${NC}"
|
|
echo "$RESPONSE"
|
|
return 1
|
|
fi
|
|
|
|
echo -e "${GREEN}✓ 약국 생성 완료: $PHARMACY_CODE${NC}"
|
|
return 0
|
|
}
|
|
```
|
|
|
|
### 4. `create_gateway_user_via_api()`
|
|
gateway API를 호출하여 관리자 계정 생성
|
|
|
|
```bash
|
|
create_gateway_user_via_api() {
|
|
echo -e "${BLUE}관리자 계정 생성 중 (gateway.db)...${NC}"
|
|
|
|
# username: pharmacy_code 소문자 (P0005 → p0005)
|
|
USERNAME=$(echo "$PHARMACY_CODE" | tr '[:upper:]' '[:lower:]')
|
|
PASSWORD="1234" # 기본 비밀번호
|
|
EMAIL="${USERNAME}@pharmq.internal"
|
|
|
|
# JSON 데이터 구성
|
|
JSON_DATA=$(cat <<EOF
|
|
{
|
|
"username": "$USERNAME",
|
|
"email": "$EMAIL",
|
|
"password": "$PASSWORD",
|
|
"name": "${PHARMACY_NAME} 관리자",
|
|
"phone": "$PHARMACY_PHONE",
|
|
"primary_pharmacy_code": "$PHARMACY_CODE",
|
|
"role": "admin"
|
|
}
|
|
EOF
|
|
)
|
|
|
|
# API 호출 (외부 도메인)
|
|
RESPONSE=$(curl -s -X POST https://gateway.pharmq.kr/api/auth/register \
|
|
-H "Content-Type: application/json" \
|
|
-d "$JSON_DATA")
|
|
|
|
# 성공 여부 확인
|
|
if echo "$RESPONSE" | grep -q '"success":true'; then
|
|
echo -e "${GREEN}✓ 관리자 계정 생성 완료${NC}"
|
|
return 0
|
|
else
|
|
echo -e "${RED}✗ 관리자 계정 생성 실패${NC}"
|
|
echo "$RESPONSE"
|
|
return 1
|
|
fi
|
|
}
|
|
```
|
|
|
|
### 5. `display_login_credentials()`
|
|
생성된 로그인 정보 출력
|
|
|
|
```bash
|
|
display_login_credentials() {
|
|
echo -e "\n${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
echo -e "${WHITE}🎉 설치 및 등록 완료!${NC}"
|
|
echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
|
|
echo -e "\n${GREEN}약국 정보:${NC}"
|
|
echo -e " 약국 코드: ${WHITE}$PHARMACY_CODE${NC}"
|
|
echo -e " 약국명: ${WHITE}$PHARMACY_NAME${NC}"
|
|
echo -e " VPN IP: ${WHITE}$VPN_IP${NC}"
|
|
|
|
echo -e "\n${GREEN}프론트엔드 로그인 정보:${NC}"
|
|
echo -e " URL: ${WHITE}https://pharmq.kr${NC}"
|
|
echo -e " 아이디: ${WHITE}$(echo "$PHARMACY_CODE" | tr '[:upper:]' '[:lower:]')${NC}"
|
|
echo -e " 비밀번호: ${WHITE}1234${NC}"
|
|
echo -e " ${YELLOW}⚠ 최초 로그인 후 비밀번호를 변경하세요!${NC}"
|
|
|
|
echo -e "\n${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
}
|
|
```
|
|
|
|
## main() 함수 수정
|
|
|
|
```bash
|
|
main() {
|
|
print_header "팜큐(FARMQ) Headscale 원클릭 설치"
|
|
|
|
# 사전 체크
|
|
detect_os
|
|
check_requirements
|
|
|
|
# 설치 과정
|
|
install_tailscale
|
|
start_tailscale
|
|
register_headscale
|
|
|
|
# VPN IP 확인
|
|
sleep 3 # Headscale에서 IP 할당 대기
|
|
get_assigned_vpn_ip || exit 1
|
|
|
|
# 약국 정보 수집
|
|
collect_pharmacy_info
|
|
|
|
# 약국 및 계정 생성
|
|
create_pharmacy_via_api || exit 1
|
|
create_gateway_user_via_api || exit 1
|
|
|
|
# 사후 설정
|
|
configure_firewall
|
|
verify_connection
|
|
|
|
# 정리 및 완료
|
|
cleanup
|
|
display_login_credentials
|
|
}
|
|
```
|
|
|
|
## API 엔드포인트
|
|
|
|
| API | URL | 용도 | 접근 방식 |
|
|
|-----|-----|------|----------|
|
|
| farmq-admin | https://demo.pharmq.kr/api/pharmacy | 약국 생성 | 외부 도메인 (HTTPS) |
|
|
| gateway | https://gateway.pharmq.kr/api/auth/register | 사용자 생성 | 외부 도메인 (HTTPS) |
|
|
|
|
**장점**:
|
|
- ✅ 모든 API가 외부 도메인으로 통일되어 있음
|
|
- ✅ HTTPS로 보안 통신
|
|
- ✅ 내부 네트워크 접근 불필요
|
|
- ✅ VPN 망 내부/외부 어디서든 실행 가능
|
|
|
|
## 보안 고려사항
|
|
|
|
1. **기본 비밀번호 1234**: 간단하지만 프론트엔드에서 강제 변경 유도 필요
|
|
2. **API 키 인증**: 현재는 public API지만 나중에 인증 토큰 추가 고려
|
|
3. **HTTPS**: 현재 HTTP이지만 production에서는 HTTPS 사용 권장
|
|
|
|
## 에러 처리
|
|
|
|
- VPN IP 할당 실패 시 스크립트 중단
|
|
- 약국 생성 실패 시 스크립트 중단
|
|
- 사용자 생성 실패 시 경고만 출력 (약국은 이미 생성됨)
|
|
|
|
## 테스트 시나리오
|
|
|
|
1. ✅ 정상 플로우: 모든 정보 입력 → 약국 및 계정 생성 → 로그인 성공
|
|
2. ✅ 선택 정보 생략: 약국명만 입력 → 약국 및 계정 생성 → 로그인 성공
|
|
3. ✅ VPN IP 할당 실패: 에러 메시지 출력 후 종료
|
|
4. ✅ 약국 생성 실패: 에러 메시지 출력 후 종료
|
|
5. ✅ 사용자 생성 실패: 경고 출력, 수동 생성 안내
|
|
|
|
## 다음 단계
|
|
|
|
1. ✅ farmq-admin API 개선 (VPN IP, hira_code 지원) - 완료
|
|
2. ✅ gateway API 개선 (pharmacy 검증, pharmacy_members 자동 추가) - 완료
|
|
3. ⏳ headscale-quick-install.sh 수정 - 진행 중
|
|
4. ⏳ 통합 테스트
|