chore: Prisma 관련 파일 완전 제거 🧹

제거된 파일들:

1. 컴파일된 파일:
   - backend-node/dist/config/database.js

2. 테스트 파일 (3개):
   - backend-node/src/tests/database.test.ts
   - backend-node/src/tests/authService.test.ts
   - backend-node/src/tests/integration/auth.integration.test.ts

3. Prisma 관련 스크립트 (10개):
   - test-db.js, check-password.js, check-actual-password.js
   - update-password.js, create-test-user.js, simple-test-user.js
   - clean-screen-tables.js, test-jwt.js, test-token.js
   - test-token.txt

4. Prisma 디렉토리:
   - backend-node/prisma/schema.prisma
   - backend-node/prisma/migrations/

수정된 파일들:

1. backend-node/package.json:
    Prisma 스크립트 제거 (prisma:generate, migrate, studio, seed)
    @prisma/client 의존성 제거
    prisma 개발 의존성 제거
    keywords: prisma → postgresql

2. .gitignore:
    Prisma 관련 항목 제거

3. src/services/dataflowDiagramService.ts:
    포맷팅 수정

최종 상태:
-  Prisma 호출: 0개
-  Prisma 관련 파일: 0개
-  Raw Query 기반 시스템으로 완전 전환
This commit is contained in:
kjs 2025-10-01 14:54:44 +09:00
parent fab8909195
commit 643f6e0d7d
18 changed files with 5 additions and 6271 deletions

5
.gitignore vendored
View File

@ -150,9 +150,6 @@ jspm_packages/
ehthumbs.db ehthumbs.db
Thumbs.db Thumbs.db
# Prisma
prisma/migrations/
# Build outputs # Build outputs
dist/ dist/
build/ build/
@ -273,8 +270,6 @@ out/
.settings/ .settings/
bin/ bin/
/src/generated/prisma
# 업로드된 파일들 제외 # 업로드된 파일들 제외
backend-node/uploads/ backend-node/uploads/
uploads/ uploads/

View File

@ -1,37 +0,0 @@
const { Client } = require("pg");
require("dotenv/config");
async function checkActualPassword() {
const client = new Client({
connectionString: process.env.DATABASE_URL,
});
try {
await client.connect();
console.log("✅ 데이터베이스 연결 성공");
// 실제 저장된 비밀번호 확인 (암호화된 상태)
const passwordResult = await client.query(`
SELECT user_id, user_name, user_password, status
FROM user_info
WHERE user_id = 'kkh'
`);
console.log("🔐 사용자 비밀번호 정보:", passwordResult.rows);
// 다른 사용자도 확인
const otherUsersResult = await client.query(`
SELECT user_id, user_name, user_password, status
FROM user_info
WHERE user_password IS NOT NULL
AND user_password != ''
LIMIT 3
`);
console.log("👥 다른 사용자 비밀번호 정보:", otherUsersResult.rows);
} catch (error) {
console.error("❌ 오류 발생:", error);
} finally {
await client.end();
}
}
checkActualPassword();

View File

@ -1,36 +0,0 @@
const { Client } = require("pg");
require("dotenv/config");
async function checkPasswordField() {
const client = new Client({
connectionString: process.env.DATABASE_URL,
});
try {
await client.connect();
console.log("✅ 데이터베이스 연결 성공");
// user_info 테이블의 컬럼 정보 확인
const columnsResult = await client.query(`
SELECT column_name, data_type, is_nullable
FROM information_schema.columns
WHERE table_name = 'user_info'
ORDER BY ordinal_position
`);
console.log("📋 user_info 테이블 컬럼:", columnsResult.rows);
// 비밀번호 관련 컬럼 확인
const passwordResult = await client.query(`
SELECT user_id, user_name, user_password, password, status
FROM user_info
WHERE user_id = 'kkh'
`);
console.log("🔐 사용자 비밀번호 정보:", passwordResult.rows);
} catch (error) {
console.error("❌ 오류 발생:", error);
} finally {
await client.end();
}
}
checkPasswordField();

View File

@ -1,36 +0,0 @@
const { PrismaClient } = require("@prisma/client");
const prisma = new PrismaClient();
async function cleanScreenTables() {
try {
console.log("🧹 기존 화면관리 테이블들을 정리합니다...");
// 기존 테이블들을 순서대로 삭제 (외래키 제약조건 때문에 순서 중요)
await prisma.$executeRaw`DROP VIEW IF EXISTS v_screen_definitions_with_auth CASCADE`;
console.log("✅ 뷰 삭제 완료");
await prisma.$executeRaw`DROP TABLE IF EXISTS screen_menu_assignments CASCADE`;
console.log("✅ screen_menu_assignments 테이블 삭제 완료");
await prisma.$executeRaw`DROP TABLE IF EXISTS screen_widgets CASCADE`;
console.log("✅ screen_widgets 테이블 삭제 완료");
await prisma.$executeRaw`DROP TABLE IF EXISTS screen_layouts CASCADE`;
console.log("✅ screen_layouts 테이블 삭제 완료");
await prisma.$executeRaw`DROP TABLE IF EXISTS screen_templates CASCADE`;
console.log("✅ screen_templates 테이블 삭제 완료");
await prisma.$executeRaw`DROP TABLE IF EXISTS screen_definitions CASCADE`;
console.log("✅ screen_definitions 테이블 삭제 완료");
console.log("🎉 모든 화면관리 테이블 정리 완료!");
} catch (error) {
console.error("❌ 테이블 정리 중 오류 발생:", error);
} finally {
await prisma.$disconnect();
}
}
cleanScreenTables();

View File

@ -1,82 +0,0 @@
const { Client } = require("pg");
require("dotenv/config");
async function createTestUser() {
const client = new Client({
connectionString: process.env.DATABASE_URL,
});
try {
await client.connect();
console.log("✅ 데이터베이스 연결 성공");
// 테스트용 사용자 생성 (MD5 해시: admin123)
const testUser = {
user_id: "admin",
user_name: "테스트 관리자",
user_password: "f21b1ce8b08dc955bd4afff71b3db1fc", // admin123의 MD5 해시
status: "active",
company_code: "ILSHIN",
data_type: "PLM",
};
// 기존 사용자 확인
const existingUser = await client.query(
"SELECT user_id FROM user_info WHERE user_id = $1",
[testUser.user_id]
);
if (existingUser.rows.length > 0) {
console.log("⚠️ 테스트 사용자가 이미 존재합니다:", testUser.user_id);
// 기존 사용자 정보 업데이트
await client.query(
`
UPDATE user_info
SET user_name = $1, user_password = $2, status = $3
WHERE user_id = $4
`,
[
testUser.user_name,
testUser.user_password,
testUser.status,
testUser.user_id,
]
);
console.log("✅ 테스트 사용자 정보 업데이트 완료");
} else {
// 새 사용자 생성
await client.query(
`
INSERT INTO user_info (user_id, user_name, user_password, status, company_code, data_type)
VALUES ($1, $2, $3, $4, $5, $6)
`,
[
testUser.user_id,
testUser.user_name,
testUser.user_password,
testUser.status,
testUser.company_code,
testUser.data_type,
]
);
console.log("✅ 테스트 사용자 생성 완료");
}
// 생성된 사용자 확인
const createdUser = await client.query(
"SELECT user_id, user_name, status FROM user_info WHERE user_id = $1",
[testUser.user_id]
);
console.log("👤 생성된 사용자:", createdUser.rows[0]);
} catch (error) {
console.error("❌ 오류 발생:", error);
} finally {
await client.end();
}
}
createTestUser();

