🐰 [flowbit] #2. TaskEvent λ„μž… - μƒνƒœλ₯Ό μ €μž₯ν•˜μ§€ 말고, λ³€ν™”λ₯Ό κΈ°λ‘ν•˜μž

bean8080πŸ«›Β·2026λ…„ 4μ›” 27일

flowbit 🐰☘️

λͺ©λ‘ 보기
2/15
post-thumbnail

☘️ 1. 였늘 λͺ©ν‘œ

μ–΄μ œλŠ” Task CRUDκΉŒμ§€ λ§Œλ“€μ—ˆλ‹€λ©΄,
μ˜€λŠ˜μ€ flowbit의 핡심 ꡬ쑰λ₯Ό λ§Œλ“œλŠ” λ‚ μ΄μ—ˆλ‹€.

β†’ μƒνƒœλ₯Ό μ €μž₯ν•˜λŠ” 게 μ•„λ‹ˆλΌ, μƒνƒœ λ³€ν™”λ₯Ό κΈ°λ‘ν•˜λŠ” ꡬ쑰


☘️ 2. μ™œ TaskEventλ₯Ό λ§Œλ“€μ—ˆλ‚˜

κΈ°μ‘΄ κ΅¬μ‘°λŠ” λ‹¨μˆœν–ˆλ‹€.

Task.status = TODO / IN_PROGRESS / DONE

μž‘μ—…μ΄ νŠΉμ • μƒνƒœ(BLOCKED λ“±)κ°€ λ˜μ—ˆμ„ λ•Œ

μ™œ λ§‰ν˜”λŠ”μ§€
μ–Έμ œλΆ€ν„° λ§‰ν˜”λŠ”μ§€
κ·Έ 전에 μ–΄λ–€ μƒνƒœμ˜€λŠ”μ§€

λ₯Ό μ•Œ 수 μ—†μ—ˆλ‹€

κ·Έλž˜μ„œ ꡬ쑰λ₯Ό μ΄λ ‡κ²Œ λ‚˜λˆ΄λ‹€.

Task β†’ ν˜„μž¬ μƒνƒœ
TaskEvent β†’ μƒνƒœ λ³€ν™” 이λ ₯

즉,

μƒνƒœ = κ²°κ³Ό
이벀트 = κ³Όμ •

결과만 보면 μ•Œ 수 μ—†λŠ” 정보λ₯Ό
κ³Όμ •μœΌλ‘œ λ‹€μ‹œ 좔적할 수 있게 λœλ‹€


☘️ 3. TaskEvent 섀계

TaskEventλŠ” μƒνƒœ λ³€ν™” 자체λ₯Ό κΈ°λ‘ν•˜λŠ” 객체닀.

public class TaskEvent {
    private Long taskId;
    private TaskEventType eventType;
    private TaskStatus fromStatus;
    private TaskStatus toStatus;
    private String description;
    private LocalDateTime createdAt;
}

핡심 ν•„λ“œλ§Œ 보면:

eventType β†’ μ–΄λ–€ μ΄λ²€νŠΈμΈμ§€
fromStatus β†’ 이전 μƒνƒœ
toStatus β†’ λ³€κ²½λœ μƒνƒœ
createdAt β†’ λ°œμƒ μ‹œμ 

이 ꡬ쑰둜 μƒνƒœ 흐름을 κ·ΈλŒ€λ‘œ 볡원할 수 μžˆλ‹€.

TODO β†’ IN_PROGRESS β†’ DONE


☘️ 4. μƒνƒœ λ³€κ²½ API κ΅¬ν˜„

λ‹¨μˆœ CRUDλ₯Ό λ„˜μ–΄μ„œ μƒνƒœ λ³€κ²½ APIλ₯Ό λ§Œλ“€μ—ˆλ‹€.

PATCH /tasks/{id}/start

β†’ TODO β†’ IN_PROGRESS

PATCH /tasks/{id}/complete

β†’ IN_PROGRESS β†’ DONE

PATCH /tasks/{id}/block

β†’ TODO / IN_PROGRESS β†’ BLOCKED

PATCH /tasks/{id}/delete

β†’ μ–΄λ–€ μƒνƒœλ“  β†’ DELETED

μ•„λž˜λŠ” μ‹€μ œλ‘œ Taskλ₯Ό μƒμ„±ν•œ λ’€ μ‚­μ œν–ˆμ„ λ•Œμ˜ 이벀트 λ‘œκ·Έμ΄λ‹€.

μƒνƒœλ§Œ λ°”λ€ŒλŠ” 게 μ•„λ‹ˆλΌ CREATED β†’ DELETED 흐름이 κ·ΈλŒ€λ‘œ κΈ°λ‘λ˜λŠ” 것을 확인할 수 μžˆλ‹€.

Task 이벀트 둜그 (CREATED β†’ DELETED 흐름)


☘️ 5. 이벀트 기둝 흐름

μƒνƒœ λ³€κ²½ μ‹œ 처리 흐름은 λ‹€μŒκ³Ό κ°™λ‹€.

ν˜„μž¬ μƒνƒœ 쑰회
μƒνƒœ λ³€κ²½
TaskEvent 생성
DB μ €μž₯

μ˜ˆμ‹œ:

STARTED:
TODO β†’ IN_PROGRESS

COMPLETED:
IN_PROGRESS β†’ DONE

TaskEvent ν…Œμ΄λΈ” - μƒνƒœ λ³€ν™” 이λ ₯ (CREATED β†’ STARTED β†’ COMPLETED β†’ BLOCKED β†’ DELETED)

