'use server'; import * as cron from 'node-cron'; import db from '@/db/db'; import { title as titleTable } from '@/db/schema/knox/titles'; import { getTitlesByCompany, Title } from '@/lib/knox-api/employee/employee'; import { sql } from 'drizzle-orm'; const COMPANIES = (process.env.KNOX_COMPANY_CODES || 'P2') .split(',') .map((c) => c.trim()) .filter(Boolean); const CRON_STRING = process.env.KNOX_TITLE_SYNC_CRON || '30 4 * * *'; const DO_FIRST_RUN = process.env.KNOX_TITLE_SYNC_FIRST_RUN === 'true'; async function upsertTitles(titles: Title[]) { if (!titles.length) return; const rows = titles.map((t) => ({ companyCode: t.companyCode, titleCode: t.titleCode, titleName: t.titleName, enTitleName: t.enTitleName, sortOrder: t.sortOrder, raw: t as unknown as Record, })); await db .insert(titleTable) .values(rows) .onConflictDoUpdate({ target: [titleTable.companyCode, titleTable.titleCode], set: { titleName: sql.raw('excluded.title_name'), enTitleName: sql.raw('excluded.en_title_name'), sortOrder: sql.raw('excluded.sort_order'), raw: sql.raw('excluded.raw'), updatedAt: sql.raw('CURRENT_TIMESTAMP'), }, }); } export async function syncKnoxTitles(): Promise { console.log('[KNOX-SYNC] 직급 동기화 시작'); for (const companyCode of COMPANIES) { try { const titles = await getTitlesByCompany(companyCode); await upsertTitles(titles); console.log(`[KNOX-SYNC] 직급 동기화 완료 - ${companyCode}: ${titles.length}건`); } catch (err) { console.error(`[KNOX-SYNC] 직급 동기화 오류 (company ${companyCode})`, err); } } console.log('[KNOX-SYNC] 직급 동기화 전체 완료'); } export async function startKnoxTitleSyncScheduler() { if (DO_FIRST_RUN) { syncKnoxTitles().catch(console.error); } cron.schedule(CRON_STRING, () => { syncKnoxTitles().catch(console.error); }); console.log(`[KNOX-SYNC] 직급 동기화 스케줄러 등록 (${CRON_STRING})`); }