mirror of
https://github.com/cna-bootcamp/phonebill.git
synced 2025-12-06 08:06:24 +00:00
307 lines
13 KiB
Markdown
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) |