μœ„ TaskEvent ν…Œμ΄λΈ” 데이터λ₯Ό 보면 λ‹¨μˆœνžˆ μƒνƒœ κ°’λ§Œ λ°”λ€ŒλŠ” 게 μ•„λ‹ˆλΌ

CREATED β†’ STARTED β†’ COMPLETED

처럼 μƒνƒœ λ³€ν™” κ³Όμ • μžμ²΄κ°€ κ·ΈλŒ€λ‘œ λ‚¨λŠ”λ‹€

μž‘μ—…μ— 따라

β†’ BLOCKED
β†’ DELETED

같은 흐름도 ν•¨κ»˜ λ‚¨λŠ”λ‹€.


☘️ 6. 이벀트 쑰회 API

GET /tasks/{id}/events

응닡 μ˜ˆμ‹œ:

[
  { "eventType": "CREATED" },
  { "eventType": "STARTED" },
  { "eventType": "COMPLETED" }
]

이걸둜 μž‘μ—…μ˜ 전체 흐름을 확인할 수 μžˆλ‹€.

λ‹¨μˆœνžˆ ν˜„μž¬ μƒνƒœκ°€ μ•„λ‹ˆλΌ
μ–΄λ–»κ²Œ 이 μƒνƒœμ— λ„λ‹¬ν–ˆλŠ”μ§€κΉŒμ§€ λ³Ό 수 μžˆλ‹€


☘️ 7. 이 ꡬ쑰의 trade-off

이벀트 기반 κ΅¬μ‘°λŠ” λͺ¨λ“  μƒνƒœ λ³€ν™”λ₯Ό κΈ°λ‘ν•˜κΈ° λ•Œλ¬Έμ—
데이터가 계속 λˆ„μ λ˜κ³ , 쑰회 μ‹œ λ³΅μž‘λ„κ°€ μ¦κ°€ν•œλ‹€.

특히 νŠΉμ • μ‹œμ μ˜ μƒνƒœλ₯Ό μž¬κ΅¬μ„±ν•˜κ±°λ‚˜ 전체 흐름을 μ‘°νšŒν•  λ•Œ μ„±λŠ₯에 λŒ€ν•œ κ³ λ €κ°€ ν•„μš”ν•˜λ‹€.

이 λ¬Έμ œλŠ” μΊμ‹±μ΄λ‚˜ 쑰회 ꡬ쑰 μ΅œμ ν™”λ₯Ό 톡해 ν•΄κ²°ν•  수 μžˆλ‹€κ³  νŒλ‹¨ν–ˆλ‹€.


☘️ 8. κ΅¬ν˜„ν•˜λ©΄μ„œ λŠλ‚€ 점

μ²˜μŒμ—λŠ” λ‹¨μˆœνžˆ status κ°’λ§Œ λ°”κΎΈλŠ” κ΅¬μ‘°μ˜€λ‹€.

task.setStatus(DONE);

μ§€κΈˆμ€ μ΄λ ‡κ²Œ λ°”λ€Œμ—ˆλ‹€.

task.complete();
taskEventRepository.save(...);

λ‹¨μˆœνžˆ status 값을 λ³€κ²½ν•˜λŠ” κ΅¬μ‘°μ—μ„œ

μƒνƒœ λ³€ν™”λ₯Ό ν–‰μœ„λ‘œ ν‘œν˜„ν•˜λŠ” ꡬ쑰둜 λ°”λ€Œμ—ˆλ‹€

이둜 인해

μƒνƒœ 변경이 λ‹¨μˆœ κ°’ 변경이 μ•„λ‹ˆλΌ
의미 μžˆλŠ” 이벀트둜 κΈ°λ‘λœλ‹€

결과적으둜

데이터 관리 방식이 μƒνƒœ μ€‘μ‹¬μ—μ„œ
흐름 μ€‘μ‹¬μœΌλ‘œ μ „ν™˜λ˜μ—ˆλ‹€


☘️ 9. 였늘 배운 핡심

μƒνƒœλŠ” 결과일 뿐이닀
μ€‘μš”ν•œ 건 λ³€ν™” 과정이닀
도메인 객체가 μƒνƒœ 변경을 μ±…μž„μ Έμ•Ό ν•œλ‹€
ServiceλŠ” 흐름을 μ‘°ν•©ν•˜λŠ” 역할이닀

κ²°κ΅­,

μƒνƒœλ₯Ό μ €μž₯ν•˜λŠ” μ‹œμŠ€ν…œμ΄ μ•„λ‹ˆλΌ
흐름을 κΈ°λ‘ν•˜λŠ” μ‹œμŠ€ν…œμœΌλ‘œ μ „ν™˜λλ‹€


☘️ 10. ν˜„μž¬ μƒνƒœ

CREATE βœ”οΈ
READ βœ”οΈ
START βœ”οΈ
COMPLETE βœ”οΈ
BLOCK βœ”οΈ
DELETE βœ”οΈ
EVENT LOGGING βœ”οΈ

λ‹¨μˆœ CRUDμ—μ„œ λ²—μ–΄λ‚˜
μƒνƒœ λ³€ν™”κΉŒμ§€ κΈ°λ‘ν•˜λŠ” κ΅¬μ‘°κΉŒμ§€ ν™•μž₯ν–ˆλ‹€.


☘️ 11. λ‹€μŒ λͺ©ν‘œ

μƒνƒœ 기반 쑰회 (GET /tasks?status=TODO)
Project 도메인 μΆ”κ°€
이벀트 쑰회 고도화

0개의 λŒ“κΈ€