# M-Project 데이터베이스 스키마 문서 ## 개요 작업보고서 시스템의 PostgreSQL 데이터베이스 스키마 정의 **최종 업데이트:** 2025-10-25 **데이터베이스 버전:** PostgreSQL 15 **스키마 버전:** 1.4 (마이그레이션 009까지 적용) --- ## 테이블 구조 ### 1. users (사용자) 사용자 계정 정보를 저장하는 테이블 | 컬럼명 | 타입 | 제약조건 | 설명 | |--------|------|----------|------| | id | INTEGER | PRIMARY KEY, AUTO_INCREMENT | 사용자 고유 ID | | username | VARCHAR(50) | UNIQUE, NOT NULL | 로그인 아이디 | | hashed_password | VARCHAR(255) | NOT NULL | 암호화된 비밀번호 (bcrypt) | | full_name | VARCHAR(100) | NULL | 사용자 실명 | | role | userrole | DEFAULT 'user' | 사용자 권한 | | is_active | BOOLEAN | DEFAULT TRUE | 계정 활성화 상태 | | created_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP | 계정 생성일시 | **인덱스:** - `users_pkey` PRIMARY KEY (id) - `users_username_key` UNIQUE (username) **참조되는 테이블:** - daily_works.created_by_id - issues.reporter_id - project_daily_works.created_by_id - projects.created_by_id --- ### 2. projects (프로젝트) 프로젝트 정보를 저장하는 테이블 | 컬럼명 | 타입 | 제약조건 | 설명 | |--------|------|----------|------| | id | BIGINT | PRIMARY KEY, AUTO_INCREMENT | 프로젝트 고유 ID | | job_no | VARCHAR(50) | UNIQUE, NOT NULL | Job 번호 | | project_name | VARCHAR(200) | NOT NULL | 프로젝트 이름 | | created_by_id | INTEGER | FOREIGN KEY → users(id) | 생성자 ID | | created_at | TIMESTAMP WITH TIME ZONE | DEFAULT NOW() | 생성일시 | | is_active | BOOLEAN | DEFAULT TRUE | 활성 상태 | **인덱스:** - `projects_pkey` PRIMARY KEY (id) - `projects_job_no_key` UNIQUE (job_no) - `idx_projects_job_no` (job_no) - `idx_projects_created_by_id` (created_by_id) - `idx_projects_is_active` (is_active) **외래키:** - `projects_created_by_id_fkey` created_by_id → users(id) **참조되는 테이블:** - issues.project_id - project_daily_works.project_id --- ### 3. issues (부적합 사항) 부적합 사항 정보를 저장하는 테이블 | 컬럼명 | 타입 | 제약조건 | 설명 | |--------|------|----------|------| | id | INTEGER | PRIMARY KEY, AUTO_INCREMENT | 부적합 사항 고유 ID | | photo_path | VARCHAR(500) | NULL | 첫 번째 사진 경로 | | photo_path2 | VARCHAR(500) | NULL | 두 번째 사진 경로 | | category | issuecategory | NOT NULL | 부적합 카테고리 | | description | TEXT | NOT NULL | 부적합 사항 설명 | | status | issuestatus | DEFAULT 'new' | 처리 상태 | | reporter_id | INTEGER | FOREIGN KEY → users(id) | 보고자 ID | | report_date | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP | 보고일시 | | work_hours | DOUBLE PRECISION | DEFAULT 0 | 작업 시간 | | detail_notes | TEXT | NULL | 상세 메모 | | project_id | BIGINT | FOREIGN KEY → projects(id) | 프로젝트 ID | **인덱스:** - `issues_pkey` PRIMARY KEY (id) - `idx_issues_category` (category) - `idx_issues_photo_path2` (photo_path2) - `idx_issues_project_id` (project_id) - `idx_issues_reporter_id` (reporter_id) - `idx_issues_status` (status) **외래키:** - `fk_issues_project_id` project_id → projects(id) - `issues_reporter_id_fkey` reporter_id → users(id) --- ### 4. daily_works (일일 공수) 전체 일일 작업 공수 정보를 저장하는 테이블 (레거시) | 컬럼명 | 타입 | 제약조건 | 설명 | |--------|------|----------|------| | id | INTEGER | PRIMARY KEY, AUTO_INCREMENT | 일일 공수 고유 ID | | date | DATE | NOT NULL, UNIQUE | 작업 날짜 | | worker_count | INTEGER | NOT NULL | 작업자 수 | | regular_hours | DOUBLE PRECISION | NOT NULL | 정규 시간 | | overtime_workers | INTEGER | DEFAULT 0 | 야근 작업자 수 | | overtime_hours | DOUBLE PRECISION | DEFAULT 0 | 야근 시간 | | overtime_total | DOUBLE PRECISION | DEFAULT 0 | 야근 총 시간 | | total_hours | DOUBLE PRECISION | NOT NULL | 총 작업 시간 | | created_by_id | INTEGER | FOREIGN KEY → users(id) | 생성자 ID | | created_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP | 생성일시 | **인덱스:** - `daily_works_pkey` PRIMARY KEY (id) - `daily_works_date_key` UNIQUE (date) - `idx_daily_works_date` (date) - `idx_daily_works_created_by_id` (created_by_id) **외래키:** - `daily_works_created_by_id_fkey` created_by_id → users(id) --- ### 5. project_daily_works (프로젝트별 일일공수) 프로젝트별 일일 작업 공수 정보를 저장하는 테이블 | 컬럼명 | 타입 | 제약조건 | 설명 | |--------|------|----------|------| | id | INTEGER | PRIMARY KEY, AUTO_INCREMENT | 프로젝트 일일공수 고유 ID | | date | DATE | NOT NULL | 작업 날짜 | | project_id | BIGINT | NOT NULL, FOREIGN KEY → projects(id) | 프로젝트 ID | | hours | DOUBLE PRECISION | NOT NULL | 작업 시간 | | created_by_id | INTEGER | NOT NULL, FOREIGN KEY → users(id) | 생성자 ID | | created_at | TIMESTAMP WITH TIME ZONE | DEFAULT CURRENT_TIMESTAMP | 생성일시 | **인덱스:** - `project_daily_works_pkey` PRIMARY KEY (id) - `idx_project_daily_works_date` (date) - `idx_project_daily_works_project_id` (project_id) - `idx_project_daily_works_date_project` (date, project_id) **외래키:** - `project_daily_works_created_by_id_fkey` created_by_id → users(id) - `project_daily_works_project_id_fkey` project_id → projects(id) ON DELETE CASCADE --- ## ENUM 타입 정의 ### userrole 사용자 권한 타입 - `admin`: 관리자 (모든 권한) - `user`: 일반 사용자 (제한된 권한) ### issuestatus 부적합 사항 처리 상태 - `new`: 신규 (미처리) - `progress`: 진행중 - `complete`: 완료 ### issuecategory 부적합 사항 카테고리 - `material_missing`: 자재누락 - `design_error`: 설계미스 - `incoming_defect`: 입고자재 불량 - `inspection_miss`: 검사미스 - `etc`: 기타 --- ## 관계도 (Entity Relationship) ``` users (1) ←→ (N) projects ↓ ↓ users (1) ←→ (N) issues ←→ (1) projects ↓ ↓ users (1) ←→ (N) daily_works ↓ users (1) ←→ (N) project_daily_works ←→ (1) projects ``` **주요 관계:** 1. **users → projects**: 사용자가 프로젝트를 생성 2. **users → issues**: 사용자가 부적합 사항을 보고 3. **projects → issues**: 프로젝트에 부적합 사항이 속함 4. **users → daily_works**: 사용자가 전체 일일공수를 입력 (레거시) 5. **users → project_daily_works**: 사용자가 프로젝트별 일일공수를 입력 6. **projects → project_daily_works**: 프로젝트에 일일공수가 속함 --- ## 마이그레이션 히스토리 | 파일명 | 설명 | 적용일 | |--------|------|--------| | `001_init.sql` | 초기 테이블 생성 (users, issues, daily_works) | 초기 | | `002_add_second_photo.sql` | issues 테이블에 두 번째 사진 필드 추가 | 초기 | | `003_update_categories.sql` | 카테고리 업데이트 (dimension_defect → design_error) | 초기 | | `004_fix_category_values.sql` | 카테고리 값 정규화 (대소문자 통일) | 초기 | | `005_recreate_enum_type.sql` | issuecategory ENUM 타입 재생성 | 초기 | | `006_add_projects_table.sql` | projects 테이블 추가 | 2025-10-25 | | `007_add_project_id_to_issues.sql` | issues 테이블에 project_id 컬럼 추가 | 2025-10-25 | | `008_fix_project_id_bigint.sql` | project_id를 BIGINT로 변경 | 2025-10-25 | | `009_add_project_daily_works_table.sql` | project_daily_works 테이블 추가 | 2025-10-25 | | `010_add_etc_category.sql` | issuecategory에 'etc' 값 추가 | 2025-10-25 | --- ## 데이터베이스 연결 정보 ### Docker 환경 - **Host:** db (컨테이너 내부), localhost (외부) - **Port:** 5432 (내부), 16432 (외부) - **Database:** mproject - **Username:** mproject - **Password:** mproject2024 - **Timezone:** Asia/Seoul ### 환경변수 ```bash DATABASE_URL=postgresql://mproject:mproject2024@db:5432/mproject POSTGRES_USER=mproject POSTGRES_PASSWORD=mproject2024 POSTGRES_DB=mproject TZ=Asia/Seoul PGTZ=Asia/Seoul ``` --- ## 기본 데이터 ### 관리자 계정 - **Username:** hyungi - **Password:** 123456 - **Role:** admin - **Full Name:** 관리자 --- ## 데이터베이스 관리 ### 백업 ```bash # 전체 백업 docker exec m-project-db pg_dump -U mproject mproject > backup_$(date +%Y%m%d_%H%M%S).sql # 스키마만 백업 docker exec m-project-db pg_dump -U mproject -s mproject > schema_backup.sql # 데이터만 백업 docker exec m-project-db pg_dump -U mproject -a mproject > data_backup.sql ``` ### 복구 ```bash # 전체 복구 docker exec -i m-project-db psql -U mproject mproject < backup.sql # 스키마 복구 docker exec -i m-project-db psql -U mproject mproject < schema_backup.sql ``` ### 테이블 상태 확인 ```bash # 모든 테이블 목록 docker exec m-project-db psql -U mproject -d mproject -c "\dt" # 특정 테이블 구조 docker exec m-project-db psql -U mproject -d mproject -c "\d table_name" # ENUM 타입 확인 docker exec m-project-db psql -U mproject -d mproject -c "\dT+" # 인덱스 확인 docker exec m-project-db psql -U mproject -d mproject -c "\di" ``` --- ## 성능 최적화 ### 인덱스 전략 1. **Primary Keys**: 모든 테이블에 자동 생성 2. **Foreign Keys**: 모든 외래키에 인덱스 생성 3. **검색 필드**: 자주 검색되는 컬럼 (date, status, category 등) 4. **복합 인덱스**: 날짜+프로젝트 조합 검색 최적화 ### 쿼리 최적화 권장사항 1. **날짜 범위 검색**: date 컬럼 인덱스 활용 2. **프로젝트별 필터링**: project_id 인덱스 활용 3. **상태별 필터링**: status, is_active 인덱스 활용 4. **JOIN 최적화**: 외래키 인덱스 활용 --- ## 보안 고려사항 1. **비밀번호 암호화**: bcrypt 해시 사용 (최소 12 rounds) 2. **SQL 인젝션 방지**: 파라미터화된 쿼리 사용 3. **접근 제어**: 역할 기반 권한 관리 4. **데이터 검증**: 애플리케이션 레벨에서 입력값 검증 5. **백업 암호화**: 민감한 데이터 백업 시 암호화 권장 --- ## 향후 확장 계획 ### 예정된 변경사항 - [ ] 부적합 사항에 우선순위 필드 추가 - [ ] 프로젝트 상태 관리 (진행중, 완료, 보류 등) - [ ] 파일 첨부 기능 확장 (문서, 도면 등) - [ ] 알림 시스템을 위한 notifications 테이블 - [ ] 감사 로그를 위한 audit_logs 테이블 ### 성능 개선 계획 - [ ] 파티셔닝: 대용량 데이터 처리를 위한 날짜별 파티셔닝 - [ ] 아카이빙: 오래된 데이터 아카이브 전략 - [ ] 캐싱: Redis를 활용한 자주 조회되는 데이터 캐싱 --- **문서 작성자:** AI Assistant **검토자:** - **승인자:** - > 이 문서는 데이터베이스 스키마 변경 시마다 업데이트되어야 합니다.