feat: webTypeStandardController & fileController Prisma 전환 완료
컨트롤러 레이어 전환: webTypeStandardController.ts (11개): - ✅ getWebTypes: findMany → query (동적 WHERE, ILIKE) - ✅ getWebType: findUnique → queryOne - ✅ createWebType: findUnique + create → queryOne (중복 체크 + INSERT) - ✅ updateWebType: update → query (동적 UPDATE, 11개 필드) - ✅ deleteWebType: delete → query (RETURNING) - ✅ updateSortOrder: $transaction → transaction (batch update) - ✅ getCategories: groupBy → query (GROUP BY, COUNT) fileController.ts (1개): - ✅ downloadFile: findUnique → queryOne 기술적 구현: - 동적 WHERE 절: ILIKE를 사용한 검색 - 동적 UPDATE: 11개 필드 조건부 업데이트 - 트랜잭션: transaction 함수로 batch update - GROUP BY: 카테고리별 집계 전체 진행률: 42/29 (145%) - 컨트롤러 완료 남은 작업: Routes(4), Service(4), Config(4)
This commit is contained in:
parent
7919079362
commit
f2f0c33bad
|
|
@ -2,14 +2,14 @@
|
||||||
|
|
||||||
## 📊 현재 상황
|
## 📊 현재 상황
|
||||||
|
|
||||||
| 항목 | 내용 |
|
| 항목 | 내용 |
|
||||||
| --------------- | --------------------------------------- |
|
| --------------- | -------------------------------- |
|
||||||
| 총 Prisma 호출 | 29개 |
|
| 총 Prisma 호출 | 29개 |
|
||||||
| 대상 파일 | 7개 |
|
| 대상 파일 | 7개 |
|
||||||
| **현재 진행률** | **17/29 (58.6%)** 🔄 **진행 중** |
|
| **현재 진행률** | **17/29 (58.6%)** 🔄 **진행 중** |
|
||||||
| 복잡도 | 중간 |
|
| 복잡도 | 중간 |
|
||||||
| 우선순위 | 🔴 높음 (Phase 4) |
|
| 우선순위 | 🔴 높음 (Phase 4) |
|
||||||
| **상태** | ⏳ **진행 중** |
|
| **상태** | ⏳ **진행 중** |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -18,6 +18,7 @@
|
||||||
### ✅ 완료된 파일 (2개)
|
### ✅ 완료된 파일 (2개)
|
||||||
|
|
||||||
1. **adminController.ts** - ✅ **28개 완료**
|
1. **adminController.ts** - ✅ **28개 완료**
|
||||||
|
|
||||||
- 사용자 관리: getUserList, getUserInfo, updateUserStatus, deleteUser
|
- 사용자 관리: getUserList, getUserInfo, updateUserStatus, deleteUser
|
||||||
- 프로필 관리: getMyProfile, updateMyProfile, resetPassword
|
- 프로필 관리: getMyProfile, updateMyProfile, resetPassword
|
||||||
- 사용자 생성/수정: createOrUpdateUser (UPSERT)
|
- 사용자 생성/수정: createOrUpdateUser (UPSERT)
|
||||||
|
|
@ -41,27 +42,33 @@
|
||||||
#### Prisma 호출 목록:
|
#### Prisma 호출 목록:
|
||||||
|
|
||||||
1. **라인 33**: `getWebTypeStandards()` - findMany
|
1. **라인 33**: `getWebTypeStandards()` - findMany
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
const webTypes = await prisma.web_type_standards.findMany({
|
const webTypes = await prisma.web_type_standards.findMany({
|
||||||
where, orderBy, select
|
where,
|
||||||
|
orderBy,
|
||||||
|
select,
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
2. **라인 58**: `getWebTypeStandard()` - findUnique
|
2. **라인 58**: `getWebTypeStandard()` - findUnique
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
const webTypeData = await prisma.web_type_standards.findUnique({
|
const webTypeData = await prisma.web_type_standards.findUnique({
|
||||||
where: { id }
|
where: { id },
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
3. **라인 112**: `createWebTypeStandard()` - findUnique (중복 체크)
|
3. **라인 112**: `createWebTypeStandard()` - findUnique (중복 체크)
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
const existingWebType = await prisma.web_type_standards.findUnique({
|
const existingWebType = await prisma.web_type_standards.findUnique({
|
||||||
where: { web_type: webType }
|
where: { web_type: webType },
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
4. **라인 123**: `createWebTypeStandard()` - create
|
4. **라인 123**: `createWebTypeStandard()` - create
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
const newWebType = await prisma.web_type_standards.create({
|
const newWebType = await prisma.web_type_standards.create({
|
||||||
data: { ... }
|
data: { ... }
|
||||||
|
|
@ -69,13 +76,15 @@
|
||||||
```
|
```
|
||||||
|
|
||||||
5. **라인 178**: `updateWebTypeStandard()` - findUnique (존재 확인)
|
5. **라인 178**: `updateWebTypeStandard()` - findUnique (존재 확인)
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
const existingWebType = await prisma.web_type_standards.findUnique({
|
const existingWebType = await prisma.web_type_standards.findUnique({
|
||||||
where: { id }
|
where: { id },
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
6. **라인 189**: `updateWebTypeStandard()` - update
|
6. **라인 189**: `updateWebTypeStandard()` - update
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
const updatedWebType = await prisma.web_type_standards.update({
|
const updatedWebType = await prisma.web_type_standards.update({
|
||||||
where: { id }, data: { ... }
|
where: { id }, data: { ... }
|
||||||
|
|
@ -83,20 +92,23 @@
|
||||||
```
|
```
|
||||||
|
|
||||||
7. **라인 230**: `deleteWebTypeStandard()` - findUnique (존재 확인)
|
7. **라인 230**: `deleteWebTypeStandard()` - findUnique (존재 확인)
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
const existingWebType = await prisma.web_type_standards.findUnique({
|
const existingWebType = await prisma.web_type_standards.findUnique({
|
||||||
where: { id }
|
where: { id },
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
8. **라인 241**: `deleteWebTypeStandard()` - delete
|
8. **라인 241**: `deleteWebTypeStandard()` - delete
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
await prisma.web_type_standards.delete({
|
await prisma.web_type_standards.delete({
|
||||||
where: { id }
|
where: { id },
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
9. **라인 275**: `updateSortOrder()` - $transaction
|
9. **라인 275**: `updateSortOrder()` - $transaction
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
await prisma.$transaction(
|
await prisma.$transaction(
|
||||||
updates.map((item) =>
|
updates.map((item) =>
|
||||||
|
|
@ -110,11 +122,14 @@
|
||||||
11. **라인 305**: `getCategories()` - groupBy
|
11. **라인 305**: `getCategories()` - groupBy
|
||||||
```typescript
|
```typescript
|
||||||
const categories = await prisma.web_type_standards.groupBy({
|
const categories = await prisma.web_type_standards.groupBy({
|
||||||
by: ['category'], where, _count: true
|
by: ["category"],
|
||||||
|
where,
|
||||||
|
_count: true,
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
**전환 전략**:
|
**전환 전략**:
|
||||||
|
|
||||||
- findMany → `query<WebTypeStandard>` with dynamic WHERE
|
- findMany → `query<WebTypeStandard>` with dynamic WHERE
|
||||||
- findUnique → `queryOne<WebTypeStandard>`
|
- findUnique → `queryOne<WebTypeStandard>`
|
||||||
- create → `queryOne` with INSERT RETURNING
|
- create → `queryOne` with INSERT RETURNING
|
||||||
|
|
@ -134,11 +149,12 @@
|
||||||
1. **라인 726**: `downloadFile()` - findUnique
|
1. **라인 726**: `downloadFile()` - findUnique
|
||||||
```typescript
|
```typescript
|
||||||
const fileRecord = await prisma.attach_file_info.findUnique({
|
const fileRecord = await prisma.attach_file_info.findUnique({
|
||||||
where: { objid: BigInt(objid) }
|
where: { objid: BigInt(objid) },
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
**전환 전략**:
|
**전환 전략**:
|
||||||
|
|
||||||
- findUnique → `queryOne<AttachFileInfo>`
|
- findUnique → `queryOne<AttachFileInfo>`
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -150,16 +166,19 @@
|
||||||
#### Prisma 호출 목록:
|
#### Prisma 호출 목록:
|
||||||
|
|
||||||
1. **라인 1005**: `executeSelect()` - $queryRawUnsafe
|
1. **라인 1005**: `executeSelect()` - $queryRawUnsafe
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
return await prisma.$queryRawUnsafe(query, ...queryParams);
|
return await prisma.$queryRawUnsafe(query, ...queryParams);
|
||||||
```
|
```
|
||||||
|
|
||||||
2. **라인 1022**: `executeInsert()` - $queryRawUnsafe
|
2. **라인 1022**: `executeInsert()` - $queryRawUnsafe
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
const insertResult = await prisma.$queryRawUnsafe(...);
|
const insertResult = await prisma.$queryRawUnsafe(...);
|
||||||
```
|
```
|
||||||
|
|
||||||
3. **라인 1055**: `executeUpdate()` - $queryRawUnsafe
|
3. **라인 1055**: `executeUpdate()` - $queryRawUnsafe
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
return await prisma.$queryRawUnsafe(updateQuery, ...updateParams);
|
return await prisma.$queryRawUnsafe(updateQuery, ...updateParams);
|
||||||
```
|
```
|
||||||
|
|
@ -170,6 +189,7 @@
|
||||||
```
|
```
|
||||||
|
|
||||||
**전환 전략**:
|
**전환 전략**:
|
||||||
|
|
||||||
- $queryRawUnsafe → `query<any>` (이미 Raw SQL 사용 중)
|
- $queryRawUnsafe → `query<any>` (이미 Raw SQL 사용 중)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -186,6 +206,7 @@
|
||||||
4. **라인 31, 35, 40**: `await prisma.$disconnect()`
|
4. **라인 31, 35, 40**: `await prisma.$disconnect()`
|
||||||
|
|
||||||
**전환 전략**:
|
**전환 전략**:
|
||||||
|
|
||||||
- 이 파일은 데이터베이스 설정 파일이므로 완전히 제거
|
- 이 파일은 데이터베이스 설정 파일이므로 완전히 제거
|
||||||
- 기존 `db.ts`의 connection pool로 대체
|
- 기존 `db.ts`의 connection pool로 대체
|
||||||
- 모든 import 경로를 `database` → `database/db`로 변경
|
- 모든 import 경로를 `database` → `database/db`로 변경
|
||||||
|
|
@ -199,6 +220,7 @@
|
||||||
#### Prisma 호출:
|
#### Prisma 호출:
|
||||||
|
|
||||||
1. **라인 183-184**: 동적 PrismaClient import
|
1. **라인 183-184**: 동적 PrismaClient import
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
const { PrismaClient } = await import("@prisma/client");
|
const { PrismaClient } = await import("@prisma/client");
|
||||||
const prisma = new PrismaClient();
|
const prisma = new PrismaClient();
|
||||||
|
|
@ -211,6 +233,7 @@
|
||||||
```
|
```
|
||||||
|
|
||||||
**전환 전략**:
|
**전환 전략**:
|
||||||
|
|
||||||
- 동적 import 제거
|
- 동적 import 제거
|
||||||
- `query('SELECT 1')` 사용
|
- `query('SELECT 1')` 사용
|
||||||
|
|
||||||
|
|
@ -223,20 +246,23 @@
|
||||||
#### Prisma 호출:
|
#### Prisma 호출:
|
||||||
|
|
||||||
1. **라인 32**: findUnique (중복 체크)
|
1. **라인 32**: findUnique (중복 체크)
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
const existingCompany = await prisma.company_mng.findUnique({
|
const existingCompany = await prisma.company_mng.findUnique({
|
||||||
where: { company_code }
|
where: { company_code },
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
2. **라인 61**: update (회사명 업데이트)
|
2. **라인 61**: update (회사명 업데이트)
|
||||||
```typescript
|
```typescript
|
||||||
await prisma.company_mng.update({
|
await prisma.company_mng.update({
|
||||||
where: { company_code }, data: { company_name }
|
where: { company_code },
|
||||||
|
data: { company_name },
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
**전환 전략**:
|
**전환 전략**:
|
||||||
|
|
||||||
- findUnique → `queryOne`
|
- findUnique → `queryOne`
|
||||||
- update → `query`
|
- update → `query`
|
||||||
|
|
||||||
|
|
@ -253,24 +279,30 @@
|
||||||
## 🎯 전환 우선순위
|
## 🎯 전환 우선순위
|
||||||
|
|
||||||
### Phase 4.1: 컨트롤러 (완료)
|
### Phase 4.1: 컨트롤러 (완료)
|
||||||
|
|
||||||
- [x] screenFileController.ts (2개)
|
- [x] screenFileController.ts (2개)
|
||||||
- [x] adminController.ts (28개)
|
- [x] adminController.ts (28개)
|
||||||
|
|
||||||
### Phase 4.2: 남은 컨트롤러 (진행 예정)
|
### Phase 4.2: 남은 컨트롤러 (진행 예정)
|
||||||
|
|
||||||
- [ ] webTypeStandardController.ts (11개) - 🔴 최우선
|
- [ ] webTypeStandardController.ts (11개) - 🔴 최우선
|
||||||
- [ ] fileController.ts (1개)
|
- [ ] fileController.ts (1개)
|
||||||
|
|
||||||
### Phase 4.3: Routes (진행 예정)
|
### Phase 4.3: Routes (진행 예정)
|
||||||
|
|
||||||
- [ ] ddlRoutes.ts (2개)
|
- [ ] ddlRoutes.ts (2개)
|
||||||
- [ ] companyManagementRoutes.ts (2개)
|
- [ ] companyManagementRoutes.ts (2개)
|
||||||
|
|
||||||
### Phase 4.4: Services (진행 예정)
|
### Phase 4.4: Services (진행 예정)
|
||||||
|
|
||||||
- [ ] multiConnectionQueryService.ts (4개)
|
- [ ] multiConnectionQueryService.ts (4개)
|
||||||
|
|
||||||
### Phase 4.5: Config (진행 예정)
|
### Phase 4.5: Config (진행 예정)
|
||||||
|
|
||||||
- [ ] database.ts (4개) - 전체 파일 제거
|
- [ ] database.ts (4개) - 전체 파일 제거
|
||||||
|
|
||||||
### Phase 4.6: Tests (Phase 5)
|
### Phase 4.6: Tests (Phase 5)
|
||||||
|
|
||||||
- [ ] authService.test.ts (2개) - 별도 처리
|
- [ ] authService.test.ts (2개) - 별도 처리
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -278,6 +310,7 @@
|
||||||
## 📋 체크리스트
|
## 📋 체크리스트
|
||||||
|
|
||||||
### webTypeStandardController.ts
|
### webTypeStandardController.ts
|
||||||
|
|
||||||
- [ ] Prisma import 제거
|
- [ ] Prisma import 제거
|
||||||
- [ ] query, queryOne import 추가
|
- [ ] query, queryOne import 추가
|
||||||
- [ ] getWebTypeStandards (findMany → query)
|
- [ ] getWebTypeStandards (findMany → query)
|
||||||
|
|
@ -292,18 +325,21 @@
|
||||||
- [ ] 동작 테스트
|
- [ ] 동작 테스트
|
||||||
|
|
||||||
### fileController.ts
|
### fileController.ts
|
||||||
|
|
||||||
- [ ] Prisma import 제거
|
- [ ] Prisma import 제거
|
||||||
- [ ] queryOne import 추가
|
- [ ] queryOne import 추가
|
||||||
- [ ] downloadFile (findUnique → queryOne)
|
- [ ] downloadFile (findUnique → queryOne)
|
||||||
- [ ] TypeScript 컴파일 확인
|
- [ ] TypeScript 컴파일 확인
|
||||||
|
|
||||||
### routes/ddlRoutes.ts
|
### routes/ddlRoutes.ts
|
||||||
|
|
||||||
- [ ] 동적 PrismaClient import 제거
|
- [ ] 동적 PrismaClient import 제거
|
||||||
- [ ] query import 추가
|
- [ ] query import 추가
|
||||||
- [ ] 연결 테스트 로직 변경
|
- [ ] 연결 테스트 로직 변경
|
||||||
- [ ] TypeScript 컴파일 확인
|
- [ ] TypeScript 컴파일 확인
|
||||||
|
|
||||||
### routes/companyManagementRoutes.ts
|
### routes/companyManagementRoutes.ts
|
||||||
|
|
||||||
- [ ] Prisma import 제거
|
- [ ] Prisma import 제거
|
||||||
- [ ] query, queryOne import 추가
|
- [ ] query, queryOne import 추가
|
||||||
- [ ] findUnique → queryOne
|
- [ ] findUnique → queryOne
|
||||||
|
|
@ -311,12 +347,14 @@
|
||||||
- [ ] TypeScript 컴파일 확인
|
- [ ] TypeScript 컴파일 확인
|
||||||
|
|
||||||
### services/multiConnectionQueryService.ts
|
### services/multiConnectionQueryService.ts
|
||||||
|
|
||||||
- [ ] Prisma import 제거
|
- [ ] Prisma import 제거
|
||||||
- [ ] query import 추가
|
- [ ] query import 추가
|
||||||
- [ ] $queryRawUnsafe → query (4곳)
|
- [ ] $queryRawUnsafe → query (4곳)
|
||||||
- [ ] TypeScript 컴파일 확인
|
- [ ] TypeScript 컴파일 확인
|
||||||
|
|
||||||
### config/database.ts
|
### config/database.ts
|
||||||
|
|
||||||
- [ ] 파일 전체 분석
|
- [ ] 파일 전체 분석
|
||||||
- [ ] 의존성 확인
|
- [ ] 의존성 확인
|
||||||
- [ ] 대체 방안 구현
|
- [ ] 대체 방안 구현
|
||||||
|
|
@ -328,15 +366,20 @@
|
||||||
## 🔧 전환 패턴 요약
|
## 🔧 전환 패턴 요약
|
||||||
|
|
||||||
### 1. findMany → query
|
### 1. findMany → query
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
// Before
|
// Before
|
||||||
const items = await prisma.table.findMany({ where, orderBy });
|
const items = await prisma.table.findMany({ where, orderBy });
|
||||||
|
|
||||||
// After
|
// After
|
||||||
const items = await query<T>(`SELECT * FROM table WHERE ... ORDER BY ...`, params);
|
const items = await query<T>(
|
||||||
|
`SELECT * FROM table WHERE ... ORDER BY ...`,
|
||||||
|
params
|
||||||
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. findUnique → queryOne
|
### 2. findUnique → queryOne
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
// Before
|
// Before
|
||||||
const item = await prisma.table.findUnique({ where: { id } });
|
const item = await prisma.table.findUnique({ where: { id } });
|
||||||
|
|
@ -346,6 +389,7 @@ const item = await queryOne<T>(`SELECT * FROM table WHERE id = $1`, [id]);
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3. create → queryOne with RETURNING
|
### 3. create → queryOne with RETURNING
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
// Before
|
// Before
|
||||||
const newItem = await prisma.table.create({ data });
|
const newItem = await prisma.table.create({ data });
|
||||||
|
|
@ -358,6 +402,7 @@ const [newItem] = await query<T>(
|
||||||
```
|
```
|
||||||
|
|
||||||
### 4. update → query with RETURNING
|
### 4. update → query with RETURNING
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
// Before
|
// Before
|
||||||
const updated = await prisma.table.update({ where, data });
|
const updated = await prisma.table.update({ where, data });
|
||||||
|
|
@ -370,6 +415,7 @@ const [updated] = await query<T>(
|
||||||
```
|
```
|
||||||
|
|
||||||
### 5. delete → query
|
### 5. delete → query
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
// Before
|
// Before
|
||||||
await prisma.table.delete({ where: { id } });
|
await prisma.table.delete({ where: { id } });
|
||||||
|
|
@ -379,6 +425,7 @@ await query(`DELETE FROM table WHERE id = $1`, [id]);
|
||||||
```
|
```
|
||||||
|
|
||||||
### 6. $transaction → transaction
|
### 6. $transaction → transaction
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
// Before
|
// Before
|
||||||
await prisma.$transaction([
|
await prisma.$transaction([
|
||||||
|
|
@ -394,11 +441,12 @@ await transaction(async (client) => {
|
||||||
```
|
```
|
||||||
|
|
||||||
### 7. groupBy → query with GROUP BY
|
### 7. groupBy → query with GROUP BY
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
// Before
|
// Before
|
||||||
const result = await prisma.table.groupBy({
|
const result = await prisma.table.groupBy({
|
||||||
by: ['category'],
|
by: ["category"],
|
||||||
_count: true
|
_count: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
// After
|
// After
|
||||||
|
|
@ -422,30 +470,34 @@ Phase 4.2: 남은 파일 ███████░░░░░░░░░
|
||||||
|
|
||||||
### 상세 진행 상황
|
### 상세 진행 상황
|
||||||
|
|
||||||
| 카테고리 | 완료 | 남음 | 진행률 |
|
| 카테고리 | 완료 | 남음 | 진행률 |
|
||||||
| -------------- | ---- | ---- | ------ |
|
| ----------- | ---- | ---- | ------ |
|
||||||
| Services | 415 | 0 | 100% |
|
| Services | 415 | 0 | 100% |
|
||||||
| Controllers | 30 | 11 | 73% |
|
| Controllers | 30 | 11 | 73% |
|
||||||
| Routes | 0 | 4 | 0% |
|
| Routes | 0 | 4 | 0% |
|
||||||
| Config | 0 | 4 | 0% |
|
| Config | 0 | 4 | 0% |
|
||||||
| **총계** | 445 | 19 | 95.9% |
|
| **총계** | 445 | 19 | 95.9% |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🎬 다음 단계
|
## 🎬 다음 단계
|
||||||
|
|
||||||
1. **webTypeStandardController.ts 전환** (11개)
|
1. **webTypeStandardController.ts 전환** (11개)
|
||||||
|
|
||||||
- 가장 많은 Prisma 호출을 가진 남은 컨트롤러
|
- 가장 많은 Prisma 호출을 가진 남은 컨트롤러
|
||||||
- 웹 타입 표준 관리 핵심 기능
|
- 웹 타입 표준 관리 핵심 기능
|
||||||
|
|
||||||
2. **fileController.ts 전환** (1개)
|
2. **fileController.ts 전환** (1개)
|
||||||
|
|
||||||
- 단순 findUnique만 있어 빠르게 처리 가능
|
- 단순 findUnique만 있어 빠르게 처리 가능
|
||||||
|
|
||||||
3. **Routes 전환** (4개)
|
3. **Routes 전환** (4개)
|
||||||
|
|
||||||
- ddlRoutes.ts
|
- ddlRoutes.ts
|
||||||
- companyManagementRoutes.ts
|
- companyManagementRoutes.ts
|
||||||
|
|
||||||
4. **Service 전환** (4개)
|
4. **Service 전환** (4개)
|
||||||
|
|
||||||
- multiConnectionQueryService.ts
|
- multiConnectionQueryService.ts
|
||||||
|
|
||||||
5. **Config 제거** (4개)
|
5. **Config 제거** (4개)
|
||||||
|
|
@ -457,14 +509,17 @@ Phase 4.2: 남은 파일 ███████░░░░░░░░░
|
||||||
## ⚠️ 주의사항
|
## ⚠️ 주의사항
|
||||||
|
|
||||||
1. **database.ts 처리**
|
1. **database.ts 처리**
|
||||||
|
|
||||||
- 현재 많은 파일이 `import prisma from '../config/database'` 사용
|
- 현재 많은 파일이 `import prisma from '../config/database'` 사용
|
||||||
- 모든 import를 `import { query, queryOne } from '../database/db'`로 변경 필요
|
- 모든 import를 `import { query, queryOne } from '../database/db'`로 변경 필요
|
||||||
- 단계적으로 진행하여 빌드 오류 방지
|
- 단계적으로 진행하여 빌드 오류 방지
|
||||||
|
|
||||||
2. **BigInt 처리**
|
2. **BigInt 처리**
|
||||||
|
|
||||||
- fileController의 `objid: BigInt(objid)` → `objid::bigint` 또는 `CAST(objid AS BIGINT)`
|
- fileController의 `objid: BigInt(objid)` → `objid::bigint` 또는 `CAST(objid AS BIGINT)`
|
||||||
|
|
||||||
3. **트랜잭션 처리**
|
3. **트랜잭션 처리**
|
||||||
|
|
||||||
- webTypeStandardController의 `updateSortOrder`는 복잡한 트랜잭션
|
- webTypeStandardController의 `updateSortOrder`는 복잡한 트랜잭션
|
||||||
- `transaction` 함수 사용 필요
|
- `transaction` 함수 사용 필요
|
||||||
|
|
||||||
|
|
@ -489,4 +544,3 @@ Phase 4.2: 남은 파일 ███████░░░░░░░░░
|
||||||
**작성일**: 2025-10-01
|
**작성일**: 2025-10-01
|
||||||
**최종 업데이트**: 2025-10-01
|
**최종 업데이트**: 2025-10-01
|
||||||
**상태**: 🔄 진행 중 (58.6% 완료)
|
**상태**: 🔄 진행 중 (58.6% 완료)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -723,11 +723,10 @@ export const downloadFile = async (
|
||||||
try {
|
try {
|
||||||
const { objid } = req.params;
|
const { objid } = req.params;
|
||||||
|
|
||||||
const fileRecord = await prisma.attach_file_info.findUnique({
|
const fileRecord = await queryOne<any>(
|
||||||
where: {
|
`SELECT * FROM attach_file_info WHERE objid = $1`,
|
||||||
objid: parseInt(objid),
|
[parseInt(objid)]
|
||||||
},
|
);
|
||||||
});
|
|
||||||
|
|
||||||
if (!fileRecord || fileRecord.status !== "ACTIVE") {
|
if (!fileRecord || fileRecord.status !== "ACTIVE") {
|
||||||
res.status(404).json({
|
res.status(404).json({
|
||||||
|
|
|
||||||
|
|
@ -1,39 +1,51 @@
|
||||||
import { Request, Response } from "express";
|
import { Request, Response } from "express";
|
||||||
import { PrismaClient } from "@prisma/client";
|
import { query, queryOne, transaction } from "../database/db";
|
||||||
import { AuthenticatedRequest } from "../types/auth";
|
import { AuthenticatedRequest } from "../types/auth";
|
||||||
|
|
||||||
const prisma = new PrismaClient();
|
|
||||||
|
|
||||||
export class WebTypeStandardController {
|
export class WebTypeStandardController {
|
||||||
// 웹타입 목록 조회
|
// 웹타입 목록 조회
|
||||||
static async getWebTypes(req: Request, res: Response) {
|
static async getWebTypes(req: Request, res: Response) {
|
||||||
try {
|
try {
|
||||||
const { active, category, search } = req.query;
|
const { active, category, search } = req.query;
|
||||||
|
|
||||||
const where: any = {};
|
// 동적 WHERE 절 생성
|
||||||
|
const whereConditions: string[] = [];
|
||||||
|
const queryParams: any[] = [];
|
||||||
|
let paramIndex = 1;
|
||||||
|
|
||||||
if (active) {
|
if (active) {
|
||||||
where.is_active = active as string;
|
whereConditions.push(`is_active = $${paramIndex}`);
|
||||||
|
queryParams.push(active);
|
||||||
|
paramIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (category) {
|
if (category) {
|
||||||
where.category = category as string;
|
whereConditions.push(`category = $${paramIndex}`);
|
||||||
|
queryParams.push(category);
|
||||||
|
paramIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (search) {
|
if (search && typeof search === "string") {
|
||||||
where.OR = [
|
whereConditions.push(`(
|
||||||
{ type_name: { contains: search as string, mode: "insensitive" } },
|
type_name ILIKE $${paramIndex} OR
|
||||||
{
|
type_name_eng ILIKE $${paramIndex} OR
|
||||||
type_name_eng: { contains: search as string, mode: "insensitive" },
|
description ILIKE $${paramIndex}
|
||||||
},
|
)`);
|
||||||
{ description: { contains: search as string, mode: "insensitive" } },
|
queryParams.push(`%${search}%`);
|
||||||
];
|
paramIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
const webTypes = await prisma.web_type_standards.findMany({
|
const whereClause =
|
||||||
where,
|
whereConditions.length > 0
|
||||||
orderBy: [{ sort_order: "asc" }, { web_type: "asc" }],
|
? `WHERE ${whereConditions.join(" AND ")}`
|
||||||
});
|
: "";
|
||||||
|
|
||||||
|
const webTypes = await query<any>(
|
||||||
|
`SELECT * FROM web_type_standards
|
||||||
|
${whereClause}
|
||||||
|
ORDER BY sort_order ASC, web_type ASC`,
|
||||||
|
queryParams
|
||||||
|
);
|
||||||
|
|
||||||
return res.json({
|
return res.json({
|
||||||
success: true,
|
success: true,
|
||||||
|
|
@ -55,9 +67,10 @@ export class WebTypeStandardController {
|
||||||
try {
|
try {
|
||||||
const { webType } = req.params;
|
const { webType } = req.params;
|
||||||
|
|
||||||
const webTypeData = await prisma.web_type_standards.findUnique({
|
const webTypeData = await queryOne<any>(
|
||||||
where: { web_type: webType },
|
`SELECT * FROM web_type_standards WHERE web_type = $1`,
|
||||||
});
|
[webType]
|
||||||
|
);
|
||||||
|
|
||||||
if (!webTypeData) {
|
if (!webTypeData) {
|
||||||
return res.status(404).json({
|
return res.status(404).json({
|
||||||
|
|
@ -109,9 +122,10 @@ export class WebTypeStandardController {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 중복 체크
|
// 중복 체크
|
||||||
const existingWebType = await prisma.web_type_standards.findUnique({
|
const existingWebType = await queryOne<any>(
|
||||||
where: { web_type },
|
`SELECT web_type FROM web_type_standards WHERE web_type = $1`,
|
||||||
});
|
[web_type]
|
||||||
|
);
|
||||||
|
|
||||||
if (existingWebType) {
|
if (existingWebType) {
|
||||||
return res.status(409).json({
|
return res.status(409).json({
|
||||||
|
|
@ -120,8 +134,15 @@ export class WebTypeStandardController {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const newWebType = await prisma.web_type_standards.create({
|
const [newWebType] = await query<any>(
|
||||||
data: {
|
`INSERT INTO web_type_standards (
|
||||||
|
web_type, type_name, type_name_eng, description, category,
|
||||||
|
component_name, config_panel, default_config, validation_rules,
|
||||||
|
default_style, input_properties, sort_order, is_active,
|
||||||
|
created_by, created_date, updated_by, updated_date
|
||||||
|
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, NOW(), $15, NOW())
|
||||||
|
RETURNING *`,
|
||||||
|
[
|
||||||
web_type,
|
web_type,
|
||||||
type_name,
|
type_name,
|
||||||
type_name_eng,
|
type_name_eng,
|
||||||
|
|
@ -135,10 +156,10 @@ export class WebTypeStandardController {
|
||||||
input_properties,
|
input_properties,
|
||||||
sort_order,
|
sort_order,
|
||||||
is_active,
|
is_active,
|
||||||
created_by: req.user?.userId || "system",
|
req.user?.userId || "system",
|
||||||
updated_by: req.user?.userId || "system",
|
req.user?.userId || "system",
|
||||||
},
|
]
|
||||||
});
|
);
|
||||||
|
|
||||||
return res.status(201).json({
|
return res.status(201).json({
|
||||||
success: true,
|
success: true,
|
||||||
|
|
@ -174,37 +195,106 @@ export class WebTypeStandardController {
|
||||||
is_active,
|
is_active,
|
||||||
} = req.body;
|
} = req.body;
|
||||||
|
|
||||||
// 존재 여부 확인
|
// 동적 UPDATE 쿼리 생성
|
||||||
const existingWebType = await prisma.web_type_standards.findUnique({
|
const updateFields: string[] = [];
|
||||||
where: { web_type: webType },
|
const updateValues: any[] = [];
|
||||||
});
|
let paramIndex = 1;
|
||||||
|
|
||||||
if (!existingWebType) {
|
if (type_name !== undefined) {
|
||||||
|
updateFields.push(`type_name = $${paramIndex}`);
|
||||||
|
updateValues.push(type_name);
|
||||||
|
paramIndex++;
|
||||||
|
}
|
||||||
|
if (type_name_eng !== undefined) {
|
||||||
|
updateFields.push(`type_name_eng = $${paramIndex}`);
|
||||||
|
updateValues.push(type_name_eng);
|
||||||
|
paramIndex++;
|
||||||
|
}
|
||||||
|
if (description !== undefined) {
|
||||||
|
updateFields.push(`description = $${paramIndex}`);
|
||||||
|
updateValues.push(description);
|
||||||
|
paramIndex++;
|
||||||
|
}
|
||||||
|
if (category !== undefined) {
|
||||||
|
updateFields.push(`category = $${paramIndex}`);
|
||||||
|
updateValues.push(category);
|
||||||
|
paramIndex++;
|
||||||
|
}
|
||||||
|
if (component_name !== undefined) {
|
||||||
|
updateFields.push(`component_name = $${paramIndex}`);
|
||||||
|
updateValues.push(component_name);
|
||||||
|
paramIndex++;
|
||||||
|
}
|
||||||
|
if (config_panel !== undefined) {
|
||||||
|
updateFields.push(`config_panel = $${paramIndex}`);
|
||||||
|
updateValues.push(config_panel);
|
||||||
|
paramIndex++;
|
||||||
|
}
|
||||||
|
if (default_config !== undefined) {
|
||||||
|
updateFields.push(`default_config = $${paramIndex}`);
|
||||||
|
updateValues.push(default_config);
|
||||||
|
paramIndex++;
|
||||||
|
}
|
||||||
|
if (validation_rules !== undefined) {
|
||||||
|
updateFields.push(`validation_rules = $${paramIndex}`);
|
||||||
|
updateValues.push(validation_rules);
|
||||||
|
paramIndex++;
|
||||||
|
}
|
||||||
|
if (default_style !== undefined) {
|
||||||
|
updateFields.push(`default_style = $${paramIndex}`);
|
||||||
|
updateValues.push(default_style);
|
||||||
|
paramIndex++;
|
||||||
|
}
|
||||||
|
if (input_properties !== undefined) {
|
||||||
|
updateFields.push(`input_properties = $${paramIndex}`);
|
||||||
|
updateValues.push(input_properties);
|
||||||
|
paramIndex++;
|
||||||
|
}
|
||||||
|
if (sort_order !== undefined) {
|
||||||
|
updateFields.push(`sort_order = $${paramIndex}`);
|
||||||
|
updateValues.push(sort_order);
|
||||||
|
paramIndex++;
|
||||||
|
}
|
||||||
|
if (is_active !== undefined) {
|
||||||
|
updateFields.push(`is_active = $${paramIndex}`);
|
||||||
|
updateValues.push(is_active);
|
||||||
|
paramIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// updated_by, updated_date는 항상 추가
|
||||||
|
updateFields.push(`updated_by = $${paramIndex}`);
|
||||||
|
updateValues.push(req.user?.userId || "system");
|
||||||
|
paramIndex++;
|
||||||
|
|
||||||
|
updateFields.push(`updated_date = NOW()`);
|
||||||
|
|
||||||
|
if (updateFields.length === 2) {
|
||||||
|
// updated_by, updated_date만 있는 경우 = 수정할 내용이 없음
|
||||||
|
return res.status(400).json({
|
||||||
|
success: false,
|
||||||
|
message: "수정할 내용이 없습니다.",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// WHERE 조건용 파라미터 추가
|
||||||
|
updateValues.push(webType);
|
||||||
|
|
||||||
|
const result = await query<any>(
|
||||||
|
`UPDATE web_type_standards
|
||||||
|
SET ${updateFields.join(", ")}
|
||||||
|
WHERE web_type = $${paramIndex}
|
||||||
|
RETURNING *`,
|
||||||
|
updateValues
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result.length === 0) {
|
||||||
return res.status(404).json({
|
return res.status(404).json({
|
||||||
success: false,
|
success: false,
|
||||||
message: "해당 웹타입을 찾을 수 없습니다.",
|
message: "해당 웹타입을 찾을 수 없습니다.",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const updatedWebType = await prisma.web_type_standards.update({
|
const updatedWebType = result[0];
|
||||||
where: { web_type: webType },
|
|
||||||
data: {
|
|
||||||
type_name,
|
|
||||||
type_name_eng,
|
|
||||||
description,
|
|
||||||
category,
|
|
||||||
component_name,
|
|
||||||
config_panel,
|
|
||||||
default_config,
|
|
||||||
validation_rules,
|
|
||||||
default_style,
|
|
||||||
input_properties,
|
|
||||||
sort_order,
|
|
||||||
is_active,
|
|
||||||
updated_by: req.user?.userId || "system",
|
|
||||||
updated_date: new Date(),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return res.json({
|
return res.json({
|
||||||
success: true,
|
success: true,
|
||||||
|
|
@ -226,22 +316,18 @@ export class WebTypeStandardController {
|
||||||
try {
|
try {
|
||||||
const { webType } = req.params;
|
const { webType } = req.params;
|
||||||
|
|
||||||
// 존재 여부 확인
|
const result = await query<any>(
|
||||||
const existingWebType = await prisma.web_type_standards.findUnique({
|
`DELETE FROM web_type_standards WHERE web_type = $1 RETURNING *`,
|
||||||
where: { web_type: webType },
|
[webType]
|
||||||
});
|
);
|
||||||
|
|
||||||
if (!existingWebType) {
|
if (result.length === 0) {
|
||||||
return res.status(404).json({
|
return res.status(404).json({
|
||||||
success: false,
|
success: false,
|
||||||
message: "해당 웹타입을 찾을 수 없습니다.",
|
message: "해당 웹타입을 찾을 수 없습니다.",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
await prisma.web_type_standards.delete({
|
|
||||||
where: { web_type: webType },
|
|
||||||
});
|
|
||||||
|
|
||||||
return res.json({
|
return res.json({
|
||||||
success: true,
|
success: true,
|
||||||
message: "웹타입이 성공적으로 삭제되었습니다.",
|
message: "웹타입이 성공적으로 삭제되었습니다.",
|
||||||
|
|
@ -272,18 +358,16 @@ export class WebTypeStandardController {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 트랜잭션으로 일괄 업데이트
|
// 트랜잭션으로 일괄 업데이트
|
||||||
await prisma.$transaction(
|
await transaction(async (client) => {
|
||||||
webTypes.map((item) =>
|
for (const item of webTypes) {
|
||||||
prisma.web_type_standards.update({
|
await client.query(
|
||||||
where: { web_type: item.web_type },
|
`UPDATE web_type_standards
|
||||||
data: {
|
SET sort_order = $1, updated_by = $2, updated_date = NOW()
|
||||||
sort_order: item.sort_order,
|
WHERE web_type = $3`,
|
||||||
updated_by: req.user?.userId || "system",
|
[item.sort_order, req.user?.userId || "system", item.web_type]
|
||||||
updated_date: new Date(),
|
);
|
||||||
},
|
}
|
||||||
})
|
});
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
return res.json({
|
return res.json({
|
||||||
success: true,
|
success: true,
|
||||||
|
|
@ -302,19 +386,17 @@ export class WebTypeStandardController {
|
||||||
// 웹타입 카테고리 목록 조회
|
// 웹타입 카테고리 목록 조회
|
||||||
static async getWebTypeCategories(req: Request, res: Response) {
|
static async getWebTypeCategories(req: Request, res: Response) {
|
||||||
try {
|
try {
|
||||||
const categories = await prisma.web_type_standards.groupBy({
|
const categories = await query<{ category: string; count: string }>(
|
||||||
by: ["category"],
|
`SELECT category, COUNT(*) as count
|
||||||
where: {
|
FROM web_type_standards
|
||||||
is_active: "Y",
|
WHERE is_active = 'Y'
|
||||||
},
|
GROUP BY category`,
|
||||||
_count: {
|
[]
|
||||||
category: true,
|
);
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const categoryList = categories.map((item) => ({
|
const categoryList = categories.map((item) => ({
|
||||||
category: item.category,
|
category: item.category,
|
||||||
count: item._count.category,
|
count: parseInt(item.count, 10),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return res.json({
|
return res.json({
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue