headscale-tailscale-replace.../FLASK_ADMIN_DEVELOPMENT_PLAN.md
시골약사 35ecd4748e PharmQ SaaS 구독 서비스 관리 시스템 완전 구현
📋 기획 및 설계:
- PharmQ SaaS 서비스 기획서 작성
- 구독 서비스 라인업 정의 (클라우드PC, AI CCTV, CRM)
- DB 스키마 설계 및 API 아키텍처 설계

🗄️ 데이터베이스 구조:
- service_products: 서비스 상품 마스터 테이블
- pharmacy_subscriptions: 약국별 구독 현황 테이블
- subscription_usage_logs: 서비스 이용 로그 테이블
- billing_history: 결제 이력 테이블
- 샘플 데이터 자동 생성 (21개 구독, 월 118만원 매출)

🔧 백엔드 API 구현:
- 구독 현황 통계 API (/api/subscriptions/stats)
- 약국별 구독 조회 API (/api/pharmacies/subscriptions)
- 구독 상세 정보 API (/api/pharmacy/{id}/subscriptions)
- 구독 생성/해지 API (/api/subscriptions)

🖥️ 프론트엔드 UI 구현:
- 대시보드 구독 현황 카드 (월 매출, 구독 수, 구독률 등)
- 약국 목록에 구독 상태 아이콘 및 월 구독료 표시
- 약국 상세 페이지 구독 서비스 섹션 추가
- 실시간 구독 생성/해지 기능 구현

 주요 특징:
- 서비스별 색상 코딩 및 이모지 아이콘 시스템
- 실시간 업데이트 (구독 생성/해지 즉시 반영)
- 반응형 디자인 (모바일/태블릿 최적화)
- 툴팁 기반 상세 정보 표시

📊 현재 구독 현황:
- 총 월 매출: ₩1,180,000
- 구독 약국: 10/14개 (71.4%)
- AI CCTV: 6개 약국, CRM: 10개 약국, 클라우드PC: 5개 약국

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-11 19:48:12 +09:00

22 KiB

🌐 Flask + Jinja2 Headplane 고도화 관리자 페이지 개발 계획

📋 프로젝트 개요

개발 목표

기존 Headplane UI를 포크하지 않고, Flask + Jinja2로 별도 관리자 페이지를 구축하여 Headscale 데이터베이스와 직접 연동하는 고도화된 관리 시스템 개발

핵심 컨셉

  • 기존 Headplane: 기본 기능 유지 (3000번 포트)
  • Flask Admin: 고도화된 관리 기능 (5000번 포트)
  • 데이터 통합: 동일한 SQLite DB 공유로 실시간 동기화
  • 팜큐 특화: 약국 관리에 최적화된 UI/UX

🏗️ 아키텍처 설계

시스템 구조

┌─────────────────┐    ┌──────────────────┐    ┌─────────────────┐
│   Headplane UI  │    │   Flask Admin    │    │  Headscale API  │
│   (포트: 3000)  │    │   (포트: 5000)   │    │  (포트: 8070)   │
│   기본 기능      │    │   고도화 기능     │    │   백엔드 API    │
└─────────────────┘    └──────────────────┘    └─────────────────┘
         │                       │                       │
         └───────────────────────┼───────────────────────┘
                                 │
                    ┌──────────────────┐
                    │  SQLite Database │
                    │ (공유 데이터)    │
                    └──────────────────┘

포트 구성

  • Headscale API: 8070 (기존 유지)
  • Headplane UI: 3000 (기존 유지)
  • Flask Admin: 5000 (신규 추가)

📂 Flask 프로젝트 구조

