# 적자 탈출 가계부 - 데이터베이스 스키마 구현

## 1. 개요

적자 탈출 가계부 애플리케이션의 데이터베이스 스키마 구현에 대한 문서입니다. 이 문서는 Supabase 자체 호스팅 환경에서 PostgreSQL 데이터베이스를 사용하여 구현된 데이터베이스 스키마를 설명합니다.

## 2. 마이그레이션 파일 구조

데이터베이스 스키마는 다음과 같은 마이그레이션 파일로 구성되어 있습니다:

1. `01_users.sql`: 사용자 정보 관리
2. `02_categories.sql`: 지출 카테고리 관리
3. `03_expenses.sql`: 지출 내역 관리
4. `04_budgets.sql`: 예산 관리
5. `05_cards.sql`: 카드 정보 관리
6. `06_limits.sql`: 지출 한도 관리
7. `07_templates.sql`: 템플릿 관리
8. `08_notifications.sql`: 알림 시스템
9. `09_analysis_settings.sql`: 분석 설정

각 마이그레이션 파일은 테이블 생성, 인덱스 생성, RLS(Row Level Security) 정책 설정, 관련 함수 및 트리거를 포함합니다.

## 3. 테이블 구조

### 3.1 사용자(users) 테이블

```sql
CREATE TABLE IF NOT EXISTS users (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  email VARCHAR(255) UNIQUE NOT NULL,
  password VARCHAR(255) NOT NULL,
  name VARCHAR(100) NOT NULL,
  created_at TIMESTAMP WITH TIME ZONE DEFAULT now()
);
```

- **주요 기능**: 사용자 정보 저장
- **RLS 정책**: 사용자는 자신의 정보만 조회/수정 가능
- **관련 트리거**: Supabase Auth와 연동하여 사용자 생성 시 프로필 자동 생성

### 3.2 카테고리(categories) 테이블

```sql
CREATE TABLE IF NOT EXISTS categories (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  name VARCHAR(50) NOT NULL,
  icon VARCHAR(50) NOT NULL,
  color VARCHAR(20) NOT NULL,
  parent_id UUID REFERENCES categories(id),
  is_income BOOLEAN DEFAULT FALSE,
  is_default BOOLEAN DEFAULT TRUE,
  created_at TIMESTAMP WITH TIME ZONE DEFAULT now(),
  updated_at TIMESTAMP WITH TIME ZONE DEFAULT now()
);
```

- **주요 기능**: 지출/수입 카테고리 관리
- **RLS 정책**: 모든 사용자가 조회 가능, 수정은 관리자만 가능
- **기본 데이터**: 40개 이상의 기본 카테고리 제공 (지출 및 수입 카테고리)
- **계층 구조**: 부모-자식 관계를 통한 카테고리 계층화

### 3.3 지출(expenses) 테이블

```sql
CREATE TABLE IF NOT EXISTS expenses (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
  amount NUMERIC(12,2) NOT NULL,
  date DATE NOT NULL,
  category_id UUID REFERENCES categories(id),
  memo TEXT,
  created_at TIMESTAMP WITH TIME ZONE DEFAULT now()
);
```

- **주요 기능**: 사용자의 지출/수입 내역 저장
- **RLS 정책**: 사용자는 자신의 지출 데이터만 접근 가능
- **관련 함수**: 월별 지출 합계 조회 함수 제공

### 3.4 예산(budgets) 테이블

```sql
CREATE TABLE IF NOT EXISTS budgets (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
  amount NUMERIC(12,2) NOT NULL,
  month INTEGER NOT NULL CHECK (month BETWEEN 1 AND 12),
  year INTEGER NOT NULL,
  created_at TIMESTAMP WITH TIME ZONE DEFAULT now(),
  UNIQUE(user_id, month, year)
);
```

- **주요 기능**: 사용자의 월별 예산 관리
- **RLS 정책**: 사용자는 자신의 예산 데이터만 접근 가능
- **관련 함수**: 예산 대비 지출 비율 조회 함수 제공

### 3.5 카드(cards) 테이블

