ERP-node/PHASE4_CONTROLLER_LAYER_MIG...

7.3 KiB

Phase 4: Controller Layer Raw Query 전환 계획

📋 개요

컨트롤러 레이어에 남아있는 Prisma 호출을 Raw Query로 전환합니다. 대부분의 컨트롤러는 Service 레이어를 호출하지만, 일부 컨트롤러에서 직접 Prisma를 사용하고 있습니다.


📊 기본 정보

항목 내용
대상 파일 7개 컨트롤러
파일 위치 backend-node/src/controllers/
Prisma 호출 70개 (28개 완료)
현재 진행률 28/70 (40%) 🔄 진행 중
복잡도 중간 (대부분 단순 CRUD)
우선순위 🟡 중간 (Phase 4)
상태 🔄 진행 중 (adminController 완료)

🎯 전환 대상 컨트롤러

1. adminController.ts 완료 (28개)

  • 라인 수: 2,569 라인
  • Prisma 호출: 28개 → 0개
  • 주요 기능:
    • 사용자 관리 (조회, 생성, 수정, 삭제)
    • 회사 관리 (조회, 생성, 수정, 삭제)
    • 부서 관리 (조회)
    • 메뉴 관리 (생성, 수정, 삭제)
    • 다국어 키 조회
  • 우선순위: 🔴 높음
  • 상태: 완료 (2025-10-01)
  • 문서: PHASE4.1_ADMIN_CONTROLLER_MIGRATION.md

2. webTypeStandardController.ts (11개)

  • Prisma 호출: 11개
  • 주요 기능: 웹타입 표준 관리
  • 우선순위: 🟡 중간

3. fileController.ts (11개)

  • Prisma 호출: 11개
  • 주요 기능: 파일 업로드/다운로드 관리
  • 우선순위: 🟡 중간

4. buttonActionStandardController.ts (11개)

  • Prisma 호출: 11개
  • 주요 기능: 버튼 액션 표준 관리
  • 우선순위: 🟡 중간

5. entityReferenceController.ts (4개)

  • Prisma 호출: 4개
  • 주요 기능: 엔티티 참조 관리
  • 우선순위: 🟢 낮음

6. dataflowExecutionController.ts (3개)

  • Prisma 호출: 3개
  • 주요 기능: 데이터플로우 실행
  • 우선순위: 🟢 낮음

7. screenFileController.ts (2개)

  • Prisma 호출: 2개
  • 주요 기능: 화면 파일 관리
  • 우선순위: 🟢 낮음

📝 전환 전략

기본 원칙

  1. Service Layer 우선

    • 가능하면 Service로 로직 이동
    • Controller는 최소한의 로직만 유지
  2. 단순 전환

    • 대부분 단순 CRUD → query, queryOne 사용
    • 복잡한 로직은 Service로 이동
  3. 에러 처리 유지

    • 기존 try-catch 구조 유지
    • 에러 메시지 일관성 유지

전환 패턴

1. findMany → query

// Before
const users = await prisma.user_info.findMany({
  where: { company_code: companyCode },
});

// After
const users = await query<UserInfo>(
  `SELECT * FROM user_info WHERE company_code = $1`,
  [companyCode]
);

2. findUnique → queryOne

// Before
const user = await prisma.user_info.findUnique({
  where: { user_id: userId },
});

// After
const user = await queryOne<UserInfo>(
  `SELECT * FROM user_info WHERE user_id = $1`,
  [userId]
);

3. create → queryOne with INSERT

// Before
const newUser = await prisma.user_info.create({
  data: userData
});

// After
const newUser = await queryOne<UserInfo>(
  `INSERT INTO user_info (user_id, user_name, ...)
   VALUES ($1, $2, ...) RETURNING *`,
  [userData.user_id, userData.user_name, ...]
);

4. update → queryOne with UPDATE

// Before
const updated = await prisma.user_info.update({
  where: { user_id: userId },
  data: updateData
});

// After
const updated = await queryOne<UserInfo>(
  `UPDATE user_info SET user_name = $1, ...
   WHERE user_id = $2 RETURNING *`,
  [updateData.user_name, ..., userId]
);

5. delete → query with DELETE

// Before
await prisma.user_info.delete({
  where: { user_id: userId },
});

// After
await query(`DELETE FROM user_info WHERE user_id = $1`, [userId]);

6. count → queryOne

// Before
const count = await prisma.user_info.count({
  where: { company_code: companyCode },
});

// After
const result = await queryOne<{ count: number }>(
  `SELECT COUNT(*) as count FROM user_info WHERE company_code = $1`,
  [companyCode]
);
const count = parseInt(result?.count?.toString() || "0", 10);

체크리스트

Phase 4.1: adminController.ts

  • Prisma import 제거
  • query, queryOne import 추가
  • 사용자 관리 함수 전환 (8개)
    • getUserList - count + findMany
    • getUserInfo - findFirst
    • updateUserStatus - update
    • deleteUserByAdmin - update
    • getMyProfile - findUnique
    • updateMyProfile - update
    • createOrUpdateUser - upsert
    • count (getUserList)
  • 회사 관리 함수 전환 (7개)
    • getCompanyList - findMany
    • createCompany - findFirst (중복체크) + create
    • updateCompany - findFirst (중복체크) + update
    • deleteCompany - findUnique + delete
  • 부서 관리 함수 전환 (2개)
    • getDepartmentList - findMany
    • findUnique (부서 조회)
  • 메뉴 관리 함수 전환 (3개)
    • createMenu - create
    • updateMenu - update
    • deleteMenu - delete
  • 기타 함수 전환 (8개)
    • getMultiLangKeys - findMany
  • 컴파일 확인
  • 린터 확인

Phase 4.2: webTypeStandardController.ts

  • Prisma import 제거
  • query, queryOne import 추가
  • 모든 함수 전환 (11개)
  • 컴파일 확인
  • 린터 확인

Phase 4.3: fileController.ts

  • Prisma import 제거
  • query, queryOne import 추가
  • 모든 함수 전환 (11개)
  • 컴파일 확인
  • 린터 확인

Phase 4.4: buttonActionStandardController.ts

  • Prisma import 제거
  • query, queryOne import 추가
  • 모든 함수 전환 (11개)
  • 컴파일 확인
  • 린터 확인

Phase 4.5: entityReferenceController.ts

  • Prisma import 제거
  • query, queryOne import 추가
  • 모든 함수 전환 (4개)
  • 컴파일 확인
  • 린터 확인

Phase 4.6: dataflowExecutionController.ts

  • Prisma import 제거
  • query, queryOne import 추가
  • 모든 함수 전환 (3개)
  • 컴파일 확인
  • 린터 확인

Phase 4.7: screenFileController.ts

  • Prisma import 제거
  • query, queryOne import 추가
  • 모든 함수 전환 (2개)
  • 컴파일 확인
  • 린터 확인

🎯 예상 결과

코드 품질

  • Prisma 의존성 완전 제거
  • 직접적인 SQL 제어
  • 타입 안전성 유지

성능

  • 불필요한 ORM 오버헤드 제거
  • 쿼리 최적화 가능

유지보수성

  • 명확한 SQL 쿼리
  • 디버깅 용이
  • 데이터베이스 마이그레이션 용이

📌 참고사항

Import 변경

// Before
import { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();

// After
import { query, queryOne } from "../database/db";

타입 정의

  • 각 테이블의 타입은 types/ 디렉토리에서 import
  • 필요시 새로운 타입 정의 추가

에러 처리

  • 기존 try-catch 구조 유지
  • 적절한 HTTP 상태 코드 반환
  • 사용자 친화적 에러 메시지