# 적자 탈출 가계부 - 데이터베이스 스키마 구현 ## 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`)이 자동으로 기록됩니다.