```sql
CREATE TABLE IF NOT EXISTS cards (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
  name VARCHAR(100) NOT NULL,
  card_type VARCHAR(20) NOT NULL CHECK (card_type IN ('credit', 'debit', 'prepaid')),
  card_number_last4 VARCHAR(4),
  issuer VARCHAR(50),
  color VARCHAR(20),
  payment_day INTEGER CHECK (payment_day BETWEEN 1 AND 31),
  monthly_limit NUMERIC(12,2),
  is_active BOOLEAN DEFAULT TRUE,
  created_at TIMESTAMP WITH TIME ZONE DEFAULT now(),
  updated_at TIMESTAMP WITH TIME ZONE DEFAULT now()
);
```

- **주요 기능**: 사용자의 카드 정보 관리
- **RLS 정책**: 사용자는 자신의 카드 데이터만 접근 가능
- **관련 함수**: 사용자별 카드 목록 조회 함수 제공

### 3.6 한도(limits) 테이블

```sql
CREATE TABLE IF NOT EXISTS limits (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
  card_id UUID REFERENCES cards(id) ON DELETE CASCADE,
  category_id UUID REFERENCES categories(id) ON DELETE SET NULL,
  amount NUMERIC(12,2) NOT NULL CHECK (amount > 0),
  period VARCHAR(20) NOT NULL CHECK (period IN ('daily', 'weekly', 'monthly')),
  start_date DATE NOT NULL,
  end_date DATE,
  is_active BOOLEAN DEFAULT TRUE,
  created_at TIMESTAMP WITH TIME ZONE DEFAULT now(),
  updated_at TIMESTAMP WITH TIME ZONE DEFAULT now(),
  CONSTRAINT card_or_category_required CHECK (card_id IS NOT NULL OR category_id IS NOT NULL),
  CONSTRAINT valid_date_range CHECK (end_date IS NULL OR end_date >= start_date)
);
```

- **주요 기능**: 카드 또는 카테고리별 지출 한도 관리
- **RLS 정책**: 사용자는 자신의 한도 데이터만 접근 가능
- **관련 함수**: 활성화된 한도 조회 및 사용량 계산 함수 제공

### 3.7 템플릿(templates) 테이블

```sql
CREATE TABLE IF NOT EXISTS templates (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
  name VARCHAR(100) NOT NULL,
  card_id UUID REFERENCES cards(id) ON DELETE SET NULL,
  category_id UUID REFERENCES categories(id) ON DELETE SET NULL,
  amount NUMERIC(12,2) NOT NULL CHECK (amount > 0),
  description TEXT,
  location VARCHAR(255),
  is_income BOOLEAN DEFAULT FALSE,
  is_favorite BOOLEAN DEFAULT FALSE,
  created_at TIMESTAMP WITH TIME ZONE DEFAULT now(),
  updated_at TIMESTAMP WITH TIME ZONE DEFAULT now(),
  UNIQUE(user_id, name)
);
```

- **주요 기능**: 자주 사용하는 지출/수입 템플릿 관리
- **RLS 정책**: 사용자는 자신의 템플릿 데이터만 접근 가능
- **관련 함수**: 템플릿으로 지출 생성 함수 제공

### 3.8 알림(notifications) 테이블

```sql
CREATE TABLE IF NOT EXISTS notifications (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
  title VARCHAR(100) NOT NULL,
  message TEXT NOT NULL,
  type VARCHAR(20) NOT NULL CHECK (type IN ('limit_warning', 'payment_due', 'tip', 'system')),
  related_id UUID,
  related_type VARCHAR(50),
  is_read BOOLEAN DEFAULT FALSE,
  created_at TIMESTAMP WITH TIME ZONE DEFAULT now(),
  read_at TIMESTAMP WITH TIME ZONE
);
```

- **주요 기능**: 사용자 알림 관리 (한도 경고, 결제일 알림 등)
- **RLS 정책**: 사용자는 자신의 알림 데이터만 접근 가능
- **관련 트리거**: 지출 한도 초과 시 자동 알림 생성

### 3.9 분석 설정(analysis_settings) 테이블

```sql
CREATE TABLE IF NOT EXISTS analysis_settings (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
  budget_period VARCHAR(20) DEFAULT 'monthly' CHECK (budget_period IN ('daily', 'weekly', 'monthly')),
  saving_goal NUMERIC(12,2),
  analysis_period INTEGER DEFAULT 3 CHECK (analysis_period > 0),
  notification_frequency VARCHAR(20) DEFAULT 'weekly' CHECK (notification_frequency IN ('daily', 'weekly', 'monthly', 'none')),
  created_at TIMESTAMP WITH TIME ZONE DEFAULT now(),
  updated_at TIMESTAMP WITH TIME ZONE DEFAULT now(),
  UNIQUE(user_id)
);
```

