# 개발로그 - 2026-01-19: 작업자 관리 스키마 동기화
## 작업 요약
작업자 관리 페이지에서 발생하던 500 에러를 수정하였습니다. 문제의 원인은 **DB 테이블 스키마와 코드 간의 불일치**였습니다.
## 발견된 문제
### 1. JavaScript 모듈 로딩 에러
- **증상**: `SyntaxError: Unexpected token '{'` 에러
- **원인**: ES6 `import` 구문을 사용하는 파일들이 `type="module"` 없이 로드됨
- **영향 파일**:
- `load-navbar.js`
- `api-config.js`
- `worker-management.js`
### 2. 작업자 상태 변경 시 500 에러
- **증상**: 작업자 활성화/비활성화 시 서버 500 에러
- **에러 메시지**: `Unknown column 'phone_number' in 'field list'`
- **원인**: 코드에서 사용하는 컬럼과 실제 DB 테이블 컬럼 불일치
### 3. DB 스키마 불일치 상세
#### 실제 workers 테이블 컬럼:
```sql
- worker_id (int, PK, auto_increment)
- worker_name (varchar(100), NOT NULL)
- join_date (date, nullable)
- job_type (varchar(100), nullable)
- salary (decimal(10,2), nullable)
- annual_leave (int, nullable)
- status (text, default 'active')
- created_at (timestamp, default current_timestamp)
- updated_at (timestamp, default current_timestamp on update)
```
#### 코드에서 사용하려던 컬럼 (존재하지 않음):
```
- phone_number ❌
- email ❌
- hire_date ❌ (join_date는 있음)
- department ❌
- notes ❌
```
## 수정 내용
### 1. HTML 파일 수정
**파일**: `web-ui/pages/management/worker-management.html`
```html
```
### 2. 백엔드 Model 수정
**파일**: `api.hyungi.net/models/workerModel.js`
#### create 함수:
```javascript
// 수정 전
const create = async (worker, callback) => {
const { worker_name, job_type = 'worker', phone_number = null,
email = null, hire_date = null, department = null,
notes = null, status = 'active' } = worker;
await db.query(
`INSERT INTO workers (worker_name, job_type, phone_number, email,
hire_date, department, notes, status)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
[worker_name, job_type, phone_number, email, formatDate(hire_date),
department, notes, status]
);
};
// 수정 후
const create = async (worker, callback) => {
const { worker_name, job_type = null, join_date = null,
salary = null, annual_leave = null, status = 'active' } = worker;
await db.query(
`INSERT INTO workers (worker_name, job_type, join_date, salary,
annual_leave, status)
VALUES (?, ?, ?, ?, ?, ?)`,
[worker_name, job_type, formatDate(join_date), salary, annual_leave, status]
);
};
```
#### update 함수:
```javascript
// 수정 전: 고정된 컬럼 업데이트
const update = async (worker, callback) => {
const { worker_id, worker_name, job_type, status, phone_number,
email, hire_date, department, notes } = worker;
await db.query(
`UPDATE workers SET worker_name = ?, job_type = ?, status = ?,
phone_number = ?, email = ?, hire_date = ?,
department = ?, notes = ?
WHERE worker_id = ?`,
[worker_name, job_type, status, phone_number, email,
formatDate(hire_date), department, notes, worker_id]
);
};
// 수정 후: 동적 컬럼 업데이트
const update = async (worker, callback) => {
const { worker_id, worker_name, job_type, status, join_date,
salary, annual_leave } = worker;
// 업데이트할 필드만 동적으로 구성
const updates = [];
const values = [];
if (worker_name !== undefined) {
updates.push('worker_name = ?');
values.push(worker_name);
}
if (job_type !== undefined) {
updates.push('job_type = ?');
values.push(job_type);
}
if (status !== undefined) {
updates.push('status = ?');
values.push(status);
}
if (join_date !== undefined) {
updates.push('join_date = ?');
values.push(formatDate(join_date));
}
if (salary !== undefined) {
updates.push('salary = ?');
values.push(salary);
}
if (annual_leave !== undefined) {
updates.push('annual_leave = ?');
values.push(annual_leave);
}
if (updates.length === 0) {
callback(new Error('업데이트할 필드가 없습니다'));
return;
}
values.push(worker_id);
const query = `UPDATE workers SET ${updates.join(', ')} WHERE worker_id = ?`;
await db.query(query, values);
};
```
### 3. 프론트엔드 JavaScript 수정
**파일**: `web-ui/js/worker-management.js`
#### toggleWorkerStatus 함수:
```javascript
// 수정 전
const updateData = {
...worker, // 모든 필드 포함 (created_at, updated_at 등 포함)
status: newStatus,
is_active: newStatus === 'active' ? 1 : 0
};
// 수정 후
const updateData = {
worker_name: worker.worker_name,
job_type: worker.job_type || null,
status: newStatus,
join_date: worker.join_date || null,
salary: worker.salary || null,
annual_leave: worker.annual_leave || null
};
```
#### saveWorker 함수:
```javascript
// 수정 전
const workerData = {
worker_name: document.getElementById('workerName').value.trim(),
job_type: document.getElementById('jobType').value || 'worker',
phone_number: document.getElementById('phoneNumber').value.trim() || null,
email: document.getElementById('email').value.trim() || null,
hire_date: document.getElementById('hireDate').value || null,
department: document.getElementById('department').value.trim() || null,
notes: document.getElementById('notes').value.trim() || null,
status: document.getElementById('isActive').checked ? 'active' : 'inactive'
};
// 수정 후
const workerData = {
worker_name: document.getElementById('workerName').value.trim(),
job_type: document.getElementById('jobType').value || null,
join_date: document.getElementById('joinDate')?.value || null,
salary: document.getElementById('salary')?.value || null,
annual_leave: document.getElementById('annualLeave')?.value || null,
status: document.getElementById('isActive').checked ? 'active' : 'inactive'
};
```
#### openWorkerModal 함수:
```javascript
// 수정 전
document.getElementById('phoneNumber').value = worker.phone_number || '';
document.getElementById('email').value = worker.email || '';
document.getElementById('hireDate').value = worker.hire_date || '';
document.getElementById('department').value = worker.department || '';
document.getElementById('notes').value = worker.notes || '';
// 수정 후
const joinDateElem = document.getElementById('joinDate');
if (joinDateElem) joinDateElem.value = worker.join_date || '';
const salaryElem = document.getElementById('salary');
if (salaryElem) salaryElem.value = worker.salary || '';
const annualLeaveElem = document.getElementById('annualLeave');
if (annualLeaveElem) annualLeaveElem.value = worker.annual_leave || '';
```
### 4. 에러 로깅 개선
**파일**: `web-ui/js/api-config.js`
```javascript
// 수정 후: 상세한 에러 로깅
if (!response.ok) {
let errorMessage = `HTTP ${response.status}`;
try {
const errorData = await response.json();
errorMessage = errorData.error || errorData.message || errorMessage;
console.error('📋 서버 에러 상세:', errorData);
} catch (e) {
try {
const errorText = await response.text();
console.error('📋 서버 에러 텍스트:', errorText);
errorMessage = errorText || errorMessage;
} catch (e2) {
console.error('📋 에러 파싱 실패');
}
}
throw new Error(errorMessage);
}
```
**파일**: `api.hyungi.net/controllers/workerController.js`
```javascript
// 작업자 수정 요청 로깅 추가
console.log('🔧 작업자 수정 요청:', {
worker_id: id,
받은데이터: req.body,
처리할데이터: workerData
});
```
## 테스트 방법
1. 브라우저에서 강력 새로고침 (Ctrl+Shift+R 또는 Cmd+Shift+R)
2. 작업자 관리 페이지 접속
3. 작업자 상태 토글 (활성화/비활성화) 테스트
4. 브라우저 콘솔에서 로그 확인:
- `📤 전송 데이터:` - 올바른 필드만 전송되는지 확인
- `📋 서버 에러 상세:` - 에러 발생 시 상세 내용 확인
## 영향 범위
### 수정된 파일:
1. `web-ui/pages/management/worker-management.html`
2. `web-ui/js/api-config.js`
3. `web-ui/js/worker-management.js`
4. `api.hyungi.net/models/workerModel.js`
5. `api.hyungi.net/controllers/workerController.js`
### 영향받는 기능:
- ✅ 작업자 목록 조회
- ✅ 작업자 상태 변경 (활성화/비활성화)
- ⚠️ 작업자 추가/수정 (HTML 폼 필드도 수정 필요)
## 향후 작업 필요 사항
### 1. HTML 폼 업데이트
`worker-management.html`의 모달 폼을 실제 테이블 구조에 맞게 수정 필요:
```html