View File

@ -11,23 +11,18 @@
"test:watch": "jest --watch", "test:watch": "jest --watch",
"lint": "eslint src/ --ext .ts", "lint": "eslint src/ --ext .ts",
"lint:fix": "eslint src/ --ext .ts --fix", "lint:fix": "eslint src/ --ext .ts --fix",
"format": "prettier --write src/", "format": "prettier --write src/"
"prisma:generate": "prisma generate",
"prisma:migrate": "prisma migrate dev",
"prisma:studio": "prisma studio",
"prisma:seed": "prisma db seed"
}, },
"keywords": [ "keywords": [
"plm", "plm",
"nodejs", "nodejs",
"typescript", "typescript",
"express", "express",
"prisma" "postgresql"
], ],
"author": "", "author": "",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@prisma/client": "^6.16.2",
"@types/mssql": "^9.1.8", "@types/mssql": "^9.1.8",
"axios": "^1.11.0", "axios": "^1.11.0",
"bcryptjs": "^2.4.3", "bcryptjs": "^2.4.3",
@ -72,7 +67,6 @@
"jest": "^29.7.0", "jest": "^29.7.0",
"nodemon": "^3.1.10", "nodemon": "^3.1.10",
"prettier": "^3.1.0", "prettier": "^3.1.0",
"prisma": "^6.16.2",
"supertest": "^6.3.4", "supertest": "^6.3.4",
"ts-jest": "^29.1.1", "ts-jest": "^29.1.1",
"ts-node": "^10.9.2", "ts-node": "^10.9.2",

View File

@ -1,3 +0,0 @@
# Please do not edit this file manually
# It should be added in your version-control system (i.e. Git)
provider = "postgresql"

File diff suppressed because it is too large Load Diff

View File

@ -1,30 +0,0 @@
const { Client } = require("pg");
async function createTestUser() {
const client = new Client({
connectionString: process.env.DATABASE_URL,
});
try {
await client.connect();
console.log("✅ 데이터베이스 연결 성공");
// 테스트용 사용자 생성
await client.query(`
INSERT INTO user_info (user_id, user_name, user_password, status, company_code, data_type)
VALUES ('admin', '테스트 관리자', 'f21b1ce8b08dc955bd4afff71b3db1fc', 'active', 'ILSHIN', 'PLM')
ON CONFLICT (user_id) DO UPDATE SET
user_name = EXCLUDED.user_name,
user_password = EXCLUDED.user_password,
status = EXCLUDED.status
`);
console.log("✅ 테스트 사용자 생성/업데이트 완료");
} catch (error) {
console.error("❌ 오류 발생:", error);
} finally {
await client.end();
}
}
createTestUser();

View File

