Files
zellyy-finance/docs/02_기술_문서/02_데이터_모델_설계.md
2025-03-21 16:08:43 +09:00

20 KiB

적자 탈출 가계부 데이터 모델 설계

개요

'적자 탈출 가계부' 애플리케이션의 데이터 모델은 사용자의 재정 데이터를 효율적으로 저장, 관리, 분석할 수 있도록 설계되었습니다. 본 문서는 데이터베이스 스키마, 주요 엔티티 간의 관계, 그리고 데이터 접근 패턴에 대해 설명합니다.

데이터베이스 선택

주요 데이터베이스: MongoDB

MongoDB를 주요 데이터베이스로 선택한 이유:

  • 유연한 스키마: 사용자별 맞춤형 카테고리, 태그 등 다양한 확장 가능성 지원
  • 문서 지향적 구조: 계층적 데이터(예: 거래 내역과 관련 메타데이터) 저장에 적합
  • 확장성: 사용자 증가에 따른 수평적 확장 용이
  • 쿼리 성능: 복잡한 집계 및 분석 쿼리 지원

보조 데이터베이스: Redis

Redis를 보조 데이터베이스로 활용:

  • 캐싱: 자주 접근하는 데이터(예: 사용자 대시보드 요약) 캐싱
  • 세션 관리: 사용자 세션 및 인증 토큰 관리
  • 실시간 데이터: 알림 및 실시간 업데이트 관리
  • 작업 큐: 비동기 작업(예: 데이터 분석, 보고서 생성) 관리

주요 데이터 엔티티

1. 사용자 (Users)

사용자 계정 및 프로필 정보를 저장합니다.

{
  _id: ObjectId,                // 사용자 고유 ID
  email: String,                // 이메일 (로그인 ID)
  password: String,             // 암호화된 비밀번호
  name: String,                 // 사용자 이름
  profileImage: String,         // 프로필 이미지 URL
  phoneNumber: String,          // 전화번호 (선택사항)
  dateOfBirth: Date,            // 생년월일 (선택사항)
  gender: String,               // 성별 (선택사항)
  occupation: String,           // 직업 (선택사항)
  monthlyIncome: Number,        // 월 평균 수입
  financialGoals: [             // 재정 목표 목록
    {
      _id: ObjectId,            // 목표 ID
      name: String,             // 목표 이름
      targetAmount: Number,     // 목표 금액
      currentAmount: Number,    // 현재 금액
      deadline: Date,           // 목표 기한
      category: String,         // 목표 카테고리
      isCompleted: Boolean,     // 완료 여부
      createdAt: Date           // 생성 일시
    }
  ],
  preferences: {                // 사용자 설정
    currency: String,           // 통화 단위
    language: String,           // 언어 설정
    theme: String,              // UI 테마
    notificationSettings: {     // 알림 설정
      budgetAlerts: Boolean,    // 예산 알림
      transactionReminders: Boolean, // 거래 리마인더
      weeklyReports: Boolean,   // 주간 보고서
      savingsTips: Boolean      // 절약 팁
    }
  },
  subscriptionTier: String,     // 구독 등급 (free, premium)
  subscriptionExpiresAt: Date,  // 구독 만료일
  createdAt: Date,              // 계정 생성일
  updatedAt: Date,              // 최종 업데이트일
  lastLoginAt: Date,            // 최근 로그인일
  isActive: Boolean,            // 계정 활성화 상태
  deactivatedAt: Date,          // 계정 비활성화일
  refreshToken: String          // 리프레시 토큰
}

2. 거래 내역 (Transactions)

사용자의 모든 수입, 지출, 이체 거래를 저장합니다.

