feat: 작업자-계정 통합 및 연차/출근 관리 시스템 구축
모든 작업자가 개인 계정으로 로그인하여 본인의 연차와 출근 기록을 확인할 수 있는 시스템을 구축했습니다. 주요 기능: - 작업자-계정 1:1 통합 (기존 작업자 자동 계정 생성) - 연차 관리 시스템 (연도별 잔액 관리) - 출근 기록 시스템 (일일 근태 기록) - 나의 대시보드 페이지 (개인 정보 조회) 데이터베이스: - workers 테이블에 salary, base_annual_leave 컬럼 추가 - work_attendance_types, vacation_types 테이블 생성 - daily_attendance_records 테이블 생성 - worker_vacation_balance 테이블 생성 - 기존 작업자 자동 계정 생성 (username: 이름 기반) - Guest 역할 추가 백엔드 API: - 한글→영문 변환 유틸리티 (hangulToRoman.js) - UserRoutes에 개인 정보 조회 API 추가 - GET /api/users/me (내 정보) - GET /api/users/me/attendance-records (출근 기록) - GET /api/users/me/vacation-balance (연차 잔액) - GET /api/users/me/work-reports (작업 보고서) - GET /api/users/me/monthly-stats (월별 통계) 프론트엔드: - 나의 대시보드 페이지 (my-dashboard.html) - 연차 정보 위젯 (총/사용/잔여) - 월별 출근 캘린더 - 근무 시간 통계 - 최근 작업 보고서 목록 - 네비게이션 바에 "나의 대시보드" 메뉴 추가 배포 시 주의사항: - 마이그레이션 실행 필요 - 자동 생성된 계정 초기 비밀번호: 1234 - 작업자들에게 첫 로그인 후 비밀번호 변경 안내 필요 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
|
||||
/**
|
||||
* @param { import("knex").Knex } knex
|
||||
* @returns { Promise<void> }
|
||||
*/
|
||||
exports.up = async function (knex) {
|
||||
const hasHireDate = await knex.schema.hasColumn('workers', 'hire_date');
|
||||
|
||||
if (!hasHireDate) {
|
||||
await knex.schema.alterTable('workers', function (table) {
|
||||
// Modify status to ENUM
|
||||
// Note: Knex might not support modifying to ENUM easily across DBs, but valid for MySQL
|
||||
// We use raw SQL for status modification to be safe with existing data
|
||||
|
||||
// Add new columns
|
||||
table.string('phone_number', 20).nullable().comment('전화번호');
|
||||
table.string('email', 100).nullable().comment('이메일');
|
||||
table.date('hire_date').nullable().comment('입사일');
|
||||
table.string('department', 100).nullable().comment('부서');
|
||||
table.text('notes').nullable().comment('비고');
|
||||
});
|
||||
|
||||
// Update status column using raw query
|
||||
await knex.raw(`
|
||||
ALTER TABLE workers
|
||||
MODIFY COLUMN status ENUM('active', 'inactive') DEFAULT 'active' COMMENT '작업자 상태 (active: 활성, inactive: 비활성)'
|
||||
`);
|
||||
|
||||
// Add indexes
|
||||
await knex.raw(`CREATE INDEX IF NOT EXISTS idx_workers_status ON workers(status)`);
|
||||
await knex.raw(`CREATE INDEX IF NOT EXISTS idx_workers_hire_date ON workers(hire_date)`);
|
||||
|
||||
// Set NULL status to active
|
||||
await knex('workers').whereNull('status').update({ status: 'active' });
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @param { import("knex").Knex } knex
|
||||
* @returns { Promise<void> }
|
||||
*/
|
||||
exports.down = async function (knex) {
|
||||
// We generally don't want to lose data on rollback of this critical schema fix,
|
||||
// but technically we should revert changes.
|
||||
// For safety, we might skip dropping columns or implement it carefully.
|
||||
|
||||
const hasHireDate = await knex.schema.hasColumn('workers', 'hire_date');
|
||||
if (hasHireDate) {
|
||||
await knex.schema.alterTable('workers', function (table) {
|
||||
table.dropColumn('phone_number');
|
||||
table.dropColumn('email');
|
||||
table.dropColumn('hire_date');
|
||||
table.dropColumn('department');
|
||||
table.dropColumn('notes');
|
||||
});
|
||||
|
||||
await knex.raw(`
|
||||
ALTER TABLE workers
|
||||
MODIFY COLUMN status VARCHAR(20) DEFAULT 'active' COMMENT '상태 (active, inactive)'
|
||||
`);
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user