2025-09-09 01:12:14 +09:00

307 lines
13 KiB
Markdown

# Auth 서비스 데이터베이스 설계서
## 1. 설계 개요
### 1.1 설계 목적
Auth 서비스의 사용자 인증 및 인가 기능 구현을 위한 독립적인 데이터베이스 설계
### 1.2 설계 원칙
- **서비스 독립성**: Auth 서비스 전용 데이터베이스 구성
- **마이크로서비스 패턴**: 다른 서비스와 직접적인 FK 관계 없음
- **캐시 우선 전략**: 타 서비스 데이터는 Redis 캐시로만 참조
- **보안 강화**: 민감 정보 암호화 저장
- **감사 추적**: 모든 인증/인가 활동 이력 관리
### 1.3 주요 기능 요구사항
- **UFR-AUTH-010**: 사용자 로그인 (ID/Password 인증, 계정 잠금)
- **UFR-AUTH-020**: 사용자 인가 (서비스별 접근 권한 확인)
## 2. 데이터베이스 아키텍처
### 2.1 데이터베이스 정보
- **DB 이름**: `phonebill_auth`
- **DBMS**: PostgreSQL 15
- **문자셋**: UTF-8
- **타임존**: Asia/Seoul
### 2.2 서비스 독립성 전략
- **직접 데이터 공유 금지**: 다른 서비스 DB와 직접 연결하지 않음
- **캐시 기반 참조**: 필요한 외부 데이터는 Redis 캐시를 통해서만 접근
- **이벤트 기반 동기화**: 필요 시 메시징을 통한 데이터 동기화
## 3. 테이블 설계
### 3.1 사용자 계정 관리
#### auth_users (사용자 계정)
```sql
-- 사용자 기본 정보 및 인증 정보
CREATE TABLE auth_users (
user_id VARCHAR(50) PRIMARY KEY, -- 사용자 ID (로그인 ID)
password_hash VARCHAR(255) NOT NULL, -- 암호화된 비밀번호 (BCrypt)
password_salt VARCHAR(100) NOT NULL, -- 비밀번호 솔트
customer_id VARCHAR(50) NOT NULL, -- 고객 식별자 (외부 참조용)
line_number VARCHAR(20), -- 회선번호 (캐시에서 조회)
account_status VARCHAR(20) DEFAULT 'ACTIVE', -- ACTIVE, LOCKED, SUSPENDED, INACTIVE
failed_login_count INTEGER DEFAULT 0, -- 로그인 실패 횟수
last_failed_login_at TIMESTAMP, -- 마지막 실패 시간
account_locked_until TIMESTAMP, -- 계정 잠금 해제 시간
last_login_at TIMESTAMP, -- 마지막 로그인 시간
last_password_changed_at TIMESTAMP, -- 비밀번호 마지막 변경 시간
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE(customer_id)
);
```
#### auth_user_sessions (사용자 세션)
```sql
-- 사용자 세션 관리
CREATE TABLE auth_user_sessions (
session_id VARCHAR(100) PRIMARY KEY, -- 세션 ID (UUID)
user_id VARCHAR(50) NOT NULL, -- 사용자 ID
session_token VARCHAR(500) NOT NULL, -- JWT 토큰
refresh_token VARCHAR(500), -- 리프레시 토큰
client_ip VARCHAR(45), -- 클라이언트 IP (IPv6 지원)
user_agent TEXT, -- User-Agent 정보
auto_login_enabled BOOLEAN DEFAULT FALSE, -- 자동 로그인 여부
expires_at TIMESTAMP NOT NULL, -- 세션 만료 시간
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
last_accessed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES auth_users(user_id) ON DELETE CASCADE
);
```
### 3.2 권한 관리
#### auth_services (서비스 정의)
```sql
-- 시스템 내 서비스 정의
CREATE TABLE auth_services (
service_code VARCHAR(30) PRIMARY KEY, -- 서비스 코드
service_name VARCHAR(100) NOT NULL, -- 서비스 이름
service_description TEXT, -- 서비스 설명
is_active BOOLEAN DEFAULT TRUE, -- 서비스 활성화 여부
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
```
#### auth_permissions (권한 정의)
```sql
-- 권한 정의 테이블
CREATE TABLE auth_permissions (
permission_id SERIAL PRIMARY KEY, -- 권한 ID
service_code VARCHAR(30) NOT NULL, -- 서비스 코드
permission_code VARCHAR(50) NOT NULL, -- 권한 코드
permission_name VARCHAR(100) NOT NULL, -- 권한 이름
permission_description TEXT, -- 권한 설명
is_active BOOLEAN DEFAULT TRUE, -- 권한 활성화 여부
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (service_code) REFERENCES auth_services(service_code),
UNIQUE(service_code, permission_code)
);
```
#### auth_user_permissions (사용자 권한)
```sql
-- 사용자별 권한 할당
CREATE TABLE auth_user_permissions (
user_permission_id SERIAL PRIMARY KEY, -- 사용자권한 ID
user_id VARCHAR(50) NOT NULL, -- 사용자 ID
permission_id INTEGER NOT NULL, -- 권한 ID
granted_by VARCHAR(50), -- 권한 부여자
granted_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
expires_at TIMESTAMP, -- 권한 만료일 (NULL = 무기한)
is_active BOOLEAN DEFAULT TRUE, -- 권한 활성화 여부
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES auth_users(user_id) ON DELETE CASCADE,
FOREIGN KEY (permission_id) REFERENCES auth_permissions(permission_id),
UNIQUE(user_id, permission_id)
);
```
### 3.3 보안 및 감사
#### auth_login_history (로그인 이력)
```sql
-- 로그인 시도 이력
CREATE TABLE auth_login_history (
history_id SERIAL PRIMARY KEY, -- 이력 ID
user_id VARCHAR(50), -- 사용자 ID (실패 시 NULL 가능)
login_type VARCHAR(20) NOT NULL, -- LOGIN, LOGOUT, AUTO_LOGIN
login_status VARCHAR(20) NOT NULL, -- SUCCESS, FAILURE, LOCKED
client_ip VARCHAR(45), -- 클라이언트 IP
user_agent TEXT, -- User-Agent 정보
failure_reason VARCHAR(100), -- 실패 사유
session_id VARCHAR(100), -- 세션 ID (성공 시)
attempted_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES auth_users(user_id) ON DELETE SET NULL
);
```
#### auth_permission_access_log (권한 접근 로그)
```sql
-- 권한 기반 접근 로그
CREATE TABLE auth_permission_access_log (
log_id SERIAL PRIMARY KEY, -- 로그 ID
user_id VARCHAR(50) NOT NULL, -- 사용자 ID
service_code VARCHAR(30) NOT NULL, -- 접근한 서비스
permission_code VARCHAR(50) NOT NULL, -- 확인된 권한
access_status VARCHAR(20) NOT NULL, -- GRANTED, DENIED
client_ip VARCHAR(45), -- 클라이언트 IP
session_id VARCHAR(100), -- 세션 ID
requested_resource VARCHAR(200), -- 요청 리소스
denial_reason VARCHAR(100), -- 거부 사유
accessed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES auth_users(user_id) ON DELETE CASCADE
);
```
## 4. 인덱스 설계
### 4.1 성능 최적화 인덱스
```sql
-- 사용자 조회 최적화
CREATE INDEX idx_auth_users_customer_id ON auth_users(customer_id);
CREATE INDEX idx_auth_users_account_status ON auth_users(account_status);
CREATE INDEX idx_auth_users_last_login ON auth_users(last_login_at);
-- 세션 관리 최적화
CREATE INDEX idx_auth_sessions_user_id ON auth_user_sessions(user_id);
CREATE INDEX idx_auth_sessions_expires_at ON auth_user_sessions(expires_at);
CREATE INDEX idx_auth_sessions_token ON auth_user_sessions(session_token);
-- 권한 조회 최적화
CREATE INDEX idx_auth_user_permissions_user_id ON auth_user_permissions(user_id);
CREATE INDEX idx_auth_user_permissions_active ON auth_user_permissions(user_id, is_active);
CREATE INDEX idx_auth_permissions_service ON auth_permissions(service_code, is_active);
-- 로그 조회 최적화
CREATE INDEX idx_auth_login_history_user_id ON auth_login_history(user_id);
CREATE INDEX idx_auth_login_history_attempted_at ON auth_login_history(attempted_at);
CREATE INDEX idx_auth_permission_log_user_id ON auth_permission_access_log(user_id);
CREATE INDEX idx_auth_permission_log_accessed_at ON auth_permission_access_log(accessed_at);
```
### 4.2 보안 관련 인덱스
```sql
-- 계정 잠금 관련 조회 최적화
CREATE INDEX idx_auth_users_failed_login ON auth_users(failed_login_count, last_failed_login_at);
CREATE INDEX idx_auth_users_locked_until ON auth_users(account_locked_until) WHERE account_locked_until IS NOT NULL;
-- IP 기반 보안 모니터링
CREATE INDEX idx_auth_login_history_ip_status ON auth_login_history(client_ip, login_status, attempted_at);
```
## 5. 제약조건 및 트리거
### 5.1 데이터 무결성 제약조건
```sql
-- 계정 상태 체크 제약조건
ALTER TABLE auth_users ADD CONSTRAINT chk_account_status
CHECK (account_status IN ('ACTIVE', 'LOCKED', 'SUSPENDED', 'INACTIVE'));
-- 로그인 상태 체크 제약조건
ALTER TABLE auth_login_history ADD CONSTRAINT chk_login_status
CHECK (login_status IN ('SUCCESS', 'FAILURE', 'LOCKED'));
-- 로그인 타입 체크 제약조건
ALTER TABLE auth_login_history ADD CONSTRAINT chk_login_type
CHECK (login_type IN ('LOGIN', 'LOGOUT', 'AUTO_LOGIN'));
-- 접근 상태 체크 제약조건
ALTER TABLE auth_permission_access_log ADD CONSTRAINT chk_access_status
CHECK (access_status IN ('GRANTED', 'DENIED'));
```
### 5.2 자동 업데이트 트리거
```sql
-- updated_at 자동 갱신 함수
CREATE OR REPLACE FUNCTION update_updated_at_column()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = CURRENT_TIMESTAMP;
RETURN NEW;
END;
$$ language 'plpgsql';
-- 각 테이블에 updated_at 트리거 적용
CREATE TRIGGER update_auth_users_updated_at BEFORE UPDATE ON auth_users
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
CREATE TRIGGER update_auth_services_updated_at BEFORE UPDATE ON auth_services
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
CREATE TRIGGER update_auth_permissions_updated_at BEFORE UPDATE ON auth_permissions
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
CREATE TRIGGER update_auth_user_permissions_updated_at BEFORE UPDATE ON auth_user_permissions
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
```
## 6. 보안 설계
### 6.1 암호화 전략
- **비밀번호**: BCrypt 해시 + 개별 솔트
- **토큰**: JWT 기반 인증 토큰
- **세션**: 안전한 세션 ID 생성 (UUID)
- **개인정보**: 필요 시 AES-256 암호화
### 6.2 계정 보안 정책
- **계정 잠금**: 5회 연속 실패 시 30분 잠금
- **세션 타임아웃**: 30분 비활성 시 자동 만료
- **토큰 갱신**: 리프레시 토큰을 통한 안전한 토큰 갱신
## 7. 캐시 전략
### 7.1 Redis 캐시 설계
```
Cache Key Pattern: auth:{category}:{identifier}
- auth:user:{user_id} -> 사용자 기본 정보 (TTL: 30분)
- auth:permissions:{user_id} -> 사용자 권한 목록 (TTL: 1시간)
- auth:session:{session_id} -> 세션 정보 (TTL: 세션 만료시간)
- auth:failed_attempts:{user_id} -> 실패 횟수 (TTL: 30분)
```
### 7.2 캐시 무효화 전략
- **권한 변경 시**: 해당 사용자 권한 캐시 삭제
- **계정 잠금/해제 시**: 사용자 정보 캐시 삭제
- **로그아웃 시**: 세션 캐시 삭제
## 8. 데이터 관계도 요약
### 8.1 핵심 관계
- `auth_users` (1) : (N) `auth_user_sessions`
- `auth_users` (1) : (N) `auth_user_permissions`
- `auth_services` (1) : (N) `auth_permissions`
- `auth_permissions` (1) : (N) `auth_user_permissions`
- `auth_users` (1) : (N) `auth_login_history`
- `auth_users` (1) : (N) `auth_permission_access_log`
### 8.2 외부 서비스 연동
- **고객 정보**: Bill-Inquiry 서비스의 고객 데이터를 캐시로만 참조
- **회선 정보**: Product-Change 서비스의 회선 데이터를 캐시로만 참조
- **서비스 메타데이터**: 각 서비스의 메뉴/기능 정보를 캐시로 관리
## 9. 성능 고려사항
### 9.1 예상 데이터 볼륨
- **사용자 수**: 10만 명 (초기), 100만 명 (목표)
- **일일 로그인**: 10만 회
- **세션 동시 접속**: 1만 개
- **로그 보관 기간**: 1년 (압축 보관)
### 9.2 성능 최적화
- **커넥션 풀**: 20개 커넥션 (초기)
- **읽기 전용 복제본**: 조회 성능 향상
- **파티셔닝**: 로그 테이블 월별 파티셔닝
- **아카이빙**: 1년 이상 로그 별도 보관
## 10. 관련 문서
- **ERD 다이어그램**: [auth-erd.puml](./auth-erd.puml)
- **스키마 스크립트**: [auth-schema.psql](./auth-schema.psql)
- **유저스토리**: [../../userstory.md](../../userstory.md)
- **API 설계서**: [../api/auth-service-api.yaml](../api/auth-service-api.yaml)