{
  _id: ObjectId,                // 거래 고유 ID
  userId: ObjectId,             // 사용자 ID (참조)
  type: String,                 // 거래 유형 (income, expense, transfer)
  amount: Number,               // 거래 금액
  currency: String,             // 통화 단위
  categoryId: ObjectId,         // 카테고리 ID (참조)
  subcategoryId: ObjectId,      // 서브카테고리 ID (참조, 선택사항)
  paymentMethodId: ObjectId,    // 결제 수단 ID (참조)
  accountId: ObjectId,          // 계좌 ID (참조)
  description: String,          // 거래 설명
  memo: String,                 // 추가 메모
  transactionDate: Date,        // 거래 일시
  location: {                   // 거래 위치 (선택사항)
    name: String,               // 장소 이름
    latitude: Number,           // 위도
    longitude: Number           // 경도
  },
  tags: [String],               // 태그 목록
  attachments: [                // 첨부 파일 (영수증 등)
    {
      url: String,              // 파일 URL
      type: String,             // 파일 유형
      name: String,             // 파일 이름
      uploadedAt: Date          // 업로드 일시
    }
  ],
  isRecurring: Boolean,         // 정기 거래 여부
  recurringDetails: {           // 정기 거래 상세 (선택사항)
    frequency: String,          // 빈도 (daily, weekly, monthly, yearly)
    interval: Number,           // 간격
    startDate: Date,            // 시작일
    endDate: Date,              // 종료일 (선택사항)
    lastProcessedDate: Date     // 마지막 처리일
  },
  status: String,               // 상태 (pending, completed, cancelled)
  createdAt: Date,              // 생성일
  updatedAt: Date,              // 수정일
  deletedAt: Date,              // 삭제일 (소프트 삭제)
  isDeleted: Boolean            // 삭제 여부
}

3. 카테고리 (Categories)

거래를 분류하기 위한 카테고리 정보를 저장합니다.

{
  _id: ObjectId,                // 카테고리 고유 ID
  userId: ObjectId,             // 사용자 ID (참조, null이면 기본 카테고리)
  name: String,                 // 카테고리 이름
  type: String,                 // 카테고리 유형 (income, expense)
  icon: String,                 // 아이콘 식별자
  color: String,                // 색상 코드
  isDefault: Boolean,           // 기본 카테고리 여부
  isActive: Boolean,            // 활성화 상태
  parentId: ObjectId,           // 부모 카테고리 ID (참조, 선택사항)
  order: Number,                // 표시 순서
  createdAt: Date,              // 생성일
  updatedAt: Date               // 수정일
}

4. 예산 (Budgets)

사용자의 예산 설정 정보를 저장합니다.

{
  _id: ObjectId,                // 예산 고유 ID
  userId: ObjectId,             // 사용자 ID (참조)
  name: String,                 // 예산 이름
  amount: Number,               // 예산 금액
  currency: String,             // 통화 단위
  period: String,               // 기간 유형 (daily, weekly, monthly, yearly)
  startDate: Date,              // 시작일
  endDate: Date,                // 종료일
  categoryIds: [ObjectId],      // 카테고리 ID 목록 (참조)
  isRecurring: Boolean,         // 반복 여부
  notificationThreshold: Number, // 알림 임계값 (%)
  createdAt: Date,              // 생성일
  updatedAt: Date,              // 수정일
  isActive: Boolean             // 활성화 상태
}

5. 계좌 (Accounts)

사용자의 금융 계좌 정보를 저장합니다.

{
  _id: ObjectId,                // 계좌 고유 ID
  userId: ObjectId,             // 사용자 ID (참조)
  name: String,                 // 계좌 이름
  type: String,                 // 계좌 유형 (checking, savings, credit, investment)
  institutionName: String,      // 금융 기관 이름
  accountNumber: String,        // 계좌 번호 (마스킹 처리)
  balance: Number,              // 현재 잔액
  currency: String,             // 통화 단위
  isLinked: Boolean,            // 외부 API 연동 여부
  externalId: String,           // 외부 API 식별자 (선택사항)
  lastSyncAt: Date,             // 마지막 동기화 일시
  icon: String,                 // 아이콘 식별자
  color: String,                // 색상 코드
  isDefault: Boolean,           // 기본 계좌 여부
  isActive: Boolean,            // 활성화 상태
  createdAt: Date,              // 생성일
  updatedAt: Date               // 수정일
}

6. 결제 수단 (PaymentMethods)

사용자의 결제 수단 정보를 저장합니다.