farmq-admin/
├── app.py                    # Flask 애플리케이션 메인
├── config.py                 # 설정 파일
├── requirements.txt          # Python 의존성
├── models/
│   ├── __init__.py
│   ├── headscale_models.py   # SQLAlchemy 모델 (재사용)
│   └── pharmacy_models.py    # 팜큐 확장 모델
├── routes/
│   ├── __init__.py
│   ├── dashboard.py          # 메인 대시보드
│   ├── pharmacy.py           # 약국 관리
│   ├── machines.py           # 머신 관리 (고도화)
│   ├── users.py              # 사용자 관리 (고도화)
│   ├── monitoring.py         # 실시간 모니터링
│   └── api.py                # REST API 엔드포인트
├── templates/
│   ├── base.html             # 기본 레이아웃
│   ├── dashboard/
│   │   ├── index.html        # 메인 대시보드
│   │   └── stats.html        # 통계 대시보드
│   ├── pharmacy/
│   │   ├── list.html         # 약국 목록
│   │   ├── detail.html       # 약국 상세
│   │   ├── create.html       # 약국 등록
│   │   └── edit.html         # 약국 수정
│   ├── machines/
│   │   ├── list.html         # 머신 목록 (고도화)
│   │   ├── detail.html       # 머신 상세 (하드웨어 정보)
│   │   └── monitoring.html   # 실시간 모니터링
│   └── users/
│       ├── list.html         # 사용자 목록 (약국 정보 포함)
│       └── detail.html       # 사용자 상세
├── static/
│   ├── css/
│   │   ├── bootstrap.min.css # Bootstrap 5
│   │   ├── custom.css        # 커스텀 스타일
│   │   └── dashboard.css     # 대시보드 전용 스타일
│   ├── js/
│   │   ├── bootstrap.min.js  # Bootstrap JS
│   │   ├── chart.min.js      # Chart.js 라이브러리
│   │   ├── dashboard.js      # 대시보드 JS
│   │   └── monitoring.js     # 실시간 모니터링 JS
│   └── img/
│       ├── logo.png          # 팜큐 로고
│       └── icons/            # 아이콘들
├── utils/
│   ├── __init__.py
│   ├── database.py           # DB 연결 유틸리티
│   ├── auth.py               # 인증 관련
│   ├── monitoring.py         # 모니터링 데이터 수집
│   └── proxmox.py            # Proxmox API 연동
└── docker/
    ├── Dockerfile            # Flask 앱용 도커파일
    └── docker-compose.yml    # 통합 컨테이너 구성

🎨 UI/UX 설계

디자인 컨셉

  • Modern Dashboard: Bootstrap 5 기반 반응형 디자인
  • 팜큐 브랜딩: 약국 관리에 특화된 색상/아이콘 사용
  • Korean-First: 한국어 우선 인터페이스
  • Mobile Responsive: 모바일/태블릿 완벽 지원

메인 대시보드 레이아웃

┌────────────────────────────────────────────────────────────┐
│ 🏥 팜큐 약국 관리 시스템              [관리자: admin] [로그아웃] │
├────────────────────────────────────────────────────────────┤
│ [대시보드] [약국관리] [머신관리] [사용자관리] [모니터링] [설정] │
├────────────────────────────────────────────────────────────┤
│ 📊 전체 현황                                               │
│ ┌──────────┬──────────┬──────────┬──────────────────────┐  │
│ │총 약국 수 │온라인    │오프라인   │평균 CPU 온도         │  │
│ │   100    │   95     │    5     │       62°C           │  │
│ └──────────┴──────────┴──────────┴──────────────────────┘  │
│                                                            │
│ 🚨 실시간 알림                     📈 성능 차트             │
│ ┌─────────────────────────┐       ┌────────────────────┐ │
│ │• 부산해운약국: CPU 85°C  │       │   [CPU 사용률 차트] │ │
│ │• 대구중앙약국: 디스크95% │       │   [메모리 사용률]   │ │
│ │• 서울약국: 연결 끊김     │       │   [네트워크 트래픽] │ │
│ └─────────────────────────┘       └────────────────────┘ │
│                                                            │
│ 📋 약국별 상태 (실시간)                                    │
│ ┌─────────────┬────────┬────────┬────────┬──────────────┐ │
│ │약국명        │상태    │CPU온도  │메모리   │마지막 접속    │ │
│ ├─────────────┼────────┼────────┼────────┼──────────────┤ │
│ │서울중앙약국   │🟢 온라인│  65°C  │  80%   │    2분 전    │ │
│ │부산해운약국   │🟡 경고  │  85°C  │  60%   │    5분 전    │ │
│ │대구중앙약국   │🔴 위험  │  70°C  │  95%   │   10분 전    │ │
│ └─────────────┴────────┴────────┴────────┴──────────────┘ │
└────────────────────────────────────────────────────────────┘

