Merge branch 'feature/v2-renewal' of http://39.117.244.52:3000/kjs/ERP-node into jskim-node

This commit is contained in:
kjs
2026-02-12 14:19:31 +09:00
20 changed files with 555 additions and 481 deletions

View File

@@ -19,8 +19,6 @@ export async function getAdminMenus(
res: Response
): Promise<void> {
try {
logger.info("=== 관리자 메뉴 목록 조회 시작 ===");
// 현재 로그인한 사용자의 정보 가져오기
const userId = req.user?.userId;
const userCompanyCode = req.user?.companyCode || "ILSHIN";
@@ -29,13 +27,6 @@ export async function getAdminMenus(
const menuType = req.query.menuType as string | undefined; // menuType 파라미터 추가
const includeInactive = req.query.includeInactive === "true"; // includeInactive 파라미터 추가
logger.info(`사용자 ID: ${userId}`);
logger.info(`사용자 회사 코드: ${userCompanyCode}`);
logger.info(`사용자 유형: ${userType}`);
logger.info(`사용자 로케일: ${userLang}`);
logger.info(`메뉴 타입: ${menuType || "전체"}`);
logger.info(`비활성 메뉴 포함: ${includeInactive}`);
const paramMap = {
userId,
userCompanyCode,
@@ -47,13 +38,6 @@ export async function getAdminMenus(
const menuList = await AdminService.getAdminMenuList(paramMap);
logger.info(
`관리자 메뉴 조회 결과: ${menuList.length}개 (타입: ${menuType || "전체"}, 회사: ${userCompanyCode})`
);
if (menuList.length > 0) {
logger.info("첫 번째 메뉴:", menuList[0]);
}
const response: ApiResponse<any[]> = {
success: true,
message: "관리자 메뉴 목록 조회 성공",
@@ -85,19 +69,12 @@ export async function getUserMenus(
res: Response
): Promise<void> {
try {
logger.info("=== 사용자 메뉴 목록 조회 시작 ===");
// 현재 로그인한 사용자의 정보 가져오기
const userId = req.user?.userId;
const userCompanyCode = req.user?.companyCode || "ILSHIN";
const userType = req.user?.userType;
const userLang = (req.query.userLang as string) || "ko";
logger.info(`사용자 ID: ${userId}`);
logger.info(`사용자 회사 코드: ${userCompanyCode}`);
logger.info(`사용자 유형: ${userType}`);
logger.info(`사용자 로케일: ${userLang}`);
const paramMap = {
userId,
userCompanyCode,
@@ -107,13 +84,6 @@ export async function getUserMenus(
const menuList = await AdminService.getUserMenuList(paramMap);
logger.info(
`사용자 메뉴 조회 결과: ${menuList.length}개 (회사: ${userCompanyCode})`
);
if (menuList.length > 0) {
logger.info("첫 번째 메뉴:", menuList[0]);
}
const response: ApiResponse<any[]> = {
success: true,
message: "사용자 메뉴 목록 조회 성공",
@@ -473,7 +443,7 @@ export const getUserLocale = async (
res: Response
): Promise<void> => {
try {
logger.info("사용자 로케일 조회 요청", {
logger.debug("사용자 로케일 조회 요청", {
query: req.query,
user: req.user,
});
@@ -496,7 +466,7 @@ export const getUserLocale = async (
if (userInfo?.locale) {
userLocale = userInfo.locale;
logger.info("데이터베이스에서 사용자 로케일 조회 성공", {
logger.debug("데이터베이스에서 사용자 로케일 조회 성공", {
userId: req.user.userId,
locale: userLocale,
});
@@ -513,7 +483,7 @@ export const getUserLocale = async (
message: "사용자 로케일 조회 성공",
};
logger.info("사용자 로케일 조회 성공", {
logger.debug("사용자 로케일 조회 성공", {
userLocale,
userId: req.user.userId,
fromDatabase: !!userInfo?.locale,
@@ -618,7 +588,7 @@ export const getCompanyList = async (
res: Response
) => {
try {
logger.info("회사 목록 조회 요청", {
logger.debug("회사 목록 조회 요청", {
query: req.query,
user: req.user,
});
@@ -658,12 +628,8 @@ export const getCompanyList = async (
message: "회사 목록 조회 성공",
};
logger.info("회사 목록 조회 성공", {
logger.debug("회사 목록 조회 성공", {
totalCount: companies.length,
companies: companies.map((c) => ({
code: c.company_code,
name: c.company_name,
})),
});
res.status(200).json(response);
@@ -1864,7 +1830,7 @@ export async function getCompanyListFromDB(
res: Response
): Promise<void> {
try {
logger.info("회사 목록 조회 요청 (Raw Query)", { user: req.user });
logger.debug("회사 목록 조회 요청 (Raw Query)", { user: req.user });
// Raw Query로 회사 목록 조회
const companies = await query<any>(
@@ -1884,7 +1850,7 @@ export async function getCompanyListFromDB(
ORDER BY regdate DESC`
);
logger.info("회사 목록 조회 성공 (Raw Query)", { count: companies.length });
logger.debug("회사 목록 조회 성공 (Raw Query)", { count: companies.length });
const response: ApiResponse<any> = {
success: true,

View File

@@ -17,9 +17,7 @@ export class AuthController {
const { userId, password }: LoginRequest = req.body;
const remoteAddr = req.ip || req.connection.remoteAddress || "unknown";
logger.info(`=== API 로그인 호출됨 ===`);
logger.info(`userId: ${userId}`);
logger.info(`password: ${password ? "***" : "null"}`);
logger.debug(`로그인 요청: ${userId}`);
// 입력값 검증
if (!userId || !password) {
@@ -50,14 +48,7 @@ export class AuthController {
companyCode: loginResult.userInfo.companyCode || "ILSHIN",
};
logger.info(`=== API 로그인 사용자 정보 디버그 ===`);
logger.info(
`PersonBean companyCode: ${loginResult.userInfo.companyCode}`
);
logger.info(`반환할 사용자 정보:`);
logger.info(`- userId: ${userInfo.userId}`);
logger.info(`- userName: ${userInfo.userName}`);
logger.info(`- companyCode: ${userInfo.companyCode}`);
logger.debug(`로그인 사용자 정보: ${userInfo.userId} (${userInfo.companyCode})`);
// 사용자의 첫 번째 접근 가능한 메뉴 조회
let firstMenuPath: string | null = null;
@@ -71,7 +62,7 @@ export class AuthController {
};
const menuList = await AdminService.getUserMenuList(paramMap);
logger.info(`로그인 후 메뉴 조회: 총 ${menuList.length}개 메뉴`);
logger.debug(`로그인 후 메뉴 조회: 총 ${menuList.length}개 메뉴`);
// 접근 가능한 첫 번째 메뉴 찾기
// 조건:
@@ -87,16 +78,9 @@ export class AuthController {
if (firstMenu) {
firstMenuPath = firstMenu.menu_url || firstMenu.url;
logger.info(`첫 번째 접근 가능한 메뉴 발견:`, {
name: firstMenu.menu_name_kor || firstMenu.translated_name,
url: firstMenuPath,
level: firstMenu.lev || firstMenu.level,
seq: firstMenu.seq,
});
logger.debug(`첫 번째 메뉴: ${firstMenuPath}`);
} else {
logger.info(
"⚠️ 접근 가능한 메뉴가 없습니다. 메인 페이지로 이동합니다."
);
logger.debug("접근 가능한 메뉴 없음, 메인 페이지로 이동");
}
} catch (menuError) {
logger.warn("메뉴 조회 중 오류 발생 (무시하고 계속):", menuError);

View File

@@ -395,11 +395,35 @@ export async function searchEntity(req: AuthenticatedRequest, res: Response) {
? `WHERE ${whereConditions.join(" AND ")}`
: "";
// 정렬 컬럼 결정: id가 있으면 id, 없으면 첫 번째 컬럼 사용
let orderByColumn = "1"; // 기본: 첫 번째 컬럼
if (existingColumns.has("id")) {
orderByColumn = '"id"';
} else {
// PK 컬럼 조회 시도
try {
const pkResult = await pool.query(
`SELECT a.attname
FROM pg_index i
JOIN pg_attribute a ON a.attrelid = i.indrelid AND a.attnum = ANY(i.indkey)
WHERE i.indrelid = $1::regclass AND i.indisprimary
ORDER BY array_position(i.indkey, a.attnum)
LIMIT 1`,
[tableName]
);
if (pkResult.rows.length > 0) {
orderByColumn = `"${pkResult.rows[0].attname}"`;
}
} catch {
// PK 조회 실패 시 기본값 유지
}
}
// 쿼리 실행 (pool은 위에서 이미 선언됨)
const countQuery = `SELECT COUNT(*) FROM ${tableName} ${whereClause}`;
const dataQuery = `
SELECT * FROM ${tableName} ${whereClause}
ORDER BY id DESC
ORDER BY ${orderByColumn} DESC
LIMIT $${paramIndex} OFFSET $${paramIndex + 1}
`;

View File

@@ -46,17 +46,7 @@ export class FlowController {
const userId = (req as any).user?.userId || "system";
const userCompanyCode = (req as any).user?.companyCode;
console.log("🔍 createFlowDefinition called with:", {
name,
description,
tableName,
dbSourceType,
dbConnectionId,
restApiConnectionId,
restApiEndpoint,
restApiJsonPath,
userCompanyCode,
});
if (!name) {
res.status(400).json({
@@ -121,13 +111,7 @@ export class FlowController {
const user = (req as any).user;
const userCompanyCode = user?.companyCode;
console.log("🎯 getFlowDefinitions called:", {
userId: user?.userId,
userCompanyCode: userCompanyCode,
userType: user?.userType,
tableName,
isActive,
});
const flows = await this.flowDefinitionService.findAll(
tableName as string | undefined,
@@ -135,7 +119,7 @@ export class FlowController {
userCompanyCode
);
console.log(`✅ Returning ${flows.length} flows to user ${user?.userId}`);
res.json({
success: true,
@@ -583,14 +567,11 @@ export class FlowController {
getStepColumnLabels = async (req: Request, res: Response): Promise<void> => {
try {
const { flowId, stepId } = req.params;
console.log("🏷️ [FlowController] 컬럼 라벨 조회 요청:", {
flowId,
stepId,
});
const step = await this.flowStepService.findById(parseInt(stepId));
if (!step) {
console.warn("⚠️ [FlowController] 스텝을 찾을 수 없음:", stepId);
res.status(404).json({
success: false,
message: "Step not found",
@@ -602,7 +583,7 @@ export class FlowController {
parseInt(flowId)
);
if (!flowDef) {
console.warn("⚠️ [FlowController] 플로우를 찾을 수 없음:", flowId);
res.status(404).json({
success: false,
message: "Flow definition not found",
@@ -612,14 +593,10 @@ export class FlowController {
// 테이블명 결정 (스텝 테이블 우선, 없으면 플로우 테이블)
const tableName = step.tableName || flowDef.tableName;
console.log("📋 [FlowController] 테이블명 결정:", {
stepTableName: step.tableName,
flowTableName: flowDef.tableName,
selectedTableName: tableName,
});
if (!tableName) {
console.warn("⚠️ [FlowController] 테이블명이 지정되지 않음");
res.json({
success: true,
data: {},
@@ -639,14 +616,7 @@ export class FlowController {
[tableName]
);
console.log(`✅ [FlowController] table_type_columns 조회 완료:`, {
tableName,
rowCount: labelRows.length,
labels: labelRows.map((r) => ({
col: r.column_name,
label: r.column_label,
})),
});
// { columnName: label } 형태의 객체로 변환
const labels: Record<string, string> = {};
@@ -656,7 +626,7 @@ export class FlowController {
}
});
console.log("📦 [FlowController] 반환할 라벨 객체:", labels);
res.json({
success: true,