# -*- coding: utf-8 -*- """ 원격 데이터베이스 동기화 모듈 로컬 SQLite와 원격 Supabase 간의 데이터 동기화를 관리합니다. 현재는 프로토타입으로 인터페이스만 정의되어 있으며, 추후 Supabase 연동 시 구현될 예정입니다. """ from abc import ABC, abstractmethod from datetime import datetime from typing import Optional, List, Dict, Any from enum import Enum from core.logger import get_logger from core.signals import get_signals # 로거 설정 logger = get_logger(__name__) class SyncStatus(Enum): """동기화 상태""" IDLE = "idle" SYNCING = "syncing" SUCCESS = "success" FAILED = "failed" OFFLINE = "offline" class SyncDirection(Enum): """동기화 방향""" UPLOAD = "upload" # 로컬 -> 원격 DOWNLOAD = "download" # 원격 -> 로컬 BOTH = "both" # 양방향 class BaseSyncManager(ABC): """ 동기화 관리자 추상 클래스 원격 데이터베이스와의 동기화 인터페이스를 정의합니다. """ @abstractmethod def connect(self) -> bool: """원격 데이터베이스에 연결합니다.""" pass @abstractmethod def disconnect(self): """연결을 종료합니다.""" pass @abstractmethod def is_connected(self) -> bool: """연결 상태를 확인합니다.""" pass @abstractmethod def sync_table(self, table_name: str, direction: SyncDirection) -> bool: """테이블을 동기화합니다.""" pass @abstractmethod def sync_all(self, direction: SyncDirection) -> bool: """모든 테이블을 동기화합니다.""" pass @abstractmethod def get_last_sync_time(self, table_name: str = None) -> Optional[datetime]: """마지막 동기화 시간을 반환합니다.""" pass class LocalOnlySyncManager(BaseSyncManager): """ 로컬 전용 동기화 관리자 (프로토타입) 원격 연결 없이 로컬 데이터베이스만 사용합니다. Supabase 연동 전까지 이 클래스를 사용합니다. """ def __init__(self): """초기화""" self.signals = get_signals() self._status = SyncStatus.OFFLINE self._last_sync_time: Dict[str, datetime] = {} logger.info("LocalOnlySyncManager 초기화 (원격 동기화 비활성화)") def connect(self) -> bool: """ 연결 시도 (항상 오프라인 상태) Returns: 항상 False """ logger.info("원격 동기화가 비활성화되어 있습니다.") self._status = SyncStatus.OFFLINE return False def disconnect(self): """연결 종료 (동작 없음)""" pass def is_connected(self) -> bool: """ 연결 상태 확인 Returns: 항상 False """ return False def sync_table(self, table_name: str, direction: SyncDirection) -> bool: """ 테이블 동기화 (동작 없음) Args: table_name: 테이블 이름 direction: 동기화 방향 Returns: 항상 True (로컬 데이터는 항상 최신) """ self._last_sync_time[table_name] = datetime.now() return True def sync_all(self, direction: SyncDirection) -> bool: """ 전체 동기화 (동작 없음) Args: direction: 동기화 방향 Returns: 항상 True """ logger.info("로컬 전용 모드: 동기화 건너뛰기") return True def get_last_sync_time(self, table_name: str = None) -> Optional[datetime]: """ 마지막 동기화 시간 반환 Args: table_name: 테이블 이름 Returns: 마지막 동기화 시간 """ if table_name: return self._last_sync_time.get(table_name) return max(self._last_sync_time.values()) if self._last_sync_time else None @property def status(self) -> SyncStatus: """현재 동기화 상태""" return self._status class SupabaseSyncManager(BaseSyncManager): """ Supabase 동기화 관리자 추후 Supabase 연동 시 구현될 예정입니다. Note: 이 클래스는 현재 스텁으로만 존재합니다. 실제 구현 시 supabase 패키지를 사용합니다. """ def __init__(self, url: str, key: str): """ 초기화 Args: url: Supabase 프로젝트 URL key: Supabase API 키 """ self.url = url self.key = key self.signals = get_signals() self._client = None self._status = SyncStatus.IDLE self._last_sync_time: Dict[str, datetime] = {} logger.info("SupabaseSyncManager 초기화 (추후 구현 예정)") def connect(self) -> bool: """ Supabase에 연결합니다. Returns: 연결 성공 여부 TODO: supabase 패키지를 사용하여 실제 연결 구현 """ # TODO: 실제 연결 구현 # from supabase import create_client # self._client = create_client(self.url, self.key) logger.warning("Supabase 연결 미구현") return False def disconnect(self): """연결을 종료합니다.""" self._client = None self._status = SyncStatus.IDLE def is_connected(self) -> bool: """연결 상태를 확인합니다.""" return self._client is not None def sync_table(self, table_name: str, direction: SyncDirection) -> bool: """ 테이블을 동기화합니다. Args: table_name: 테이블 이름 direction: 동기화 방향 Returns: 동기화 성공 여부 TODO: - 마지막 동기화 시간 이후 변경된 레코드 조회 - 충돌 해결 로직 구현 - 배치 처리 구현 """ # TODO: 실제 동기화 구현 logger.warning(f"테이블 동기화 미구현: {table_name}") return False def sync_all(self, direction: SyncDirection) -> bool: """ 모든 테이블을 동기화합니다. Args: direction: 동기화 방향 Returns: 동기화 성공 여부 """ tables = [ "instructions", "faults", "works", "miscs", "daily_inspections", "todos", "memos" ] success = True for table in tables: if not self.sync_table(table, direction): success = False if success: self.signals.sync_completed.emit() else: self.signals.sync_error.emit("일부 테이블 동기화 실패") return success def get_last_sync_time(self, table_name: str = None) -> Optional[datetime]: """마지막 동기화 시간을 반환합니다.""" if table_name: return self._last_sync_time.get(table_name) return max(self._last_sync_time.values()) if self._last_sync_time else None @property def status(self) -> SyncStatus: """현재 동기화 상태""" return self._status def get_sync_manager() -> BaseSyncManager: """ 동기화 관리자 인스턴스를 반환합니다. 현재는 LocalOnlySyncManager를 반환합니다. 추후 설정에 따라 SupabaseSyncManager를 반환할 수 있습니다. Returns: 동기화 관리자 인스턴스 """ # TODO: 설정에 따라 적절한 관리자 반환 return LocalOnlySyncManager()