refactor(db): Replace SELECT * with explicit columns in models

Replaced `SELECT *` statements across multiple data models with explicit column lists to improve query performance, reduce data transfer, and increase code clarity. This is part of the Phase 2 refactoring plan.

- Refactored queries in the following models:
  - projectModel
  - toolsModel
  - attendanceModel
  - dailyIssueReportModel
  - issueTypeModel
  - workReportModel
  - userModel
  - dailyWorkReportModel

fix(api): Add missing volume mounts to docker-compose

Modified docker-compose.yml to mount the `config`, `middlewares`, `utils`, and `services` directories into the API container. This fixes a `MODULE_NOT_FOUND` error that caused the container to crash on startup.

feat(db): Add migration for missing project columns

Created a new database migration to add `is_active`, `project_status`, and `completed_date` columns to the `projects` table, resolving an inconsistency between the model code and the schema.

docs: Add deployment notes

Added a new markdown file to document the testing (macOS, Docker Desktop) and production (Synology NAS, Container Manager) environments.
This commit is contained in:
Hyungi Ahn
2025-12-19 10:33:29 +09:00
parent b67362a733
commit bc5df77595
11 changed files with 59 additions and 19 deletions

View File

@@ -0,0 +1,23 @@
/**
* @param { import("knex").Knex } knex
* @returns { Promise<void> }
*/
exports.up = function(knex) {
return knex.schema.table('projects', function (table) {
table.boolean('is_active').defaultTo(true).after('pm');
table.string('project_status').defaultTo('active').after('is_active');
table.date('completed_date').nullable().after('project_status');
});
};
/**
* @param { import("knex").Knex } knex
* @returns { Promise<void> }
*/
exports.down = function(knex) {
return knex.schema.table('projects', function (table) {
table.dropColumn('is_active');
table.dropColumn('project_status');
table.dropColumn('completed_date');
});
};

View File

