# ๐Ÿ“‹ Phase 3.15: Batch Services Raw Query ์ „ํ™˜ ๊ณ„ํš ## ๐Ÿ“‹ ๊ฐœ์š” ๋ฐฐ์น˜ ๊ด€๋ จ ์„œ๋น„์Šค๋“ค์€ ์ด **24๊ฐœ์˜ Prisma ํ˜ธ์ถœ**์ด ์žˆ์œผ๋ฉฐ, ๋ฐฐ์น˜ ์ž‘์—… ์‹คํ–‰ ๋ฐ ๊ด€๋ฆฌ๋ฅผ ๋‹ด๋‹นํ•ฉ๋‹ˆ๋‹ค. ### ๐Ÿ“Š ๊ธฐ๋ณธ ์ •๋ณด | ํ•ญ๋ชฉ | ๋‚ด์šฉ | | --------------- | ---------------------------------------------------------- | | ๋Œ€์ƒ ์„œ๋น„์Šค | 4๊ฐœ (BatchExternalDb, ExecutionLog, Management, Scheduler) | | ํŒŒ์ผ ์œ„์น˜ | `backend-node/src/services/batch*.ts` | | ์ด ํŒŒ์ผ ํฌ๊ธฐ | 2,161 ๋ผ์ธ | | Prisma ํ˜ธ์ถœ | 0๊ฐœ (์ „ํ™˜ ์™„๋ฃŒ) | | **ํ˜„์žฌ ์ง„ํ–‰๋ฅ ** | **24/24 (100%)** โœ… **์ „ํ™˜ ์™„๋ฃŒ** | | ๋ณต์žก๋„ | ๋†’์Œ (์™ธ๋ถ€ DB ์—ฐ๋™, ์Šค์ผ€์ค„๋ง, ํŠธ๋žœ์žญ์…˜) | | ์šฐ์„ ์ˆœ์œ„ | ๐Ÿ”ด ๋†’์Œ (Phase 3.15) | | **์ƒํƒœ** | โœ… **์™„๋ฃŒ** | --- ## โœ… ์ „ํ™˜ ์™„๋ฃŒ ๋‚ด์—ญ ### ์ „ํ™˜๋œ Prisma ํ˜ธ์ถœ (24๊ฐœ) #### 1. BatchExternalDbService (8๊ฐœ) - `getAvailableConnections()` - findMany โ†’ query - `getTables()` - $queryRaw โ†’ query (information_schema) - `getTableColumns()` - $queryRaw โ†’ query (information_schema) - `getExternalTables()` - findUnique โ†’ queryOne (x5) #### 2. BatchExecutionLogService (7๊ฐœ) - `getExecutionLogs()` - findMany + count โ†’ query (JOIN + ๋™์  WHERE) - `createExecutionLog()` - create โ†’ queryOne (INSERT RETURNING) - `updateExecutionLog()` - update โ†’ queryOne (๋™์  UPDATE) - `deleteExecutionLog()` - delete โ†’ query - `getLatestExecutionLog()` - findFirst โ†’ queryOne - `getExecutionStats()` - findMany โ†’ query (๋™์  WHERE) #### 3. BatchManagementService (5๊ฐœ) - `getAvailableConnections()` - findMany โ†’ query - `getTables()` - $queryRaw โ†’ query (information_schema) - `getTableColumns()` - $queryRaw โ†’ query (information_schema) - `getExternalTables()` - findUnique โ†’ queryOne (x2) #### 4. BatchSchedulerService (4๊ฐœ) - `loadActiveBatchConfigs()` - findMany โ†’ query (JOIN with json_agg) - `updateBatchSchedule()` - findUnique โ†’ query (JOIN with json_agg) - `getDataFromSource()` - $queryRawUnsafe โ†’ query - `insertDataToTarget()` - $executeRawUnsafe โ†’ query ### ์ฃผ์š” ๊ธฐ์ˆ ์  ํ•ด๊ฒฐ ์‚ฌํ•ญ 1. **์™ธ๋ถ€ DB ์—ฐ๊ฒฐ ์กฐํšŒ ๋ฐ˜๋ณต** - 5๊ฐœ์˜ `findUnique` ํ˜ธ์ถœ์„ `queryOne`์œผ๋กœ ์ผ๊ด„ ์ „ํ™˜ - ์•”ํ˜ธํ™”/๋ณตํ˜ธํ™” ๋กœ์ง ์œ ์ง€ 2. **๋ฐฐ์น˜ ์„ค์ • + ๋งคํ•‘ JOIN** - Prisma `include` โ†’ `json_agg` + `json_build_object` - `FILTER (WHERE bm.id IS NOT NULL)` ๋กœ NULL ๋ฐฉ์ง€ - ๊ณ„์ธต์  JSON ๋ฐ์ดํ„ฐ ์ƒ์„ฑ 3. **๋™์  WHERE ์ ˆ ์ƒ์„ฑ** - ์กฐ๊ฑด๋ถ€ ํ•„ํ„ฐ๋ง (batch_config_id, execution_status, ๋‚ ์งœ ๋ฒ”์œ„) - ํŒŒ๋ผ๋ฏธํ„ฐ ์ธ๋ฑ์Šค ๋™์  ๊ด€๋ฆฌ 4. **๋™์  UPDATE ์ฟผ๋ฆฌ** - undefined ํ•„๋“œ ์ œ์™ธ - 8๊ฐœ ํ•„๋“œ์˜ ์กฐ๊ฑด๋ถ€ ์—…๋ฐ์ดํŠธ 5. **ํ†ต๊ณ„ ์ฟผ๋ฆฌ ์ „ํ™˜** - ํด๋ผ์ด์–ธํŠธ ์‚ฌ์ด๋“œ ์ง‘๊ณ„ ์œ ์ง€ - ์›๋ณธ ๋ฐ์ดํ„ฐ๋งŒ ์ฟผ๋ฆฌ๋กœ ์กฐํšŒ ### ์ปดํŒŒ์ผ ์ƒํƒœ โœ… TypeScript ์ปดํŒŒ์ผ ์„ฑ๊ณต โœ… Linter ์˜ค๋ฅ˜ ์—†์Œ --- ## ๐Ÿ” ์„œ๋น„์Šค๋ณ„ ์ƒ์„ธ ๋ถ„์„ ### 1. BatchExternalDbService (8๊ฐœ ํ˜ธ์ถœ, 943 ๋ผ์ธ) **์ฃผ์š” ๊ธฐ๋Šฅ**: - ์™ธ๋ถ€ DB์—์„œ ๋ฐฐ์น˜ ๋ฐ์ดํ„ฐ ์กฐํšŒ - ์™ธ๋ถ€ DB๋กœ ๋ฐฐ์น˜ ๋ฐ์ดํ„ฐ ์ €์žฅ - ์™ธ๋ถ€ DB ์—ฐ๊ฒฐ ๊ด€๋ฆฌ - ๋ฐ์ดํ„ฐ ๋ณ€ํ™˜ ๋ฐ ๋งคํ•‘ **์˜ˆ์ƒ Prisma ํ˜ธ์ถœ**: - `getExternalDbConnection()` - ์™ธ๋ถ€ DB ์—ฐ๊ฒฐ ์ •๋ณด ์กฐํšŒ - `fetchDataFromExternalDb()` - ์™ธ๋ถ€ DB ๋ฐ์ดํ„ฐ ์กฐํšŒ - `saveDataToExternalDb()` - ์™ธ๋ถ€ DB ๋ฐ์ดํ„ฐ ์ €์žฅ - `validateExternalDbConnection()` - ์—ฐ๊ฒฐ ๊ฒ€์ฆ - `getExternalDbTables()` - ํ…Œ์ด๋ธ” ๋ชฉ๋ก ์กฐํšŒ - `getExternalDbColumns()` - ์ปฌ๋Ÿผ ์ •๋ณด ์กฐํšŒ - `executeBatchQuery()` - ๋ฐฐ์น˜ ์ฟผ๋ฆฌ ์‹คํ–‰ - `getBatchExecutionStatus()` - ์‹คํ–‰ ์ƒํƒœ ์กฐํšŒ **๊ธฐ์ˆ ์  ๊ณ ๋ ค์‚ฌํ•ญ**: - ๋‹ค์–‘ํ•œ DB ํƒ€์ž… ์ง€์› (PostgreSQL, MySQL, Oracle, MSSQL) - ์—ฐ๊ฒฐ ํ’€ ๊ด€๋ฆฌ - ํŠธ๋žœ์žญ์…˜ ์ฒ˜๋ฆฌ - ์—๋Ÿฌ ํ•ธ๋“ค๋ง ๋ฐ ์žฌ์‹œ๋„ --- ### 2. BatchExecutionLogService (7๊ฐœ ํ˜ธ์ถœ, 299 ๋ผ์ธ) **์ฃผ์š” ๊ธฐ๋Šฅ**: - ๋ฐฐ์น˜ ์‹คํ–‰ ๋กœ๊ทธ ์ƒ์„ฑ - ๋ฐฐ์น˜ ์‹คํ–‰ ์ด๋ ฅ ์กฐํšŒ - ๋ฐฐ์น˜ ์‹คํ–‰ ํ†ต๊ณ„ - ๋กœ๊ทธ ์ •๋ฆฌ **์˜ˆ์ƒ Prisma ํ˜ธ์ถœ**: - `createExecutionLog()` - ์‹คํ–‰ ๋กœ๊ทธ ์ƒ์„ฑ - `updateExecutionLog()` - ์‹คํ–‰ ๋กœ๊ทธ ์—…๋ฐ์ดํŠธ - `getExecutionLogs()` - ์‹คํ–‰ ๋กœ๊ทธ ๋ชฉ๋ก ์กฐํšŒ - `getExecutionLogById()` - ์‹คํ–‰ ๋กœ๊ทธ ๋‹จ๊ฑด ์กฐํšŒ - `getExecutionStats()` - ์‹คํ–‰ ํ†ต๊ณ„ ์กฐํšŒ - `cleanupOldLogs()` - ์˜ค๋ž˜๋œ ๋กœ๊ทธ ์‚ญ์ œ - `getFailedExecutions()` - ์‹คํŒจํ•œ ์‹คํ–‰ ์กฐํšŒ **๊ธฐ์ˆ ์  ๊ณ ๋ ค์‚ฌํ•ญ**: - ๋Œ€์šฉ๋Ÿ‰ ๋กœ๊ทธ ์ฒ˜๋ฆฌ - ํ†ต๊ณ„ ์ฟผ๋ฆฌ ์ตœ์ ํ™” - ๋กœ๊ทธ ๋ณด๊ด€ ์ •์ฑ… - ํŽ˜์ด์ง• ๋ฐ ํ•„ํ„ฐ๋ง --- ### 3. BatchManagementService (5๊ฐœ ํ˜ธ์ถœ, 373 ๋ผ์ธ) **์ฃผ์š” ๊ธฐ๋Šฅ**: - ๋ฐฐ์น˜ ์ž‘์—… ์„ค์ • ๊ด€๋ฆฌ - ๋ฐฐ์น˜ ์ž‘์—… ์‹คํ–‰ - ๋ฐฐ์น˜ ์ž‘์—… ์ค‘์ง€ - ๋ฐฐ์น˜ ์ž‘์—… ๋ชจ๋‹ˆํ„ฐ๋ง **์˜ˆ์ƒ Prisma ํ˜ธ์ถœ**: - `getBatchJobs()` - ๋ฐฐ์น˜ ์ž‘์—… ๋ชฉ๋ก ์กฐํšŒ - `getBatchJob()` - ๋ฐฐ์น˜ ์ž‘์—… ๋‹จ๊ฑด ์กฐํšŒ - `createBatchJob()` - ๋ฐฐ์น˜ ์ž‘์—… ์ƒ์„ฑ - `updateBatchJob()` - ๋ฐฐ์น˜ ์ž‘์—… ์ˆ˜์ • - `deleteBatchJob()` - ๋ฐฐ์น˜ ์ž‘์—… ์‚ญ์ œ **๊ธฐ์ˆ ์  ๊ณ ๋ ค์‚ฌํ•ญ**: - JSON ์„ค์ • ํ•„๋“œ (job_config) - ์ž‘์—… ์ƒํƒœ ๊ด€๋ฆฌ - ๋™์‹œ ์‹คํ–‰ ์ œ์–ด - ์˜์กด์„ฑ ๊ด€๋ฆฌ --- ### 4. BatchSchedulerService (4๊ฐœ ํ˜ธ์ถœ, 546 ๋ผ์ธ) **์ฃผ์š” ๊ธฐ๋Šฅ**: - ๋ฐฐ์น˜ ์Šค์ผ€์ค„ ์„ค์ • - Cron ํ‘œํ˜„์‹ ๊ด€๋ฆฌ - ์Šค์ผ€์ค„ ์‹คํ–‰ - ๋‹ค์Œ ์‹คํ–‰ ์‹œ๊ฐ„ ๊ณ„์‚ฐ **์˜ˆ์ƒ Prisma ํ˜ธ์ถœ**: - `getScheduledBatches()` - ์Šค์ผ€์ค„๋œ ๋ฐฐ์น˜ ์กฐํšŒ - `createSchedule()` - ์Šค์ผ€์ค„ ์ƒ์„ฑ - `updateSchedule()` - ์Šค์ผ€์ค„ ์ˆ˜์ • - `deleteSchedule()` - ์Šค์ผ€์ค„ ์‚ญ์ œ **๊ธฐ์ˆ ์  ๊ณ ๋ ค์‚ฌํ•ญ**: - Cron ํ‘œํ˜„์‹ ํŒŒ์‹ฑ - ์‹œ๊ฐ„๋Œ€ ์ฒ˜๋ฆฌ - ์‹คํ–‰ ์ด๋ ฅ ์ถ”์  - ์Šค์ผ€์ค„ ์ถฉ๋Œ ๋ฐฉ์ง€ --- ## ๐Ÿ’ก ํ†ตํ•ฉ ์ „ํ™˜ ์ „๋žต ### Phase 1: ํ•ต์‹ฌ ์„œ๋น„์Šค ์ „ํ™˜ (12๊ฐœ) **BatchManagementService (5๊ฐœ) + BatchExecutionLogService (7๊ฐœ)** - ๋ฐฐ์น˜ ๊ด€๋ฆฌ ๋ฐ ๋กœ๊น… ๊ธฐ๋Šฅ ์šฐ์„  - ์ƒ๋Œ€์ ์œผ๋กœ ๋‹จ์ˆœํ•œ CRUD ### Phase 2: ์Šค์ผ€์ค„๋Ÿฌ ์ „ํ™˜ (4๊ฐœ) **BatchSchedulerService (4๊ฐœ)** - ์Šค์ผ€์ค„ ๊ด€๋ฆฌ - Cron ํ‘œํ˜„์‹ ์ฒ˜๋ฆฌ ### Phase 3: ์™ธ๋ถ€ DB ์—ฐ๋™ ์ „ํ™˜ (8๊ฐœ) **BatchExternalDbService (8๊ฐœ)** - ๊ฐ€์žฅ ๋ณต์žกํ•œ ์„œ๋น„์Šค - ์™ธ๋ถ€ DB ์—ฐ๊ฒฐ ๋ฐ ์ฟผ๋ฆฌ --- ## ๐Ÿ’ป ์ „ํ™˜ ์˜ˆ์‹œ ### ์˜ˆ์‹œ 1: ๋ฐฐ์น˜ ์‹คํ–‰ ๋กœ๊ทธ ์ƒ์„ฑ **๋ณ€๊ฒฝ ์ „**: ```typescript const log = await prisma.batch_execution_logs.create({ data: { batch_id: batchId, status: "running", started_at: new Date(), execution_params: params, company_code: companyCode, }, }); ``` **๋ณ€๊ฒฝ ํ›„**: ```typescript const log = await queryOne( `INSERT INTO batch_execution_logs (batch_id, status, started_at, execution_params, company_code) VALUES ($1, $2, NOW(), $3, $4) RETURNING *`, [batchId, "running", JSON.stringify(params), companyCode] ); ``` ### ์˜ˆ์‹œ 2: ๋ฐฐ์น˜ ํ†ต๊ณ„ ์กฐํšŒ **๋ณ€๊ฒฝ ์ „**: ```typescript const stats = await prisma.batch_execution_logs.groupBy({ by: ["status"], where: { batch_id: batchId, started_at: { gte: startDate, lte: endDate }, }, _count: { id: true }, }); ``` **๋ณ€๊ฒฝ ํ›„**: ```typescript const stats = await query<{ status: string; count: string }>( `SELECT status, COUNT(*) as count FROM batch_execution_logs WHERE batch_id = $1 AND started_at >= $2 AND started_at <= $3 GROUP BY status`, [batchId, startDate, endDate] ); ``` ### ์˜ˆ์‹œ 3: ์™ธ๋ถ€ DB ์—ฐ๊ฒฐ ๋ฐ ์ฟผ๋ฆฌ **๋ณ€๊ฒฝ ์ „**: ```typescript // ์—ฐ๊ฒฐ ์ •๋ณด ์กฐํšŒ const connection = await prisma.external_db_connections.findUnique({ where: { id: connectionId }, }); // ์™ธ๋ถ€ DB ์ฟผ๋ฆฌ ์‹คํ–‰ (Prisma ์‚ฌ์šฉ ๋ถˆ๊ฐ€, ์ด๋ฏธ Raw Query์ผ ๊ฐ€๋Šฅ์„ฑ) const externalData = await externalDbClient.query(sql); ``` **๋ณ€๊ฒฝ ํ›„**: ```typescript // ์—ฐ๊ฒฐ ์ •๋ณด ์กฐํšŒ const connection = await queryOne( `SELECT * FROM external_db_connections WHERE id = $1`, [connectionId] ); // ์™ธ๋ถ€ DB ์ฟผ๋ฆฌ ์‹คํ–‰ (๊ธฐ์กด ๋กœ์ง ์œ ์ง€) const externalData = await externalDbClient.query(sql); ``` ### ์˜ˆ์‹œ 4: ์Šค์ผ€์ค„ ๊ด€๋ฆฌ **๋ณ€๊ฒฝ ์ „**: ```typescript const schedule = await prisma.batch_schedules.create({ data: { batch_id: batchId, cron_expression: cronExp, is_active: true, next_run_at: calculateNextRun(cronExp), }, }); ``` **๋ณ€๊ฒฝ ํ›„**: ```typescript const nextRun = calculateNextRun(cronExp); const schedule = await queryOne( `INSERT INTO batch_schedules (batch_id, cron_expression, is_active, next_run_at, created_at, updated_at) VALUES ($1, $2, $3, $4, NOW(), NOW()) RETURNING *`, [batchId, cronExp, true, nextRun] ); ``` --- ## ๐Ÿ”ง ๊ธฐ์ˆ ์  ๊ณ ๋ ค์‚ฌํ•ญ ### 1. ์™ธ๋ถ€ DB ์—ฐ๊ฒฐ ๊ด€๋ฆฌ ```typescript import { DatabaseConnectorFactory } from "../database/connectorFactory"; // ์™ธ๋ถ€ DB ์—ฐ๊ฒฐ ์ƒ์„ฑ const connector = DatabaseConnectorFactory.create(connection); const externalClient = await connector.connect(); try { // ์ฟผ๋ฆฌ ์‹คํ–‰ const result = await externalClient.query(sql, params); } finally { await connector.disconnect(); } ``` ### 2. ํŠธ๋žœ์žญ์…˜ ์ฒ˜๋ฆฌ ```typescript await transaction(async (client) => { // ๋ฐฐ์น˜ ์ƒํƒœ ์—…๋ฐ์ดํŠธ await client.query(`UPDATE batch_jobs SET status = $1 WHERE id = $2`, [ "running", batchId, ]); // ์‹คํ–‰ ๋กœ๊ทธ ์ƒ์„ฑ await client.query( `INSERT INTO batch_execution_logs (batch_id, status, started_at) VALUES ($1, $2, NOW())`, [batchId, "running"] ); }); ``` ### 3. Cron ํ‘œํ˜„์‹ ์ฒ˜๋ฆฌ ```typescript import cron from "node-cron"; // Cron ํ‘œํ˜„์‹ ๊ฒ€์ฆ const isValid = cron.validate(cronExpression); // ๋‹ค์Œ ์‹คํ–‰ ์‹œ๊ฐ„ ๊ณ„์‚ฐ function calculateNextRun(cronExp: string): Date { // Cron ํŒŒ์„œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋‹ค์Œ ์‹คํ–‰ ์‹œ๊ฐ„ ๊ณ„์‚ฐ // ... } ``` ### 4. ๋Œ€์šฉ๋Ÿ‰ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ```typescript // ์ŠคํŠธ๋ฆฌ๋ฐ ๋ฐฉ์‹์œผ๋กœ ๋Œ€์šฉ๋Ÿ‰ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ const stream = await query( `SELECT * FROM large_table WHERE batch_id = $1`, [batchId] ); for await (const row of stream) { // ํ–‰ ๋‹จ์œ„ ์ฒ˜๋ฆฌ } ``` --- ## ๐Ÿ“ ์ „ํ™˜ ์ฒดํฌ๋ฆฌ์ŠคํŠธ ### BatchExternalDbService (8๊ฐœ) - [ ] `getExternalDbConnection()` - ์—ฐ๊ฒฐ ์ •๋ณด ์กฐํšŒ - [ ] `fetchDataFromExternalDb()` - ์™ธ๋ถ€ DB ๋ฐ์ดํ„ฐ ์กฐํšŒ - [ ] `saveDataToExternalDb()` - ์™ธ๋ถ€ DB ๋ฐ์ดํ„ฐ ์ €์žฅ - [ ] `validateExternalDbConnection()` - ์—ฐ๊ฒฐ ๊ฒ€์ฆ - [ ] `getExternalDbTables()` - ํ…Œ์ด๋ธ” ๋ชฉ๋ก ์กฐํšŒ - [ ] `getExternalDbColumns()` - ์ปฌ๋Ÿผ ์ •๋ณด ์กฐํšŒ - [ ] `executeBatchQuery()` - ๋ฐฐ์น˜ ์ฟผ๋ฆฌ ์‹คํ–‰ - [ ] `getBatchExecutionStatus()` - ์‹คํ–‰ ์ƒํƒœ ์กฐํšŒ ### BatchExecutionLogService (7๊ฐœ) - [ ] `createExecutionLog()` - ์‹คํ–‰ ๋กœ๊ทธ ์ƒ์„ฑ - [ ] `updateExecutionLog()` - ์‹คํ–‰ ๋กœ๊ทธ ์—…๋ฐ์ดํŠธ - [ ] `getExecutionLogs()` - ์‹คํ–‰ ๋กœ๊ทธ ๋ชฉ๋ก ์กฐํšŒ - [ ] `getExecutionLogById()` - ์‹คํ–‰ ๋กœ๊ทธ ๋‹จ๊ฑด ์กฐํšŒ - [ ] `getExecutionStats()` - ์‹คํ–‰ ํ†ต๊ณ„ ์กฐํšŒ - [ ] `cleanupOldLogs()` - ์˜ค๋ž˜๋œ ๋กœ๊ทธ ์‚ญ์ œ - [ ] `getFailedExecutions()` - ์‹คํŒจํ•œ ์‹คํ–‰ ์กฐํšŒ ### BatchManagementService (5๊ฐœ) - [ ] `getBatchJobs()` - ๋ฐฐ์น˜ ์ž‘์—… ๋ชฉ๋ก ์กฐํšŒ - [ ] `getBatchJob()` - ๋ฐฐ์น˜ ์ž‘์—… ๋‹จ๊ฑด ์กฐํšŒ - [ ] `createBatchJob()` - ๋ฐฐ์น˜ ์ž‘์—… ์ƒ์„ฑ - [ ] `updateBatchJob()` - ๋ฐฐ์น˜ ์ž‘์—… ์ˆ˜์ • - [ ] `deleteBatchJob()` - ๋ฐฐ์น˜ ์ž‘์—… ์‚ญ์ œ ### BatchSchedulerService (4๊ฐœ) - [ ] `getScheduledBatches()` - ์Šค์ผ€์ค„๋œ ๋ฐฐ์น˜ ์กฐํšŒ - [ ] `createSchedule()` - ์Šค์ผ€์ค„ ์ƒ์„ฑ - [ ] `updateSchedule()` - ์Šค์ผ€์ค„ ์ˆ˜์ • - [ ] `deleteSchedule()` - ์Šค์ผ€์ค„ ์‚ญ์ œ ### ๊ณตํ†ต ์ž‘์—… - [ ] import ๋ฌธ ์ˆ˜์ • (๋ชจ๋“  ์„œ๋น„์Šค) - [ ] Prisma import ์™„์ „ ์ œ๊ฑฐ (๋ชจ๋“  ์„œ๋น„์Šค) - [ ] ํŠธ๋žœ์žญ์…˜ ๋กœ์ง ํ™•์ธ - [ ] ์—๋Ÿฌ ํ•ธ๋“ค๋ง ๊ฒ€์ฆ --- ## ๐Ÿงช ํ…Œ์ŠคํŠธ ๊ณ„ํš ### ๋‹จ์œ„ ํ…Œ์ŠคํŠธ (24๊ฐœ) - ๊ฐ Prisma ํ˜ธ์ถœ๋ณ„ 1๊ฐœ์”ฉ ### ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ (8๊ฐœ) - BatchExternalDbService: ์™ธ๋ถ€ DB ์—ฐ๋™ ํ…Œ์ŠคํŠธ (2๊ฐœ) - BatchExecutionLogService: ๋กœ๊ทธ ์ƒ์„ฑ ๋ฐ ์กฐํšŒ ํ…Œ์ŠคํŠธ (2๊ฐœ) - BatchManagementService: ๋ฐฐ์น˜ ์ž‘์—… ์‹คํ–‰ ํ…Œ์ŠคํŠธ (2๊ฐœ) - BatchSchedulerService: ์Šค์ผ€์ค„ ์‹คํ–‰ ํ…Œ์ŠคํŠธ (2๊ฐœ) ### ์„ฑ๋Šฅ ํ…Œ์ŠคํŠธ - ๋Œ€์šฉ๋Ÿ‰ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ์„ฑ๋Šฅ - ๋™์‹œ ๋ฐฐ์น˜ ์‹คํ–‰ ์„ฑ๋Šฅ - ์™ธ๋ถ€ DB ์—ฐ๊ฒฐ ํ’€ ์„ฑ๋Šฅ --- ## ๐ŸŽฏ ์˜ˆ์ƒ ๋‚œ์ด๋„ ๋ฐ ์†Œ์š” ์‹œ๊ฐ„ - **๋‚œ์ด๋„**: โญโญโญโญโญ (๋งค์šฐ ๋†’์Œ) - ์™ธ๋ถ€ DB ์—ฐ๋™ - ํŠธ๋žœ์žญ์…˜ ์ฒ˜๋ฆฌ - ์Šค์ผ€์ค„๋ง ๋กœ์ง - ๋Œ€์šฉ๋Ÿ‰ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ - **์˜ˆ์ƒ ์†Œ์š” ์‹œ๊ฐ„**: 4~5์‹œ๊ฐ„ - Phase 1 (BatchManagement + ExecutionLog): 1.5์‹œ๊ฐ„ - Phase 2 (Scheduler): 1์‹œ๊ฐ„ - Phase 3 (ExternalDb): 2์‹œ๊ฐ„ - ํ…Œ์ŠคํŠธ ๋ฐ ๋ฌธ์„œํ™”: 0.5์‹œ๊ฐ„ --- ## โš ๏ธ ์ฃผ์˜์‚ฌํ•ญ ### ์ค‘์š” ์ฒดํฌํฌ์ธํŠธ 1. โœ… ์™ธ๋ถ€ DB ์—ฐ๊ฒฐ์€ ๋ฐ˜๋“œ์‹œ try-finally์—์„œ ํ•ด์ œ 2. โœ… ๋ฐฐ์น˜ ์‹คํ–‰ ์ค‘ ์—๋Ÿฌ ์‹œ ๋กค๋ฐฑ ์ฒ˜๋ฆฌ 3. โœ… Cron ํ‘œํ˜„์‹ ๊ฒ€์ฆ ํ•„์ˆ˜ 4. โœ… ๋Œ€์šฉ๋Ÿ‰ ๋ฐ์ดํ„ฐ๋Š” ์ŠคํŠธ๋ฆฌ๋ฐ ๋ฐฉ์‹ ์‚ฌ์šฉ 5. โœ… ๋™์‹œ ์‹คํ–‰ ์ œํ•œ ํ™•์ธ ### ์„ฑ๋Šฅ ์ตœ์ ํ™” - ์—ฐ๊ฒฐ ํ’€ ํ™œ์šฉ - ๋ฐฐ์น˜ ์ฟผ๋ฆฌ ์ตœ์ ํ™” - ์ธ๋ฑ์Šค ํ™•์ธ - ๋ถˆํ•„์š”ํ•œ ๋กœ๊ทธ ์ œ๊ฑฐ --- **์ƒํƒœ**: โณ **๋Œ€๊ธฐ ์ค‘** **ํŠน์ด์‚ฌํ•ญ**: ์™ธ๋ถ€ DB ์—ฐ๋™, ์Šค์ผ€์ค„๋ง, ํŠธ๋žœ์žญ์…˜ ์ฒ˜๋ฆฌ ํฌํ•จ **โš ๏ธ ์ฃผ์˜**: ๋ฐฐ์น˜ ์‹œ์Šคํ…œ์˜ ํ•ต์‹ฌ ๊ธฐ๋Šฅ์ด๋ฏ€๋กœ ์‹ ์ค‘ํ•œ ํ…Œ์ŠคํŠธ ํ•„์ˆ˜!