{
  _id: ObjectId,                // 결제 수단 고유 ID
  userId: ObjectId,             // 사용자 ID (참조)
  name: String,                 // 결제 수단 이름
  type: String,                 // 유형 (cash, credit_card, debit_card, bank_transfer, mobile_payment)
  accountId: ObjectId,          // 연결된 계좌 ID (참조, 선택사항)
  cardInfo: {                   // 카드 정보 (선택사항)
    lastFourDigits: String,     // 카드 번호 마지막 4자리
    expiryDate: String,         // 만료일
    cardNetwork: String         // 카드 네트워크 (Visa, Mastercard 등)
  },
  icon: String,                 // 아이콘 식별자
  color: String,                // 색상 코드
  isDefault: Boolean,           // 기본 결제 수단 여부
  isActive: Boolean,            // 활성화 상태
  createdAt: Date,              // 생성일
  updatedAt: Date               // 수정일
}

7. 절약 챌린지 (SavingChallenges)

사용자의 절약 챌린지 정보를 저장합니다.

{
  _id: ObjectId,                // 챌린지 고유 ID
  title: String,                // 챌린지 제목
  description: String,          // 챌린지 설명
  type: String,                 // 챌린지 유형 (system, custom)
  creatorId: ObjectId,          // 생성자 ID (참조, system이면 null)
  targetAmount: Number,         // 목표 절약 금액
  duration: Number,             // 기간 (일 단위)
  difficulty: String,           // 난이도 (easy, medium, hard)
  categoryIds: [ObjectId],      // 관련 카테고리 ID 목록 (참조)
  tips: [String],               // 절약 팁 목록
  imageUrl: String,             // 챌린지 이미지 URL
  isPublic: Boolean,            // 공개 여부
  participantCount: Number,     // 참여자 수
  successRate: Number,          // 성공률 (%)
  createdAt: Date,              // 생성일
  updatedAt: Date,              // 수정일
  isActive: Boolean             // 활성화 상태
}

8. 사용자 챌린지 참여 (UserChallenges)

사용자의 챌린지 참여 정보를 저장합니다.

{
  _id: ObjectId,                // 참여 고유 ID
  userId: ObjectId,             // 사용자 ID (참조)
  challengeId: ObjectId,        // 챌린지 ID (참조)
  startDate: Date,              // 시작일
  endDate: Date,                // 종료일
  targetAmount: Number,         // 개인 목표 금액
  currentAmount: Number,        // 현재 절약 금액
  status: String,               // 상태 (in_progress, completed, failed)
  progress: Number,             // 진행률 (%)
  dailyLogs: [                  // 일일 기록
    {
      date: Date,               // 날짜
      amount: Number,           // 절약 금액
      note: String              // 메모
    }
  ],
  completedAt: Date,            // 완료일 (선택사항)
  reward: {                     // 보상 정보 (선택사항)
    type: String,               // 보상 유형
    description: String,        // 보상 설명
    claimedAt: Date             // 수령일
  },
  createdAt: Date,              // 생성일
  updatedAt: Date               // 수정일
}

9. 재정 분석 (FinancialAnalytics)

사용자의 재정 분석 데이터를 저장합니다.

{
  _id: ObjectId,                // 분석 고유 ID
  userId: ObjectId,             // 사용자 ID (참조)
  period: String,               // 기간 유형 (daily, weekly, monthly, yearly)
  startDate: Date,              // 시작일
  endDate: Date,                // 종료일
  totalIncome: Number,          // 총 수입
  totalExpense: Number,         // 총 지출
  netCashflow: Number,          // 순 현금 흐름
  savingsRate: Number,          // 저축률 (%)
  categoryBreakdown: [          // 카테고리별 지출 분석
    {
      categoryId: ObjectId,     // 카테고리 ID (참조)
      amount: Number,           // 금액
      percentage: Number,       // 비율 (%)
      trend: Number             // 전기 대비 변화율 (%)
    }
  ],
  topExpenses: [                // 주요 지출 항목
    {
      transactionId: ObjectId,  // 거래 ID (참조)
      amount: Number,           // 금액
      description: String,      // 설명
      date: Date                // 날짜
    }
  ],
  trends: {                     // 추세 분석
    incomeGrowth: Number,       // 수입 증가율 (%)
    expenseGrowth: Number,      // 지출 증가율 (%)
    savingsGrowth: Number       // 저축 증가율 (%)
  },
  financialHealthScore: {       // 재정 건강 점수
    overall: Number,            // 종합 점수
    budgetAdherence: Number,    // 예산 준수 점수
    savingsRate: Number,        // 저축률 점수
    debtManagement: Number,     // 부채 관리 점수
    expenseEfficiency: Number   // 지출 효율성 점수
  },
  insights: [                   // 인사이트 목록
    {
      type: String,             // 인사이트 유형
      description: String,      // 설명
      potentialSavings: Number, // 잠재적 절약 금액
      priority: String          // 우선순위 (high, medium, low)
    }
  ],
  createdAt: Date,              // 생성일
  updatedAt: Date               // 수정일
}

10. 알림 (Notifications)

사용자에게 전송되는 알림 정보를 저장합니다.

{
  _id: ObjectId,                // 알림 고유 ID
  userId: ObjectId,             // 사용자 ID (참조)
  type: String,                 // 알림 유형 (budget_alert, transaction_reminder, saving_tip, etc)
  title: String,                // 알림 제목
  message: String,              // 알림 내용
  data: {                       // 관련 데이터
    entityType: String,         // 엔티티 유형 (budget, transaction, challenge, etc)
    entityId: ObjectId,         // 엔티티 ID (참조)
    action: String              // 필요한 액션
  },
  isRead: Boolean,              // 읽음 여부
  readAt: Date,                 // 읽은 일시
  isActionTaken: Boolean,       // 액션 수행 여부
  actionTakenAt: Date,          // 액션 수행 일시
  expiresAt: Date,              // 만료일 (선택사항)
  priority: String,             // 우선순위 (high, medium, low)
  createdAt: Date,              // 생성일
  updatedAt: Date               // 수정일
}

데이터 관계 다이어그램

+-------------+       +----------------+       +-------------+
|   Users     |------>| Transactions   |<------| Categories  |
+-------------+       +----------------+       +-------------+
      |                      |                       |
      |                      |                       |
      v                      v                       v
+-------------+       +----------------+       +-------------+
|  Accounts   |------>| PaymentMethods |       |   Budgets   |
+-------------+       +----------------+       +-------------+
      |                                               |
      |                                               |
      v                                               v
+-------------+       +----------------+       +-------------+
| UserChallenges|<---->|SavingChallenges|       |FinancialAnalytics|
+-------------+       +----------------+       +-------------+
                                                      |
                                                      |
                                                      v
                                               +-------------+
                                               |Notifications |
                                               +-------------+

인덱싱 전략

효율적인 쿼리 성능을 위한 인덱스 설계:

사용자 컬렉션

  • email: 로그인 및 사용자 조회
  • subscriptionTier, subscriptionExpiresAt: 구독 관리

거래 내역 컬렉션

  • userId: 사용자별 거래 조회
  • userId + transactionDate: 날짜별 거래 조회
  • userId + categoryId: 카테고리별 거래 조회
  • userId + type: 수입/지출별 조회
  • userId + isRecurring: 정기 거래 조회

카테고리 컬렉션

  • userId: 사용자별 카테고리 조회
  • userId + type: 수입/지출 카테고리 조회

예산 컬렉션

  • userId: 사용자별 예산 조회
  • userId + period + startDate: 기간별 예산 조회

계좌 컬렉션

  • userId: 사용자별 계좌 조회
  • userId + type: 계좌 유형별 조회

절약 챌린지 컬렉션

  • isPublic: 공개 챌린지 조회
  • difficulty: 난이도별 챌린지 조회

사용자 챌린지 참여 컬렉션

  • userId: 사용자별 챌린지 참여 조회
  • userId + status: 상태별 챌린지 조회
  • challengeId: 챌린지별 참여자 조회

재정 분석 컬렉션

  • userId: 사용자별 분석 조회
  • userId + period + startDate: 기간별 분석 조회

알림 컬렉션

  • userId: 사용자별 알림 조회
  • userId + isRead: 읽지 않은 알림 조회
  • userId + priority: 우선순위별 알림 조회

데이터 접근 패턴

주요 사용 사례에 따른 데이터 접근 패턴:

1. 대시보드 로딩

  • 사용자 기본 정보 조회
  • 최근 거래 내역 조회 (제한된 수)
  • 현재 월 예산 대비 지출 현황 조회
  • 재정 건강 점수 조회
  • 읽지 않은 알림 조회

2. 거래 내역 조회

  • 기간별 거래 내역 페이지네이션 조회
  • 카테고리별 필터링
  • 금액별 정렬

3. 예산 관리

  • 현재 활성 예산 조회
  • 카테고리별 예산 대비 지출 현황 조회
  • 예산 초과 카테고리 식별

4. 재정 분석

  • 기간별 수입/지출 추이 조회
  • 카테고리별 지출 분석 조회
  • 전월 대비 변화율 계산
  • 절약 인사이트 생성

5. 절약 챌린지

  • 추천 챌린지 조회
  • 사용자 참여 챌린지 상태 조회
  • 챌린지 진행 상황 업데이트

데이터 마이그레이션 전략

애플리케이션 발전에 따른 데이터 마이그레이션 전략:

1. 스키마 변경 관리

  • 하위 호환성 유지: 필드 추가 시 기본값 설정
  • 버전 관리: 스키마 버전 필드 추가
  • 점진적 마이그레이션: 대규모 데이터 세트의 경우 배치 처리

2. 데이터 백업

  • 정기적인 전체 백업: 일일 단위
  • 증분 백업: 시간 단위
  • 지리적 복제: 재해 복구 대비

3. 데이터 보존 정책

  • 트랜잭션 데이터: 7년 보존
  • 분석 데이터: 집계 데이터는 영구 보존, 원시 데이터는 2년 보존
  • 사용자 활동 로그: 1년 보존
  • 삭제된 계정 데이터: 30일 후 완전 삭제

데이터 보안

사용자 재정 데이터 보호를 위한 보안 조치:

1. 데이터 암호화

  • 저장 데이터(Data at Rest): AES-256 암호화
  • 전송 중 데이터(Data in Transit): TLS 1.3
  • 민감 정보(계좌 번호, 카드 정보): 필드 수준 암호화

2. 접근 제어

  • 역할 기반 접근 제어(RBAC) 구현
  • 최소 권한 원칙 적용
  • API 키 및 토큰 관리

3. 감사 및 모니터링

  • 데이터 접근 로깅
  • 이상 행동 감지
  • 정기적인 보안 감사

성능 최적화

대규모 데이터 처리를 위한 성능 최적화 전략:

1. 쿼리 최적화

  • 적절한 인덱스 사용
  • 프로젝션을 통한 필요 필드만 조회
  • 페이지네이션 구현

2. 캐싱 전략

  • 자주 접근하는 데이터 Redis 캐싱
  • 사용자별 대시보드 데이터 캐싱
  • 분석 결과 캐싱

3. 데이터 집계

  • 실시간 집계 대신 사전 계산된 집계 데이터 활용
  • 배치 처리를 통한 분석 데이터 생성
  • 시계열 데이터 최적화

결론

'적자 탈출 가계부' 애플리케이션의 데이터 모델은 사용자의 재정 데이터를 효율적으로 관리하고 분석하기 위해 설계되었습니다. MongoDB의 유연한 스키마를 활용하여 다양한 사용자 요구사항을 수용하고, Redis를 통한 캐싱으로 성능을 최적화하였습니다.

이 데이터 모델은 초기 MVP 출시 후 사용자 피드백과 실제 사용 패턴에 따라 지속적으로 개선될 예정입니다. 특히 AI 기반 분석 및 추천 기능 강화를 위한 데이터 구조 최적화가 향후 중점적으로 이루어질 계획입니다.