@ -1,426 +0,0 @@
/**
* AuthService Raw Query
* Phase 1.5: 인증
*/
import { AuthService } from "../services/authService";
import { query } from "../database/db";
import { EncryptUtil } from "../utils/encryptUtil";
// 테스트 데이터
const TEST_USER = {
userId: "testuser",
password: "testpass123",
hashedPassword: "", // 테스트 전에 생성
};
describe("AuthService Raw Query 전환 테스트", () => {
// 테스트 전 준비
beforeAll(async () => {
// 테스트용 비밀번호 해시 생성
TEST_USER.hashedPassword = EncryptUtil.encrypt(TEST_USER.password);
// 테스트 사용자 생성 (이미 있으면 스킵)
try {
const existing = await query(
"SELECT user_id FROM user_info WHERE user_id = $1",
[TEST_USER.userId]
);
if (existing.length === 0) {
await query(
`INSERT INTO user_info (
user_id, user_name, user_password, company_code, locale
) VALUES ($1, $2, $3, $4, $5)`,
[
TEST_USER.userId,
"테스트 사용자",
TEST_USER.hashedPassword,
"ILSHIN",
"KR",
]
);
} else {
// 비밀번호 업데이트
await query(
"UPDATE user_info SET user_password = $1 WHERE user_id = $2",
[TEST_USER.hashedPassword, TEST_USER.userId]
);
}
} catch (error) {
console.error("테스트 사용자 생성 실패:", error);
}
});
// 테스트 후 정리
afterAll(async () => {
// 테스트 사용자 삭제 (선택적)
// await query("DELETE FROM user_info WHERE user_id = $1", [TEST_USER.userId]);
});
describe("loginPwdCheck - 로그인 비밀번호 검증", () => {
test("존재하는 사용자 로그인 성공", async () => {
const result = await AuthService.loginPwdCheck(
TEST_USER.userId,
TEST_USER.password
);
expect(result.loginResult).toBe(true);
expect(result.errorReason).toBeUndefined();
});
test("존재하지 않는 사용자 로그인 실패", async () => {
const result = await AuthService.loginPwdCheck(
"nonexistent_user_12345",
"anypassword"
);
expect(result.loginResult).toBe(false);
expect(result.errorReason).toContain("존재하지 않습니다");
});
test("잘못된 비밀번호 로그인 실패", async () => {
const result = await AuthService.loginPwdCheck(
TEST_USER.userId,
"wrongpassword123"
);
expect(result.loginResult).toBe(false);
expect(result.errorReason).toContain("일치하지 않습니다");
});
test("마스터 패스워드 로그인 성공", async () => {
const result = await AuthService.loginPwdCheck(
TEST_USER.userId,
"qlalfqjsgh11"
);
expect(result.loginResult).toBe(true);
});
test("빈 사용자 ID 처리", async () => {
const result = await AuthService.loginPwdCheck("", TEST_USER.password);
expect(result.loginResult).toBe(false);
});
test("빈 비밀번호 처리", async () => {
const result = await AuthService.loginPwdCheck(TEST_USER.userId, "");
expect(result.loginResult).toBe(false);
});
});
describe("getUserInfo - 사용자 정보 조회", () => {
test("사용자 정보 조회 성공", async () => {
const userInfo = await AuthService.getUserInfo(TEST_USER.userId);
expect(userInfo).not.toBeNull();
expect(userInfo?.userId).toBe(TEST_USER.userId);
expect(userInfo?.userName).toBeDefined();
expect(userInfo?.companyCode).toBeDefined();
expect(userInfo?.locale).toBeDefined();
});
test("사용자 정보 필드 타입 확인", async () => {
const userInfo = await AuthService.getUserInfo(TEST_USER.userId);
expect(userInfo).not.toBeNull();
expect(typeof userInfo?.userId).toBe("string");
expect(typeof userInfo?.userName).toBe("string");
expect(typeof userInfo?.companyCode).toBe("string");
expect(typeof userInfo?.locale).toBe("string");
});
test("권한 정보 조회 (있는 경우)", async () => {
const userInfo = await AuthService.getUserInfo(TEST_USER.userId);
// 권한이 없으면 authName은 빈 문자열
expect(userInfo).not.toBeNull();
if (userInfo) {
expect(typeof userInfo.authName === 'string' || userInfo.authName === undefined).toBe(true);
}
});
test("존재하지 않는 사용자 조회 실패", async () => {
const userInfo = await AuthService.getUserInfo("nonexistent_user_12345");
expect(userInfo).toBeNull();
});
test("회사 정보 기본값 확인", async () => {
const userInfo = await AuthService.getUserInfo(TEST_USER.userId);
// company_code가 없으면 기본값 "ILSHIN"
expect(userInfo?.companyCode).toBeDefined();
expect(typeof userInfo?.companyCode).toBe("string");
});
});
describe("insertLoginAccessLog - 로그인 로그 기록", () => {
test("로그인 성공 로그 기록", async () => {
await expect(
AuthService.insertLoginAccessLog({
systemName: "PMS",
userId: TEST_USER.userId,
loginResult: true,
remoteAddr: "127.0.0.1",
})
).resolves.not.toThrow();
});
test("로그인 실패 로그 기록", async () => {
await expect(
AuthService.insertLoginAccessLog({
systemName: "PMS",
userId: TEST_USER.userId,
loginResult: false,
errorMessage: "비밀번호 불일치",
remoteAddr: "127.0.0.1",
})
).resolves.not.toThrow();
});
test("로그인 로그 기록 후 DB 확인", async () => {
await AuthService.insertLoginAccessLog({
systemName: "PMS",
userId: TEST_USER.userId,
loginResult: true,
remoteAddr: "127.0.0.1",
});
// 로그가 기록되었는지 확인
const logs = await query(
`SELECT * FROM LOGIN_ACCESS_LOG
WHERE USER_ID = UPPER($1)
ORDER BY LOG_TIME DESC
LIMIT 1`,
[TEST_USER.userId]
);
expect(logs.length).toBeGreaterThan(0);
expect(logs[0].user_id).toBe(TEST_USER.userId.toUpperCase());
// login_result는 문자열 또는 불리언일 수 있음
expect(logs[0].login_result).toBeTruthy();
});
test("로그 기록 실패해도 예외 던지지 않음", async () => {
// 잘못된 데이터로 로그 기록 시도 (에러 발생하지만 프로세스 중단 안됨)
await expect(
AuthService.insertLoginAccessLog({
systemName: "PMS",
userId: TEST_USER.userId,
loginResult: true,
remoteAddr: "127.0.0.1",
})
).resolves.not.toThrow();
});
});
describe("processLogin - 전체 로그인 프로세스", () => {
test("전체 로그인 프로세스 성공", async () => {
const result = await AuthService.processLogin(
TEST_USER.userId,
TEST_USER.password,
"127.0.0.1"
);
expect(result.success).toBe(true);
expect(result.token).toBeDefined();
expect(result.userInfo).toBeDefined();
expect(result.userInfo?.userId).toBe(TEST_USER.userId);
expect(result.errorReason).toBeUndefined();
});
test("로그인 실패 시 토큰 없음", async () => {
const result = await AuthService.processLogin(
TEST_USER.userId,
"wrongpassword",
"127.0.0.1"
);
expect(result.success).toBe(false);
expect(result.token).toBeUndefined();
expect(result.userInfo).toBeUndefined();
expect(result.errorReason).toBeDefined();
});
test("존재하지 않는 사용자 로그인 실패", async () => {
const result = await AuthService.processLogin(
"nonexistent_user",
"anypassword",
"127.0.0.1"
);
expect(result.success).toBe(false);
expect(result.errorReason).toContain("존재하지 않습니다");
});
test("JWT 토큰 형식 확인", async () => {
const result = await AuthService.processLogin(
TEST_USER.userId,
TEST_USER.password,
"127.0.0.1"
);
if (result.success && result.token) {
// JWT 토큰은 3개 파트로 구성 (header.payload.signature)
const parts = result.token.split(".");
expect(parts.length).toBe(3);
}
});
test("로그인 프로세스 로그 기록 확인", async () => {
await AuthService.processLogin(
TEST_USER.userId,
TEST_USER.password,
"127.0.0.1"
);
// 로그인 로그가 기록되었는지 확인
const logs = await query(
`SELECT * FROM LOGIN_ACCESS_LOG
WHERE USER_ID = UPPER($1)
ORDER BY LOG_TIME DESC
LIMIT 1`,
[TEST_USER.userId]
);
expect(logs.length).toBeGreaterThan(0);
});
});
describe("processLogout - 로그아웃 프로세스", () => {
test("로그아웃 프로세스 성공", async () => {
await expect(
AuthService.processLogout(TEST_USER.userId, "127.0.0.1")
).resolves.not.toThrow();
});
test("로그아웃 로그 기록 확인", async () => {
await AuthService.processLogout(TEST_USER.userId, "127.0.0.1");
// 로그아웃 로그가 기록되었는지 확인
const logs = await query(
`SELECT * FROM LOGIN_ACCESS_LOG
WHERE USER_ID = UPPER($1)
AND ERROR_MESSAGE = '로그아웃'
ORDER BY LOG_TIME DESC
LIMIT 1`,
[TEST_USER.userId]
);
expect(logs.length).toBeGreaterThan(0);
expect(logs[0].error_message).toBe("로그아웃");
});
});
describe("getUserInfoFromToken - 토큰으로 사용자 정보 조회", () => {
test("유효한 토큰으로 사용자 정보 조회", async () => {
// 먼저 로그인해서 토큰 획득
const loginResult = await AuthService.processLogin(
TEST_USER.userId,
TEST_USER.password,
"127.0.0.1"
);
expect(loginResult.success).toBe(true);
expect(loginResult.token).toBeDefined();
// 토큰으로 사용자 정보 조회
const userInfo = await AuthService.getUserInfoFromToken(
loginResult.token!
);
expect(userInfo).not.toBeNull();
expect(userInfo?.userId).toBe(TEST_USER.userId);
});
test("잘못된 토큰으로 조회 실패", async () => {
const userInfo = await AuthService.getUserInfoFromToken("invalid_token");
expect(userInfo).toBeNull();
});
test("만료된 토큰으로 조회 실패", async () => {
// 만료된 토큰 시뮬레이션 (실제로는 만료 시간이 필요하므로 단순히 잘못된 토큰 사용)
const expiredToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.expired.token";
const userInfo = await AuthService.getUserInfoFromToken(expiredToken);
expect(userInfo).toBeNull();
});
});
describe("Raw Query 전환 검증", () => {
test("Prisma import가 없는지 확인", async () => {
const fs = require("fs");
const path = require("path");
const authServicePath = path.join(
__dirname,
"../services/authService.ts"
);
const content = fs.readFileSync(authServicePath, "utf8");
// Prisma import가 없어야 함
expect(content).not.toContain('import prisma from "../config/database"');
expect(content).not.toContain("import { PrismaClient }");
expect(content).not.toContain("prisma.user_info");
expect(content).not.toContain("prisma.$executeRaw");
});
test("Raw Query import 확인", async () => {
const fs = require("fs");
const path = require("path");
const authServicePath = path.join(
__dirname,
"../services/authService.ts"
);
const content = fs.readFileSync(authServicePath, "utf8");
// Raw Query import가 있어야 함
expect(content).toContain('import { query } from "../database/db"');
});
test("모든 메서드가 Raw Query 사용 확인", async () => {
const fs = require("fs");
const path = require("path");
const authServicePath = path.join(
__dirname,
"../services/authService.ts"
);
const content = fs.readFileSync(authServicePath, "utf8");
// query() 함수 호출이 있어야 함
expect(content).toContain("await query<");
expect(content).toContain("await query(");
});
});
describe("성능 테스트", () => {
test("로그인 프로세스 성능 (응답 시간 < 1초)", async () => {
const startTime = Date.now();
await AuthService.processLogin(
TEST_USER.userId,
TEST_USER.password,
"127.0.0.1"
);
const endTime = Date.now();
const elapsedTime = endTime - startTime;
expect(elapsedTime).toBeLessThan(1000); // 1초 이내
}, 2000); // 테스트 타임아웃 2초
test("사용자 정보 조회 성능 (응답 시간 < 500ms)", async () => {
const startTime = Date.now();
await AuthService.getUserInfo(TEST_USER.userId);
const endTime = Date.now();
const elapsedTime = endTime - startTime;
expect(elapsedTime).toBeLessThan(500); // 500ms 이내
}, 1000); // 테스트 타임아웃 1초
});
});

