summaryrefslogtreecommitdiff
path: root/db/schema/knox/pending-actions.ts
blob: ef41dca715741b98d45714d68b7e5f9e472952c9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
import { jsonb, text, timestamp, integer, serial } from "drizzle-orm/pg-core";
import { knoxSchema } from "./employee";
import { approvalLogs } from "./approvals";
import { users } from "@/db/schema/users";

/**
 * Pending Actions 테이블
 * 
 * 결재가 필요한 액션들을 보류(pending) 상태로 저장하고,
 * 결재 승인 후 실제 비즈니스 로직을 실행하는 워크플로우를 관리
 * 
 * 워크플로우:
 * 1. 사용자 요청 → pendingAction 생성 (status: 'pending')
 * 2. Knox 결재 상신 → approvalLog와 연결
 * 3. [폴링으로 결재 상태 감지]
 * 4. 결재 승인 → status: 'approved' → 액션 실행
 * 5. 실행 완료 → status: 'executed'
 */
export const pendingActions = knoxSchema.table("pending_actions", {
  // 기본 정보
  id: serial("id").primaryKey(),
  
  // 결재 연결 (approvalLogs의 apInfId와 논리적으로 연결)
  // 주의: FK 제약 조건을 사용하지 않음
  // 이유: pending_actions는 Knox 상신 전에 생성되지만,
  //       approval_logs는 Knox와 동기화되어 나중에 생성되므로
  //       FK 제약이 있으면 Saga Pattern의 순서(DB → Knox)를 지킬 수 없음
  apInfId: text("ap_inf_id").notNull(),
  
  // 액션 정보
  actionType: text("action_type").notNull(), // 예: 'vendor_investigation_request', 'purchase_order_request'
  actionPayload: jsonb("action_payload").notNull(), // 실행에 필요한 모든 파라미터 저장
  
  // 상태 관리
  // pending: 결재 대기 중
  // approved: 결재 승인됨 (실행 대기)
  // executed: 실행 완료
  // failed: 실행 실패
  // rejected: 결재 반려됨
  // cancelled: 결재 취소됨
  status: text("status").notNull().default("pending"),
  
  // 실행 결과 (옵션)
  executionResult: jsonb("execution_result"), // 실행 결과 저장 (성공/실패 정보)
  errorMessage: text("error_message"), // 실패 시 에러 메시지
  
  // 실행 시간
  executedAt: timestamp("executed_at"), // 실제 액션이 실행된 시간
  
  // 생성자 정보
  createdBy: integer("created_by")
    .notNull()
    .references(() => users.id, { onDelete: "set null" }),
  
  // 타임스탬프
  createdAt: timestamp("created_at").notNull().defaultNow(),
  updatedAt: timestamp("updated_at").notNull().defaultNow(),
});