9.6 KiB
9.6 KiB
데이터베이스 설계 문서
1. 개요
| DB | 용도 | 연결 방식 |
|---|---|---|
| MariaDB | 사용자, 인증, 디바이스, 알림 규칙, 시스템 설정 | SQLModel + SQLAlchemy (async, aiomysql) |
| MongoDB | 디바이스 로그, 텔레메트리, 분석 결과, 알림 | Beanie + Motor (async) |
| Redis | 캐싱, 세션, 속도 제한, Celery 브로커 | redis-py (async, hiredis) |
2. MariaDB 스키마
2.1 users
사용자 계정 정보.
| 컬럼 | 타입 | 제약 | 설명 |
|---|---|---|---|
| id | INT | PK, AUTO_INCREMENT | |
| VARCHAR(255) | UNIQUE, INDEX | 로그인 ID | |
| hashed_password | VARCHAR(255) | NOT NULL | bcrypt 해시 |
| role | VARCHAR(20) | DEFAULT 'user' | superadmin/admin/manager/user/device |
| is_active | BOOLEAN | DEFAULT TRUE | 계정 활성 여부 |
| is_verified | BOOLEAN | DEFAULT FALSE | 이메일 인증 여부 |
| last_login_at | DATETIME | NULLABLE | 마지막 로그인 |
| is_deleted | BOOLEAN | DEFAULT FALSE | 소프트 삭제 |
| deleted_at | DATETIME | NULLABLE | 삭제 시각 |
| created_at | DATETIME | server_default=NOW() | |
| updated_at | DATETIME | onupdate=NOW() |
2.2 user_profiles
사용자 프로필 (1:1).
| 컬럼 | 타입 | 제약 | 설명 |
|---|---|---|---|
| id | INT | PK | |
| user_id | INT | FK→users.id, UNIQUE | |
| full_name | VARCHAR(100) | 이름 | |
| phone | VARCHAR(20) | 전화번호 | |
| organization | VARCHAR(100) | 소속 | |
| avatar_url | VARCHAR(500) | 프로필 이미지 | |
| created_at | DATETIME | ||
| updated_at | DATETIME |
2.3 refresh_tokens
리프레시 토큰 저장소. 토큰 순환(rotation) 방식 사용.
| 컬럼 | 타입 | 제약 | 설명 |
|---|---|---|---|
| id | INT | PK | |
| user_id | INT | FK→users.id, INDEX | |
| token | VARCHAR(500) | UNIQUE, INDEX | JWT 리프레시 토큰 |
| expires_at | DATETIME | NOT NULL | 만료 시각 |
| is_revoked | BOOLEAN | DEFAULT FALSE | 폐기 여부 |
| device_info | VARCHAR(255) | 접속 디바이스 정보 | |
| created_at | DATETIME | ||
| updated_at | DATETIME |
2.4 oauth_accounts
소셜 로그인 연동 계정.
| 컬럼 | 타입 | 제약 | 설명 |
|---|---|---|---|
| id | INT | PK | |
| user_id | INT | FK→users.id, INDEX | |
| provider | VARCHAR(50) | google/kakao/naver | |
| provider_user_id | VARCHAR(255) | 제공자 사용자 ID | |
| access_token | VARCHAR(500) | OAuth 액세스 토큰 | |
| refresh_token | VARCHAR(500) | OAuth 리프레시 토큰 | |
| expires_at | DATETIME | NULLABLE | 토큰 만료 |
| created_at | DATETIME | ||
| updated_at | DATETIME |
2.5 devices
IoT 디바이스 정보.
| 컬럼 | 타입 | 제약 | 설명 |
|---|---|---|---|
| id | INT | PK | |
| device_uid | VARCHAR(100) | UNIQUE, INDEX | 디바이스 고유 식별자 |
| name | VARCHAR(100) | 디바이스 이름 | |
| device_type | VARCHAR(50) | 센서 유형 (temperature, humidity 등) | |
| status | VARCHAR(20) | DEFAULT 'offline' | online/offline/error/maintenance |
| firmware_version | VARCHAR(50) | 펌웨어 버전 | |
| ip_address | VARCHAR(45) | IPv4/IPv6 | |
| group_id | INT | FK→device_groups.id, NULLABLE | |
| owner_id | INT | FK→users.id, NULLABLE | |
| last_seen_at | DATETIME | NULLABLE | 마지막 통신 시각 |
| metadata_json | VARCHAR(2000) | DEFAULT '{}' | 추가 메타데이터 |
| is_deleted | BOOLEAN | DEFAULT FALSE | |
| deleted_at | DATETIME | NULLABLE | |
| created_at | DATETIME | ||
| updated_at | DATETIME |
2.6 device_groups
디바이스 그룹 (논리적 분류).
| 컬럼 | 타입 | 제약 | 설명 |
|---|---|---|---|
| id | INT | PK | |
| name | VARCHAR(100) | UNIQUE | 그룹명 |
| description | VARCHAR(500) | 설명 | |
| created_at | DATETIME | ||
| updated_at | DATETIME |
2.7 alert_rules
알림 발생 조건 규칙.
| 컬럼 | 타입 | 제약 | 설명 |
|---|---|---|---|
| id | INT | PK | |
| name | VARCHAR(100) | 규칙명 | |
| description | VARCHAR(500) | 설명 | |
| metric | VARCHAR(100) | 감시 메트릭 (temperature, humidity 등) | |
| condition | VARCHAR(50) | 조건 (gt, lt, eq, gte, lte) | |
| threshold | FLOAT | 임계값 | |
| severity | VARCHAR(20) | DEFAULT 'warning' | critical/warning/info |
| is_enabled | BOOLEAN | DEFAULT TRUE | |
| device_group_id | INT | FK→device_groups.id, NULLABLE | 대상 그룹 |
| created_by | INT | FK→users.id, NULLABLE | 생성자 |
| created_at | DATETIME | ||
| updated_at | DATETIME |
2.8 alerts
발생한 알림 이력.
| 컬럼 | 타입 | 제약 | 설명 |
|---|---|---|---|
| id | INT | PK | |
| rule_id | INT | FK→alert_rules.id, NULLABLE | 원인 규칙 |
| device_id | INT | FK→devices.id, NULLABLE | 대상 디바이스 |
| severity | VARCHAR(20) | critical/warning/info | |
| message | VARCHAR(500) | 알림 메시지 | |
| is_acknowledged | BOOLEAN | DEFAULT FALSE | 확인 여부 |
| acknowledged_by | INT | FK→users.id, NULLABLE | 확인한 사용자 |
| acknowledged_at | DATETIME | NULLABLE | 확인 시각 |
| created_at | DATETIME | ||
| updated_at | DATETIME |
2.9 system_configs
시스템 설정 키-값 저장소.
| 컬럼 | 타입 | 제약 | 설명 |
|---|---|---|---|
| id | INT | PK | |
| key | VARCHAR(100) | UNIQUE, INDEX | 설정 키 |
| value | VARCHAR(2000) | 설정 값 | |
| description | VARCHAR(500) | 설명 | |
| is_secret | BOOLEAN | DEFAULT FALSE | 비밀 값 여부 |
| created_at | DATETIME | ||
| updated_at | DATETIME |
2.10 audit_logs
감사 로그 (변경 이력 추적).
| 컬럼 | 타입 | 제약 | 설명 |
|---|---|---|---|
| id | INT | PK | |
| user_id | INT | FK→users.id, NULLABLE | 행위자 |
| action | VARCHAR(100) | 액션 (create, update, delete, login 등) | |
| resource_type | VARCHAR(50) | 대상 리소스 타입 | |
| resource_id | VARCHAR(50) | 대상 리소스 ID | |
| details | VARCHAR(2000) | DEFAULT '{}' | 변경 상세 (JSON) |
| ip_address | VARCHAR(45) | 요청 IP | |
| created_at | DATETIME | ||
| updated_at | DATETIME |
3. MariaDB ER 다이어그램
users ──────────┬──── 1:1 ──── user_profiles
│
├──── 1:N ──── refresh_tokens
│
├──── 1:N ──── oauth_accounts
│
├──── 1:N ──── devices (owner_id)
│
├──── 1:N ──── alert_rules (created_by)
│
├──── 1:N ──── alerts (acknowledged_by)
│
└──── 1:N ──── audit_logs (user_id)
device_groups ──┬──── 1:N ──── devices (group_id)
│
└──── 1:N ──── alert_rules (device_group_id)
alert_rules ────┬──── 1:N ──── alerts (rule_id)
devices ────────┴──── 1:N ──── alerts (device_id)
4. MongoDB 컬렉션
4.1 device_logs
디바이스 이벤트 로그. TTL 인덱스로 90일 후 자동 삭제.
{
"_id": "ObjectId",
"device_id": "sensor-temp-001",
"event_type": "status_change",
"payload": {
"status": "online",
"reason": "boot"
},
"ip_address": "192.168.1.100",
"timestamp": "2025-01-15T12:00:00Z"
}
인덱스:
device_id(단일)event_type(단일)timestamp(내림차순)
4.2 telemetry_data
디바이스 센서 측정 데이터 (시계열).
{
"_id": "ObjectId",
"device_id": "sensor-temp-001",
"metrics": {
"temperature": 23.5,
"humidity": 45.2,
"pressure": 1013.25
},
"timestamp": "2025-01-15T12:05:00Z"
}
인덱스:
device_id(단일)timestamp(내림차순)(device_id, timestamp)(복합, 범위 쿼리 최적화)
4.3 analytics_results
분석 수행 결과 저장.
{
"_id": "ObjectId",
"analysis_type": "daily_telemetry",
"parameters": {
"date": "2025-01-14"
},
"result": {
"count": 1440,
"avg_value": 23.8
},
"device_id": "sensor-temp-001",
"period_start": "2025-01-14T00:00:00Z",
"period_end": "2025-01-15T00:00:00Z",
"created_at": "2025-01-15T01:05:00Z"
}
인덱스:
analysis_type(단일)device_id(단일)created_at(내림차순)
4.4 notifications
사용자별 알림 메시지.
{
"_id": "ObjectId",
"user_id": 1,
"title": "디바이스 오프라인 알림",
"message": "sensor-temp-001이 오프라인 상태입니다.",
"notification_type": "warning",
"is_read": false,
"read_at": null,
"created_at": "2025-01-15T12:10:00Z"
}
인덱스:
user_id(단일)(user_id, is_read)(복합, 읽지 않은 알림 조회)created_at(내림차순)
5. Redis 사용 패턴
| 용도 | 키 패턴 | TTL | 설명 |
|---|---|---|---|
| 속도 제한 | rate_limit:{ip} |
60초 | IP별 요청 카운터 |
| Celery 브로커 | redis://...6379/1 | - | 태스크 큐 |
| Celery 결과 | redis://...6379/2 | - | 태스크 결과 저장 |
6. 마이그레이션
Alembic으로 MariaDB 스키마를 관리한다.
# 마이그레이션 생성
alembic revision --autogenerate -m "description"
# 마이그레이션 적용
alembic upgrade head
# 롤백
alembic downgrade -1
# 현재 리비전 확인
alembic current
# 히스토리 확인
alembic history
MongoDB는 스키마리스이므로 별도 마이그레이션이 불필요하다. 인덱스는 Beanie 모델의 Settings.indexes로 앱 시작 시 자동 생성된다.