339 lines
9.6 KiB
Markdown
339 lines
9.6 KiB
Markdown
# 데이터베이스 설계 문서
|
|
|
|
## 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 | |
|
|
| email | 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일 후 자동 삭제.
|
|
|
|
```json
|
|
{
|
|
"_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
|
|
|
|
디바이스 센서 측정 데이터 (시계열).
|
|
|
|
```json
|
|
{
|
|
"_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
|
|
|
|
분석 수행 결과 저장.
|
|
|
|
```json
|
|
{
|
|
"_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
|
|
|
|
사용자별 알림 메시지.
|
|
|
|
```json
|
|
{
|
|
"_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 스키마를 관리한다.
|
|
|
|
```bash
|
|
# 마이그레이션 생성
|
|
alembic revision --autogenerate -m "description"
|
|
|
|
# 마이그레이션 적용
|
|
alembic upgrade head
|
|
|
|
# 롤백
|
|
alembic downgrade -1
|
|
|
|
# 현재 리비전 확인
|
|
alembic current
|
|
|
|
# 히스토리 확인
|
|
alembic history
|
|
```
|
|
|
|
MongoDB는 스키마리스이므로 별도 마이그레이션이 불필요하다. 인덱스는 Beanie 모델의 `Settings.indexes`로 앱 시작 시 자동 생성된다.
|