ERP-node/.cursor/rules/database-guide.mdc

146 lines
3.1 KiB
Plaintext
Raw Normal View History

2025-08-21 09:41:46 +09:00
---
description:
globs:
2025-08-21 09:41:46 +09:00
alwaysApply: true
---
2025-08-21 09:41:46 +09:00
# 데이터베이스 가이드
## 데이터베이스 설정
### PostgreSQL 연결
- **드라이버**: `pg` (node-postgres)
- **설정 파일**: `backend-node/src/config/database.ts`
- **환경 변수**: `backend-node/.env` (DATABASE_URL)
### 연결 풀 사용
```typescript
import { Pool } from 'pg';
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
max: 20,
idleTimeoutMillis: 30000,
});
```
## 쿼리 패턴
### 기본 CRUD
```typescript
// SELECT
const result = await pool.query(
'SELECT * FROM example_table WHERE company_code = $1 ORDER BY created_at DESC',
[companyCode]
);
// INSERT
const result = await pool.query(
'INSERT INTO example_table (company_code, name) VALUES ($1, $2) RETURNING *',
[companyCode, name]
);
// UPDATE
const result = await pool.query(
'UPDATE example_table SET name = $1, updated_at = NOW() WHERE id = $2 AND company_code = $3 RETURNING *',
[name, id, companyCode]
);
// DELETE
const result = await pool.query(
'DELETE FROM example_table WHERE id = $1 AND company_code = $2 RETURNING id',
[id, companyCode]
);
2025-08-21 09:41:46 +09:00
```
### 트랜잭션 처리
```typescript
const client = await pool.connect();
try {
await client.query('BEGIN');
await client.query('INSERT INTO ...', [params]);
await client.query('UPDATE ...', [params]);
await client.query('COMMIT');
} catch (e) {
await client.query('ROLLBACK');
throw e;
} finally {
client.release();
2025-08-21 09:41:46 +09:00
}
```
### 동적 조건 처리
```typescript
const conditions: string[] = ['company_code = $1'];
const params: any[] = [companyCode];
let paramIndex = 2;
2025-08-21 09:41:46 +09:00
if (searchText) {
conditions.push(`name ILIKE $${paramIndex}`);
params.push(`%${searchText}%`);
paramIndex++;
}
2025-08-21 09:41:46 +09:00
if (status) {
conditions.push(`status = $${paramIndex}`);
params.push(status);
paramIndex++;
}
2025-08-21 09:41:46 +09:00
const query = `SELECT * FROM example_table WHERE ${conditions.join(' AND ')} ORDER BY created_at DESC`;
const result = await pool.query(query, params);
2025-08-21 09:41:46 +09:00
```
## 주요 테이블 구조
### 메뉴 관리
- **menu_info**: 메뉴 정보
- **menu_auth_group**: 메뉴 권한 그룹
- **auth_group**: 권한 그룹 정보
2025-08-21 09:41:46 +09:00
### 사용자 관리
- **user_info**: 사용자 정보
- **dept_info**: 부서 정보
- **user_auth**: 사용자 권한
2025-08-21 09:41:46 +09:00
### 코드 관리
- **code_info**: 공통 코드
- **code_category**: 코드 카테고리
2025-08-21 09:41:46 +09:00
## 마이그레이션
2025-08-21 09:41:46 +09:00
마이그레이션 파일은 `db/migrations/` 디렉토리에 순번으로 관리:
2025-08-21 09:41:46 +09:00
```
db/migrations/
├── 001_initial_schema.sql
├── 002_add_company_code.sql
├── ...
└── 1021_create_numbering_audit_log.sql
2025-08-21 09:41:46 +09:00
```
## 성능 최적화
### 인덱스 활용
```sql
CREATE INDEX idx_example_company_code ON example_table(company_code);
2025-08-21 09:41:46 +09:00
CREATE INDEX idx_user_dept ON user_info(dept_code);
```
### 페이징 처리
```typescript
const query = `
SELECT * FROM example_table
WHERE company_code = $1
ORDER BY created_at DESC
LIMIT $2 OFFSET $3
`;
const result = await pool.query(query, [companyCode, limit, offset]);
2025-08-21 09:41:46 +09:00
```
### 슬로우 쿼리 확인
```sql
SELECT query, mean_time, calls
FROM pg_stat_statements
ORDER BY mean_time DESC;
```