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

## 개요

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

## 데이터베이스 선택

### 주요 데이터베이스: MongoDB

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

### 보조 데이터베이스: Redis

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

## 주요 데이터 엔티티

### 1. 사용자 (Users)

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

```javascript
{
  _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)

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

```javascript
{
  _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)

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

```javascript
{
  _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)

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

```javascript
{
  _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)

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

```javascript
{
  _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)

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

```javascript
{
  _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)

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

```javascript
{
  _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)

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

```javascript
{
  _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)

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

```javascript
{
  _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)

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

```javascript
{
  _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 기반 분석 및 추천 기능 강화를 위한 데이터 구조 최적화가 향후 중점적으로 이루어질 계획입니다.