auto commit

This commit is contained in:
bangdk 2024-11-25 08:40:59 +09:00
parent 6320be5717
commit ef73aae117
9 changed files with 634 additions and 6 deletions

20
.gitignore vendored
View File

@ -1,13 +1,21 @@
# Env files
.env*
!.env.example
backups/
logs/
# Dependencies
node_modules/
# OS files
.DS_Store
config/
# Data directories
backups/
init-scripts/
logs/
shared/
fems-mqtt/log/mosquitto.log
fems-mqtt/data/
# Mosquitto specific
fems-mqtt/config/
!fems-mqtt/log/
!fems-mqtt/log/mosquitto.log
!fems-mqtt/data/
!fems-mqtt/data/mosquitto.db

View File

@ -0,0 +1,208 @@
// src/config/permissions.ts
// 기본 권한 정의
export const PERMISSIONS = {
// 회사 관련 권한
COMPANY_VIEW: "company:view",
COMPANY_EDIT: "company:edit",
COMPANY_DELETE: "company:delete",
// 지점/공장 관련 권한
BRANCH_VIEW: "branch:view",
BRANCH_CREATE: "branch:create",
BRANCH_EDIT: "branch:edit",
BRANCH_DELETE: "branch:delete",
// 사용자 관련 권한
USER_VIEW: "user:view",
USER_CREATE: "user:create",
USER_EDIT: "user:edit",
USER_DELETE: "user:delete",
// 부서 관련 권한
DEPARTMENT_VIEW: "department:view",
DEPARTMENT_CREATE: "department:create",
DEPARTMENT_EDIT: "department:edit",
DEPARTMENT_DELETE: "department:delete",
// 설비 관련 권한
EQUIPMENT_VIEW: "equipment:view",
EQUIPMENT_CREATE: "equipment:create",
EQUIPMENT_EDIT: "equipment:edit",
EQUIPMENT_DELETE: "equipment:delete",
// 에너지 모니터링 권한
ENERGY_VIEW: "energy:view",
ENERGY_ANALYZE: "energy:analyze",
// 알람 관련 권한
ALARM_VIEW: "alarm:view",
ALARM_CREATE: "alarm:create",
ALARM_EDIT: "alarm:edit",
ALARM_DELETE: "alarm:delete",
// 보고서 관련 권한
REPORT_VIEW: "report:view",
REPORT_CREATE: "report:create",
REPORT_EDIT: "report:edit",
REPORT_DELETE: "report:delete",
// 설정 관련 권한
SETTINGS_VIEW: "settings:view",
SETTINGS_EDIT: "settings:edit",
} as const;
// 경로별 필요 권한 정의
export const PATH_PERMISSIONS: Record<string, string[]> = {
// 대시보드
"/dashboard": [PERMISSIONS.ENERGY_VIEW],
"/dashboard/overview": [PERMISSIONS.ENERGY_VIEW],
"/dashboard/kpi": [PERMISSIONS.ENERGY_VIEW],
"/dashboard/costs": [PERMISSIONS.ENERGY_VIEW],
// 에너지 모니터링
"/monitoring/electricity": [PERMISSIONS.ENERGY_VIEW],
"/monitoring/gas": [PERMISSIONS.ENERGY_VIEW],
"/monitoring/water": [PERMISSIONS.ENERGY_VIEW],
"/monitoring/steam": [PERMISSIONS.ENERGY_VIEW],
// 설비 관리
"/equipment": [PERMISSIONS.EQUIPMENT_VIEW],
"/equipment/inventory": [PERMISSIONS.EQUIPMENT_VIEW],
"/equipment/monitoring": [PERMISSIONS.EQUIPMENT_VIEW],
"/equipment/maintenance": [PERMISSIONS.EQUIPMENT_VIEW],
"/equipment/create": [PERMISSIONS.EQUIPMENT_CREATE],
"/equipment/edit": [PERMISSIONS.EQUIPMENT_EDIT],
// 분석/리포트
"/analysis": [PERMISSIONS.ENERGY_ANALYZE],
"/analysis/energy": [PERMISSIONS.ENERGY_ANALYZE],
"/analysis/efficiency": [PERMISSIONS.ENERGY_ANALYZE],
"/analysis/reports": [PERMISSIONS.REPORT_VIEW],
"/analysis/reports/create": [PERMISSIONS.REPORT_CREATE],
"/analysis/reports/edit": [PERMISSIONS.REPORT_EDIT],
// 알람/이벤트
"/alarm": [PERMISSIONS.ALARM_VIEW],
"/alarm/realtime": [PERMISSIONS.ALARM_VIEW],
"/alarm/history": [PERMISSIONS.ALARM_VIEW],
"/alarm/settings": [PERMISSIONS.ALARM_EDIT],
// 관리자 설정
"/admin/company": [PERMISSIONS.COMPANY_VIEW],
"/admin/company/profile": [PERMISSIONS.COMPANY_EDIT],
"/admin/company/branches": [PERMISSIONS.BRANCH_VIEW],
"/admin/company/billing": [PERMISSIONS.COMPANY_VIEW],
// 사용자 관리
"/admin/user": [PERMISSIONS.USER_VIEW],
"/admin/user/departments": [PERMISSIONS.DEPARTMENT_VIEW],
"/admin/user/roles": [PERMISSIONS.USER_VIEW],
"/admin/user/accounts": [PERMISSIONS.USER_VIEW],
"/admin/user/create": [PERMISSIONS.USER_CREATE],
"/admin/user/edit": [PERMISSIONS.USER_EDIT],
// 시스템 설정
"/admin/system": [PERMISSIONS.SETTINGS_VIEW],
"/admin/system/general": [PERMISSIONS.SETTINGS_EDIT],
"/admin/system/integration": [PERMISSIONS.SETTINGS_EDIT],
"/admin/system/backup": [PERMISSIONS.SETTINGS_EDIT],
};
// 역할별 기본 권한 정의
export const ROLE_PERMISSIONS: Record<string, string[]> = {
super_admin: Object.values(PERMISSIONS),
company_admin: [
PERMISSIONS.COMPANY_VIEW,
PERMISSIONS.COMPANY_EDIT,
PERMISSIONS.BRANCH_VIEW,
PERMISSIONS.BRANCH_CREATE,
PERMISSIONS.BRANCH_EDIT,
PERMISSIONS.USER_VIEW,
PERMISSIONS.USER_CREATE,
PERMISSIONS.USER_EDIT,
PERMISSIONS.DEPARTMENT_VIEW,
PERMISSIONS.DEPARTMENT_CREATE,
PERMISSIONS.DEPARTMENT_EDIT,
PERMISSIONS.EQUIPMENT_VIEW,
PERMISSIONS.EQUIPMENT_CREATE,
PERMISSIONS.EQUIPMENT_EDIT,
PERMISSIONS.ENERGY_VIEW,
PERMISSIONS.ENERGY_ANALYZE,
PERMISSIONS.ALARM_VIEW,
PERMISSIONS.ALARM_CREATE,
PERMISSIONS.ALARM_EDIT,
PERMISSIONS.REPORT_VIEW,
PERMISSIONS.REPORT_CREATE,
PERMISSIONS.SETTINGS_VIEW,
PERMISSIONS.SETTINGS_EDIT,
],
branch_admin: [
PERMISSIONS.BRANCH_VIEW,
PERMISSIONS.USER_VIEW,
PERMISSIONS.USER_CREATE,
PERMISSIONS.EQUIPMENT_VIEW,
PERMISSIONS.EQUIPMENT_CREATE,
PERMISSIONS.ENERGY_VIEW,
PERMISSIONS.ENERGY_ANALYZE,
PERMISSIONS.ALARM_VIEW,
PERMISSIONS.ALARM_CREATE,
PERMISSIONS.REPORT_VIEW,
PERMISSIONS.REPORT_CREATE,
],
user: [
PERMISSIONS.ENERGY_VIEW,
PERMISSIONS.EQUIPMENT_VIEW,
PERMISSIONS.ALARM_VIEW,
PERMISSIONS.REPORT_VIEW,
],
};
// 권한 그룹 정의
export const PERMISSION_GROUPS = {
COMPANY_MANAGEMENT: [
PERMISSIONS.COMPANY_VIEW,
PERMISSIONS.COMPANY_EDIT,
PERMISSIONS.COMPANY_DELETE,
],
BRANCH_MANAGEMENT: [
PERMISSIONS.BRANCH_VIEW,
PERMISSIONS.BRANCH_CREATE,
PERMISSIONS.BRANCH_EDIT,
PERMISSIONS.BRANCH_DELETE,
],
USER_MANAGEMENT: [
PERMISSIONS.USER_VIEW,
PERMISSIONS.USER_CREATE,
PERMISSIONS.USER_EDIT,
PERMISSIONS.USER_DELETE,
],
EQUIPMENT_MANAGEMENT: [
PERMISSIONS.EQUIPMENT_VIEW,
PERMISSIONS.EQUIPMENT_CREATE,
PERMISSIONS.EQUIPMENT_EDIT,
PERMISSIONS.EQUIPMENT_DELETE,
],
ENERGY_MONITORING: [PERMISSIONS.ENERGY_VIEW, PERMISSIONS.ENERGY_ANALYZE],
ALARM_MANAGEMENT: [
PERMISSIONS.ALARM_VIEW,
PERMISSIONS.ALARM_CREATE,
PERMISSIONS.ALARM_EDIT,
PERMISSIONS.ALARM_DELETE,
],
REPORT_MANAGEMENT: [
PERMISSIONS.REPORT_VIEW,
PERMISSIONS.REPORT_CREATE,
PERMISSIONS.REPORT_EDIT,
PERMISSIONS.REPORT_DELETE,
],
} as const;

