# Phase 4: 남은 Prisma 호출 전환 계획 ## 📊 현재 상황 | 항목 | 내용 | | --------------- | --------------------------------------- | | 총 Prisma 호출 | 29개 | | 대상 파일 | 7개 | | **현재 진행률** | **17/29 (58.6%)** 🔄 **진행 중** | | 복잡도 | 중간 | | 우선순위 | 🔴 높음 (Phase 4) | | **상태** | ⏳ **진행 중** | --- ## 📁 파일별 현황 ### ✅ 완료된 파일 (2개) 1. **adminController.ts** - ✅ **28개 완료** - 사용자 관리: getUserList, getUserInfo, updateUserStatus, deleteUser - 프로필 관리: getMyProfile, updateMyProfile, resetPassword - 사용자 생성/수정: createOrUpdateUser (UPSERT) - 회사 관리: getCompanyList, createCompany, updateCompany, deleteCompany - 부서 관리: getDepartmentList, getDeptInfo - 메뉴 관리: createMenu, updateMenu, deleteMenu - 다국어: getMultiLangKeys, updateLocale 2. **screenFileController.ts** - ✅ **2개 완료** - getScreenComponentFiles: findMany → query (LIKE) - getComponentFiles: findMany → query (LIKE) --- ## ⏳ 남은 파일 (5개, 총 12개 호출) ### 1. webTypeStandardController.ts (11개) 🔴 최우선 **위치**: `backend-node/src/controllers/webTypeStandardController.ts` #### Prisma 호출 목록: 1. **라인 33**: `getWebTypeStandards()` - findMany ```typescript const webTypes = await prisma.web_type_standards.findMany({ where, orderBy, select }); ``` 2. **라인 58**: `getWebTypeStandard()` - findUnique ```typescript const webTypeData = await prisma.web_type_standards.findUnique({ where: { id } }); ``` 3. **라인 112**: `createWebTypeStandard()` - findUnique (중복 체크) ```typescript const existingWebType = await prisma.web_type_standards.findUnique({ where: { web_type: webType } }); ``` 4. **라인 123**: `createWebTypeStandard()` - create ```typescript const newWebType = await prisma.web_type_standards.create({ data: { ... } }); ``` 5. **라인 178**: `updateWebTypeStandard()` - findUnique (존재 확인) ```typescript const existingWebType = await prisma.web_type_standards.findUnique({ where: { id } }); ``` 6. **라인 189**: `updateWebTypeStandard()` - update ```typescript const updatedWebType = await prisma.web_type_standards.update({ where: { id }, data: { ... } }); ``` 7. **라인 230**: `deleteWebTypeStandard()` - findUnique (존재 확인) ```typescript const existingWebType = await prisma.web_type_standards.findUnique({ where: { id } }); ``` 8. **라인 241**: `deleteWebTypeStandard()` - delete ```typescript await prisma.web_type_standards.delete({ where: { id } }); ``` 9. **라인 275**: `updateSortOrder()` - $transaction ```typescript await prisma.$transaction( updates.map((item) => prisma.web_type_standards.update({ ... }) ) ); ``` 10. **라인 277**: `updateSortOrder()` - update (트랜잭션 내부) 11. **라인 305**: `getCategories()` - groupBy ```typescript const categories = await prisma.web_type_standards.groupBy({ by: ['category'], where, _count: true }); ``` **전환 전략**: - findMany → `query` with dynamic WHERE - findUnique → `queryOne` - create → `queryOne` with INSERT RETURNING - update → `queryOne` with UPDATE RETURNING - delete → `query` with DELETE - $transaction → `transaction` with client.query - groupBy → `query` with GROUP BY, COUNT --- ### 2. fileController.ts (1개) 🟡 **위치**: `backend-node/src/controllers/fileController.ts` #### Prisma 호출: 1. **라인 726**: `downloadFile()` - findUnique ```typescript const fileRecord = await prisma.attach_file_info.findUnique({ where: { objid: BigInt(objid) } }); ``` **전환 전략**: - findUnique → `queryOne` --- ### 3. multiConnectionQueryService.ts (4개) 🟢 **위치**: `backend-node/src/services/multiConnectionQueryService.ts` #### Prisma 호출 목록: 1. **라인 1005**: `executeSelect()` - $queryRawUnsafe ```typescript return await prisma.$queryRawUnsafe(query, ...queryParams); ``` 2. **라인 1022**: `executeInsert()` - $queryRawUnsafe ```typescript const insertResult = await prisma.$queryRawUnsafe(...); ``` 3. **라인 1055**: `executeUpdate()` - $queryRawUnsafe ```typescript return await prisma.$queryRawUnsafe(updateQuery, ...updateParams); ``` 4. **라인 1071**: `executeDelete()` - $queryRawUnsafe ```typescript return await prisma.$queryRawUnsafe(...); ``` **전환 전략**: - $queryRawUnsafe → `query` (이미 Raw SQL 사용 중) --- ### 4. config/database.ts (4개) 🟢 **위치**: `backend-node/src/config/database.ts` #### Prisma 호출: 1. **라인 1**: PrismaClient import 2. **라인 17**: prisma 인스턴스 생성 3. **라인 22**: `await prisma.$connect()` 4. **라인 31, 35, 40**: `await prisma.$disconnect()` **전환 전략**: - 이 파일은 데이터베이스 설정 파일이므로 완전히 제거 - 기존 `db.ts`의 connection pool로 대체 - 모든 import 경로를 `database` → `database/db`로 변경 --- ### 5. routes/ddlRoutes.ts (2개) 🟢 **위치**: `backend-node/src/routes/ddlRoutes.ts` #### Prisma 호출: 1. **라인 183-184**: 동적 PrismaClient import ```typescript const { PrismaClient } = await import("@prisma/client"); const prisma = new PrismaClient(); ``` 2. **라인 186-187**: 연결 테스트 ```typescript await prisma.$queryRaw`SELECT 1`; await prisma.$disconnect(); ``` **전환 전략**: - 동적 import 제거 - `query('SELECT 1')` 사용 --- ### 6. routes/companyManagementRoutes.ts (2개) 🟢 **위치**: `backend-node/src/routes/companyManagementRoutes.ts` #### Prisma 호출: 1. **라인 32**: findUnique (중복 체크) ```typescript const existingCompany = await prisma.company_mng.findUnique({ where: { company_code } }); ``` 2. **라인 61**: update (회사명 업데이트) ```typescript await prisma.company_mng.update({ where: { company_code }, data: { company_name } }); ``` **전환 전략**: - findUnique → `queryOne` - update → `query` --- ### 7. tests/authService.test.ts (2개) ⚠️ **위치**: `backend-node/src/tests/authService.test.ts` 테스트 파일은 별도 처리 필요 (Phase 5에서 처리) --- ## 🎯 전환 우선순위 ### Phase 4.1: 컨트롤러 (완료) - [x] screenFileController.ts (2개) - [x] adminController.ts (28개) ### Phase 4.2: 남은 컨트롤러 (진행 예정) - [ ] webTypeStandardController.ts (11개) - 🔴 최우선 - [ ] fileController.ts (1개) ### Phase 4.3: Routes (진행 예정) - [ ] ddlRoutes.ts (2개) - [ ] companyManagementRoutes.ts (2개) ### Phase 4.4: Services (진행 예정) - [ ] multiConnectionQueryService.ts (4개) ### Phase 4.5: Config (진행 예정) - [ ] database.ts (4개) - 전체 파일 제거 ### Phase 4.6: Tests (Phase 5) - [ ] authService.test.ts (2개) - 별도 처리 --- ## 📋 체크리스트 ### webTypeStandardController.ts - [ ] Prisma import 제거 - [ ] query, queryOne import 추가 - [ ] getWebTypeStandards (findMany → query) - [ ] getWebTypeStandard (findUnique → queryOne) - [ ] createWebTypeStandard (findUnique + create → queryOne) - [ ] updateWebTypeStandard (findUnique + update → queryOne) - [ ] deleteWebTypeStandard (findUnique + delete → query) - [ ] updateSortOrder ($transaction → transaction) - [ ] getCategories (groupBy → query with GROUP BY) - [ ] TypeScript 컴파일 확인 - [ ] Linter 오류 확인 - [ ] 동작 테스트 ### fileController.ts - [ ] Prisma import 제거 - [ ] queryOne import 추가 - [ ] downloadFile (findUnique → queryOne) - [ ] TypeScript 컴파일 확인 ### routes/ddlRoutes.ts - [ ] 동적 PrismaClient import 제거 - [ ] query import 추가 - [ ] 연결 테스트 로직 변경 - [ ] TypeScript 컴파일 확인 ### routes/companyManagementRoutes.ts - [ ] Prisma import 제거 - [ ] query, queryOne import 추가 - [ ] findUnique → queryOne - [ ] update → query - [ ] TypeScript 컴파일 확인 ### services/multiConnectionQueryService.ts - [ ] Prisma import 제거 - [ ] query import 추가 - [ ] $queryRawUnsafe → query (4곳) - [ ] TypeScript 컴파일 확인 ### config/database.ts - [ ] 파일 전체 분석 - [ ] 의존성 확인 - [ ] 대체 방안 구현 - [ ] 모든 import 경로 변경 - [ ] 파일 삭제 또는 완전 재작성 --- ## 🔧 전환 패턴 요약 ### 1. findMany → query ```typescript // Before const items = await prisma.table.findMany({ where, orderBy }); // After const items = await query(`SELECT * FROM table WHERE ... ORDER BY ...`, params); ``` ### 2. findUnique → queryOne ```typescript // Before const item = await prisma.table.findUnique({ where: { id } }); // After const item = await queryOne(`SELECT * FROM table WHERE id = $1`, [id]); ``` ### 3. create → queryOne with RETURNING ```typescript // Before const newItem = await prisma.table.create({ data }); // After const [newItem] = await query( `INSERT INTO table (col1, col2) VALUES ($1, $2) RETURNING *`, [val1, val2] ); ``` ### 4. update → query with RETURNING ```typescript // Before const updated = await prisma.table.update({ where, data }); // After const [updated] = await query( `UPDATE table SET col1 = $1 WHERE id = $2 RETURNING *`, [val1, id] ); ``` ### 5. delete → query ```typescript // Before await prisma.table.delete({ where: { id } }); // After await query(`DELETE FROM table WHERE id = $1`, [id]); ``` ### 6. $transaction → transaction ```typescript // Before await prisma.$transaction([ prisma.table.update({ ... }), prisma.table.update({ ... }) ]); // After await transaction(async (client) => { await client.query(`UPDATE table SET ...`, params1); await client.query(`UPDATE table SET ...`, params2); }); ``` ### 7. groupBy → query with GROUP BY ```typescript // Before const result = await prisma.table.groupBy({ by: ['category'], _count: true }); // After const result = await query( `SELECT category, COUNT(*) as count FROM table GROUP BY category`, [] ); ``` --- ## 📈 진행 상황 ### 전체 진행률: 17/29 (58.6%) ``` Phase 1-3: Service Layer ████████████████████████████ 100% (415/415) Phase 4.1: Controllers ████████████████████████████ 100% (30/30) Phase 4.2: 남은 파일 ███████░░░░░░░░░░░░░░░░░░░░ 58% (17/29) ``` ### 상세 진행 상황 | 카테고리 | 완료 | 남음 | 진행률 | | -------------- | ---- | ---- | ------ | | Services | 415 | 0 | 100% | | Controllers | 30 | 11 | 73% | | Routes | 0 | 4 | 0% | | Config | 0 | 4 | 0% | | **총계** | 445 | 19 | 95.9% | --- ## 🎬 다음 단계 1. **webTypeStandardController.ts 전환** (11개) - 가장 많은 Prisma 호출을 가진 남은 컨트롤러 - 웹 타입 표준 관리 핵심 기능 2. **fileController.ts 전환** (1개) - 단순 findUnique만 있어 빠르게 처리 가능 3. **Routes 전환** (4개) - ddlRoutes.ts - companyManagementRoutes.ts 4. **Service 전환** (4개) - multiConnectionQueryService.ts 5. **Config 제거** (4개) - database.ts 완전 제거 또는 재작성 - 모든 의존성 제거 --- ## ⚠️ 주의사항 1. **database.ts 처리** - 현재 많은 파일이 `import prisma from '../config/database'` 사용 - 모든 import를 `import { query, queryOne } from '../database/db'`로 변경 필요 - 단계적으로 진행하여 빌드 오류 방지 2. **BigInt 처리** - fileController의 `objid: BigInt(objid)` → `objid::bigint` 또는 `CAST(objid AS BIGINT)` 3. **트랜잭션 처리** - webTypeStandardController의 `updateSortOrder`는 복잡한 트랜잭션 - `transaction` 함수 사용 필요 4. **타입 안전성** - 모든 Raw Query에 명시적 타입 지정 필요 - `query`, `queryOne` 등 --- ## 📝 완료 후 작업 - [ ] 전체 컴파일 확인 - [ ] Linter 오류 해결 - [ ] 통합 테스트 실행 - [ ] Prisma 관련 의존성 완전 제거 (package.json) - [ ] `prisma/` 디렉토리 정리 - [ ] 문서 업데이트 - [ ] 커밋 및 Push --- **작성일**: 2025-10-01 **최종 업데이트**: 2025-10-01 **상태**: 🔄 진행 중 (58.6% 완료)