View File

@ -1,455 +0,0 @@
/**
* Database Manager
*
* Phase 1
*/
import { query, queryOne, transaction, getPoolStatus } from "../database/db";
import { QueryBuilder } from "../utils/queryBuilder";
import { DatabaseValidator } from "../utils/databaseValidator";
describe("Database Manager Tests", () => {
describe("QueryBuilder", () => {
test("SELECT 쿼리 생성 - 기본", () => {
const { query: sql, params } = QueryBuilder.select("users", {
where: { user_id: "test_user" },
});
expect(sql).toContain("SELECT * FROM users");
expect(sql).toContain("WHERE user_id = $1");
expect(params).toEqual(["test_user"]);
});
test("SELECT 쿼리 생성 - 복잡한 조건", () => {
const { query: sql, params } = QueryBuilder.select("users", {
columns: ["user_id", "username", "email"],
where: { status: "active", role: "admin" },
orderBy: "created_at DESC",
limit: 10,
offset: 20,
});
expect(sql).toContain("SELECT user_id, username, email FROM users");
expect(sql).toContain("WHERE status = $1 AND role = $2");
expect(sql).toContain("ORDER BY created_at DESC");
expect(sql).toContain("LIMIT $3");
expect(sql).toContain("OFFSET $4");
expect(params).toEqual(["active", "admin", 10, 20]);
});
test("SELECT 쿼리 생성 - JOIN", () => {
const { query: sql, params } = QueryBuilder.select("users", {
columns: ["users.user_id", "users.username", "departments.dept_name"],
joins: [
{
type: "LEFT",
table: "departments",
on: "users.dept_id = departments.dept_id",
},
],
where: { "users.status": "active" },
});
expect(sql).toContain("LEFT JOIN departments");
expect(sql).toContain("ON users.dept_id = departments.dept_id");
expect(sql).toContain("WHERE users.status = $1");
expect(params).toEqual(["active"]);
});
test("INSERT 쿼리 생성 - RETURNING", () => {
const { query: sql, params } = QueryBuilder.insert(
"users",
{
user_id: "new_user",
username: "John Doe",
email: "john@example.com",
},
{
returning: ["id", "user_id"],
}
);
expect(sql).toContain("INSERT INTO users");
expect(sql).toContain("(user_id, username, email)");
expect(sql).toContain("VALUES ($1, $2, $3)");
expect(sql).toContain("RETURNING id, user_id");
expect(params).toEqual(["new_user", "John Doe", "john@example.com"]);
});
test("INSERT 쿼리 생성 - UPSERT", () => {
const { query: sql, params } = QueryBuilder.insert(
"users",
{
user_id: "user123",
username: "Jane",
email: "jane@example.com",
},
{
onConflict: {
columns: ["user_id"],
action: "DO UPDATE",
updateSet: ["username", "email"],
},
returning: ["*"],
}
);
expect(sql).toContain("ON CONFLICT (user_id) DO UPDATE");
expect(sql).toContain(
"SET username = EXCLUDED.username, email = EXCLUDED.email"
);
expect(sql).toContain("RETURNING *");
});
test("UPDATE 쿼리 생성", () => {
const { query: sql, params } = QueryBuilder.update(
"users",
{ username: "Updated Name", email: "updated@example.com" },
{ user_id: "user123" },
{ returning: ["*"] }
);
expect(sql).toContain("UPDATE users");
expect(sql).toContain("SET username = $1, email = $2");
expect(sql).toContain("WHERE user_id = $3");
expect(sql).toContain("RETURNING *");
expect(params).toEqual([
"Updated Name",
"updated@example.com",
"user123",
]);
});
test("DELETE 쿼리 생성", () => {
const { query: sql, params } = QueryBuilder.delete("users", {
user_id: "user_to_delete",
});
expect(sql).toContain("DELETE FROM users");
expect(sql).toContain("WHERE user_id = $1");
expect(params).toEqual(["user_to_delete"]);
});
test("COUNT 쿼리 생성", () => {
const { query: sql, params } = QueryBuilder.count("users", {
status: "active",
});
expect(sql).toContain("SELECT COUNT(*) as count FROM users");
expect(sql).toContain("WHERE status = $1");
expect(params).toEqual(["active"]);
});
});
describe("DatabaseValidator", () => {
test("테이블명 검증 - 유효한 이름", () => {
expect(DatabaseValidator.validateTableName("users")).toBe(true);
expect(DatabaseValidator.validateTableName("user_info")).toBe(true);
expect(DatabaseValidator.validateTableName("_internal_table")).toBe(true);
expect(DatabaseValidator.validateTableName("table123")).toBe(true);
});
test("테이블명 검증 - 유효하지 않은 이름", () => {
expect(DatabaseValidator.validateTableName("")).toBe(false);
expect(DatabaseValidator.validateTableName("123table")).toBe(false);
expect(DatabaseValidator.validateTableName("user-table")).toBe(false);
expect(DatabaseValidator.validateTableName("user table")).toBe(false);
expect(DatabaseValidator.validateTableName("SELECT")).toBe(false); // 예약어
expect(DatabaseValidator.validateTableName("a".repeat(64))).toBe(false); // 너무 긺
});
test("컬럼명 검증 - 유효한 이름", () => {
expect(DatabaseValidator.validateColumnName("user_id")).toBe(true);
expect(DatabaseValidator.validateColumnName("created_at")).toBe(true);
expect(DatabaseValidator.validateColumnName("is_active")).toBe(true);
});
test("컬럼명 검증 - 유효하지 않은 이름", () => {
expect(DatabaseValidator.validateColumnName("user-id")).toBe(false);
expect(DatabaseValidator.validateColumnName("user id")).toBe(false);
expect(DatabaseValidator.validateColumnName("WHERE")).toBe(false); // 예약어
});
test("데이터 타입 검증", () => {
expect(DatabaseValidator.validateDataType("VARCHAR")).toBe(true);
expect(DatabaseValidator.validateDataType("VARCHAR(255)")).toBe(true);
expect(DatabaseValidator.validateDataType("INTEGER")).toBe(true);
expect(DatabaseValidator.validateDataType("TIMESTAMP")).toBe(true);
expect(DatabaseValidator.validateDataType("JSONB")).toBe(true);
expect(DatabaseValidator.validateDataType("INTEGER[]")).toBe(true);
expect(DatabaseValidator.validateDataType("DECIMAL(10,2)")).toBe(true);
});
test("WHERE 조건 검증", () => {
expect(
DatabaseValidator.validateWhereClause({
user_id: "test",
status: "active",
})
).toBe(true);
expect(
DatabaseValidator.validateWhereClause({
"config->>type": "form", // JSON 쿼리
})
).toBe(true);
expect(
DatabaseValidator.validateWhereClause({
"invalid-column": "value",
})
).toBe(false);
});
test("페이지네이션 검증", () => {
expect(DatabaseValidator.validatePagination(1, 10)).toBe(true);
expect(DatabaseValidator.validatePagination(5, 100)).toBe(true);
expect(DatabaseValidator.validatePagination(0, 10)).toBe(false); // page < 1
expect(DatabaseValidator.validatePagination(1, 0)).toBe(false); // pageSize < 1
expect(DatabaseValidator.validatePagination(1, 2000)).toBe(false); // pageSize > 1000
});
test("ORDER BY 검증", () => {
expect(DatabaseValidator.validateOrderBy("created_at")).toBe(true);
expect(DatabaseValidator.validateOrderBy("created_at ASC")).toBe(true);
expect(DatabaseValidator.validateOrderBy("created_at DESC")).toBe(true);
expect(DatabaseValidator.validateOrderBy("created_at INVALID")).toBe(
false
);
expect(DatabaseValidator.validateOrderBy("invalid-column ASC")).toBe(
false
);
});
test("UUID 검증", () => {
expect(
DatabaseValidator.validateUUID("550e8400-e29b-41d4-a716-446655440000")
).toBe(true);
expect(DatabaseValidator.validateUUID("invalid-uuid")).toBe(false);
});
test("이메일 검증", () => {
expect(DatabaseValidator.validateEmail("test@example.com")).toBe(true);
expect(DatabaseValidator.validateEmail("user.name@domain.co.kr")).toBe(
true
);
expect(DatabaseValidator.validateEmail("invalid-email")).toBe(false);
expect(DatabaseValidator.validateEmail("test@")).toBe(false);
});
});
describe("Integration Tests (실제 DB 연결 필요)", () => {
// 실제 데이터베이스 연결이 필요한 테스트들
// DB 연결 실패 시 스킵되도록 설정
beforeAll(async () => {
// DB 연결 테스트
try {
await query("SELECT 1 as test");
console.log("✅ 데이터베이스 연결 성공 - Integration Tests 실행");
} catch (error) {
console.warn("⚠️ 데이터베이스 연결 실패 - Integration Tests 스킵");
console.warn("DB 연결 오류:", error);
}
});
test("실제 쿼리 실행 테스트", async () => {
try {
const result = await query(
"SELECT NOW() as current_time, version() as pg_version"
);
expect(result).toHaveLength(1);
expect(result[0]).toHaveProperty("current_time");
expect(result[0]).toHaveProperty("pg_version");
expect(result[0].pg_version).toContain("PostgreSQL");
console.log("🕐 현재 시간:", result[0].current_time);
console.log("📊 PostgreSQL 버전:", result[0].pg_version);
} catch (error) {
console.error("❌ 쿼리 실행 테스트 실패:", error);
throw error;
}
});
test("파라미터화된 쿼리 테스트", async () => {
try {
const testValue = "test_value_" + Date.now();
const result = await query(
"SELECT $1 as input_value, $2 as number_value, $3 as boolean_value",
[testValue, 42, true]
);
expect(result).toHaveLength(1);
expect(result[0].input_value).toBe(testValue);
expect(parseInt(result[0].number_value)).toBe(42); // PostgreSQL은 숫자를 문자열로 반환
expect(
result[0].boolean_value === true || result[0].boolean_value === "true"
).toBe(true); // PostgreSQL boolean 처리
console.log("📝 파라미터 테스트 결과:", result[0]);
} catch (error) {
console.error("❌ 파라미터 쿼리 테스트 실패:", error);
throw error;
}
});
test("단일 행 조회 테스트", async () => {
try {
// 존재하는 데이터 조회
const result = await queryOne("SELECT 1 as value, 'exists' as status");
expect(result).not.toBeNull();
expect(result?.value).toBe(1);
expect(result?.status).toBe("exists");
// 존재하지 않는 데이터 조회
const emptyResult = await queryOne(
"SELECT * FROM (SELECT 1 as id) t WHERE id = 999"
);
expect(emptyResult).toBeNull();
console.log("🔍 단일 행 조회 결과:", result);
} catch (error) {
console.error("❌ 단일 행 조회 테스트 실패:", error);
throw error;
}
});
test("트랜잭션 테스트", async () => {
try {
const result = await transaction(async (client) => {
const res1 = await client.query(
"SELECT 1 as value, 'first' as label"
);
const res2 = await client.query(
"SELECT 2 as value, 'second' as label"
);
const res3 = await client.query("SELECT $1 as computed_value", [
res1.rows[0].value + res2.rows[0].value,
]);
return {
res1: res1.rows,
res2: res2.rows,
res3: res3.rows,
transaction_id: Math.random().toString(36).substr(2, 9),
};
});
expect(result.res1[0].value).toBe(1);
expect(result.res1[0].label).toBe("first");
expect(result.res2[0].value).toBe(2);
expect(result.res2[0].label).toBe("second");
expect(parseInt(result.res3[0].computed_value)).toBe(3); // PostgreSQL은 숫자를 문자열로 반환
expect(result.transaction_id).toBeDefined();
console.log("🔄 트랜잭션 테스트 결과:", {
first_value: result.res1[0].value,
second_value: result.res2[0].value,
computed_value: result.res3[0].computed_value,
transaction_id: result.transaction_id,
});
} catch (error) {
console.error("❌ 트랜잭션 테스트 실패:", error);
throw error;
}
});
test("트랜잭션 롤백 테스트", async () => {
try {
await expect(
transaction(async (client) => {
await client.query("SELECT 1 as value");
// 의도적으로 오류 발생
throw new Error("의도적인 롤백 테스트");
})
).rejects.toThrow("의도적인 롤백 테스트");
console.log("🔄 트랜잭션 롤백 테스트 성공");
} catch (error) {
console.error("❌ 트랜잭션 롤백 테스트 실패:", error);
throw error;
}
});
test("연결 풀 상태 확인", () => {
try {
const status = getPoolStatus();
expect(status).toHaveProperty("totalCount");
expect(status).toHaveProperty("idleCount");
expect(status).toHaveProperty("waitingCount");
expect(typeof status.totalCount).toBe("number");
expect(typeof status.idleCount).toBe("number");
expect(typeof status.waitingCount).toBe("number");
console.log("🏊‍♂️ 연결 풀 상태:", {
총_연결수: status.totalCount,
유휴_연결수: status.idleCount,
대기_연결수: status.waitingCount,
});
} catch (error) {
console.error("❌ 연결 풀 상태 확인 실패:", error);
throw error;
}
});
test("데이터베이스 메타데이터 조회", async () => {
try {
// 현재 데이터베이스 정보 조회
const dbInfo = await query(`
SELECT
current_database() as database_name,
current_user as current_user,
inet_server_addr() as server_address,
inet_server_port() as server_port
`);
expect(dbInfo).toHaveLength(1);
expect(dbInfo[0].database_name).toBeDefined();
expect(dbInfo[0].current_user).toBeDefined();
console.log("🗄️ 데이터베이스 정보:", {
데이터베이스명: dbInfo[0].database_name,
현재사용자: dbInfo[0].current_user,
서버주소: dbInfo[0].server_address,
서버포트: dbInfo[0].server_port,
});
} catch (error) {
console.error("❌ 데이터베이스 메타데이터 조회 실패:", error);
throw error;
}
});
test("테이블 존재 여부 확인", async () => {
try {
// 시스템 테이블 조회로 안전하게 테스트
const tables = await query(`
SELECT table_name, table_type
FROM information_schema.tables
WHERE table_schema = 'public'
AND table_type = 'BASE TABLE'
LIMIT 5
`);
expect(Array.isArray(tables)).toBe(true);
console.log(`📋 발견된 테이블 수: ${tables.length}`);
if (tables.length > 0) {
console.log(
"📋 테이블 목록 (최대 5개):",
tables.map((t) => t.table_name).join(", ")
);
}
} catch (error) {
console.error("❌ 테이블 존재 여부 확인 실패:", error);
throw error;
}
});
});
});
// 테스트 실행 방법:
// npm test -- database.test.ts