BIN
fems-mqtt/data/mosquitto.db Normal file

Binary file not shown.

2
fems-mqtt/data/passwd Normal file
View File

@ -0,0 +1,2 @@
fems:$7$101$p+0HKWVdeWzlO1o4$+GB5GrYz2g6TO75UHWzMDZH+eC8w/ZA4u3qk/0tMBoeSVnqTaInIdANM7trDQsEnT+G2wOr9G6ND+5YOySqxYQ==
nodered_user:$7$101$bnRKi1qgGP06mJIZ$ksMvwVPG9Dp7+gWHKZnEXkgTV1W+Md9HHuOKSh4yFylwyZ2yEsRYOb/7oQ58Xxeu1YZNNrICiRCjnb9iDz0dpQ==

View File

@ -16152,3 +16152,106 @@ To fix this, use `chmod 0700 /mosquitto/config/passwd`.
1732490536: New connection from ::1:43836 on port 1883.
1732490536: New client connected from ::1:43836 as auto-7B9071EC-9348-5AC2-2FE5-3F75319EAB71 (p2, c1, k60, u'fems').
1732490536: Client auto-7B9071EC-9348-5AC2-2FE5-3F75319EAB71 closed its connection.
1732490687: mosquitto version 2.0.20 starting
1732490687: Config loaded from /mosquitto/config/mosquitto.conf.
1732490687: Opening ipv4 listen socket on port 1883.
1732490687: Opening ipv6 listen socket on port 1883.
1732490687: mosquitto version 2.0.20 running
1732490691: New connection from 172.19.0.9:33118 on port 1883.
1732490691: New client connected from 172.19.0.9:33118 as fems_realtime_40 (p2, c1, k60, u'fems').
1732490718: New connection from ::1:54086 on port 1883.
1732490718: New client connected from ::1:54086 as auto-2D4F3C8B-9D04-17FC-D813-CB77A364BAE6 (p2, c1, k60, u'fems').
1732490718: Client auto-2D4F3C8B-9D04-17FC-D813-CB77A364BAE6 closed its connection.
1732490748: New connection from ::1:55062 on port 1883.
1732490748: New client connected from ::1:55062 as auto-92F8F9BC-0250-47AB-F726-9AC0F1894772 (p2, c1, k60, u'fems').
1732490748: Client auto-92F8F9BC-0250-47AB-F726-9AC0F1894772 closed its connection.
1732490778: New connection from ::1:51410 on port 1883.
1732490778: New client connected from ::1:51410 as auto-73A6A1E9-3235-19AB-1C6A-78810845C0EF (p2, c1, k60, u'fems').
1732490778: Client auto-73A6A1E9-3235-19AB-1C6A-78810845C0EF closed its connection.
1732490808: New connection from ::1:60058 on port 1883.
1732490808: New client connected from ::1:60058 as auto-0D81837A-5F32-0F2A-5A84-F1CD500A34BB (p2, c1, k60, u'fems').
1732490808: Client auto-0D81837A-5F32-0F2A-5A84-F1CD500A34BB closed its connection.
1732490838: New connection from ::1:40688 on port 1883.
1732490838: New client connected from ::1:40688 as auto-C92A19DE-7AFF-91B8-D9B7-E783E566B0AE (p2, c1, k60, u'fems').
1732490838: Client auto-C92A19DE-7AFF-91B8-D9B7-E783E566B0AE closed its connection.
1732490868: New connection from ::1:51326 on port 1883.
1732490868: New client connected from ::1:51326 as auto-77597FD6-78CB-5036-3503-424EC4E59336 (p2, c1, k60, u'fems').
1732490868: Client auto-77597FD6-78CB-5036-3503-424EC4E59336 closed its connection.
1732490898: New connection from ::1:36716 on port 1883.
1732490898: New client connected from ::1:36716 as auto-71130DEF-B28B-83D2-7860-DB3A1ED0BBF5 (p2, c1, k60, u'fems').
1732490898: Client auto-71130DEF-B28B-83D2-7860-DB3A1ED0BBF5 closed its connection.
1732490928: New connection from ::1:46640 on port 1883.
1732490928: New client connected from ::1:46640 as auto-ABA29341-7728-9CA0-CC93-0B941290691D (p2, c1, k60, u'fems').
1732490928: Client auto-ABA29341-7728-9CA0-CC93-0B941290691D closed its connection.
1732490958: New connection from ::1:42752 on port 1883.
1732490958: New client connected from ::1:42752 as auto-243B1078-D0D2-ED05-A6C8-F0BF776AEB6B (p2, c1, k60, u'fems').
1732490959: Client auto-243B1078-D0D2-ED05-A6C8-F0BF776AEB6B closed its connection.
1732490989: New connection from ::1:41906 on port 1883.
1732490989: New client connected from ::1:41906 as auto-9C33A78D-8294-B6C1-58C3-FF516DD1E0B8 (p2, c1, k60, u'fems').
1732490989: Client auto-9C33A78D-8294-B6C1-58C3-FF516DD1E0B8 closed its connection.
1732491019: New connection from ::1:41178 on port 1883.
1732491019: New client connected from ::1:41178 as auto-A139E080-C259-3D39-0329-7E7A1573E190 (p2, c1, k60, u'fems').
1732491019: Client auto-A139E080-C259-3D39-0329-7E7A1573E190 closed its connection.
1732491049: New connection from ::1:38994 on port 1883.
1732491049: New client connected from ::1:38994 as auto-AF07BC5F-6663-3268-0FA1-3DE70038B9B8 (p2, c1, k60, u'fems').
1732491049: Client auto-AF07BC5F-6663-3268-0FA1-3DE70038B9B8 closed its connection.
1732491079: New connection from ::1:48114 on port 1883.
1732491079: New client connected from ::1:48114 as auto-7D97DF2B-7E14-B971-9639-EFA16634D860 (p2, c1, k60, u'fems').
1732491079: Client auto-7D97DF2B-7E14-B971-9639-EFA16634D860 closed its connection.
1732491109: New connection from ::1:58464 on port 1883.
1732491109: New client connected from ::1:58464 as auto-8ADAE7A2-8E93-8DA1-758C-A3F3AE0D4764 (p2, c1, k60, u'fems').
1732491109: Client auto-8ADAE7A2-8E93-8DA1-758C-A3F3AE0D4764 closed its connection.
1732491139: New connection from ::1:36580 on port 1883.
1732491139: New client connected from ::1:36580 as auto-D058BA2D-FDB5-448B-BF4F-3A246A151455 (p2, c1, k60, u'fems').
1732491139: Client auto-D058BA2D-FDB5-448B-BF4F-3A246A151455 closed its connection.
1732491169: New connection from ::1:36214 on port 1883.
1732491169: New client connected from ::1:36214 as auto-7E3A3113-C7D5-E795-8321-61B07DF68BBD (p2, c1, k60, u'fems').
1732491169: Client auto-7E3A3113-C7D5-E795-8321-61B07DF68BBD closed its connection.
1732491199: New connection from ::1:50750 on port 1883.
1732491199: New client connected from ::1:50750 as auto-154D1239-5A81-35AB-1A45-140DC068F894 (p2, c1, k60, u'fems').
1732491199: Client auto-154D1239-5A81-35AB-1A45-140DC068F894 closed its connection.
1732491229: New connection from ::1:60768 on port 1883.
1732491229: New client connected from ::1:60768 as auto-278B5CC2-EE66-DDDC-FDFD-0328223CD5F5 (p2, c1, k60, u'fems').
1732491229: Client auto-278B5CC2-EE66-DDDC-FDFD-0328223CD5F5 closed its connection.
1732491259: New connection from ::1:44754 on port 1883.
1732491259: New client connected from ::1:44754 as auto-7E2B7353-2DA6-5780-6E11-4D95D3FA7C1D (p2, c1, k60, u'fems').
1732491259: Client auto-7E2B7353-2DA6-5780-6E11-4D95D3FA7C1D closed its connection.
1732491289: New connection from ::1:33370 on port 1883.
1732491289: New client connected from ::1:33370 as auto-4E6B0FAD-1679-EC09-5B7D-7D78E9239449 (p2, c1, k60, u'fems').
1732491289: Client auto-4E6B0FAD-1679-EC09-5B7D-7D78E9239449 closed its connection.
1732491319: New connection from ::1:43742 on port 1883.
1732491319: New client connected from ::1:43742 as auto-4962452D-D915-2E77-3F10-B4210A376198 (p2, c1, k60, u'fems').
1732491319: Client auto-4962452D-D915-2E77-3F10-B4210A376198 closed its connection.
1732491349: New connection from ::1:38400 on port 1883.
1732491349: New client connected from ::1:38400 as auto-E64FFAD5-8EC3-AB42-32AC-9B47A0E869DA (p2, c1, k60, u'fems').
1732491350: Client auto-E64FFAD5-8EC3-AB42-32AC-9B47A0E869DA closed its connection.
1732491380: New connection from ::1:50554 on port 1883.
1732491380: New client connected from ::1:50554 as auto-49A2BA59-20A9-86EC-738E-6C0747EACBC5 (p2, c1, k60, u'fems').
1732491380: Client auto-49A2BA59-20A9-86EC-738E-6C0747EACBC5 closed its connection.
1732491410: New connection from ::1:51472 on port 1883.
1732491410: New client connected from ::1:51472 as auto-926B3BC4-A256-C884-31B3-B769F5D556A5 (p2, c1, k60, u'fems').
1732491410: Client auto-926B3BC4-A256-C884-31B3-B769F5D556A5 closed its connection.
1732491440: New connection from ::1:38310 on port 1883.
1732491440: New client connected from ::1:38310 as auto-008FD4ED-5203-D152-D76E-2F5D9F8DD0A9 (p2, c1, k60, u'fems').
1732491440: Client auto-008FD4ED-5203-D152-D76E-2F5D9F8DD0A9 closed its connection.
1732491470: New connection from ::1:45430 on port 1883.
1732491470: New client connected from ::1:45430 as auto-460F179A-BA65-9CAB-D343-D578EDC0E52A (p2, c1, k60, u'fems').
1732491470: Client auto-460F179A-BA65-9CAB-D343-D578EDC0E52A closed its connection.
1732491500: New connection from ::1:35036 on port 1883.
1732491500: New client connected from ::1:35036 as auto-73657D0E-57B0-E4B4-203D-695B9272A1D2 (p2, c1, k60, u'fems').
1732491500: Client auto-73657D0E-57B0-E4B4-203D-695B9272A1D2 closed its connection.
1732491530: New connection from ::1:41792 on port 1883.
1732491530: New client connected from ::1:41792 as auto-D9A66FCF-9FA2-681C-6219-94E21F9ACC56 (p2, c1, k60, u'fems').
1732491530: Client auto-D9A66FCF-9FA2-681C-6219-94E21F9ACC56 closed its connection.
1732491560: New connection from ::1:38248 on port 1883.
1732491560: New client connected from ::1:38248 as auto-94A398BB-6697-A0FE-51D2-B03938E2A628 (p2, c1, k60, u'fems').
1732491560: Client auto-94A398BB-6697-A0FE-51D2-B03938E2A628 closed its connection.
1732491590: New connection from ::1:55668 on port 1883.
1732491590: New client connected from ::1:55668 as auto-A7E0C188-D363-E61F-6705-41E2F1CF00FC (p2, c1, k60, u'fems').
1732491590: Client auto-A7E0C188-D363-E61F-6705-41E2F1CF00FC closed its connection.
1732491620: New connection from ::1:41604 on port 1883.
1732491620: New client connected from ::1:41604 as auto-EE19F34E-4E04-1D13-CE67-A1FFBA9612D4 (p2, c1, k60, u'fems').
1732491620: Client auto-EE19F34E-4E04-1D13-CE67-A1FFBA9612D4 closed its connection.
1732491650: New connection from ::1:55334 on port 1883.
1732491650: New client connected from ::1:55334 as auto-698C8684-502F-6421-8FBE-C6C6DFC9CBB0 (p2, c1, k60, u'fems').
1732491650: Client auto-698C8684-502F-6421-8FBE-C6C6DFC9CBB0 closed its connection.

