Files
zellyy-finance/docs/02_기술_문서/Appwrite_전환_가이드.md

7.9 KiB

Appwrite 전환 가이드

개요

Zellyy Finance는 백엔드 서비스를 Supabase에서 Appwrite로 전환합니다. 이 문서는 전환 과정과 새로운 코드 구조에 대한 가이드를 제공합니다.

전환 이유

  1. 더 나은 성능: Appwrite는 경량화된 서비스로 더 빠른 응답 시간 제공
  2. 확장성: 사용자 증가에 따른 확장성 개선
  3. 기능 세트: Appwrite의 실시간 데이터베이스와 인증 시스템 활용
  4. 유지보수 용이성: 단일 백엔드 서비스로 통합하여 유지보수 간소화

코드 구조

src/
├── lib/
│   ├── appwrite/ (Appwrite 서비스)
│   │   ├── index.ts (단일 진입점)
│   │   ├── client.ts (클라이언트 설정)
│   │   ├── config.ts (환경 설정)
│   │   └── setup.ts (데이터베이스 설정)
│   └── capacitor/ (네이티브 기능)
│       ├── index.ts (단일 진입점)
│       ├── buildInfo.ts (빌드 정보 관련)
│       ├── notification.ts (알림 관련)
│       └── permissions.ts (권한 관련)
├── hooks/
│   ├── auth/
│   │   └── useAppwriteAuth.ts (인증 관련 훅)
│   └── transactions/
│       └── useAppwriteTransactions.ts (트랜잭션 관련 훅)
├── components/
│   ├── auth/
│   │   └── AppwriteConnectionStatus.tsx (연결 상태 표시)
│   ├── migration/
│   │   └── SupabaseToAppwriteMigration.tsx (마이그레이션 도구)
│   └── native/
│       ├── PermissionRequest.tsx (권한 요청 UI)
│       └── NotificationSettings.tsx (알림 설정 UI)
└── utils/
    └── appwriteTransactionUtils.ts (트랜잭션 유틸리티)

환경 설정

.env 파일에 다음 환경 변수를 설정합니다:

# Appwrite 설정
VITE_APPWRITE_ENDPOINT=https://a11.ism.kr/v1
VITE_APPWRITE_PROJECT_ID=zellyy-finance
VITE_APPWRITE_DATABASE_ID=zellyy-finance
VITE_APPWRITE_TRANSACTIONS_COLLECTION_ID=transactions

# 네이티브 설정
VITE_ANDROID_MIN_API_LEVEL=21
VITE_ANDROID_TARGET_API_LEVEL=33
VITE_ANDROID_NOTIFICATION_CHANNEL_ID=zellyy_finance_notifications

마이그레이션 단계

  1. 데이터베이스 설정

    • Appwrite 데이터베이스 및 컬렉션 생성
    • 필요한 인덱스 및 권한 설정
  2. 인증 시스템 전환

    • Appwrite 인증 시스템 설정
    • 사용자 계정 마이그레이션
  3. 데이터 마이그레이션

    • 트랜잭션 데이터 마이그레이션
    • 데이터 무결성 검증
  4. Supabase 코드 제거

    • 마이그레이션 완료 후 Supabase 관련 코드 제거
    • 환경 변수 정리

주요 컴포넌트 및 훅

1. Appwrite 클라이언트 설정

// src/lib/appwrite/client.ts
import { Client, Account, Databases, Storage } from 'appwrite';
import { config } from './config';

// 클라이언트 초기화
export const client = new Client()
  .setEndpoint(config.endpoint)
  .setProject(config.projectId);

// 서비스 초기화
export const account = new Account(client);
export const databases = new Databases(client);
export const storage = new Storage(client);

2. 인증 훅

// src/hooks/auth/useAppwriteAuth.ts
import { useState, useEffect } from 'react';
import { account } from '../../lib/appwrite';