- **주요 기능**: 사용자별 분석 설정 관리
- **RLS 정책**: 사용자는 자신의 분석 설정 데이터만 접근 가능
- **관련 트리거**: 사용자 생성 시 기본 분석 설정 자동 생성
- **관련 함수**: 지출 분석 및 추세 분석 함수 제공

## 4. Row Level Security(RLS) 정책

모든 테이블에는 Row Level Security 정책이 적용되어 있습니다. 이를 통해 사용자는 자신의 데이터만 접근할 수 있으며, 다른 사용자의 데이터에는 접근할 수 없습니다.

기본적인 RLS 정책 패턴:

```sql
-- 테이블에 RLS 활성화
ALTER TABLE table_name ENABLE ROW LEVEL SECURITY;

-- 조회 정책
CREATE POLICY "select_policy" ON table_name
  FOR SELECT USING (auth.uid() = user_id);

-- 삽입 정책
CREATE POLICY "insert_policy" ON table_name
  FOR INSERT WITH CHECK (auth.uid() = user_id);

-- 수정 정책
CREATE POLICY "update_policy" ON table_name
  FOR UPDATE USING (auth.uid() = user_id);

-- 삭제 정책
CREATE POLICY "delete_policy" ON table_name
  FOR DELETE USING (auth.uid() = user_id);
```

## 5. 인덱스

성능 최적화를 위해 각 테이블에 적절한 인덱스가 생성되어 있습니다:

- 외래 키 컬럼에 대한 인덱스
- 자주 조회되는 컬럼에 대한 인덱스
- 복합 인덱스 (예: `user_id`와 `date` 조합)

## 6. 함수 및 트리거

다양한 비즈니스 로직을 지원하기 위해 여러 함수와 트리거가 구현되어 있습니다:

### 6.1 주요 함수

- `get_monthly_expenses`: 월별 지출 합계 조회
- `get_budget_usage`: 예산 대비 지출 비율 조회
- `get_user_cards`: 사용자별 카드 목록 조회
- `get_active_limits`: 활성화된 한도 및 사용량 조회
- `create_expense_from_template`: 템플릿으로 지출 생성
- `mark_notification_as_read`: 알림 읽음 표시
- `get_expense_analysis`: 카테고리별 지출 분석
- `get_monthly_expense_trend`: 월별 지출 추세 분석

### 6.2 주요 트리거

- `update_updated_at_column`: 레코드 업데이트 시 `updated_at` 자동 갱신
- `create_user_profile`: Supabase Auth 사용자 생성 시 프로필 자동 생성
- `create_limit_warning_notification`: 지출 한도 초과 시 알림 자동 생성
- `create_default_analysis_settings`: 사용자 생성 시 기본 분석 설정 자동 생성

## 7. 마이그레이션 실행 방법

마이그레이션 파일을 실행하기 위한 스크립트가 제공됩니다:

```bash
# 실행 권한 부여
chmod +x run_migrations.sh

# 스크립트 실행
./run_migrations.sh
```

환경 변수를 통해 데이터베이스 연결 정보를 설정할 수 있습니다:

```bash
DB_HOST=localhost DB_PORT=5432 DB_NAME=postgres DB_USER=postgres DB_PASSWORD=postgres ./run_migrations.sh
```

## 8. 향후 확장 계획

1. **데이터 동기화**: 오프라인 모드 지원을 위한 동기화 메커니즘 구현
2. **데이터 분석**: 더 다양한 분석 함수 및 뷰 추가
3. **데이터 마이그레이션**: 버전 관리 및 롤백 메커니즘 개선
4. **성능 최적화**: 대규모 데이터셋에 대한 쿼리 성능 최적화

## 9. 참고 사항

- 모든 날짜/시간 데이터는 타임존 정보를 포함합니다 (`TIMESTAMP WITH TIME ZONE`).
- 금액 데이터는 `NUMERIC(12,2)` 타입을 사용하여 정확한 소수점 계산을 보장합니다.
- UUID를 기본 키로 사용하여 분산 환경에서의 확장성을 고려했습니다.
- 모든 테이블에는 생성 시간(`created_at`)이 자동으로 기록됩니다.