View File

@ -0,0 +1,45 @@
// src/config/config.js
require("dotenv").config({
path: `.env.${process.env.NODE_ENV || "development"}`,
});
const config = {
port: process.env.REALTIME_API_PORT || 3004,
timescaledb: {
host: process.env.TIMESCALEDB_HOST || "localhost",
port: parseInt(process.env.TIMESCALEDB_PORT) || 5433,
database: process.env.TIMESCALEDB_DB,
user: process.env.TIMESCALEDB_USER,
password: process.env.TIMESCALEDB_PASSWORD,
},
redis: {
host: process.env.REDIS_HOST || "localhost",
port: parseInt(process.env.REDIS_PORT) || 6379,
password: process.env.REDIS_PASSWORD,
db: parseInt(process.env.REDIS_DB) || 0,
retryStrategy: (times) => {
return Math.min(times * 50, 2000);
},
},
mqtt: {
url: process.env.MQTT_BROKER_URL || "mqtt://localhost:1883",
options: {
username: process.env.MQTT_USERNAME,
password: process.env.MQTT_PASSWORD,
clientId: `fems_realtime_${process.pid}`,
clean: true,
reconnectPeriod: 5000,
connectTimeout: 30000,
},
},
mainBackend: {
url: process.env.NEXT_PUBLIC_API_URL || "http://localhost:3000",
adminApiKey: process.env.ADMIN_API_KEY,
},
};
module.exports = config;