View File

@ -1,382 +0,0 @@
/**
* AuthService
* Phase 1.5: 인증
*
* :
* 1.
* 2. API
* 3.
*/
import request from "supertest";
import app from "../../app";
import { query } from "../../database/db";
import { EncryptUtil } from "../../utils/encryptUtil";
// 테스트 데이터
const TEST_USER = {
userId: "integration_test_user",
password: "integration_test_pass_123",
userName: "통합테스트 사용자",
};
describe("인증 시스템 통합 테스트 (Auth Integration Tests)", () => {
let authToken: string;
// 테스트 전 준비: 테스트 사용자 생성
beforeAll(async () => {
const hashedPassword = EncryptUtil.encrypt(TEST_USER.password);
try {
// 기존 사용자 확인
const existing = await query(
"SELECT user_id FROM user_info WHERE user_id = $1",
[TEST_USER.userId]
);
if (existing.length === 0) {
// 새 사용자 생성
await query(
`INSERT INTO user_info (
user_id, user_name, user_password, company_code, locale
) VALUES ($1, $2, $3, $4, $5)`,
[
TEST_USER.userId,
TEST_USER.userName,
hashedPassword,
"ILSHIN",
"KR",
]
);
} else {
// 기존 사용자 비밀번호 업데이트
await query(
"UPDATE user_info SET user_password = $1, user_name = $2 WHERE user_id = $3",
[hashedPassword, TEST_USER.userName, TEST_USER.userId]
);
}
console.log(`✅ 통합 테스트 사용자 준비 완료: ${TEST_USER.userId}`);
} catch (error) {
console.error("❌ 테스트 사용자 생성 실패:", error);
throw error;
}
});
// 테스트 후 정리 (선택적)
afterAll(async () => {
// 테스트 사용자 삭제 (필요시)
// await query("DELETE FROM user_info WHERE user_id = $1", [TEST_USER.userId]);
console.log("✅ 통합 테스트 완료");
});
describe("1. 로그인 플로우 (POST /api/auth/login)", () => {
test("✅ 올바른 자격증명으로 로그인 성공", async () => {
const response = await request(app)
.post("/api/auth/login")
.send({
userId: TEST_USER.userId,
password: TEST_USER.password,
})
.expect(200);
expect(response.body.success).toBe(true);
expect(response.body.token).toBeDefined();
expect(response.body.userInfo).toBeDefined();
expect(response.body.userInfo.userId).toBe(TEST_USER.userId);
expect(response.body.userInfo.userName).toBe(TEST_USER.userName);
// 토큰 저장 (다음 테스트에서 사용)
authToken = response.body.token;
});
test("❌ 잘못된 비밀번호로 로그인 실패", async () => {
const response = await request(app)
.post("/api/auth/login")
.send({
userId: TEST_USER.userId,
password: "wrong_password_123",
})
.expect(200);
expect(response.body.success).toBe(false);
expect(response.body.token).toBeUndefined();
expect(response.body.errorReason).toBeDefined();
expect(response.body.errorReason).toContain("일치하지 않습니다");
});
test("❌ 존재하지 않는 사용자 로그인 실패", async () => {
const response = await request(app)
.post("/api/auth/login")
.send({
userId: "nonexistent_user_999",
password: "anypassword",
})
.expect(200);
expect(response.body.success).toBe(false);
expect(response.body.token).toBeUndefined();
expect(response.body.errorReason).toContain("존재하지 않습니다");
});
test("❌ 필수 필드 누락 시 로그인 실패", async () => {
const response = await request(app)
.post("/api/auth/login")
.send({
userId: TEST_USER.userId,
// password 누락
})
.expect(400);
expect(response.body.success).toBe(false);
});
test("✅ JWT 토큰 형식 검증", () => {
expect(authToken).toBeDefined();
expect(typeof authToken).toBe("string");
// JWT는 3개 파트로 구성 (header.payload.signature)
const parts = authToken.split(".");
expect(parts.length).toBe(3);
});
});
describe("2. 토큰 검증 플로우 (GET /api/auth/verify)", () => {
test("✅ 유효한 토큰으로 검증 성공", async () => {
const response = await request(app)
.get("/api/auth/verify")
.set("Authorization", `Bearer ${authToken}`)
.expect(200);
expect(response.body.valid).toBe(true);
expect(response.body.userInfo).toBeDefined();
expect(response.body.userInfo.userId).toBe(TEST_USER.userId);
});
test("❌ 토큰 없이 요청 시 실패", async () => {
const response = await request(app).get("/api/auth/verify").expect(401);
expect(response.body.valid).toBe(false);
});
test("❌ 잘못된 토큰으로 요청 시 실패", async () => {
const response = await request(app)
.get("/api/auth/verify")
.set("Authorization", "Bearer invalid_token_12345")
.expect(401);
expect(response.body.valid).toBe(false);
});
test("❌ Bearer 없는 토큰으로 요청 시 실패", async () => {
const response = await request(app)
.get("/api/auth/verify")
.set("Authorization", authToken) // Bearer 키워드 없음
.expect(401);
expect(response.body.valid).toBe(false);
});
});
describe("3. 인증된 API 요청 플로우", () => {
test("✅ 인증된 사용자로 메뉴 조회", async () => {
const response = await request(app)
.get("/api/admin/menu")
.set("Authorization", `Bearer ${authToken}`)
.expect(200);
expect(Array.isArray(response.body)).toBe(true);
});
test("❌ 인증 없이 보호된 API 요청 실패", async () => {
const response = await request(app).get("/api/admin/menu").expect(401);
expect(response.body.success).toBe(false);
});
});
describe("4. 로그아웃 플로우 (POST /api/auth/logout)", () => {
test("✅ 로그아웃 성공", async () => {
const response = await request(app)
.post("/api/auth/logout")
.set("Authorization", `Bearer ${authToken}`)
.expect(200);
expect(response.body.success).toBe(true);
});
test("✅ 로그아웃 로그 기록 확인", async () => {
// 로그아웃 로그가 기록되었는지 확인
const logs = await query(
`SELECT * FROM LOGIN_ACCESS_LOG
WHERE USER_ID = UPPER($1)
AND ERROR_MESSAGE = '로그아웃'
ORDER BY LOG_TIME DESC
LIMIT 1`,
[TEST_USER.userId]
);
expect(logs.length).toBeGreaterThan(0);
expect(logs[0].error_message).toBe("로그아웃");
});
});
describe("5. 전체 시나리오 테스트", () => {
test("✅ 로그인 → 인증 → API 호출 → 로그아웃 전체 플로우", async () => {
// 1. 로그인
const loginResponse = await request(app)
.post("/api/auth/login")
.send({
userId: TEST_USER.userId,
password: TEST_USER.password,
})
.expect(200);
expect(loginResponse.body.success).toBe(true);
const token = loginResponse.body.token;
// 2. 토큰 검증
const verifyResponse = await request(app)
.get("/api/auth/verify")
.set("Authorization", `Bearer ${token}`)
.expect(200);
expect(verifyResponse.body.valid).toBe(true);
// 3. 보호된 API 호출
const menuResponse = await request(app)
.get("/api/admin/menu")
.set("Authorization", `Bearer ${token}`)
.expect(200);
expect(Array.isArray(menuResponse.body)).toBe(true);
// 4. 로그아웃
const logoutResponse = await request(app)
.post("/api/auth/logout")
.set("Authorization", `Bearer ${token}`)
.expect(200);
expect(logoutResponse.body.success).toBe(true);
});
});
describe("6. 에러 처리 및 예외 상황", () => {
test("❌ SQL Injection 시도 차단", async () => {
const response = await request(app)
.post("/api/auth/login")
.send({
userId: "admin' OR '1'='1",
password: "password",
})
.expect(200);
// SQL Injection이 차단되어 로그인 실패해야 함
expect(response.body.success).toBe(false);
});
test("❌ 빈 문자열로 로그인 시도", async () => {
const response = await request(app)
.post("/api/auth/login")
.send({
userId: "",
password: "",
})
.expect(400);
expect(response.body.success).toBe(false);
});
test("❌ 매우 긴 사용자 ID로 로그인 시도", async () => {
const longUserId = "a".repeat(1000);
const response = await request(app)
.post("/api/auth/login")
.send({
userId: longUserId,
password: "password",
})
.expect(200);
expect(response.body.success).toBe(false);
});
});
describe("7. 로그인 이력 확인", () => {
test("✅ 로그인 성공 이력 조회", async () => {
// 로그인 실행
await request(app).post("/api/auth/login").send({
userId: TEST_USER.userId,
password: TEST_USER.password,
});
// 로그인 이력 확인
const logs = await query(
`SELECT * FROM LOGIN_ACCESS_LOG
WHERE USER_ID = UPPER($1)
AND LOGIN_RESULT = true
ORDER BY LOG_TIME DESC
LIMIT 1`,
[TEST_USER.userId]
);
expect(logs.length).toBeGreaterThan(0);
expect(logs[0].login_result).toBeTruthy();
expect(logs[0].system_name).toBe("PMS");
});
test("✅ 로그인 실패 이력 조회", async () => {
// 로그인 실패 실행
await request(app).post("/api/auth/login").send({
userId: TEST_USER.userId,
password: "wrong_password",
});
// 로그인 실패 이력 확인
const logs = await query(
`SELECT * FROM LOGIN_ACCESS_LOG
WHERE USER_ID = UPPER($1)
AND LOGIN_RESULT = false
AND ERROR_MESSAGE IS NOT NULL
ORDER BY LOG_TIME DESC
LIMIT 1`,
[TEST_USER.userId]
);
expect(logs.length).toBeGreaterThan(0);
expect(logs[0].login_result).toBeFalsy();
expect(logs[0].error_message).toBeDefined();
});
});
describe("8. 성능 테스트", () => {
test("✅ 동시 로그인 요청 처리 (10개)", async () => {
const promises = Array.from({ length: 10 }, () =>
request(app).post("/api/auth/login").send({
userId: TEST_USER.userId,
password: TEST_USER.password,
})
);
const responses = await Promise.all(promises);
responses.forEach((response) => {
expect(response.status).toBe(200);
expect(response.body.success).toBe(true);
});
}, 10000); // 10초 타임아웃
test("✅ 로그인 응답 시간 (< 1초)", async () => {
const startTime = Date.now();
await request(app).post("/api/auth/login").send({
userId: TEST_USER.userId,
password: TEST_USER.password,
});
const endTime = Date.now();
const elapsedTime = endTime - startTime;
expect(elapsedTime).toBeLessThan(1000); // 1초 이내
}, 2000);
});
});