🎯 핵심 기능 명세

1. 통합 대시보드

# routes/dashboard.py
@app.route('/')
def dashboard():
    stats = {
        'total_pharmacies': get_pharmacy_count(),
        'online_machines': get_online_machines_count(),
        'offline_machines': get_offline_machines_count(),
        'avg_cpu_temp': get_average_cpu_temperature(),
        'alerts': get_active_alerts(),
        'recent_activities': get_recent_activities()
    }
    return render_template('dashboard/index.html', stats=stats)

2. 약국 관리 시스템

2-1. 약국 목록 페이지

<!-- templates/pharmacy/list.html -->
<div class="container-fluid">
    <div class="row">
        <div class="col-12">
            <div class="card">
                <div class="card-header d-flex justify-content-between">
                    <h5>🏥 약국 관리</h5>
                    <button class="btn btn-primary" onclick="location.href='/pharmacy/create'">
                        <i class="fas fa-plus"></i> 새 약국 등록
                    </button>
                </div>
                <div class="card-body">
                    <table class="table table-hover">
                        <thead>
                            <tr>
                                <th>약국명</th>
                                <th>사업자번호</th>
                                <th>담당자</th>
                                <th>연결된 머신</th>
                                <th>상태</th>
                                <th>마지막 접속</th>
                                <th>액션</th>
                            </tr>
                        </thead>
                        <tbody>
                            {% for pharmacy in pharmacies %}
                            <tr>
                                <td>
                                    <strong>{{ pharmacy.pharmacy_name }}</strong><br>
                                    <small class="text-muted">{{ pharmacy.address }}</small>
                                </td>
                                <td>{{ pharmacy.business_number }}</td>
                                <td>
                                    {{ pharmacy.manager_name }}<br>
                                    <small class="text-muted">{{ pharmacy.phone }}</small>
                                </td>
                                <td>
                                    <span class="badge bg-info">{{ pharmacy.machine_count }}대</span>
                                </td>
                                <td>
                                    {% if pharmacy.is_online %}
                                        <span class="badge bg-success">🟢 온라인</span>
                                    {% else %}
                                        <span class="badge bg-danger">🔴 오프라인</span>
                                    {% endif %}
                                </td>
                                <td>{{ pharmacy.last_seen_humanized }}</td>
                                <td>
                                    <div class="btn-group btn-group-sm">
                                        <a href="/pharmacy/{{ pharmacy.id }}" class="btn btn-outline-primary">상세</a>
                                        <a href="/pharmacy/{{ pharmacy.id }}/edit" class="btn btn-outline-warning">수정</a>
                                        <a href="/pharmacy/{{ pharmacy.id }}/monitoring" class="btn btn-outline-info">모니터링</a>
                                    </div>
                                </td>
                            </tr>
                            {% endfor %}
                        </tbody>
                    </table>
                </div>
            </div>
        </div>
    </div>
</div>

3. 고도화된 머신 관리

3-1. 머신 상세 페이지 (하드웨어 정보 포함)

