feat: TBM 시스템 구축 및 페이지 권한 관리 기능 추가

## 주요 변경사항

### 1. TBM (Tool Box Meeting) 시스템 구축
- **데이터베이스 스키마** (5개 테이블 생성)
  - tbm_sessions: TBM 세션 관리
  - tbm_team_assignments: 팀 구성 관리
  - tbm_safety_checks: 안전 체크리스트 마스터 (17개 항목)
  - tbm_safety_records: 안전 체크 기록
  - team_handovers: 작업 인계 관리

- **API 엔드포인트** (17개)
  - TBM 세션 CRUD
  - 팀 구성 관리
  - 안전 체크리스트
  - 작업 인계
  - 통계 및 리포트

- **프론트엔드**
  - TBM 관리 페이지 (/pages/work/tbm.html)
  - 모달 기반 UI (세션 생성, 팀 구성, 안전 체크)

### 2. 페이지 권한 관리 시스템
- 페이지별 접근 권한 설정 기능
- 관리자 페이지 (/pages/admin/page-access.html)
- 사용자별 페이지 권한 부여/회수
- TBM 페이지 등록 및 권한 연동

### 3. 네비게이션 role 표시 버그 수정
- load-navbar.js: case-insensitive role 매칭 적용
- JWT의 "Admin" role이 "관리자"로 정상 표시
- admin-only 메뉴 항목 정상 표시

### 4. 대시보드 개선
- 작업 현황 테이블 가독성 향상
- 고대비 색상 및 명확한 구분선 적용
- 이모지 제거 및 SVG 아이콘 적용

### 5. 문서화
- TBM 배포 가이드 작성 (docs/TBM_DEPLOYMENT_GUIDE.md)
- 데이터베이스 스키마 상세 기록
- 배포 절차 및 체크리스트 제공

## 기술 스택
- Backend: Node.js, Express, MySQL
- Frontend: Vanilla JavaScript, HTML5, CSS3
- Database: MySQL (InnoDB)

## 파일 변경사항

### 신규 파일
- api.hyungi.net/db/migrations/20260120000000_create_tbm_system.js
- api.hyungi.net/db/migrations/20260120000001_add_tbm_page.js
- api.hyungi.net/models/tbmModel.js
- api.hyungi.net/models/pageAccessModel.js
- api.hyungi.net/controllers/tbmController.js
- api.hyungi.net/controllers/pageAccessController.js
- api.hyungi.net/routes/tbmRoutes.js
- web-ui/pages/work/tbm.html
- web-ui/pages/admin/page-access.html
- web-ui/js/page-access-management.js
- docs/TBM_DEPLOYMENT_GUIDE.md

### 수정 파일
- api.hyungi.net/config/routes.js (TBM 라우트 추가)
- web-ui/js/load-navbar.js (role 매칭 버그 수정)
- web-ui/pages/admin/workers.html (HTML 구조 수정)
- web-ui/pages/dashboard.html (이모지 제거)
- web-ui/css/design-system.css (색상 팔레트 추가)
- web-ui/css/modern-dashboard.css (가독성 개선)
- web-ui/js/modern-dashboard.js (SVG 아이콘 적용)

## 배포 시 주의사항
⚠️ 본 서버 배포 시 반드시 마이그레이션 실행 필요:
```bash
npm run db:migrate
```

상세한 배포 절차는 docs/TBM_DEPLOYMENT_GUIDE.md 참조

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Hyungi Ahn
2026-01-20 15:38:17 +09:00
parent 0ec099b493
commit 4d0c4c0801
18 changed files with 3321 additions and 107 deletions

View File

@@ -0,0 +1,393 @@
# TBM 시스템 배포 가이드
## 📋 개요
TBM (Tool Box Meeting) 시스템은 아침 안전 회의 및 팀 구성 관리를 위한 기능입니다.
**배포일**: 2026-01-20
**버전**: 1.0.0
---
## 🗄️ 데이터베이스 마이그레이션
### 필수 마이그레이션 파일
본 서버에 배포 시 반드시 실행해야 할 마이그레이션:
1. **`20260120000000_create_tbm_system.js`** - TBM 시스템 테이블 생성
2. **`20260120000001_add_tbm_page.js`** - TBM 페이지 등록
### 생성되는 테이블
#### 1. `tbm_sessions` - TBM 세션 (아침 미팅)
```sql
CREATE TABLE `tbm_sessions` (
`session_id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
`session_date` DATE NOT NULL COMMENT 'TBM 날짜',
`leader_id` INT NOT NULL COMMENT '팀장 worker_id',
`project_id` INT NULL COMMENT '프로젝트 ID',
`work_location` VARCHAR(200) NULL COMMENT '작업 장소',
`work_description` TEXT NULL COMMENT '작업 내용',
`safety_notes` TEXT NULL COMMENT '안전 관련 특이사항',
`status` ENUM('draft', 'completed', 'cancelled') DEFAULT 'draft' COMMENT '상태',
`start_time` TIME NULL COMMENT 'TBM 시작 시간',
`end_time` TIME NULL COMMENT 'TBM 종료 시간',
`created_by` INT NOT NULL COMMENT '생성자 user_id',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX `idx_session_date_leader` (`session_date`, `leader_id`),
FOREIGN KEY (`leader_id`) REFERENCES `workers` (`worker_id`),
FOREIGN KEY (`project_id`) REFERENCES `projects` (`project_id`) ON DELETE SET NULL,
FOREIGN KEY (`created_by`) REFERENCES `users` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
```
#### 2. `tbm_team_assignments` - TBM 팀 구성
```sql
CREATE TABLE `tbm_team_assignments` (
`assignment_id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
`session_id` INT UNSIGNED NOT NULL COMMENT 'TBM 세션 ID',
`worker_id` INT NOT NULL COMMENT '팀원 worker_id',
`assigned_role` VARCHAR(100) NULL COMMENT '역할/담당',
`work_detail` TEXT NULL COMMENT '세부 작업 내용',
`is_present` BOOLEAN DEFAULT TRUE COMMENT '출석 여부',
`absence_reason` TEXT NULL COMMENT '결석 사유',
`assigned_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE KEY `uk_session_worker` (`session_id`, `worker_id`),
FOREIGN KEY (`session_id`) REFERENCES `tbm_sessions` (`session_id`) ON DELETE CASCADE,
FOREIGN KEY (`worker_id`) REFERENCES `workers` (`worker_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
```
#### 3. `tbm_safety_checks` - 안전 체크리스트 마스터
```sql
CREATE TABLE `tbm_safety_checks` (
`check_id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
`check_category` VARCHAR(50) NOT NULL COMMENT '카테고리 (PPE, EQUIPMENT, ENVIRONMENT, EMERGENCY)',
`check_item` VARCHAR(200) NOT NULL COMMENT '체크 항목',
`description` TEXT NULL COMMENT '설명',
`display_order` INT DEFAULT 0 COMMENT '표시 순서',
`is_required` BOOLEAN DEFAULT TRUE COMMENT '필수 체크 여부',
`is_active` BOOLEAN DEFAULT TRUE COMMENT '활성 여부',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX `idx_check_category` (`check_category`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
```
**초기 데이터 (17개 항목)**:
- PPE (개인 보호 장비): 5개
- EQUIPMENT (장비 점검): 4개
- ENVIRONMENT (작업 환경): 4개
- EMERGENCY (비상 대응): 3개
#### 4. `tbm_safety_records` - 안전 체크 기록
```sql
CREATE TABLE `tbm_safety_records` (
`record_id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
`session_id` INT UNSIGNED NOT NULL COMMENT 'TBM 세션 ID',
`check_id` INT UNSIGNED NOT NULL COMMENT '체크 항목 ID',
`is_checked` BOOLEAN DEFAULT FALSE COMMENT '체크 여부',
`notes` TEXT NULL COMMENT '비고/특이사항',
`checked_by` INT NULL COMMENT '체크한 user_id',
`checked_at` TIMESTAMP NULL COMMENT '체크 시간',
UNIQUE KEY `uk_session_check` (`session_id`, `check_id`),
FOREIGN KEY (`session_id`) REFERENCES `tbm_sessions` (`session_id`) ON DELETE CASCADE,
FOREIGN KEY (`check_id`) REFERENCES `tbm_safety_checks` (`check_id`),
FOREIGN KEY (`checked_by`) REFERENCES `users` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
```
#### 5. `team_handovers` - 작업 인계
```sql
CREATE TABLE `team_handovers` (
`handover_id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
`session_id` INT UNSIGNED NOT NULL COMMENT 'TBM 세션 ID',
`from_leader_id` INT NOT NULL COMMENT '인계자 worker_id',
`to_leader_id` INT NOT NULL COMMENT '인수자 worker_id',
`handover_date` DATE NOT NULL COMMENT '인계 날짜',
`handover_time` TIME NULL COMMENT '인계 시간',
`reason` ENUM('half_day', 'early_leave', 'emergency', 'other') NOT NULL COMMENT '인계 사유',
`handover_notes` TEXT NULL COMMENT '인계 내용',
`worker_ids` TEXT NULL COMMENT '인계하는 작업자 IDs (JSON array)',
`is_confirmed` BOOLEAN DEFAULT FALSE COMMENT '인수 확인 여부',
`confirmed_at` TIMESTAMP NULL COMMENT '인수 확인 시간',
`confirmed_by` INT NULL COMMENT '인수 확인자 user_id',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX `idx_session_handover_date` (`session_id`, `handover_date`),
FOREIGN KEY (`session_id`) REFERENCES `tbm_sessions` (`session_id`) ON DELETE CASCADE,
FOREIGN KEY (`from_leader_id`) REFERENCES `workers` (`worker_id`),
FOREIGN KEY (`to_leader_id`) REFERENCES `workers` (`worker_id`),
FOREIGN KEY (`confirmed_by`) REFERENCES `users` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
```
---
## 🚀 배포 절차
### 1. 데이터베이스 마이그레이션 실행
```bash
# 본 서버에서 실행
cd /path/to/api.hyungi.net
# 환경 변수 설정 (필요 시)
export DB_HOST=your_db_host
export DB_PORT=your_db_port
export DB_USER=your_db_user
export DB_PASSWORD=your_db_password
export DB_NAME=hyungi
# 마이그레이션 실행
npm run db:migrate
# 또는 직접 실행
npx knex migrate:latest --knexfile knexfile.js
```
### 2. 마이그레이션 확인
```bash
# 마이그레이션 상태 확인
npx knex migrate:status --knexfile knexfile.js
# 테이블 생성 확인
mysql -u root -p -e "SHOW TABLES LIKE 'tbm%'" hyungi
mysql -u root -p -e "SHOW TABLES LIKE 'team_handovers'" hyungi
# 안전 체크리스트 초기 데이터 확인
mysql -u root -p -e "SELECT check_category, COUNT(*) as count FROM tbm_safety_checks GROUP BY check_category" hyungi
```
예상 결과:
```
+----------------+-------+
| check_category | count |
+----------------+-------+
| PPE | 5 |
| EQUIPMENT | 4 |
| ENVIRONMENT | 4 |
| EMERGENCY | 3 |
+----------------+-------+
```
### 3. API 서버 재시작
```bash
# PM2 사용 시
pm2 restart api-hyungi
# 또는 직접 재시작
pm2 stop api-hyungi
pm2 start ecosystem.config.js --env production
```
### 4. 페이지 권한 확인
```bash
# TBM 페이지가 pages 테이블에 등록되었는지 확인
mysql -u root -p -e "SELECT * FROM pages WHERE page_key='tbm'\G" hyungi
```
예상 결과:
```
page_id: [auto_increment]
page_key: tbm
page_name: TBM 관리
page_path: /pages/work/tbm.html
category: work
description: Tool Box Meeting - 아침 안전 회의 및 팀 구성 관리
is_admin_only: 0
display_order: 10
```
---
## 📡 API 엔드포인트
### TBM 세션 관리
- `POST /api/tbm/sessions` - TBM 세션 생성
- `GET /api/tbm/sessions/date/:date` - 특정 날짜의 TBM 세션 목록
- `GET /api/tbm/sessions/:sessionId` - TBM 세션 상세 조회
- `PUT /api/tbm/sessions/:sessionId` - TBM 세션 수정
- `POST /api/tbm/sessions/:sessionId/complete` - TBM 세션 완료
### 팀 구성 관리
- `POST /api/tbm/sessions/:sessionId/team` - 팀원 추가 (단일)
- `POST /api/tbm/sessions/:sessionId/team/batch` - 팀원 일괄 추가
- `GET /api/tbm/sessions/:sessionId/team` - 팀 구성 조회
- `DELETE /api/tbm/sessions/:sessionId/team/:workerId` - 팀원 제거
### 안전 체크리스트
- `GET /api/tbm/safety-checks` - 모든 안전 체크 항목 조회
- `GET /api/tbm/sessions/:sessionId/safety` - 안전 체크 기록 조회
- `POST /api/tbm/sessions/:sessionId/safety` - 안전 체크 일괄 저장
### 작업 인계
- `POST /api/tbm/handovers` - 작업 인계 생성
- `POST /api/tbm/handovers/:handoverId/confirm` - 작업 인계 확인
- `GET /api/tbm/handovers/date/:date` - 특정 날짜의 인계 목록
- `GET /api/tbm/handovers/pending` - 나에게 온 미확인 인계 건
### 통계 및 리포트
- `GET /api/tbm/statistics/tbm?startDate=&endDate=` - TBM 통계
- `GET /api/tbm/statistics/leaders?startDate=&endDate=` - 리더별 통계
---
## 🔐 권한 설정
### 1. 관리자가 페이지 권한 설정
1. 관리자 계정으로 로그인
2. `/pages/admin/page-access.html` 접속
3. 권한을 부여할 사용자 선택
4. "TBM 관리" 페이지 체크
5. 저장
### 2. 기본 권한 (권장)
- **그룹장 (Leader)**: TBM 페이지 접근 권한 부여 필요
- **관리자 (Admin)**: 자동으로 모든 페이지 접근 가능
- **일반 작업자 (User)**: 필요에 따라 부여
---
## 📁 파일 구조
### 백엔드 (API)
```
api.hyungi.net/
├── db/migrations/
│ ├── 20260120000000_create_tbm_system.js # TBM 테이블 생성
│ └── 20260120000001_add_tbm_page.js # TBM 페이지 등록
├── models/
│ └── tbmModel.js # TBM 데이터 모델
├── controllers/
│ └── tbmController.js # TBM 컨트롤러
├── routes/
│ └── tbmRoutes.js # TBM 라우트
└── config/
└── routes.js # 라우트 등록 (수정됨)
```
### 프론트엔드 (Web UI)
```
web-ui/
├── pages/work/
│ └── tbm.html # TBM 페이지
└── js/
└── tbm.js # TBM JavaScript (예정)
```
---
## ⚠️ 주의사항
### 1. 외래 키 제약 조건
- `workers` 테이블의 `worker_id`**signed INT(11)**
- `users` 테이블의 `user_id`**signed INT(11)**
- `projects` 테이블의 PK는 `project_id` (NOT `id`)
- 외래 키 컬럼은 반드시 **signed INT**로 선언 (unsigned 사용 금지)
### 2. 데이터 정합성
- TBM 세션 삭제 시 관련 팀 구성, 안전 체크 기록 자동 삭제 (CASCADE)
- 작업자 삭제 시 관련 TBM 세션도 삭제됨 (workers 테이블의 CASCADE 설정)
### 3. 백업
마이그레이션 실행 전 **반드시 데이터베이스 백업**:
```bash
mysqldump -u root -p hyungi > backup_before_tbm_$(date +%Y%m%d_%H%M%S).sql
```
### 4. 롤백
문제 발생 시 롤백:
```bash
# 한 단계 롤백
npx knex migrate:rollback --knexfile knexfile.js
# 또는 백업 복구
mysql -u root -p hyungi < backup_before_tbm_YYYYMMDD_HHMMSS.sql
```
---
## ✅ 배포 체크리스트
배포 전 확인:
- [ ] 데이터베이스 백업 완료
- [ ] 마이그레이션 파일 본 서버에 복사 완료
- [ ] 환경 변수 설정 확인 (DB 접속 정보)
- [ ] 마이그레이션 실행 완료
- [ ] 5개 테이블 생성 확인
- [ ] tbm_safety_checks 초기 데이터 (17개) 확인
- [ ] pages 테이블에 TBM 페이지 등록 확인
- [ ] API 서버 재시작 완료
- [ ] API 엔드포인트 테스트 (최소 1개)
- [ ] TBM 페이지 접속 테스트
- [ ] 권한 설정 테스트 (그룹장 계정)
---
## 🔍 테스트 방법
### 1. API 테스트
```bash
# 안전 체크 항목 조회
curl -X GET http://localhost:20005/api/tbm/safety-checks \
-H "Authorization: Bearer YOUR_TOKEN"
# 오늘 날짜의 TBM 세션 조회
curl -X GET http://localhost:20005/api/tbm/sessions/date/2026-01-20 \
-H "Authorization: Bearer YOUR_TOKEN"
```
### 2. 웹 페이지 테스트
1. 그룹장 계정으로 로그인
2. `/pages/work/tbm.html` 접속
3. "새 TBM 시작" 버튼 클릭
4. TBM 세션 생성 및 팀 구성
---
## 📞 문제 해결
### 문제 1: 마이그레이션 실패 (errno: 150)
**원인**: 외래 키 제약 조건 오류 (데이터 타입 불일치)
**해결**: 마이그레이션 파일에서 외래 키 컬럼을 signed INT로 수정
### 문제 2: API 엔드포인트 404
**원인**: 라우트 등록 누락 또는 서버 미재시작
**해결**:
```bash
pm2 logs api-hyungi --lines 50 # 로그 확인
pm2 restart api-hyungi # 서버 재시작
```
### 문제 3: TBM 페이지 접근 불가
**원인**: 페이지 권한 미설정
**해결**: 관리자가 `/pages/admin/page-access.html`에서 권한 부여
---
## 📝 변경 이력
### v1.0.0 (2026-01-20)
- TBM 시스템 초기 배포
- 5개 테이블 생성
- 17개 안전 체크리스트 항목
- API 엔드포인트 17개
- 페이지 권한 시스템 연동
---
## 📚 관련 문서
- [작업자-계정 연동 가이드](./worker-account-integration.md)
- [페이지 권한 관리 가이드](./page-access-management.md)
- [데이터베이스 스키마](./database-schema.md)
---
**작성자**: Claude
**최종 수정일**: 2026-01-20