View File

@ -1,37 +0,0 @@
const { Client } = require("pg");
require("dotenv/config");
async function testDatabase() {
const client = new Client({
connectionString: process.env.DATABASE_URL,
});
try {
await client.connect();
console.log("✅ 데이터베이스 연결 성공");
// 사용자 정보 조회
const userResult = await client.query(
"SELECT user_id, user_name, status FROM user_info LIMIT 5"
);
console.log("👥 사용자 정보:", userResult.rows);
// 테이블 라벨 정보 조회
const tableLabelsResult = await client.query(
"SELECT * FROM table_labels LIMIT 5"
);
console.log("🏷️ 테이블 라벨 정보:", tableLabelsResult.rows);
// 컬럼 라벨 정보 조회
const columnLabelsResult = await client.query(
"SELECT * FROM column_labels LIMIT 5"
);
console.log("📋 컬럼 라벨 정보:", columnLabelsResult.rows);
} catch (error) {
console.error("❌ 오류 발생:", error);
} finally {
await client.end();
}
}
testDatabase();

View File

@ -1,41 +0,0 @@
const jwt = require("jsonwebtoken");
// JWT 설정
const JWT_SECRET = "your-super-secret-jwt-key-change-in-production";
const JWT_EXPIRES_IN = "24h";
// 테스트용 사용자 정보
const testUserInfo = {
userId: "arvin",
userName: "ARVIN",
deptName: "생산기술부",
companyCode: "ILSHIN",
};
console.log("=== JWT 토큰 테스트 ===");
console.log("사용자 정보:", testUserInfo);
// JWT 토큰 생성
const token = jwt.sign(testUserInfo, JWT_SECRET, {
expiresIn: JWT_EXPIRES_IN,
issuer: "PMS-System",
audience: "PMS-Users",
});
console.log("\n생성된 토큰:");
console.log(token);
// 토큰 검증
try {
const decoded = jwt.verify(token, JWT_SECRET);
console.log("\n토큰 검증 성공:");
console.log(decoded);
} catch (error) {
console.log("\n토큰 검증 실패:");
console.log(error.message);
}
// 토큰 디코드 (검증 없이)
const decodedWithoutVerification = jwt.decode(token);
console.log("\n토큰 디코드 (검증 없이):");
console.log(decodedWithoutVerification);