export const useAppwriteAuth = () => {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);

  // 사용자 세션 확인
  useEffect(() => {
    const checkSession = async () => {
      try {
        const session = await account.getSession('current');
        if (session) {
          const currentUser = await account.get();
          setUser(currentUser);
        }
      } catch (error) {
        console.error('세션 확인 오류:', error);
      } finally {
        setLoading(false);
      }
    };

    checkSession();
  }, []);

  // 로그인 함수
  const login = async (email, password) => {
    try {
      await account.createEmailSession(email, password);
      const currentUser = await account.get();
      setUser(currentUser);
      return { success: true };
    } catch (error) {
      console.error('로그인 오류:', error);
      return { success: false, error };
    }
  };

  // 로그아웃 함수
  const logout = async () => {
    try {
      await account.deleteSession('current');
      setUser(null);
      return { success: true };
    } catch (error) {
      console.error('로그아웃 오류:', error);
      return { success: false, error };
    }
  };

  return { user, loading, login, logout };
};

3. 트랜잭션 훅

// src/hooks/transactions/useAppwriteTransactions.ts
import { useState, useEffect, useCallback } from 'react';
import { databases } from '../../lib/appwrite';
import { config } from '../../lib/appwrite/config';
import { Query } from 'appwrite';

export const useAppwriteTransactions = (userId) => {
  const [transactions, setTransactions] = useState([]);
  const [loading, setLoading] = useState(true);

  // 트랜잭션 불러오기
  const fetchTransactions = useCallback(async () => {
    if (!userId) return;
    
    try {
      setLoading(true);
      const response = await databases.listDocuments(
        config.databaseId,
        config.transactionsCollectionId,
        [Query.equal('userId', userId)]
      );
      setTransactions(response.documents);
    } catch (error) {
      console.error('트랜잭션 불러오기 오류:', error);
    } finally {
      setLoading(false);
    }
  }, [userId]);

  // 초기 데이터 로드
  useEffect(() => {
    fetchTransactions();
  }, [fetchTransactions]);

  // 트랜잭션 추가
  const addTransaction = async (transaction) => {
    try {
      const newTransaction = await databases.createDocument(
        config.databaseId,
        config.transactionsCollectionId,
        'unique()',
        {
          ...transaction,
          userId,
          createdAt: new Date().toISOString(),
        }
      );
      setTransactions((prev) => [...prev, newTransaction]);
      return { success: true, transaction: newTransaction };
    } catch (error) {
      console.error('트랜잭션 추가 오류:', error);
      return { success: false, error };
    }
  };

  // 트랜잭션 업데이트
  const updateTransaction = async (id, data) => {
    try {
      const updatedTransaction = await databases.updateDocument(
        config.databaseId,
        config.transactionsCollectionId,
        id,
        data
      );
      setTransactions((prev) =>
        prev.map((t) => (t.$id === id ? updatedTransaction : t))
      );
      return { success: true, transaction: updatedTransaction };
    } catch (error) {
      console.error('트랜잭션 업데이트 오류:', error);
      return { success: false, error };
    }
  };

  // 트랜잭션 삭제
  const deleteTransaction = async (id) => {
    try {
      await databases.deleteDocument(
        config.databaseId,
        config.transactionsCollectionId,
        id
      );
      setTransactions((prev) => prev.filter((t) => t.$id !== id));
      return { success: true };
    } catch (error) {
      console.error('트랜잭션 삭제 오류:', error);
      return { success: false, error };
    }
  };

  return {
    transactions,
    loading,
    fetchTransactions,
    addTransaction,
    updateTransaction,
    deleteTransaction,
  };
};

마이그레이션 도구 사용법

  1. 설정 페이지에서 "Appwrite 설정" 메뉴 선택
  2. "Supabase에서 Appwrite로 마이그레이션" 섹션에서 "마이그레이션 시작" 버튼 클릭
  3. 마이그레이션 진행 상황 확인
  4. 완료 후 데이터 검증

주의사항

  1. 마이그레이션 중에는 데이터 변경을 최소화하세요.
  2. 마이그레이션 전에 데이터 백업을 수행하세요.
  3. 마이그레이션 후 모든 기능이 정상 작동하는지 테스트하세요.
  4. 문제 발생 시 개발팀에 즉시 보고하세요.