<!-- templates/machines/detail.html -->
<div class="container-fluid">
    <div class="row">
        <!-- 기본 정보 -->
        <div class="col-md-6">
            <div class="card">
                <div class="card-header">
                    <h5>🖥️ 머신 기본 정보</h5>
                </div>
                <div class="card-body">
                    <dl class="row">
                        <dt class="col-sm-4">머신명:</dt>
                        <dd class="col-sm-8">{{ machine.given_name }}</dd>
                        
                        <dt class="col-sm-4">호스트명:</dt>
                        <dd class="col-sm-8">{{ machine.hostname }}</dd>
                        
                        <dt class="col-sm-4">IP 주소:</dt>
                        <dd class="col-sm-8">
                            <code>{{ machine.ipv4 }}</code>
                        </dd>
                        
                        <dt class="col-sm-4">소속 약국:</dt>
                        <dd class="col-sm-8">
                            <a href="/pharmacy/{{ machine.pharmacy.id }}">
                                {{ machine.pharmacy.pharmacy_name }}
                            </a>
                        </dd>
                        
                        <dt class="col-sm-4">마지막 접속:</dt>
                        <dd class="col-sm-8">
                            {% if machine.is_online() %}
                                <span class="badge bg-success">🟢 온라인</span>
                            {% else %}
                                <span class="badge bg-danger">🔴 {{ machine.last_seen_humanized }}</span>
                            {% endif %}
                        </dd>
                    </dl>
                </div>
            </div>
        </div>
        
        <!-- 하드웨어 사양 -->
        <div class="col-md-6">
            <div class="card">
                <div class="card-header">
                    <h5>⚙️ 하드웨어 사양</h5>
                </div>
                <div class="card-body">
                    {% if machine.specs %}
                    <dl class="row">
                        <dt class="col-sm-4">CPU:</dt>
                        <dd class="col-sm-8">{{ machine.specs.cpu_model }} ({{ machine.specs.cpu_cores }}코어)</dd>
                        
                        <dt class="col-sm-4">RAM:</dt>
                        <dd class="col-sm-8">{{ machine.specs.ram_gb }}GB</dd>
                        
                        <dt class="col-sm-4">Storage:</dt>
                        <dd class="col-sm-8">{{ machine.specs.storage_gb }}GB</dd>
                        
                        <dt class="col-sm-4">GPU:</dt>
                        <dd class="col-sm-8">{{ machine.specs.gpu_model or '없음' }}</dd>
                    </dl>
                    {% else %}
                    <p class="text-muted">하드웨어 정보가 등록되지 않았습니다.</p>
                    <a href="/machines/{{ machine.id }}/specs" class="btn btn-outline-primary btn-sm">
                        하드웨어 정보 등록
                    </a>
                    {% endif %}
                </div>
            </div>
        </div>
    </div>
    
    <!-- 실시간 모니터링 -->
    <div class="row mt-4">
        <div class="col-12">
            <div class="card">
                <div class="card-header">
                    <h5>📊 실시간 모니터링</h5>
                </div>
                <div class="card-body">
                    {% if machine.latest_monitoring %}
                    <div class="row">
                        <div class="col-md-3">
                            <div class="text-center">
                                <canvas id="cpuChart" width="100" height="100"></canvas>
                                <h6 class="mt-2">CPU 사용률</h6>
                                <span class="h4 text-primary">{{ machine.latest_monitoring.cpu_usage }}%</span>
                            </div>
                        </div>
                        <div class="col-md-3">
                            <div class="text-center">
                                <canvas id="memoryChart" width="100" height="100"></canvas>
                                <h6 class="mt-2">메모리 사용률</h6>
                                <span class="h4 text-info">{{ machine.latest_monitoring.memory_usage }}%</span>
                            </div>
                        </div>
                        <div class="col-md-3">
                            <div class="text-center">
                                <div class="display-4 text-warning">🌡️</div>
                                <h6>CPU 온도</h6>
                                <span class="h4 text-warning">{{ machine.latest_monitoring.cpu_temperature }}°C</span>
                            </div>
                        </div>
                        <div class="col-md-3">
                            <div class="text-center">
                                <div class="display-4 text-success">💾</div>
                                <h6>디스크 사용률</h6>
                                <span class="h4 text-success">{{ machine.latest_monitoring.disk_usage }}%</span>
                            </div>
                        </div>
                    </div>
                    {% else %}
                    <div class="alert alert-info">
                        <i class="fas fa-info-circle"></i>
                        아직 모니터링 데이터가 없습니다. 잠시 후 다시 확인해주세요.
                    </div>
                    {% endif %}
                </div>
            </div>
        </div>
    </div>
</div>

<script>
// 실시간 업데이트를 위한 JavaScript
function updateMonitoring() {
    fetch(`/api/machines/{{ machine.id }}/monitoring`)
        .then(response => response.json())
        .then(data => {
            // 차트 업데이트 로직
            updateCharts(data);
        });
}

// 5초마다 업데이트
setInterval(updateMonitoring, 5000);
</script>

4. 실시간 모니터링 시스템

# routes/monitoring.py
from flask import Blueprint, jsonify
from utils.monitoring import collect_monitoring_data
from utils.proxmox import ProxmoxAPI

monitoring_bp = Blueprint('monitoring', __name__)

@monitoring_bp.route('/api/monitoring/realtime')
def realtime_monitoring():
    """실시간 모니터링 데이터 API"""
    data = {
        'total_machines': get_total_machines(),
        'online_count': get_online_machines_count(),
        'alerts': get_active_alerts(),
        'performance': get_performance_summary()
    }
    return jsonify(data)