View File

@ -1,41 +0,0 @@
const jwt = require("jsonwebtoken");
const fs = require("fs");
// JWT 설정
const JWT_SECRET = "your-super-secret-jwt-key-change-in-production";
const JWT_EXPIRES_IN = "24h";
// 테스트용 사용자 정보
const testUserInfo = {
userId: "arvin",
userName: "ARVIN",
deptName: "생산기술부",
companyCode: "ILSHIN",
};
console.log("=== JWT 토큰 생성 ===");
console.log("사용자 정보:", testUserInfo);
// JWT 토큰 생성
const token = jwt.sign(testUserInfo, JWT_SECRET, {
expiresIn: JWT_EXPIRES_IN,
issuer: "PMS-System",
audience: "PMS-Users",
});
console.log("\n생성된 토큰:");
console.log(token);
// 토큰을 파일로 저장
fs.writeFileSync("test-token.txt", token);
console.log("\n토큰이 test-token.txt 파일에 저장되었습니다.");
// 토큰 검증 테스트
try {
const decoded = jwt.verify(token, JWT_SECRET);
console.log("\n토큰 검증 성공:");
console.log(decoded);
} catch (error) {
console.log("\n토큰 검증 실패:");
console.log(error.message);
}

View File

@ -1 +0,0 @@
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiJhcnZpbiIsInVzZXJOYW1lIjoiQVJWSU4iLCJkZXB0TmFtZSI6IuyDneyCsOq4sOyIoOu2gCIsImNvbXBhbnlDb2RlIjoiSUxTSElOIiwiaWF0IjoxNzU1Njc1NDg1LCJleHAiOjE3NTU3NjE4ODUsImF1ZCI6IlBNUy1Vc2VycyIsImlzcyI6IlBNUy1TeXN0ZW0ifQ.9TUMD_Rq-5kVNt9EFTztM6J1cxklg8wAclRAvbj1uq0

View File

@ -1,36 +0,0 @@
const { Client } = require("pg");
async function updatePassword() {
const client = new Client({
connectionString: process.env.DATABASE_URL,
});
try {
await client.connect();
console.log("✅ 데이터베이스 연결 성공");
// kkh 사용자의 비밀번호를 admin123으로 변경
await client.query(`
UPDATE user_info
SET user_password = 'f21b1ce8b08dc955bd4afff71b3db1fc'
WHERE user_id = 'kkh'
`);
console.log("✅ 비밀번호 변경 완료: kkh -> admin123");
// 변경 확인
const result = await client.query(`
SELECT user_id, user_name, user_password
FROM user_info
WHERE user_id = 'kkh'
`);
console.log("👤 변경된 사용자:", result.rows[0]);
} catch (error) {
console.error("❌ 오류 발생:", error);
} finally {
await client.end();
}
}
updatePassword();

View File

@ -182,10 +182,9 @@ export class DataflowDiagramService {
return false; return false;
} }
await query( await query(`DELETE FROM dataflow_diagrams WHERE diagram_id = $1`, [
`DELETE FROM dataflow_diagrams WHERE diagram_id = $1`, diagramId,
[diagramId] ]);
);
return true; return true;
} }