View File

@ -0,0 +1,55 @@
// src/config/database.js
const logger = require("./logger");
module.exports = {
development: {
host: process.env.POSTGRES_HOST || "fems-timescaledb",
port: parseInt(process.env.DB_PORT) || 5442,
database: process.env.POSTGRES_DB || "fems_timeseries",
username: process.env.POSTGRES_USER || "fems_user",
password: process.env.POSTGRES_PASSWORD,
dialect: "postgres",
logging: (msg) => logger.debug(msg),
dialectOptions: {
ssl: false,
},
define: {
timestamps: true,
underscored: true,
},
pool: {
max: 5,
min: 0,
acquire: 60000,
idle: 10000,
},
retry: {
max: 5,
},
},
production: {
host: process.env.POSTGRES_HOST,
port: parseInt(process.env.DB_PORT),
database: process.env.POSTGRES_DB,
username: process.env.POSTGRES_USER,
password: process.env.POSTGRES_PASSWORD,
dialect: "postgres",
logging: false,
dialectOptions: {
ssl: process.env.DB_SSL === "true",
},
define: {
timestamps: true,
underscored: true,
},
pool: {
max: 10,
min: 2,
acquire: 60000,
idle: 10000,
},
retry: {
max: 5,
},
},
};

View File

@ -0,0 +1,190 @@
// src/config/logger.js
const winston = require("winston");
require("winston-daily-rotate-file");
const path = require("path");
const fs = require("fs");
class Logger {
constructor() {
if (Logger.instance) {
return Logger.instance;
}
this.initializeDirs();
this.createLogger();
Logger.instance = this;
return this;
}
initializeDirs() {
// 로그 디렉토리 설정
this.logDir = path.join(__dirname, "../../logs");
this.errorLogDir = path.join(this.logDir, "error");
this.infoLogDir = path.join(this.logDir, "info");
this.systemLogDir = path.join(this.logDir, "system");
// 로그 디렉토리 생성
[this.errorLogDir, this.infoLogDir, this.systemLogDir].forEach((dir) => {
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}
});
}
createLogger() {
// 공통 로그 포맷
const commonLogFormat = winston.format.combine(
winston.format.timestamp({ format: "YYYY-MM-DD HH:mm:ss" }),
winston.format.errors({ stack: true }),
winston.format.splat(),
winston.format.json()
);
// 콘솔 출력용 포맷
const consoleFormat = winston.format.combine(
winston.format.colorize(),
winston.format.timestamp({ format: "YYYY-MM-DD HH:mm:ss" }),
winston.format.printf(
({ level, message, timestamp, stack, ...metadata }) => {
let msg = `${timestamp} [${level}]: ${message}`;
if (stack) msg += `\n${stack}`;
if (Object.keys(metadata).length > 0) {
msg += `\n${JSON.stringify(metadata, null, 2)}`;
}
return msg;
}
)
);
// 트랜스포트 설정
this.transports = {
error: new winston.transports.DailyRotateFile({
level: "error",
dirname: this.errorLogDir,
filename: "error-%DATE%.log",
datePattern: "YYYY-MM-DD",
zippedArchive: true,
maxSize: "20m",
maxFiles: "14d",
format: commonLogFormat,
}),
info: new winston.transports.DailyRotateFile({
level: "info",
dirname: this.infoLogDir,
filename: "info-%DATE%.log",
datePattern: "YYYY-MM-DD",
zippedArchive: true,
maxSize: "20m",
maxFiles: "14d",
format: commonLogFormat,
}),
system: new winston.transports.DailyRotateFile({
dirname: this.systemLogDir,
filename: "system-%DATE%.log",
datePattern: "YYYY-MM-DD",
zippedArchive: true,
maxSize: "20m",
maxFiles: "14d",
format: commonLogFormat,
}),
};
// Winston 로거 생성
this.logger = winston.createLogger({
level: process.env.NODE_ENV === "production" ? "info" : "debug",
defaultMeta: {
service: "fems-edge",
environment: process.env.NODE_ENV || "development",
},
transports: Object.values(this.transports),
// exitOnError: false를 추가하여 에러 발생 시 프로세스가 종료되지 않도록 함
exitOnError: false,
});
// 개발 환경에서만 콘솔 출력 추가
if (process.env.NODE_ENV !== "production") {
this.logger.add(
new winston.transports.Console({
level: "debug",
format: consoleFormat,
})
);
}
// 로그 회전 이벤트 핸들러
this.setupRotateHandlers();
}
setupRotateHandlers() {
this.transports.error.on("rotate", (oldFilename, newFilename) => {
this.logger.info("Error log rotated", { oldFilename, newFilename });
});
this.transports.info.on("rotate", (oldFilename, newFilename) => {
this.logger.info("Info log rotated", { oldFilename, newFilename });
});
}
// 유틸리티 메서드들
logHttpRequest(req) {
this.logger.info("HTTP Request", {
method: req.method,
url: req.originalUrl,
params: req.params,
query: req.query,
body: req.body,
ip: req.ip,
userAgent: req.get("user-agent"),
});
}
logMqttMessage(topic, payload) {
this.logger.debug("MQTT Message", {
topic,
payload,
timestamp: new Date().toISOString(),
});
}
logPerformance(operation, duration) {
this.logger.info("Performance Metric", {
operation,
duration,
timestamp: new Date().toISOString(),
});
}
logQuery(query, duration) {
this.logger.debug("Database Query", {
query: typeof query === "string" ? query.trim() : query,
duration: `${duration}ms`,
timestamp: new Date().toISOString(),
});
}
// Express 미들웨어용 스트림
get stream() {
return {
write: (message) => {
this.logger.info(message.trim());
},
};
}
}
// 싱글톤 인스턴스 생성
const loggerInstance = new Logger();
// 편의를 위한 메서드 바인딩
module.exports = {
error: loggerInstance.logger.error.bind(loggerInstance.logger),
warn: loggerInstance.logger.warn.bind(loggerInstance.logger),
info: loggerInstance.logger.info.bind(loggerInstance.logger),
debug: loggerInstance.logger.debug.bind(loggerInstance.logger),
logHttpRequest: loggerInstance.logHttpRequest.bind(loggerInstance),
logMqttMessage: loggerInstance.logMqttMessage.bind(loggerInstance),
logPerformance: loggerInstance.logPerformance.bind(loggerInstance),
logQuery: loggerInstance.logQuery.bind(loggerInstance),
stream: loggerInstance.stream,
logger: loggerInstance.logger,
};

View File

@ -0,0 +1,17 @@
# config/postgres/init-scripts/00-init-user.sh
#!/bin/bash
set -e
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL
-- TimescaleDB 확장 활성화
CREATE EXTENSION IF NOT EXISTS timescaledb CASCADE;
-- 사용자 권한 설정
ALTER USER $POSTGRES_USER WITH PASSWORD '$POSTGRES_PASSWORD';
ALTER USER $POSTGRES_USER SET client_encoding TO 'utf8';
ALTER USER $POSTGRES_USER SET timezone TO 'UTC';
-- 데이터베이스 설정
ALTER DATABASE $POSTGRES_DB SET timezone TO 'UTC';
EOSQL