@monitoring_bp.route('/api/machines/<int:machine_id>/monitoring')
def machine_monitoring(machine_id):
    """특정 머신 모니터링 데이터"""
    monitoring_data = collect_monitoring_data(machine_id)
    return jsonify(monitoring_data)

🔧 기술 스택

Backend

  • Flask 3.0: 웹 프레임워크
  • SQLAlchemy 2.0: ORM (기존 모델 재사용)
  • Jinja2: 템플릿 엔진
  • Flask-Login: 사용자 인증
  • APScheduler: 백그라운드 작업 (모니터링 데이터 수집)

Frontend

  • Bootstrap 5: CSS 프레임워크
  • Chart.js: 차트 라이브러리
  • Font Awesome: 아이콘
  • jQuery: DOM 조작
  • Socket.io: 실시간 통신

데이터베이스

  • SQLite: 기존 Headscale DB 공유
  • 확장 테이블: PharmacyInfo, MachineSpecs, MonitoringData

배포

  • Docker: 컨테이너화
  • Nginx: 리버스 프록시 (옵션)

📅 개발 로드맵

Phase 1: 기본 프레임워크 구축 (1-2일)

  • Flask 애플리케이션 기본 구조 생성
  • SQLAlchemy 모델 연동 (기존 모델 재사용)
  • Bootstrap 기반 기본 템플릿 구성
  • 라우팅 구조 설계

Phase 2: 핵심 기능 구현 (3-4일)

  • 메인 대시보드 구현
  • 약국 관리 CRUD 기능
  • 머신 관리 고도화 (하드웨어 정보 포함)
  • 사용자 관리 확장 (약국 정보 연동)

Phase 3: 실시간 기능 (2-3일)

  • 모니터링 데이터 수집 시스템
  • 실시간 차트 및 알림
  • WebSocket 기반 라이브 업데이트
  • Proxmox API 연동

Phase 4: 통합 및 최적화 (2-3일)

  • 기존 Headplane과 데이터 동기화 테스트
  • Docker 컨테이너화
  • 성능 최적화
  • 사용자 테스트 및 피드백 반영

Phase 5: 배포 및 운영 (1-2일)

  • Docker Compose 통합 구성
  • 프로덕션 배포
  • 모니터링 및 로깅 설정
  • 사용자 교육 자료 작성

💰 예상 리소스

개발 시간

  • 총 개발 기간: 8-12일
  • 개발자: 1명 (풀타임)
  • 일일 작업량: 6-8시간

기술적 요구사항

  • Python 3.8+
  • 메모리: 최소 512MB (Flask 앱)
  • 디스크: 추가 100MB (정적 파일 포함)

🚀 시작하기

1단계: 개발 환경 준비

# Flask 프로젝트 디렉터리 생성
mkdir farmq-admin
cd farmq-admin

# Python 가상환경 생성
python3 -m venv flask-venv
source flask-venv/bin/activate

# 필수 패키지 설치
pip install flask sqlalchemy jinja2 flask-login apscheduler

2단계: 기본 구조 생성

# 프로젝트 구조 생성
mkdir -p {routes,templates,static/{css,js,img},utils,models}
touch app.py config.py requirements.txt

3단계: 첫 번째 구현

  • 기본 Flask 앱 생성
  • SQLAlchemy 연동
  • 간단한 대시보드 페이지

🎯 성공 지표

기능적 목표

  • 100개 약국 데이터 완벽 관리
  • 실시간 모니터링 정확도 95% 이상
  • 기존 Headplane과 데이터 100% 동기화
  • 페이지 로딩 시간 2초 이내

사용성 목표

  • 관리 업무 효율성 70% 향상
  • 모바일 접근성 완벽 지원
  • 한국어 UI 100% 완성
  • 사용자 만족도 4.8/5.0 이상

이제 이 계획을 바탕으로 Flask 관리자 페이지 개발을 시작하시겠습니까?


📅 작성일: 2025-09-09
👤 작성자: Claude Code Assistant
🎯 목표: Headplane UI 고도화를 위한 Flask 기반 관리자 시스템