에러수정

This commit is contained in:
kjs 2025-09-29 18:04:56 +09:00
parent 467c5598ab
commit 126b3e1175
3 changed files with 528 additions and 59 deletions

View File

@ -52,14 +52,20 @@ import { BatchSchedulerService } from "./services/batchSchedulerService";
const app = express();
// 기본 미들웨어
app.use(helmet({
contentSecurityPolicy: {
directives: {
...helmet.contentSecurityPolicy.getDefaultDirectives(),
"frame-ancestors": ["'self'", "http://localhost:9771", "http://localhost:3000"], // 프론트엔드 도메인 허용
app.use(
helmet({
contentSecurityPolicy: {
directives: {
...helmet.contentSecurityPolicy.getDefaultDirectives(),
"frame-ancestors": [
"'self'",
"http://localhost:9771",
"http://localhost:3000",
], // 프론트엔드 도메인 허용
},
},
},
}));
})
);
app.use(compression());
app.use(express.json({ limit: "10mb" }));
app.use(express.urlencoded({ extended: true, limit: "10mb" }));
@ -104,7 +110,7 @@ app.use(
// Rate Limiting (개발 환경에서는 완화)
const limiter = rateLimit({
windowMs: 1 * 60 * 1000, // 1분
max: config.nodeEnv === "development" ? 10000 : 100, // 개발환경에서는 10000으로 증가, 운영환경에서는 100
max: config.nodeEnv === "development" ? 10000 : 10000, // 개발환경에서는 10000으로 증가, 운영환경에서는 100
message: {
error: "너무 많은 요청이 발생했습니다. 잠시 후 다시 시도해주세요.",
},
@ -191,7 +197,7 @@ app.listen(PORT, HOST, async () => {
logger.info(`📊 Environment: ${config.nodeEnv}`);
logger.info(`🔗 Health check: http://${HOST}:${PORT}/health`);
logger.info(`🌐 External access: http://39.117.244.52:${PORT}/health`);
// 배치 스케줄러 초기화
try {
await BatchSchedulerService.initialize();

View File

@ -11,15 +11,15 @@ import {
import { MultiConnectionQueryService } from "./multiConnectionQueryService";
import { logger } from "../utils/logger";
export interface EnhancedControlAction extends ControlAction {
// 🆕 기본 ControlAction 속성들 (상속됨)
id?: number;
actionType?: string;
export interface EnhancedControlAction
extends Omit<ControlAction, "id" | "conditions" | "fieldMappings"> {
// 🆕 기본 ControlAction 속성들 (일부 재정의)
id: string; // ControlAction과 호환성을 위해 string 타입 유지
fromTable: string;
// 🆕 추가 속성들
conditions?: ControlCondition[];
fieldMappings?: any[];
// 🆕 추가 속성들 (선택적으로 재정의)
conditions: ControlCondition[]; // 필수 속성으로 변경
fieldMappings: any[]; // 필수 속성으로 변경
// 🆕 UPDATE 액션 관련 필드
updateConditions?: UpdateCondition[];
@ -166,16 +166,16 @@ export class EnhancedDataflowControlService extends DataflowControlService {
let actionResult: any;
// 커넥션 ID 추출
const sourceConnectionId = enhancedAction.fromConnection?.connectionId || enhancedAction.fromConnection?.id || 0;
const targetConnectionId = enhancedAction.toConnection?.connectionId || enhancedAction.toConnection?.id || 0;
const sourceConnectionId = enhancedAction.fromConnection?.id || 0;
const targetConnectionId = enhancedAction.toConnection?.id || 0;
switch (enhancedAction.actionType) {
case "insert":
actionResult = await this.executeMultiConnectionInsert(
actionResult = await this.executeEnhancedMultiConnectionInsert(
enhancedAction,
sourceData,
enhancedAction.fromTable,
enhancedAction.targetTable,
enhancedAction.targetTable || enhancedAction.fromTable,
sourceConnectionId,
targetConnectionId,
null
@ -183,11 +183,11 @@ export class EnhancedDataflowControlService extends DataflowControlService {
break;
case "update":
actionResult = await this.executeMultiConnectionUpdate(
actionResult = await this.executeEnhancedMultiConnectionUpdate(
enhancedAction,
sourceData,
enhancedAction.fromTable,
enhancedAction.targetTable,
enhancedAction.targetTable || enhancedAction.fromTable,
sourceConnectionId,
targetConnectionId,
null
@ -195,11 +195,11 @@ export class EnhancedDataflowControlService extends DataflowControlService {
break;
case "delete":
actionResult = await this.executeMultiConnectionDelete(
actionResult = await this.executeEnhancedMultiConnectionDelete(
enhancedAction,
sourceData,
enhancedAction.fromTable,
enhancedAction.targetTable,
enhancedAction.targetTable || enhancedAction.fromTable,
sourceConnectionId,
targetConnectionId,
null
@ -247,8 +247,8 @@ export class EnhancedDataflowControlService extends DataflowControlService {
/**
* 🆕 INSERT
*/
async executeMultiConnectionInsert(
action: EnhancedControlAction,
async executeEnhancedMultiConnectionInsert(
action: ControlAction,
sourceData: Record<string, any>,
sourceTable: string,
targetTable: string,
@ -257,16 +257,17 @@ export class EnhancedDataflowControlService extends DataflowControlService {
multiConnService: any
): Promise<any> {
try {
logger.info(`다중 커넥션 INSERT 실행: action=${action.action}`);
const enhancedAction = action as EnhancedControlAction;
logger.info(`다중 커넥션 INSERT 실행: action=${action.id}`);
// 커넥션 ID 결정
const fromConnId = fromConnectionId || action.fromConnection?.connectionId || 0;
const toConnId = toConnectionId || action.toConnection?.connectionId || 0;
const fromConnId = fromConnectionId || action.fromConnection?.id || 0;
const toConnId = toConnectionId || action.toConnection?.id || 0;
// FROM 테이블에서 소스 데이터 조회 (조건이 있는 경우)
let fromData = sourceData;
if (
action.fromTable &&
enhancedAction.fromTable &&
action.conditions &&
action.conditions.length > 0
) {
@ -277,7 +278,7 @@ export class EnhancedDataflowControlService extends DataflowControlService {
const fromResults =
await this.multiConnectionService.fetchDataFromConnection(
fromConnId,
action.fromTable,
enhancedAction.fromTable,
queryConditions
);
@ -302,7 +303,7 @@ export class EnhancedDataflowControlService extends DataflowControlService {
const insertResult =
await this.multiConnectionService.insertDataToConnection(
toConnId,
action.targetTable,
action.targetTable || enhancedAction.fromTable,
mappedData
);
@ -317,8 +318,8 @@ export class EnhancedDataflowControlService extends DataflowControlService {
/**
* 🆕 UPDATE
*/
async executeMultiConnectionUpdate(
action: EnhancedControlAction,
async executeEnhancedMultiConnectionUpdate(
action: ControlAction,
sourceData: Record<string, any>,
sourceTable: string,
targetTable: string,
@ -327,26 +328,30 @@ export class EnhancedDataflowControlService extends DataflowControlService {
multiConnService: any
): Promise<any> {
try {
logger.info(`다중 커넥션 UPDATE 실행: action=${action.action}`);
const enhancedAction = action as EnhancedControlAction;
logger.info(`다중 커넥션 UPDATE 실행: action=${action.id}`);
// 커넥션 ID 결정
const fromConnId = fromConnectionId || action.fromConnection?.connectionId || 0;
const toConnId = toConnectionId || action.toConnection?.connectionId || 0;
const fromConnId = fromConnectionId || action.fromConnection?.id || 0;
const toConnId = toConnectionId || action.toConnection?.id || 0;
// UPDATE 조건 확인
if (!action.updateConditions || action.updateConditions.length === 0) {
if (
!enhancedAction.updateConditions ||
enhancedAction.updateConditions.length === 0
) {
throw new Error("UPDATE 작업에는 업데이트 조건이 필요합니다.");
}
// FROM 테이블에서 업데이트 조건 확인
const updateConditions = this.buildUpdateConditions(
action.updateConditions,
enhancedAction.updateConditions,
sourceData
);
const fromResults =
await this.multiConnectionService.fetchDataFromConnection(
fromConnId,
action.fromTable || action.targetTable,
enhancedAction.fromTable || action.targetTable || "default_table",
updateConditions
);
@ -360,13 +365,13 @@ export class EnhancedDataflowControlService extends DataflowControlService {
// 업데이트 필드 매핑 적용
const updateData = this.applyUpdateFieldMappings(
action.updateFields || [],
enhancedAction.updateFields || [],
fromResults[0]
);
// WHERE 조건 구성 (TO 테이블 대상)
const whereConditions = this.buildWhereConditions(
action.updateFields || [],
enhancedAction.updateFields || [],
fromResults[0]
);
@ -374,7 +379,7 @@ export class EnhancedDataflowControlService extends DataflowControlService {
const updateResult =
await this.multiConnectionService.updateDataToConnection(
toConnId,
action.targetTable,
action.targetTable || enhancedAction.fromTable,
updateData,
whereConditions
);
@ -390,8 +395,8 @@ export class EnhancedDataflowControlService extends DataflowControlService {
/**
* 🆕 DELETE
*/
async executeMultiConnectionDelete(
action: EnhancedControlAction,
async executeEnhancedMultiConnectionDelete(
action: ControlAction,
sourceData: Record<string, any>,
sourceTable: string,
targetTable: string,
@ -400,28 +405,30 @@ export class EnhancedDataflowControlService extends DataflowControlService {
multiConnService: any
): Promise<any> {
try {
logger.info(`다중 커넥션 DELETE 실행: action=${action.action}`);
const enhancedAction = action as EnhancedControlAction;
logger.info(`다중 커넥션 DELETE 실행: action=${action.id}`);
// 커넥션 ID 결정
const fromConnId =
fromConnectionId || action.fromConnection?.connectionId || 0;
const toConnId =
toConnectionId || action.toConnection?.connectionId || 0;
const fromConnId = fromConnectionId || action.fromConnection?.id || 0;
const toConnId = toConnectionId || action.toConnection?.id || 0;
// DELETE 조건 확인
if (!action.deleteConditions || action.deleteConditions.length === 0) {
if (
!enhancedAction.deleteConditions ||
enhancedAction.deleteConditions.length === 0
) {
throw new Error("DELETE 작업에는 삭제 조건이 필요합니다.");
}
// FROM 테이블에서 삭제 트리거 조건 확인
const deleteConditions = this.buildDeleteConditions(
action.deleteConditions,
enhancedAction.deleteConditions,
sourceData
);
const fromResults =
await this.multiConnectionService.fetchDataFromConnection(
fromConnId,
action.fromTable || action.targetTable,
enhancedAction.fromTable || action.targetTable || "default_table",
deleteConditions
);
@ -432,7 +439,7 @@ export class EnhancedDataflowControlService extends DataflowControlService {
// WHERE 조건 구성 (TO 테이블 대상)
const whereConditions = this.buildDeleteWhereConditions(
action.deleteWhereConditions || [],
enhancedAction.deleteWhereConditions || [],
fromResults[0]
);
@ -441,14 +448,14 @@ export class EnhancedDataflowControlService extends DataflowControlService {
}
// 안전장치 적용
const maxDeleteCount = action.maxDeleteCount || 100;
const maxDeleteCount = enhancedAction.maxDeleteCount || 100;
// Dry Run 실행 (선택사항)
if (action.dryRunFirst) {
if (enhancedAction.dryRunFirst) {
const countResult =
await this.multiConnectionService.fetchDataFromConnection(
toConnId,
action.targetTable,
action.targetTable || enhancedAction.fromTable,
whereConditions
);
@ -465,13 +472,13 @@ export class EnhancedDataflowControlService extends DataflowControlService {
const deleteResult =
await this.multiConnectionService.deleteDataFromConnection(
toConnId,
action.targetTable,
action.targetTable || enhancedAction.fromTable,
whereConditions,
maxDeleteCount
);
// 삭제 로그 기록 (선택사항)
if (action.logAllDeletes) {
if (enhancedAction.logAllDeletes) {
logger.info(
`삭제 실행 로그: ${JSON.stringify({
action: action.id,

View File

@ -39,7 +39,9 @@
"clsx": "^2.1.1",
"cmdk": "^1.1.1",
"date-fns": "^4.1.0",
"docx-preview": "^0.3.6",
"lucide-react": "^0.525.0",
"mammoth": "^1.11.0",
"next": "15.4.4",
"react": "19.1.0",
"react-day-picker": "^9.9.0",
@ -47,8 +49,10 @@
"react-hook-form": "^7.62.0",
"react-hot-toast": "^2.6.0",
"react-window": "^2.1.0",
"sheetjs-style": "^0.15.8",
"sonner": "^2.0.7",
"tailwind-merge": "^3.3.1",
"xlsx": "^0.18.5",
"zod": "^4.1.5"
},
"devDependencies": {
@ -3351,6 +3355,15 @@
"win32"
]
},
"node_modules/@xmldom/xmldom": {
"version": "0.8.11",
"resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.11.tgz",
"integrity": "sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw==",
"license": "MIT",
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/@xyflow/react": {
"version": "12.8.5",
"resolved": "https://registry.npmjs.org/@xyflow/react/-/react-12.8.5.tgz",
@ -3406,6 +3419,22 @@
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
}
},
"node_modules/adler-32": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.2.0.tgz",
"integrity": "sha512-/vUqU/UY4MVeFsg+SsK6c+/05RZXIHZMGJA+PX5JyWI0ZRcBpupnRuPLU/NXXoFwMYCPCoxIfElM2eS+DUXCqQ==",
"license": "Apache-2.0",
"dependencies": {
"exit-on-epipe": "~1.0.1",
"printj": "~1.1.0"
},
"bin": {
"adler32": "bin/adler32.njs"
},
"engines": {
"node": ">=0.8"
}
},
"node_modules/ajv": {
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
@ -3705,6 +3734,32 @@
"dev": true,
"license": "MIT"
},
"node_modules/base64-js": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"license": "MIT"
},
"node_modules/bluebird": {
"version": "3.4.7",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz",
"integrity": "sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==",
"license": "MIT"
},
"node_modules/brace-expansion": {
"version": "1.1.12",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
@ -3837,6 +3892,28 @@
],
"license": "CC-BY-4.0"
},
"node_modules/cfb": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/cfb/-/cfb-1.2.2.tgz",
"integrity": "sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==",
"license": "Apache-2.0",
"dependencies": {
"adler-32": "~1.3.0",
"crc-32": "~1.2.0"
},
"engines": {
"node": ">=0.8"
}
},
"node_modules/cfb/node_modules/adler-32": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.3.1.tgz",
"integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==",
"license": "Apache-2.0",
"engines": {
"node": ">=0.8"
}
},
"node_modules/chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
@ -3939,6 +4016,28 @@
"react-dom": "^18 || ^19 || ^19.0.0-rc"
}
},
"node_modules/codepage": {
"version": "1.14.0",
"resolved": "https://registry.npmjs.org/codepage/-/codepage-1.14.0.tgz",
"integrity": "sha512-iz3zJLhlrg37/gYRWgEPkaFTtzmnEv1h+r7NgZum2lFElYQPi0/5bnmuDfODHxfp0INEfnRqyfyeIJDbb7ahRw==",
"license": "Apache-2.0",
"dependencies": {
"commander": "~2.14.1",
"exit-on-epipe": "~1.0.1"
},
"bin": {
"codepage": "bin/codepage.njs"
},
"engines": {
"node": ">=0.8"
}
},
"node_modules/codepage/node_modules/commander": {
"version": "2.14.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.14.1.tgz",
"integrity": "sha512-+YR16o3rK53SmWHU3rEM3tPAh2rwb1yPcQX5irVn7mb0gXbwuCCrnkbV5+PBfETdfg1vui07nM6PCG1zndcjQw==",
"license": "MIT"
},
"node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
@ -3971,6 +4070,12 @@
"node": ">= 0.8"
}
},
"node_modules/commander": {
"version": "2.17.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz",
"integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==",
"license": "MIT"
},
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@ -3995,6 +4100,24 @@
"node": "^14.18.0 || >=16.10.0"
}
},
"node_modules/core-util-is": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
"license": "MIT"
},
"node_modules/crc-32": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz",
"integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==",
"license": "Apache-2.0",
"bin": {
"crc32": "bin/crc32.njs"
},
"engines": {
"node": ">=0.8"
}
},
"node_modules/cross-spawn": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
@ -4308,6 +4431,12 @@
"integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==",
"license": "MIT"
},
"node_modules/dingbat-to-unicode": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/dingbat-to-unicode/-/dingbat-to-unicode-1.0.1.tgz",
"integrity": "sha512-98l0sW87ZT58pU4i61wa2OHwxbiYSbuxsCBozaVnYX2iCnr3bLM3fIes1/ej7h1YdOKuKt/MLs706TVnALA65w==",
"license": "BSD-2-Clause"
},
"node_modules/doctrine": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
@ -4321,6 +4450,15 @@
"node": ">=0.10.0"
}
},
"node_modules/docx-preview": {
"version": "0.3.6",
"resolved": "https://registry.npmjs.org/docx-preview/-/docx-preview-0.3.6.tgz",
"integrity": "sha512-gKVPE18hlpfuhQHiptsw1rbOwzQeGSwK10/w7hv1ZMEqHmjtCuTpz6AUMfu1twIPGxgpcsMXThKI6B6WsP3L1w==",
"license": "Apache-2.0",
"dependencies": {
"jszip": ">=3.0.0"
}
},
"node_modules/dotenv": {
"version": "16.6.1",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz",
@ -4334,6 +4472,15 @@
"url": "https://dotenvx.com"
}
},
"node_modules/duck": {
"version": "0.1.12",
"resolved": "https://registry.npmjs.org/duck/-/duck-0.1.12.tgz",
"integrity": "sha512-wkctla1O6VfP89gQ+J/yDesM0S7B7XLXjKGzXxMDVFg7uEn706niAtyYovKbyq1oT9YwDcly721/iUWoc8MVRg==",
"license": "BSD",
"dependencies": {
"underscore": "^1.13.1"
}
},
"node_modules/dunder-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
@ -5049,6 +5196,15 @@
"node": ">=0.10.0"
}
},
"node_modules/exit-on-epipe": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz",
"integrity": "sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw==",
"license": "Apache-2.0",
"engines": {
"node": ">=0.8"
}
},
"node_modules/exsolve": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.7.tgz",
@ -5263,6 +5419,15 @@
"node": ">= 6"
}
},
"node_modules/frac": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz",
"integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==",
"license": "Apache-2.0",
"engines": {
"node": ">=0.8"
}
},
"node_modules/function-bind": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
@ -5577,6 +5742,12 @@
"node": ">= 4"
}
},
"node_modules/immediate": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
"integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==",
"license": "MIT"
},
"node_modules/import-fresh": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
@ -5604,6 +5775,12 @@
"node": ">=0.8.19"
}
},
"node_modules/inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"license": "ISC"
},
"node_modules/internal-slot": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz",
@ -6132,6 +6309,18 @@
"node": ">=4.0"
}
},
"node_modules/jszip": {
"version": "3.10.1",
"resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz",
"integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==",
"license": "(MIT OR GPL-3.0-or-later)",
"dependencies": {
"lie": "~3.3.0",
"pako": "~1.0.2",
"readable-stream": "~2.3.6",
"setimmediate": "^1.0.5"
}
},
"node_modules/keyv": {
"version": "4.5.4",
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
@ -6176,6 +6365,15 @@
"node": ">= 0.8.0"
}
},
"node_modules/lie": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz",
"integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==",
"license": "MIT",
"dependencies": {
"immediate": "~3.0.5"
}
},
"node_modules/lightningcss": {
"version": "1.30.1",
"resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz",
@ -6451,6 +6649,17 @@
"loose-envify": "cli.js"
}
},
"node_modules/lop": {
"version": "0.4.2",
"resolved": "https://registry.npmjs.org/lop/-/lop-0.4.2.tgz",
"integrity": "sha512-RefILVDQ4DKoRZsJ4Pj22TxE3omDO47yFpkIBoDKzkqPRISs5U1cnAdg/5583YPkWPaLIYHOKRMQSvjFsO26cw==",
"license": "BSD-2-Clause",
"dependencies": {
"duck": "^0.1.12",
"option": "~0.2.1",
"underscore": "^1.13.1"
}
},
"node_modules/lucide-react": {
"version": "0.525.0",
"resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.525.0.tgz",
@ -6470,6 +6679,39 @@
"@jridgewell/sourcemap-codec": "^1.5.5"
}
},
"node_modules/mammoth": {
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/mammoth/-/mammoth-1.11.0.tgz",
"integrity": "sha512-BcEqqY/BOwIcI1iR5tqyVlqc3KIaMRa4egSoK83YAVrBf6+yqdAAbtUcFDCWX8Zef8/fgNZ6rl4VUv+vVX8ddQ==",
"license": "BSD-2-Clause",
"dependencies": {
"@xmldom/xmldom": "^0.8.6",
"argparse": "~1.0.3",
"base64-js": "^1.5.1",
"bluebird": "~3.4.0",
"dingbat-to-unicode": "^1.0.1",
"jszip": "^3.7.1",
"lop": "^0.4.2",
"path-is-absolute": "^1.0.0",
"underscore": "^1.13.1",
"xmlbuilder": "^10.0.0"
},
"bin": {
"mammoth": "bin/mammoth"
},
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/mammoth/node_modules/argparse": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
"license": "MIT",
"dependencies": {
"sprintf-js": "~1.0.2"
}
},
"node_modules/math-intrinsics": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
@ -6855,6 +7097,12 @@
"dev": true,
"license": "MIT"
},
"node_modules/option": {
"version": "0.2.4",
"resolved": "https://registry.npmjs.org/option/-/option-0.2.4.tgz",
"integrity": "sha512-pkEqbDyl8ou5cpq+VsnQbe/WlEy5qS7xPzMS1U55OCG9KPvwFD46zDbxQIj3egJSFc3D+XhYOPUzz49zQAVy7A==",
"license": "BSD-2-Clause"
},
"node_modules/optionator": {
"version": "0.9.4",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
@ -6923,6 +7171,12 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/pako": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
"integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==",
"license": "(MIT AND Zlib)"
},
"node_modules/parent-module": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
@ -6946,6 +7200,15 @@
"node": ">=8"
}
},
"node_modules/path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/path-key": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
@ -7173,6 +7436,18 @@
}
}
},
"node_modules/printj": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/printj/-/printj-1.1.2.tgz",
"integrity": "sha512-zA2SmoLaxZyArQTOPj5LXecR+RagfPSU5Kw1qP+jkWeNlrq+eJZyY2oS68SU1Z/7/myXM4lo9716laOFAVStCQ==",
"license": "Apache-2.0",
"bin": {
"printj": "bin/printj.njs"
},
"engines": {
"node": ">=0.8"
}
},
"node_modules/prisma": {
"version": "6.16.2",
"resolved": "https://registry.npmjs.org/prisma/-/prisma-6.16.2.tgz",
@ -7199,6 +7474,12 @@
}
}
},
"node_modules/process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
"license": "MIT"
},
"node_modules/prop-types": {
"version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
@ -7437,6 +7718,27 @@
"react-dom": "^18.0.0 || ^19.0.0"
}
},
"node_modules/readable-stream": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
"integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
"license": "MIT",
"dependencies": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
"isarray": "~1.0.0",
"process-nextick-args": "~2.0.0",
"safe-buffer": "~5.1.1",
"string_decoder": "~1.1.1",
"util-deprecate": "~1.0.1"
}
},
"node_modules/readable-stream/node_modules/isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
"license": "MIT"
},
"node_modules/readdirp": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
@ -7591,6 +7893,12 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
"license": "MIT"
},
"node_modules/safe-push-apply": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz",
@ -7694,6 +8002,12 @@
"node": ">= 0.4"
}
},
"node_modules/setimmediate": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
"integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==",
"license": "MIT"
},
"node_modules/sharp": {
"version": "0.34.4",
"resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.4.tgz",
@ -7760,6 +8074,28 @@
"node": ">=8"
}
},
"node_modules/sheetjs-style": {
"version": "0.15.8",
"resolved": "https://registry.npmjs.org/sheetjs-style/-/sheetjs-style-0.15.8.tgz",
"integrity": "sha512-/wRiwnq5ck7aO+zLBs+u5JqQK4agUTIGCS0nxgaMjFl6XdlVaaB/RNJcP6S6Efj3+RYbSZuAoyqmSnbzxfT7Kg==",
"license": "Apache-2.0",
"dependencies": {
"adler-32": "~1.2.0",
"cfb": "^1.1.4",
"codepage": "~1.14.0",
"commander": "~2.17.1",
"crc-32": "~1.2.0",
"exit-on-epipe": "~1.0.1",
"ssf": "~0.10.3",
"wmf": "~1.0.1"
},
"bin": {
"xlsx": "bin/xlsx.njs"
},
"engines": {
"node": ">=0.8"
}
},
"node_modules/side-channel": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
@ -7855,6 +8191,27 @@
"node": ">=0.10.0"
}
},
"node_modules/sprintf-js": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
"integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
"license": "BSD-3-Clause"
},
"node_modules/ssf": {
"version": "0.10.3",
"resolved": "https://registry.npmjs.org/ssf/-/ssf-0.10.3.tgz",
"integrity": "sha512-pRuUdW0WwyB2doSqqjWyzwCD6PkfxpHAHdZp39K3dp/Hq7f+xfMwNAWIi16DyrRg4gg9c/RvLYkJTSawTPTm1w==",
"license": "Apache-2.0",
"dependencies": {
"frac": "~1.1.2"
},
"bin": {
"ssf": "bin/ssf.njs"
},
"engines": {
"node": ">=0.8"
}
},
"node_modules/stable-hash": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/stable-hash/-/stable-hash-0.0.5.tgz",
@ -7876,6 +8233,15 @@
"node": ">= 0.4"
}
},
"node_modules/string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"license": "MIT",
"dependencies": {
"safe-buffer": "~5.1.0"
}
},
"node_modules/string.prototype.includes": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz",
@ -8359,6 +8725,12 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/underscore": {
"version": "1.13.7",
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.7.tgz",
"integrity": "sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g==",
"license": "MIT"
},
"node_modules/undici-types": {
"version": "6.21.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
@ -8463,6 +8835,12 @@
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
}
},
"node_modules/util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
"license": "MIT"
},
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
@ -8568,6 +8946,24 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/wmf": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz",
"integrity": "sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==",
"license": "Apache-2.0",
"engines": {
"node": ">=0.8"
}
},
"node_modules/word": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/word/-/word-0.3.0.tgz",
"integrity": "sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==",
"license": "Apache-2.0",
"engines": {
"node": ">=0.8"
}
},
"node_modules/word-wrap": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
@ -8578,6 +8974,66 @@
"node": ">=0.10.0"
}
},
"node_modules/xlsx": {
"version": "0.18.5",
"resolved": "https://registry.npmjs.org/xlsx/-/xlsx-0.18.5.tgz",
"integrity": "sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==",
"license": "Apache-2.0",
"dependencies": {
"adler-32": "~1.3.0",
"cfb": "~1.2.1",
"codepage": "~1.15.0",
"crc-32": "~1.2.1",
"ssf": "~0.11.2",
"wmf": "~1.0.1",
"word": "~0.3.0"
},
"bin": {
"xlsx": "bin/xlsx.njs"
},
"engines": {
"node": ">=0.8"
}
},
"node_modules/xlsx/node_modules/adler-32": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.3.1.tgz",
"integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==",
"license": "Apache-2.0",
"engines": {
"node": ">=0.8"
}
},
"node_modules/xlsx/node_modules/codepage": {
"version": "1.15.0",
"resolved": "https://registry.npmjs.org/codepage/-/codepage-1.15.0.tgz",
"integrity": "sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==",
"license": "Apache-2.0",
"engines": {
"node": ">=0.8"
}
},
"node_modules/xlsx/node_modules/ssf": {
"version": "0.11.2",
"resolved": "https://registry.npmjs.org/ssf/-/ssf-0.11.2.tgz",
"integrity": "sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==",
"license": "Apache-2.0",
"dependencies": {
"frac": "~1.1.2"
},
"engines": {
"node": ">=0.8"
}
},
"node_modules/xmlbuilder": {
"version": "10.1.1",
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-10.1.1.tgz",
"integrity": "sha512-OyzrcFLL/nb6fMGHbiRDuPup9ljBycsdCypwuyg5AAHvyWzGfChJpCXMG88AGTIMFhGZ9RccFN1e6lhg3hkwKg==",
"license": "MIT",
"engines": {
"node": ">=4.0"
}
},
"node_modules/yallist": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz",