# Superport Database Entity Mapping > **최종 업데이트**: 2025-08-13 > **데이터베이스**: PostgreSQL > **ORM**: SeaORM (Rust) ## 📋 목차 - [엔티티 관계도 (ERD)](#엔티티-관계도-erd) - [엔티티 정의](#엔티티-정의) - [관계 매핑](#관계-매핑) - [인덱스 및 제약조건](#인덱스-및-제약조건) - [소프트 딜리트 구조](#소프트-딜리트-구조) --- ## 🗺️ 엔티티 관계도 (ERD) ``` ┌─────────────┐ │ addresses │ │─────────────│ │ id (PK) │ │ si_do │ │ si_gun_gu │ │ eup_myeon_ │ │ dong │ │ detail_ │ │ address │ │ postal_code │ │ is_active │ │ created_at │ │ updated_at │ └─────────────┘ │ │ 1:N ▼ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ companies │ │ company_ │ │ warehouse_ │ │─────────────│ │ branches │ │ locations │ │ id (PK) │◄──►│─────────────│ │─────────────│ │ name │ 1:N│ id (PK) │ │ id (PK) │ │ address │ │ company_id │ │ name │ │ address_id │ │ (FK) │ │ code (UQ) │ │ contact_* │ │ branch_name │ │ address_id │ │ company_ │ │ address │ │ (FK) │ │ types │ │ phone │ │ manager_* │ │ remark │ │ address_id │ │ capacity │ │ is_active │ │ (FK) │ │ is_active │ │ is_partner │ │ manager_* │ │ remark │ │ is_customer │ │ remark │ │ created_at │ │ created_at │ │ created_at │ │ updated_at │ │ updated_at │ │ updated_at │ └─────────────┘ └─────────────┘ └─────────────┘ │ │ │ │ 1:N │ 1:N ▼ ▼ ┌─────────────┐ ┌─────────────┐ │ licenses │ │ equipment │ │─────────────│ │─────────────│ │ id (PK) │ │ id (PK) │ │ company_id │ │ manufacturer│ │ (FK) │ │ serial_ │ │ branch_id │ │ number (UQ) │ │ (FK) │ │ barcode │ │ license_key │ │ equipment_ │ │ (UQ) │ │ number (UQ) │ │ product_ │ │ category1 │ │ name │ │ category2 │ │ vendor │ │ category3 │ │ license_ │ │ model_name │ │ type │ │ purchase_* │ │ user_count │ │ status │ │ purchase_* │ │ current_ │ │ expiry_date │ │ company_id │ │ is_active │ │ (FK) │ │ remark │ │ current_ │ │ created_at │ │ branch_id │ │ updated_at │ │ (FK) │ └─────────────┘ │ warehouse_ │ │ location_id │ │ (FK) │ │ inspection_*│ │ is_active │ │ remark │ │ created_at │ │ updated_at │ └─────────────┘ │ │ 1:N ▼ ┌─────────────┐ │ equipment_ │ │ history │ │─────────────│ │ id (PK) │ │ equipment_ │ │ id (FK) │ │ transaction_│ │ type │ │ quantity │ │ transaction_│ │ date │ │ remarks │ │ created_by │ │ user_id │ │ created_at │ └─────────────┘ ┌─────────────┐ ┌─────────────┐ │ users │ │ user_tokens │ │─────────────│ 1:N │─────────────│ │ id (PK) │◄──────────────────►│ id (PK) │ │ username │ │ user_id │ │ (UQ) │ │ (FK) │ │ email (UQ) │ │ token │ │ password_ │ │ expires_at │ │ hash │ │ created_at │ │ name │ └─────────────┘ │ phone │ │ role │ │ is_active │ │ created_at │ │ updated_at │ └─────────────┘ ``` --- ## 📊 엔티티 정의 ### 1. **addresses** (주소 정보) ```rust pub struct Model { pub id: i32, // 기본키 pub si_do: String, // 시/도 (필수) pub si_gun_gu: String, // 시/군/구 (필수) pub eup_myeon_dong: String, // 읍/면/동 (필수) pub detail_address: Option, // 상세주소 pub postal_code: Option, // 우편번호 pub is_active: bool, // 소프트 딜리트 플래그 pub created_at: Option, pub updated_at: Option, } ``` ### 2. **companies** (회사 정보) ```rust pub struct Model { pub id: i32, // 기본키 pub name: String, // 회사명 (필수) pub address: Option, // 주소 (레거시) pub address_id: Option, // 주소 FK pub contact_name: Option, // 담당자명 pub contact_position: Option, // 담당자 직책 pub contact_phone: Option, // 담당자 전화번호 pub contact_email: Option, // 담당자 이메일 pub company_types: Option>, // 회사 유형 배열 pub remark: Option, // 비고 pub is_active: Option, // 활성화 상태 pub is_partner: Option, // 파트너사 여부 pub is_customer: Option, // 고객사 여부 pub created_at: Option, pub updated_at: Option, } ``` ### 3. **company_branches** (회사 지점) ```rust pub struct Model { pub id: i32, // 기본키 pub company_id: i32, // 회사 FK (필수) pub branch_name: String, // 지점명 (필수) pub address: Option, // 주소 pub phone: Option, // 전화번호 pub address_id: Option, // 주소 FK pub manager_name: Option, // 관리자명 pub manager_phone: Option, // 관리자 전화번호 pub remark: Option, // 비고 pub created_at: Option, pub updated_at: Option, } ``` ### 4. **warehouse_locations** (창고 위치) ```rust pub struct Model { pub id: i32, // 기본키 pub name: String, // 창고명 (필수) pub code: String, // 창고 코드 (고유) pub address_id: Option, // 주소 FK pub manager_name: Option, // 관리자명 pub manager_phone: Option, // 관리자 전화번호 pub capacity: Option, // 수용 용량 pub is_active: Option, // 활성화 상태 pub remark: Option, // 비고 pub created_at: Option, pub updated_at: Option, } ``` ### 5. **users** (사용자) ```rust pub struct Model { pub id: i32, // 기본키 pub username: String, // 사용자명 (고유) pub email: String, // 이메일 (고유) pub password_hash: String, // 비밀번호 해시 (필수) pub name: String, // 실명 (필수) pub phone: Option, // 전화번호 pub role: UserRole, // 권한 (Enum: admin/manager/staff) pub is_active: Option, // 활성화 상태 pub created_at: Option, pub updated_at: Option, } ``` ### 6. **user_tokens** (사용자 토큰) ```rust pub struct Model { pub id: i32, // 기본키 pub user_id: i32, // 사용자 FK pub token: String, // 리프레시 토큰 pub expires_at: DateTimeWithTimeZone, // 만료 시간 pub created_at: Option, } ``` ### 7. **equipment** (장비) ```rust pub struct Model { pub id: i32, // 기본키 pub manufacturer: String, // 제조사 (필수) pub serial_number: Option, // 시리얼 번호 (고유) pub barcode: Option, // 바코드 pub equipment_number: String, // 장비 번호 (고유) pub category1: Option, // 카테고리 1 pub category2: Option, // 카테고리 2 pub category3: Option, // 카테고리 3 pub model_name: Option, // 모델명 pub purchase_date: Option, // 구매일 pub purchase_price: Option, // 구매가격 pub status: Option, // 상태 (Enum) pub current_company_id: Option, // 현재 회사 FK pub current_branch_id: Option, // 현재 지점 FK pub warehouse_location_id: Option, // 창고 위치 FK pub last_inspection_date: Option, // 마지막 점검일 pub next_inspection_date: Option, // 다음 점검일 pub remark: Option, // 비고 pub is_active: bool, // 활성화 상태 pub created_at: Option, pub updated_at: Option, } ``` ### 8. **equipment_history** (장비 이력) ```rust pub struct Model { pub id: i32, // 기본키 pub equipment_id: i32, // 장비 FK (필수) pub transaction_type: String, // 거래 유형 (필수) pub quantity: i32, // 수량 (필수) pub transaction_date: DateTimeWithTimeZone, // 거래일 (필수) pub remarks: Option, // 비고 pub created_by: Option, // 생성자 FK pub user_id: Option, // 사용자 FK pub created_at: Option, } ``` ### 9. **licenses** (라이선스) ```rust pub struct Model { pub id: i32, // 기본키 pub company_id: Option, // 회사 FK pub branch_id: Option, // 지점 FK pub license_key: String, // 라이선스 키 (고유) pub product_name: Option, // 제품명 pub vendor: Option, // 공급업체 pub license_type: Option, // 라이선스 유형 pub user_count: Option, // 사용자 수 pub purchase_date: Option, // 구매일 pub expiry_date: Option, // 만료일 pub purchase_price: Option, // 구매가격 pub remark: Option, // 비고 pub is_active: Option, // 활성화 상태 pub created_at: Option, pub updated_at: Option, } ``` --- ## 🔗 관계 매핑 ### 1:N 관계 | 부모 테이블 | 자식 테이블 | 외래키 | 관계 설명 | |-------------|-------------|---------|-----------| | `addresses` | `companies` | `address_id` | 주소 → 회사 | | `addresses` | `company_branches` | `address_id` | 주소 → 지점 | | `addresses` | `warehouse_locations` | `address_id` | 주소 → 창고 | | `companies` | `company_branches` | `company_id` | 회사 → 지점 | | `companies` | `equipment` | `current_company_id` | 회사 → 장비 | | `companies` | `licenses` | `company_id` | 회사 → 라이선스 | | `company_branches` | `equipment` | `current_branch_id` | 지점 → 장비 | | `company_branches` | `licenses` | `branch_id` | 지점 → 라이선스 | | `warehouse_locations` | `equipment` | `warehouse_location_id` | 창고 → 장비 | | `equipment` | `equipment_history` | `equipment_id` | 장비 → 이력 | | `users` | `user_tokens` | `user_id` | 사용자 → 토큰 | ### 관계 제약조건 - **CASCADE DELETE**: `companies` → `company_branches` - **NO ACTION**: 나머지 모든 관계 (데이터 무결성 보장) - **UNIQUE 제약**: `serial_number`, `equipment_number`, `license_key`, `warehouse_code` --- ## 📇 인덱스 및 제약조건 ### 기본키 (Primary Key) 모든 테이블에서 `id` 컬럼이 SERIAL PRIMARY KEY ### 고유 제약조건 (Unique Constraints) ```sql -- 사용자 UNIQUE(username) UNIQUE(email) -- 장비 UNIQUE(serial_number) UNIQUE(equipment_number) -- 라이선스 UNIQUE(license_key) -- 창고 위치 UNIQUE(code) ``` ### 인덱스 (Indexes) ```sql -- 소프트 딜리트용 인덱스 CREATE INDEX idx_companies_is_active ON companies(is_active); CREATE INDEX idx_equipment_is_active ON equipment(is_active); CREATE INDEX idx_licenses_is_active ON licenses(is_active); CREATE INDEX idx_warehouse_locations_is_active ON warehouse_locations(is_active); CREATE INDEX idx_addresses_is_active ON addresses(is_active); CREATE INDEX idx_users_is_active ON users(is_active); -- 복합 인덱스 (성능 최적화) CREATE INDEX idx_company_branches_company_id_is_active ON company_branches(company_id, is_active); CREATE INDEX idx_equipment_company_id_is_active ON equipment(company_id, is_active); CREATE INDEX idx_licenses_company_id_is_active ON licenses(company_id, is_active); ``` --- ## 🗑️ 소프트 딜리트 구조 ### 소프트 딜리트 적용 테이블 - ✅ `companies` - ✅ `equipment` - ✅ `licenses` - ✅ `warehouse_locations` - ✅ `addresses` - ✅ `users` - ❌ `equipment_history` (이력은 보존) - ❌ `user_tokens` (자동 만료) - ❌ `company_branches` (회사와 함께 삭제) ### 소프트 딜리트 동작 방식 ```sql -- 삭제 (소프트 딜리트) UPDATE companies SET is_active = false WHERE id = 1; -- 조회 (활성 데이터만) SELECT * FROM companies WHERE is_active = true; -- 조회 (삭제된 데이터만) SELECT * FROM companies WHERE is_active = false; -- 복구 UPDATE companies SET is_active = true WHERE id = 1; ``` ### 연관된 데이터 처리 규칙 1. **회사 삭제 시**: - 회사: `is_active = false` - 지점: CASCADE DELETE (물리 삭제) - 장비: `current_company_id = NULL` - 라이선스: `is_active = false` 2. **장비 삭제 시**: - 장비: `is_active = false` - 이력: 유지 (삭제 안됨) 3. **사용자 삭제 시**: - 사용자: `is_active = false` - 토큰: 물리 삭제 --- ## 📈 Enum 타입 정의 ### UserRole ```rust pub enum UserRole { Admin, // 관리자 Manager, // 매니저 Staff, // 일반 직원 } ``` ### EquipmentStatus ```rust pub enum EquipmentStatus { Available, // 사용 가능 Inuse, // 사용 중 Maintenance, // 점검 중 Disposed, // 폐기 } ``` --- ## 🔄 마이그레이션 이력 ### Migration 001: 기본 테이블 생성 - 모든 핵심 테이블 생성 - 기본 관계 설정 ### Migration 002: 회사 타입 필드 추가 - `company_types` 배열 필드 - `is_partner`, `is_customer` 플래그 ### Migration 003: 소프트 딜리트 구현 - 모든 테이블에 `is_active` 필드 추가 - 성능 최적화용 인덱스 생성 ### Migration 004: 관계 정리 - 불필요한 관계 제거 - 제약조건 최적화 ### Migration 005: 제약조건 수정 - CASCADE 규칙 조정 - 외래키 제약조건 강화 --- **문서 버전**: 1.0 **최종 검토**: 2025-08-13 **담당자**: Database Engineering Team