@@ -137,7 +137,7 @@ class AttendanceModel {
// 휴가 유형 정보 조회
const [vacationTypes] = await db.execute(
'SELECT * FROM vacation_types WHERE type_code = ?',
'SELECT id, type_code, type_name, hours_deduction, description, is_active, created_at, updated_at FROM vacation_types WHERE type_code = ?',
[vacationType]
);
@@ -222,7 +222,7 @@ class AttendanceModel {
static async getAttendanceTypes() {
const db = await getDb();
const [rows] = await db.execute(
'SELECT * FROM work_attendance_types WHERE is_active = TRUE ORDER BY id'
'SELECT id, type_code, type_name, description, is_active, created_at, updated_at FROM work_attendance_types WHERE is_active = TRUE ORDER BY id'
);
return rows;
}
@@ -231,7 +231,7 @@ class AttendanceModel {
static async getVacationTypes() {
const db = await getDb();
const [rows] = await db.execute(
'SELECT * FROM vacation_types WHERE is_active = TRUE ORDER BY hours_deduction DESC'
'SELECT id, type_code, type_name, hours_deduction, description, is_active, created_at, updated_at FROM vacation_types WHERE is_active = TRUE ORDER BY hours_deduction DESC'
);
return rows;
}
@@ -242,7 +242,7 @@ class AttendanceModel {
const currentYear = year || new Date().getFullYear();
const [rows] = await db.execute(`
SELECT * FROM worker_vacation_balance
SELECT id, worker_id, year, total_annual_leave, used_annual_leave, notes, created_at, updated_at FROM worker_vacation_balance
WHERE worker_id = ? AND year = ?
`, [workerId, currentYear]);

View File

@@ -66,7 +66,7 @@ const getAllByDate = async (date) => {
const getById = async (id, callback) => {
try {
const db = await getDb();
const [rows] = await db.query(`SELECT * FROM DailyIssueReports WHERE id = ?`, [id]);
const [rows] = await db.query(`SELECT id, date, worker_id, project_id, issue_type_id, description, created_at, start_time, end_time FROM DailyIssueReports WHERE id = ?`, [id]);
callback(null, rows[0]);
} catch (err) {
callback(err);

View File

@@ -7,7 +7,7 @@ const { getDb } = require('../dbPool');
const getAllWorkTypes = async (callback) => {
try {
const db = await getDb();
const [rows] = await db.query('SELECT * FROM work_types ORDER BY name ASC');
const [rows] = await db.query('SELECT id, name, description, category, created_at, updated_at FROM work_types ORDER BY name ASC');
callback(null, rows);
} catch (err) {
console.error('작업 유형 조회 오류:', err);
@@ -18,7 +18,7 @@ const getAllWorkTypes = async (callback) => {
const getAllWorkStatusTypes = async (callback) => {
try {
const db = await getDb();
const [rows] = await db.query('SELECT * FROM work_status_types ORDER BY id ASC');
const [rows] = await db.query('SELECT id, name, description, is_error, created_at FROM work_status_types ORDER BY id ASC');
callback(null, rows);
} catch (err) {
console.error('업무 상태 유형 조회 오류:', err);
@@ -29,7 +29,7 @@ const getAllWorkStatusTypes = async (callback) => {
const getAllErrorTypes = async (callback) => {
try {
const db = await getDb();
const [rows] = await db.query('SELECT * FROM error_types ORDER BY name ASC');
const [rows] = await db.query('SELECT id, name, description, severity, solution_guide, created_at, updated_at FROM error_types ORDER BY name ASC');
callback(null, rows);
} catch (err) {
console.error('에러 유형 조회 오류:', err);
@@ -689,7 +689,7 @@ const removeByDateAndWorker = async (date, worker_id, deletedBy, callback) => {
// 삭제 전 정보 저장 (감사 로그용)
const [reportInfos] = await conn.query(
'SELECT * FROM daily_work_reports WHERE report_date = ? AND worker_id = ?',
'SELECT id, report_date, worker_id, project_id, work_type_id, work_status_id, error_type_id, work_hours, created_at, updated_at, created_by, updated_by FROM daily_work_reports WHERE report_date = ? AND worker_id = ?',
[date, worker_id]
);
@@ -948,7 +948,7 @@ const removeReportById = async (reportId, deletedByUserId) => {
await conn.beginTransaction();
// 감사 로그를 위해 삭제 전 정보 조회
const [reportInfo] = await conn.query('SELECT * FROM daily_work_reports WHERE id = ?', [reportId]);
const [reportInfo] = await conn.query('SELECT id, report_date, worker_id, project_id, work_type_id, work_status_id, error_type_id, work_hours, created_at, updated_at, created_by, updated_by FROM daily_work_reports WHERE id = ?', [reportId]);
// 실제 삭제 작업
const [result] = await conn.query('DELETE FROM daily_work_reports WHERE id = ?', [reportId]);

View File

@@ -18,7 +18,7 @@ const create = async (type, callback) => {
const getAll = async (callback) => {
try {
const db = await getDb();
const [rows] = await db.query(`SELECT * FROM IssueTypes ORDER BY category, subcategory`);
const [rows] = await db.query(`SELECT issue_type_id, category, subcategory FROM IssueTypes ORDER BY category, subcategory`);
callback(null, rows);
} catch (err) {
callback(err);

View File

@@ -29,7 +29,7 @@ const getAll = async (callback) => {
try {
const db = await getDb();
const [rows] = await db.query(
`SELECT * FROM projects ORDER BY project_id DESC`
`SELECT project_id, job_no, project_name, contract_date, due_date, delivery_method, site, pm, is_active, project_status, completed_date, created_at, updated_at FROM projects ORDER BY project_id DESC`
);
callback(null, rows);
} catch (err) {
@@ -42,7 +42,7 @@ const getActiveProjects = async (callback) => {
try {
const db = await getDb();
const [rows] = await db.query(
`SELECT * FROM projects
`SELECT project_id, job_no, project_name, contract_date, due_date, delivery_method, site, pm, is_active, project_status, completed_date, created_at, updated_at FROM projects
WHERE is_active = TRUE
ORDER BY project_name ASC`
);
@@ -56,7 +56,7 @@ const getById = async (project_id, callback) => {
try {
const db = await getDb();
const [rows] = await db.query(
`SELECT * FROM projects WHERE project_id = ?`,
`SELECT project_id, job_no, project_name, contract_date, due_date, delivery_method, site, pm, is_active, project_status, completed_date, created_at, updated_at FROM projects WHERE project_id = ?`,
[project_id]
);
callback(null, rows[0]);

View File

@@ -4,7 +4,7 @@ const { getDb } = require('../dbPool');
const getAll = async (callback) => {
try {
const db = await getDb();
const [rows] = await db.query('SELECT * FROM Tools');
const [rows] = await db.query('SELECT id, name, location, stock, status, factory_id, map_x, map_y, map_zone, map_note FROM Tools');
callback(null, rows);
} catch (err) {
callback(err);
@@ -15,7 +15,7 @@ const getAll = async (callback) => {
const getById = async (id, callback) => {
try {
const db = await getDb();
const [rows] = await db.query('SELECT * FROM Tools WHERE id = ?', [id]);
const [rows] = await db.query('SELECT id, name, location, stock, status, factory_id, map_x, map_y, map_zone, map_note FROM Tools WHERE id = ?', [id]);
callback(null, rows[0]);
} catch (err) {
callback(err);

View File

@@ -5,7 +5,7 @@ const findByUsername = async (username) => {
try {
const db = await getDb();
const [rows] = await db.query(
'SELECT * FROM users WHERE username = ?', [username]
'SELECT user_id, username, password, name, email, role, access_level, worker_id, is_active, last_login_at, password_changed_at, failed_login_attempts, locked_until, created_at, updated_at FROM users WHERE username = ?', [username]
);
return rows[0];
} catch (err) {

View File

@@ -110,7 +110,7 @@ const getByRange = async (start, end, callback) => {
try {
const db = await getDb();
const [rows] = await db.query(
`SELECT * FROM WorkReports
`SELECT id, \`date\`, worker_id, project_id, morning_task_id, afternoon_task_id, overtime_hours, overtime_task_id, work_details, note, memo, created_at, updated_at, morning_project_id, afternoon_project_id, overtime_project_id, task_id FROM WorkReports
WHERE \`date\` BETWEEN ? AND ?
ORDER BY \`date\` ASC`,
[start, end]
@@ -128,7 +128,7 @@ const getById = async (id, callback) => {
try {
const db = await getDb();
const [rows] = await db.query(
`SELECT * FROM WorkReports WHERE id = ?`,
`SELECT id, \`date\`, worker_id, project_id, morning_task_id, afternoon_task_id, overtime_hours, overtime_task_id, work_details, note, memo, created_at, updated_at, morning_project_id, afternoon_project_id, overtime_project_id, task_id FROM WorkReports WHERE id = ?`,
[id]
);
callback(null, rows[0]);