Files
tk-factory-services/system1-factory/api/models/notificationModel.js
Hyungi Ahn 550633b89d feat: 3-System 분리 프로젝트 초기 코드 작성
TK-FB(공장관리+신고)와 M-Project(부적합관리)를 3개 독립 시스템으로
분리하기 위한 전체 코드 구조 작성.
- SSO 인증 서비스 (bcrypt + pbkdf2 이중 해시 지원)
- System 1: 공장관리 (TK-FB 기반, 신고 코드 제거)
- System 2: 신고 (TK-FB에서 workIssue 코드 추출)
- System 3: 부적합관리 (M-Project 기반)
- Gateway 포털 (path-based 라우팅)
- 통합 docker-compose.yml 및 배포 스크립트

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 14:40:11 +09:00

198 lines
5.8 KiB
JavaScript

// models/notificationModel.js
const { getDb } = require('../dbPool');
// 순환 참조를 피하기 위해 함수 내에서 require
async function getRecipientIds(notificationType) {
const db = await getDb();
const [rows] = await db.query(
`SELECT user_id FROM notification_recipients
WHERE notification_type = ? AND is_active = 1`,
[notificationType]
);
return rows.map(r => r.user_id);
}
const notificationModel = {
// 알림 생성
async create(notificationData) {
const db = await getDb();
const { user_id, type, title, message, link_url, reference_type, reference_id, created_by } = notificationData;
const [result] = await db.query(
`INSERT INTO notifications (user_id, type, title, message, link_url, reference_type, reference_id, created_by)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
[user_id || null, type || 'system', title, message || null, link_url || null, reference_type || null, reference_id || null, created_by || null]
);
return result.insertId;
},
// 읽지 않은 알림 조회 (특정 사용자 또는 전체)
async getUnread(userId = null) {
const db = await getDb();
const [rows] = await db.query(
`SELECT * FROM notifications
WHERE is_read = 0
AND (user_id IS NULL OR user_id = ?)
ORDER BY created_at DESC
LIMIT 50`,
[userId || 0]
);
return rows;
},
// 전체 알림 조회 (페이징)
async getAll(userId = null, page = 1, limit = 20) {
const db = await getDb();
const offset = (page - 1) * limit;
const [rows] = await db.query(
`SELECT * FROM notifications
WHERE (user_id IS NULL OR user_id = ?)
ORDER BY created_at DESC
LIMIT ? OFFSET ?`,
[userId || 0, limit, offset]
);
const [[{ total }]] = await db.query(
`SELECT COUNT(*) as total FROM notifications
WHERE (user_id IS NULL OR user_id = ?)`,
[userId || 0]
);
return { notifications: rows, total, page, limit };
},
// 알림 읽음 처리
async markAsRead(notificationId) {
const db = await getDb();
const [result] = await db.query(
`UPDATE notifications SET is_read = 1, read_at = NOW() WHERE notification_id = ?`,
[notificationId]
);
return result.affectedRows > 0;
},
// 모든 알림 읽음 처리
async markAllAsRead(userId = null) {
const db = await getDb();
const [result] = await db.query(
`UPDATE notifications SET is_read = 1, read_at = NOW()
WHERE is_read = 0 AND (user_id IS NULL OR user_id = ?)`,
[userId || 0]
);
return result.affectedRows;
},
// 알림 삭제
async delete(notificationId) {
const db = await getDb();
const [result] = await db.query(
`DELETE FROM notifications WHERE notification_id = ?`,
[notificationId]
);
return result.affectedRows > 0;
},
// 오래된 알림 삭제 (30일 이상)
async deleteOld(days = 30) {
const db = await getDb();
const [result] = await db.query(
`DELETE FROM notifications WHERE created_at < DATE_SUB(NOW(), INTERVAL ? DAY)`,
[days]
);
return result.affectedRows;
},
// 읽지 않은 알림 개수
async getUnreadCount(userId = null) {
const db = await getDb();
const [[{ count }]] = await db.query(
`SELECT COUNT(*) as count FROM notifications
WHERE is_read = 0 AND (user_id IS NULL OR user_id = ?)`,
[userId || 0]
);
return count;
},
// 수리 신청 알림 생성 헬퍼 (지정된 수신자에게 전송)
async createRepairNotification(repairData) {
const { equipment_id, equipment_name, repair_type, request_id, created_by } = repairData;
// 수리 알림 수신자 목록 가져오기
const recipientIds = await getRecipientIds('repair');
if (recipientIds.length === 0) {
// 수신자가 지정되지 않은 경우 전체 알림 (user_id = null)
return await this.create({
type: 'repair',
title: `수리 신청: ${equipment_name || '설비'}`,
message: `${repair_type} 수리가 신청되었습니다.`,
link_url: `/pages/admin/repair-management.html`,
reference_type: 'work_issue_reports',
reference_id: request_id,
created_by
});
}
// 지정된 수신자 각각에게 알림 생성
const results = [];
for (const userId of recipientIds) {
const notificationId = await this.create({
user_id: userId,
type: 'repair',
title: `수리 신청: ${equipment_name || '설비'}`,
message: `${repair_type} 수리가 신청되었습니다.`,
link_url: `/pages/admin/repair-management.html`,
reference_type: 'work_issue_reports',
reference_id: request_id,
created_by
});
results.push(notificationId);
}
return results;
},
// 일반 알림 생성 (유형별 지정된 수신자에게 전송)
async createTypedNotification(notificationData) {
const { type, title, message, link_url, reference_type, reference_id, created_by } = notificationData;
// 해당 유형의 수신자 목록 가져오기
const recipientIds = await getRecipientIds(type);
if (recipientIds.length === 0) {
// 수신자가 지정되지 않은 경우 전체 알림
return await this.create({
type,
title,
message,
link_url,
reference_type,
reference_id,
created_by
});
}
// 지정된 수신자 각각에게 알림 생성
const results = [];
for (const userId of recipientIds) {
const notificationId = await this.create({
user_id: userId,
type,
title,
message,
link_url,
reference_type,
reference_id,
created_by
});
results.push(notificationId);
}
return results;
}
};
module.exports = notificationModel;