02-types-task

Dec 7, 2025

TaskNode

📁 관련 코드: lib/types/nodes/task.ts

이메일에서 추출된 할일/요청을 저장합니다.

핵심 개념: Task vs Memory

┌─────────────────────────────────────────────────────────────┐
이메일: "보고서를 금요일까지 보내주세요. 회의 결과도 정리해서요" 
└─────────────────────────────────────────────────────────────┘
                              
                              LLM 추출
              ┌───────────────┴───────────────┐
              
┌─────────────────────────┐     ┌─────────────────────────┐
Memory (TASK 카테고리)   TaskNode               
"보고서 요청 받음"       title: "보고서 제출"    
importance: 0.8        dueDate: 금요일        
status: PENDING        
└─────────────────────────┘     └─────────────────────────┘
              
              └───────── sourceMemoryId ──────┘

왜 분리하는가?


Memory

Task

역할

정보 저장

액션 추적

상태

없음 (사실)

있음 (pending → completed)

시간

occurredAt (발생 시점)

dueDate (마감 시점)

Memory: "김철수가 보고서를 요청했다"라는 사실 Task: "보고서를 제출해야 한다"라는 할일

TaskStatus

enum TaskStatus {
  PENDING = 'pending',        // 대기 중
  IN_PROGRESS = 'in_progress', // 진행 중
  COMPLETED = 'completed',     // 완료
  CANCELLED = 'cancelled',     // 취소
}

상태 전이

              ┌────────────────┐
    Task PENDING     
              └───────┬────────┘
                      시작
                      
              ┌────────────────┐
              IN_PROGRESS   
              └───────┬────────┘
                      
          ┌───────────┴───────────┐
          
┌────────────────┐      ┌────────────────┐
COMPLETED    CANCELLED    
└────────────────┘      └────────────────┘

상태별 쿼리 예시

// 해야 할 일
const todoTasks = tasks.filter(
  t => t.status === TaskStatus.PENDING || t.status === TaskStatus.IN_PROGRESS
);

// 완료된 일
const doneTasks = tasks.filter(t => t.status === TaskStatus.COMPLETED);

// 이번 주 완료한 일
const thisWeekCompleted = tasks.filter(
  t => t.status === TaskStatus.COMPLETED &&
       t.completedAt && t.completedAt >= startOfWeek
);

TaskPriority

enum TaskPriority {
  URGENT = 'urgent',   // 즉시
  HIGH = 'high',       // 높음
  NORMAL = 'normal',   // 보통
  LOW = 'low',         // 낮음
}

Priority vs Importance


TaskPriority

ImportanceTier

적용 대상

TaskNode

MemoryNode

의미

언제 해야 하나

얼마나 중요한 정보인가

예시

URGENT = 오늘 해야 함

CRITICAL = 계약금 정보

"계약금 500만원 입금 확인해주세요"

Memory.importance = CRITICAL (계약금이므로 중요한 정보)
Task.priority = URGENT (즉시 확인 필요)

inferTaskPriority: 자동 우선순위

const priority = inferTaskPriority(title, description, dueDate);

우선순위 결정 로직:

  1. 키워드 기반

    • urgent, asap, 긴급, 즉시 → URGENT

    • important, 중요, priority → HIGH

  2. 마감일 기반

    • 1일 이내 → URGENT

    • 3일 이내 → HIGH

    • 그 외 → NORMAL

People: Assignee vs Requester

assigneeId?: string;   // 누가 해야 하나
requesterId?: string;  // 누가 요청했나

사용 시나리오

이메일 From: 김철수
내용: "이영희씨, 보고서 작성 부탁드립니다"

TaskNode:
  requesterId: [김철수의 PersonNode ID]
  assigneeId: [이영희의 PersonNode ID]

왜 ID만 저장하는가?

대안 1: Person 객체 전체 포함

// ❌ 비효율적
assignee: PersonNode;  // 중복 데이터

대안 2: ID만 저장하고 필요시 조회

// ✅ 선택한 방식
assigneeId: string;

// 사용 시
const assignee = await getPersonById(task.assigneeId);

sourceMemoryId: 원본 추적

sourceMemoryId: string;  // 추출된 Memory ID

왜 필요한가?

시나리오: "이 할일이 어디서 나온 거야?"

const task = getTask(taskId);
const sourceMemory = getMemory(task.sourceMemoryId);
const sourceEmail = getEmail(sourceMemory.sourceId);

// 원본 이메일까지 추적 가능

그래프 관계

[Email]
   
   └── extracted_to ──→ [Memory: 보고서 요청]
                              
                              └── created ──→ [Task: 보고서 제출]

Helper Functions

isTaskOverdue

if (isTaskOverdue(task)) {
  notifyUser("마감일이 지났습니다!");
}

체크 로직:

  • dueDate가 없으면 → false

  • COMPLETED/CANCELLED면 → false

  • 현재 시간 > dueDate면 → true

completeTask

const completedTask = completeTask(task);
// {
//   ...task,
//   status: TaskStatus.COMPLETED,
//   completedAt: new Date(),
//   updatedAt: new Date(),
// }

그래프에서의 관계

[TaskNode: 보고서 제출]
        
        ├── EXTRACTED_FROM ──→ [MemoryNode: 보고서 요청]
        
        ├── ASSIGNED_TO ─────→ [PersonNode: 이영희]
        
        ├── REQUESTED_BY ────→ [PersonNode: 김철수]
        
        └── RELATED_TO ──────→ [EntityNode: Q1 프로젝트]

Factory 사용 예시

const task = createTaskNode({
  id: generateUUID(),
  title: "보고서 제출",
  description: "Q1 실적 보고서 작성 및 제출",
  dueDate: new Date('2024-01-25'),
  assigneeId: assignee.id,
  requesterId: requester.id,
  sourceMemoryId: memory.id,
  sourceType: SourceType.BOOTSTRAPPED,
  confidence: 0.9,
});

// status: PENDING (기본값)
// priority: NORMAL (기본값)

// 또는 자동 우선순위 적용
const priority = inferTaskPriority(
  task.title,
  task.description,
  task.dueDate
);
task.priority = priority;

다음 문서

  • → Implicit Relationships: 암시적 관계

  • → MemoryNode: Task의 원본 Memory