Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
107 commits
Select commit Hold shift + click to select a range
efc73b9
docs: 작업과 일정 분리 기능 문서화
GoGradually Jan 19, 2026
9f7ce6d
feat: 작업 취소 및 완료 이벤트 추가
GoGradually Jan 20, 2026
a2c3192
feat: 작업 모델 클래스 추가
GoGradually Jan 20, 2026
e601cec
feat: 작업 ID로 그래프 노드 수정
GoGradually Jan 20, 2026
81afbb6
feat: 작업 ID에 따른 다음 및 이전 작업 ID 메서드 수정
GoGradually Jan 20, 2026
c2c3c05
test: Graph 테스트 코드 수정 - 단순 ID 참조로 변경
GoGradually Jan 20, 2026
45f26c7
feat: 작업 ID에 따른 사이클 체크 로직 수정
GoGradually Jan 20, 2026
19a1775
feat: 중요도 및 긴급도 제약 조건 클래스 일정에서 작업으로 이동
GoGradually Jan 20, 2026
2e97232
feat: TemporalConstraint 클래스 및 테스트 코드 추가
GoGradually Jan 20, 2026
6ed9a17
feat: 작업 ID에 따른 다음 및 이전 작업 ID 조회 메서드 수정
GoGradually Jan 20, 2026
6eca0a5
feat: 작업 삭제 이벤트에 따른 의존성 삭제 메소드 호출
GoGradually Jan 20, 2026
166e8bb
feat: 일정 삭제 이벤트에 작업 ID 추가
GoGradually Jan 20, 2026
65c9321
feat: 일정 취소 이벤트 핸들러에 작업 서비스 추가
GoGradually Jan 20, 2026
ee4aa04
feat: 일정 완료 이벤트 핸들러에 작업 서비스 추가
GoGradually Jan 20, 2026
a8d92ec
feat: 작업 유형 열거형 이동 및 통계 기록 메서드 구현
GoGradually Jan 20, 2026
a49c900
feat: 작업 리포지토리 인터페이스 추가 및 소유자 ID로 작업 조회 메서드 구현
GoGradually Jan 20, 2026
200553e
feat: 통계 기록을 위한 Recorder 인터페이스 추가
GoGradually Jan 20, 2026
e5dcde1
feat: 작업을 찾을 수 없을 때 발생하는 예외 클래스 추가
GoGradually Jan 20, 2026
38d0f1b
feat: 작업 패치를 위한 TaskPatch 클래스 추가
GoGradually Jan 20, 2026
75abc83
feat: Task 유틸리티 클래스 추가 및 샘플 작업 생성 메서드 구현
GoGradually Jan 20, 2026
80e526a
test: 일정 관련 테스트 케이스 수정 및 유틸리티 메서드 개선
GoGradually Jan 20, 2026
5184aa0
feat: Task ID로 모든 일정 조회 메서드 추가
GoGradually Jan 20, 2026
7b79776
feat: SchedulePatch 클래스에서 불필요한 필드 제거 및 시작 시간 필드 추가
GoGradually Jan 20, 2026
128120d
feat: Schedule 클래스에 taskId 필드 추가 및 불필요한 필드 제거
GoGradually Jan 20, 2026
a51bc0e
feat: DependencyRepository에서 scheduleId를 taskId로 변경하여 의존성 삭제 메서드 수정
GoGradually Jan 20, 2026
beaf0cd
test: SchedulePatch에서 시작 시간 필드로 변경
GoGradually Jan 20, 2026
b12e5e3
feat: ScheduleControllerAdvice에서 TaskNotFoundException 처리 추가
GoGradually Jan 21, 2026
4a89959
Merge branch 'refs/heads/master' into feat/일정과-작업-분리
GoGradually Jan 21, 2026
460227e
feat: 난이도 변경 메서드 추가 및 테스트 케이스 개선
GoGradually Jan 21, 2026
c28be33
feat: 작업의 난이도 변경 메서드 추가
GoGradually Jan 21, 2026
df6a816
feat: 작업의 난이도를 urgency에서 difficulty로 변경
GoGradually Jan 21, 2026
dac9fa2
feat: 피보나치 난이도 검증기 추가
GoGradually Jan 21, 2026
ec28d38
feat: 피보나치 난이도 검증을 위한 어노테이션 추가
GoGradually Jan 21, 2026
c15b832
feat: 일정 패치 클래스에서 불필요한 필드 및 메서드 제거
GoGradually Jan 21, 2026
334d186
feat: 일정 클래스에 작업 ID 및 생성/수정 시간 필드 추가
GoGradually Jan 21, 2026
aa7639f
feat: 일정과 작업의 분리 및 일정 등록 기능 추가
GoGradually Jan 21, 2026
d97d99a
feat: 작업 및 일정 도메인 설명 수정
GoGradually Jan 21, 2026
8cd9254
feat: 작업 서비스 클래스 추가 및 CRUD 기능 구현
GoGradually Jan 21, 2026
c3c691a
test: 작업 서비스 클래스에 대한 단위 테스트 추가
GoGradually Jan 21, 2026
121ac9f
feat: 작업 의존성 조정 명령어 클래스 추가
GoGradually Jan 21, 2026
ab771bf
test: 작업 의존성 조정 서비스에 대한 단위 테스트 추가
GoGradually Jan 21, 2026
fb3d191
feat: 작업 조정 서비스 추가 및 CRUD 기능 구현
GoGradually Jan 21, 2026
959e59d
feat: 일정과 작업 분리를 위한 명령어 클래스 수정
GoGradually Jan 21, 2026
5ceba89
test: createSchedule 메서드에 대한 단위 테스트 추가
GoGradually Jan 21, 2026
5974186
feat: 작업 생성 및 조정 시 일정과 작업 통합 처리 기능 추가
GoGradually Jan 21, 2026
70108d8
test: detachSchedulesByTaskId 메서드에 대한 단위 테스트 추가
GoGradually Jan 21, 2026
bd54abe
feat: 일정 소유자 검증 및 작업 ID에 따른 일정 삭제/분리 기능 추가
GoGradually Jan 21, 2026
b8a25d4
test: 작업 서비스 통합에 따른 일정 상태 변경 서비스 테스트 수정
GoGradually Jan 21, 2026
7c999cc
feat: 일정 시작 및 종료 시 작업 상태 동기화 기능 추가
GoGradually Jan 21, 2026
cd93763
refactor: 작업 타입 모델 경로 수정
GoGradually Jan 21, 2026
47a9647
feat: 일정 요청 모델에 작업 ID 및 난이도 유효성 검사 추가
GoGradually Jan 21, 2026
3022814
feat: 일정 응답 모델에 작업 ID 추가 및 중요도/난이도 필드 레거시 처리
GoGradually Jan 21, 2026
8477c43
feat: 일정 생성 및 수정 시 작업 정보 동기화 기능 추가
GoGradually Jan 21, 2026
2cb1fce
feat: 일정 패치 요청 모델 추가
GoGradually Jan 21, 2026
a6c3c38
feat: 일정 간단 응답 모델 추가
GoGradually Jan 21, 2026
a30384c
feat: 일정 간단 요청 모델 추가
GoGradually Jan 21, 2026
36cb910
feat: 작업과 분리된 일정 관리 API 구현
GoGradually Jan 21, 2026
022a173
test: 일정 관리 API에 대한 단위 테스트 추가
GoGradually Jan 21, 2026
0b8edda
feat: 작업 관리 API를 위한 TaskControllerV1 구현
GoGradually Jan 21, 2026
cbeb233
test: TaskControllerV1에 대한 단위 테스트 추가
GoGradually Jan 21, 2026
f6ca0e4
feat: 작업 요청 모델(TaskRequest) 추가
GoGradually Jan 21, 2026
66b46b4
feat: 작업 응답 모델(TaskResponse) 추가
GoGradually Jan 21, 2026
519b91c
feat: 일정 요청 모델(TaskScheduleRequest) 추가
GoGradually Jan 21, 2026
09c92dc
feat: 작업 취소 이벤트 핸들러(TaskCanceledIntegratedEventHandler) 추가
GoGradually Jan 21, 2026
81b4429
feat: 작업 취소 이벤트 매퍼(TaskCanceledEventMapper) 추가
GoGradually Jan 21, 2026
aba81ef
feat: 작업 취소 페이로드(TaskCanceledPayload) 모델 추가
GoGradually Jan 21, 2026
892c90b
feat: 작업 완료 페이로드(TaskCompletedPayload) 모델 추가
GoGradually Jan 21, 2026
1d55310
feat: 작업 완료 이벤트 핸들러(TaskCompletedIntegratedEventHandler) 추가
GoGradually Jan 21, 2026
0b2b9da
feat: 작업 완료 이벤트 매퍼(TaskCompletedEventMapper) 추가
GoGradually Jan 21, 2026
7b9b207
feat: 작업(Task)에 대한 큐와 Exchange 정의 추가
GoGradually Jan 21, 2026
6767e50
docs: 작업 완료 및 취소 이벤트 발행/구독 정의 추가
GoGradually Jan 21, 2026
8a00efc
docs: 일정과 작업 분리 관련 기능 추가
GoGradually Jan 21, 2026
8742209
feat: Dependency 클래스에 ownerId 필드 추가 및 검증 로직 구현
GoGradually Jan 21, 2026
0cc042a
feat: DependencyRepository에 fromId로 의존성 조회 메서드 추가
GoGradually Jan 21, 2026
671a318
feat: Task 클래스에 inboundDependencyCount 필드 및 조정 메서드 추가
GoGradually Jan 21, 2026
0296690
test: DependencyServiceTest에 Task의 inboundDependencyCount 증가 및 감소 테스트 추가
GoGradually Jan 21, 2026
20ecd03
feat: DependencyService에 Task의 inboundCount 조정 로직 추가
GoGradually Jan 21, 2026
171a207
test: Dependency 생성자에 ownerId 추가
GoGradually Jan 22, 2026
2fcda56
feat: Schedule 클래스에 taskId 필드 및 고유 제약 조건 추가
GoGradually Jan 22, 2026
e307522
test: Dependency 생성자에 taskId 추가
GoGradually Jan 22, 2026
d9e3f15
feat: ScheduleRepository에 taskId로 조회하는 메서드 추가
GoGradually Jan 22, 2026
a8c0c85
feat: TaskRepository에 ownerId로 조회하는 메서드 및 낙관적 락 조회 메서드 추가
GoGradually Jan 22, 2026
c303093
feat: 작업 없이 일정을 생성할 때 의존 관계 설정을 금지하는 로직 추가
GoGradually Jan 22, 2026
b3ff50c
feat: 일정 추가 시 작업이 이미 연결된 경우 예외 처리 로직 추가
GoGradually Jan 22, 2026
6c3d5e3
style: 코드 줄바꿈 적용
GoGradually Jan 22, 2026
3ae5ff5
test: 작업 완료 시 연결된 일정 상태 확인 테스트 추가
GoGradually Jan 22, 2026
7526d9d
feat: 작업 완료 시 일정 동기화 로직 추가
GoGradually Jan 22, 2026
dfd24b1
feat: 의존성 추가 및 제거 로직에 소유자 ID 포함
GoGradually Jan 22, 2026
902767e
docs: Task와 Schedule 분리 문서에 inboundTaskCount 추가
GoGradually Jan 22, 2026
1448fa4
feat: 일정에서 연관된 의존 관계를 제거하는 이벤트 제거 - 더 이상 의존이 일정을 알지 않음
GoGradually Jan 22, 2026
f4afc1d
fix: ScheduleControllerAdvice에서 TaskNotFoundException 처리 제거
GoGradually Jan 22, 2026
3cfced4
feat: TaskControllerAdvice 추가 및 예외 처리 로직 구현
GoGradually Jan 22, 2026
9e7107a
feat: TaskResponse에 들어오는 의존 관계 수 추가
GoGradually Jan 22, 2026
3cfda34
feat: 일정 생성 시 Task와 의존관계를 함께 생성하는 기능 추가
GoGradually Jan 22, 2026
3516ac7
feat: 일정 생성 시 레거시 방식으로 스케줄 생성 로직 변경
GoGradually Jan 22, 2026
85dd441
refactor: ScheduleControllerV1Test에서 TaskService 의존성 제거
GoGradually Jan 22, 2026
b352303
feat: 작업 목록 조회 API에 페이지네이션 및 필터링 기능 추가
GoGradually Jan 22, 2026
c95c8cd
refactor: ScheduleControllerV1에서 TaskService 의존성 제거
GoGradually Jan 22, 2026
1017d9d
docs: 일정과 작업 분리 관련 문서 추가 및 수정
GoGradually Jan 22, 2026
af2d4d3
feat: 커서 기반의 작업 조회 기능 추가
GoGradually Jan 22, 2026
a457ccf
test: 커서 기반 작업 조회 기능에 대한 단위 테스트 추가
GoGradually Jan 22, 2026
65ce3ce
feat: 커서 기반 작업 조회 기능 추가
GoGradually Jan 22, 2026
0cb7a3c
feat: 작업 커서 페이지 응답 DTO 추가
GoGradually Jan 22, 2026
a1b2e33
test: 커서 기반 작업 조회 기능에 대한 테스트 추가
GoGradually Jan 22, 2026
fc753e3
refactor: 커서 기반 작업 조회에서 마지막 작업 가져오기 수정
GoGradually Jan 22, 2026
c5e1719
feat: TaskController에 작업 목록 커서 조회 기능 추가
GoGradually Jan 22, 2026
f298162
docs: 작업 조회 페이지네이션 완료 표시 추가
GoGradually Jan 22, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 42 additions & 40 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,28 +39,30 @@ PinIt 이 추구하는 핵심 목적은 다음 세 가지입니다.

## 🧩 Domain Overview

### 1. Schedule (일정 도메인)
### 1. Task (작업 도메인)

사용자가 실제로 수행하는 “할 일/작업”에 해당합니다.
* 특정 시점 이전에 끝내야 하는 “일” 자체를 관리
* 마감일, 중요도, 난이도(피보나치: 1, 2, 3, 5, 8, 13, 21)
* Task 간 의존/우선순위, 작업 쪼개기 대상
* 상태는 완료/미완료 중심 (시간대 실행 상태는 관리하지 않음)

* 일정 타입 (집중 작업, 행정 작업, 짧은 업무 등)
* 중요도 / 난이도
* 예상 소요 시간
* 마감 일자
* 현재 상태 (예정, 진행 중, 완료 등)
* 고정 일정 여부 (캘린더 상에서 움직일 수 있는지 여부)
### 2. Schedule (일정 도메인)

### 2. Dependency (일정 관계 도메인)
* 특정 시간대에 실행되는 “일정/약속” 관리 (회의·약속 등 Task 없이도 생성 가능)
* 지정 시작 시각, 상태(시작/일시정지/중지/완료), 실행 히스토리(누적 소요 시간)
* 필요 시 기존 Task를 일정으로 복사해 시간 슬롯에 배치, 일정 완료/취소 시 연결된 Task 완료/미완료와 연동

일정 간 “선후 관계”를 관리하는 도메인입니다.
### 3. Dependency (작업 관계 도메인)

* `from` 일정이 **먼저** 끝나야 `to` 일정을 시작할 수 있음
* 일정 간 **사이클 검사**를 통해 잘못된 의존 관계를 방지
* 일정 삭제 시 관련 의존 관계를 적절히 처리
Task 간 “선후 관계”를 관리합니다.

* `from` Task가 **먼저** 끝나야 `to` Task를 시작할 수 있음
* Task 그래프를 기반으로 사이클 검사 수행
* Task 삭제/연결 해제 시 연관된 의존 관계를 정리

> 복잡한 의존관계/사이클 검사는 “복잡한 일정(프로젝트)”을 AI와 함께 구체화할 때 핵심이 되는 도메인입니다.

### 3. Member / User (사용자 도메인)
### 4. Member / User (사용자 도메인)

사용자의 시간 사용 패턴 및 환경을 담는 도메인입니다.

Expand All @@ -70,41 +72,42 @@ PinIt 이 추구하는 핵심 목적은 다음 세 가지입니다.

이 정보들을 기반으로, **AI 추천 시 “그 사람에게 맞는 플랜”**을 만들 수 있도록 설계합니다.

---

## 🔧 주요 기능 (백엔드 기준)

### 1. 일정 관리 API
### API 버전 정책 (Task/Schedule 분리)

* **일정 생성**
* **V0**: 기존 호환용. 일정 생성/수정 시 Task를 함께 생성하거나 수정하며, 요청/응답에 작업 속성(마감일, 중요도/난이도[Fibonacci: 1,2,3,5,8,13,21])이 포함됩니다.
* **V1**: 분리 권장. 일정 단독 CRUD/상태 전환만 다루며 Task 정보를 노출하지 않습니다.
* **작업 → 일정 복사**: `POST /v1/tasks/{taskId}/schedules`로 기존 작업을 지정 시각에 일정으로 등록할 수 있습니다.
* **삭제 플래그**: `DELETE /v1/tasks/{taskId}?deleteSchedules=` 혹은 `DELETE /v0|v1/schedules/{scheduleId}?deleteTaskAlso=` 로
연관 삭제 여부를 선택합니다(미설정 시 연관만 해제).

* 일정의 기본 정보(제목, 타입, 마감일, 중요도, 난이도, 예상 소요 시간 등)를 입력받아 생성
* **일정 조회**
---

* 특정 날짜의 일정 목록 조회
* 주간 단위 일정 조회 (ex. `/schedules/week`)
* **일정 상세 조회**
## 🔧 주요 기능 (백엔드 기준)

* 단일 일정의 상세 정보 반환
* **일정 수정 (PATCH)**
### 1. 작업(Task) 관리 API

* 변경된 필드만 부분 업데이트
* DTO에 없는 필드가 `null` 로 덮어씌워지는 문제를 피하기 위해
**“Patch 전용 객체/도메인 로직”**을 두는 방향으로 설계
* **일정 삭제**
* **작업 생성**: 제목/설명/마감일/중요도/난이도[Fibonacci]/TaskType/의존 관계 입력
* **작업 조회·상세**: 회원별 작업 목록 및 단건 조회
* **작업 수정 (PATCH)**: 변경 필드만 부분 업데이트(패치 객체로 null 덮어쓰기 방지)
* **작업 완료/되돌리기**: 완료 ↔ 미완료 상태 전환
* **작업 삭제**: 의존 관계 함께 삭제, 옵션으로 연관 일정 삭제 또는 분리
* **작업 → 일정 복사**: 기존 작업을 지정 시각의 일정으로 등록

* 삭제 시 관련 의존관계를 포함한 도메인 규칙을 지키도록 구현
### 2. 일정(Schedule) 관리 API

### 2. 일정 의존관계 관리
* **일정 생성**: V1은 제목/설명/지정 시작 시각만으로 일정 생성(작업 없이 가능), V0 레거시는 Task 속성까지 포함해 일정+작업 동시 생성
* **일정 조회·상세**: 특정 날짜/주간 목록 조회, 단건 조회
* **일정 수정 (PATCH)**: 제목/설명/지정 시작 시각 등 변경 필드만 부분 업데이트
* **일정 상태 전환**: 시작, 일시중지, 재시작, 완료, 취소
* **일정 삭제**: 상태 규칙을 준수해 삭제, 필요 시 연관 Task 상태 연동

* 일정 간 **선행/후행 관계 등록**
* 일정 삭제 시, 연관된 의존관계 정리
* **사이클 검사**
### 3. 의존관계 관리

* 사용자의 모든 의존 그래프를 기반으로 위상 정렬 등으로 사이클 여부 검사
* 잘못된 의존관계로 인해 계획이 꼬이는 것을 방지
* Task 간 **선행/후행 관계 등록**
* **사이클 검사**로 잘못된 의존 그래프 방지
* Task 삭제/분리 시 연관 의존관계 정리

### 3. 통계 및 피드백을 위한 데이터 수집
### 4. 통계 및 피드백을 위한 데이터 수집

(구현/설계 범위에 맞추어 점진적으로 확장)

Expand Down Expand Up @@ -162,4 +165,3 @@ PinIt 이 추구하는 핵심 목적은 다음 세 가지입니다.


---

7 changes: 7 additions & 0 deletions docs/다음 풀 리퀘스트/다음 풀 리퀘스트.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
## 프론트/타 서비스가 바뀐 뒤에야 수행할 수 있는 작업들

- [ ] 일정에 존재하는 사이클 체크 관련 기능이 작업으로 이동해야 함
- 일정은 의존 관계 및 사이클 체크 기능이 없음. 작업에서만 존재
- [ ] V0 제거 - 일정은 일정만, 작업은 작업만
- README.md 문서와 "Task과 Schedule 분리.md" 참고
- 더 이상 프론트는 V0 인터페이스를 사용하지 않음
76 changes: 76 additions & 0 deletions docs/일정과 작업 분리/Task와 Schedule 분리.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# Task와 Schedule 분리

## 작업(Task)과 일정(Schedule)의 분리 필요성

- 작업
- 특정 시점 이전까지 완성되어야 하는 일
- 작업은 근데 우선순위가 있다. - 사전일정/사후일정 넣기
- 일정 쪼개기 기능은 작업에만 해당됨 - 일정 쪼개기가 아닌 작업 쪼개기
- 일정
- 다른 사람과 함께 정한 반드시 그 시간대에 진행되어야 하는 일
- 일정은 우선순위가 없다. - 사전일정/사후일정 없음
- 일정은 시작/일시정지/중지/완료 기능이 필요함
- 일정은 현재 사용자의 진행하고 있는 상태를 반영해야 함 - ScheduleState 개념이 그대로 존재
- 작업은 완료/미완료 상태만 반영하면 됨
- 일정을 어느 시간에 넣어야 하는가에 대한 자동화 - 일정 자동 배치 기능
- 진행한 일정에 대한 통계 - 일정 통계 기능

- 일정은 반드시 작업과 연결될 필요는 없음
- 사용자는 단순히 일정만 등록할 수 있어야 함
- 예: 회의, 약속 등

- 작업은 사용자의 원함에 의해, 일정으로 복사될 수 있음
- 사용자는 작업을 오늘의 일정에 등록하고, 그 일정에 맞춰 작업을 진행할 수 있음
- 만약 해당 일정이 완료되면, 작업도 완료 처리됨
- 만약 해당 일정이 취소되면, 작업도 미완료 상태로 돌아감

## Task와 Schedule 의 도메인 상태 분리

- Task
- id
- title
- description
- dueDate
- isCompleted
- ImportanceConstraint
- TemporalConstraint
- inboundTaskCount
- createdAt
- updatedAt

- Schedule
- id
- title
- description
- designatedStartTime
- state (예: 예정, 진행 중, 일시 정지, 완료)
- ScheduleHistory
- createdAt
- updatedAt

> Dependency는 Task 기반으로 각 작업의 우선순위를 정하는 데 사용

## 총 기능

하단 네비게이션 바가 다음과 같이 분류되어야 한다.

- 오늘 할당된 일
- 오늘 일정을 디테일하게 볼 수 있는 화면
- 일정
- 작업
- 통계

그리고, + 버튼이 일정과 작업을 함께 관리해선 안된다.
오늘 할당된 일이 일정과 작업을 함께 확인해서, 오늘 추천할 일을 결정하도록 해야 한다.

(혹은, 오늘 할 일의 빠른 추가용도의 버튼으로 남아있는 것)

---

이 문서대로 코드를 변경한다.

이때, 프론트에 공개되는 API가 변경되어야 할 경우에는, V1로 버저닝 후 새 클래스를 추가한다.(OCP 준수)



> 이후 일정/작업/통계 도메인 각각 멀티모듈로 변경 필요
34 changes: 34 additions & 0 deletions docs/일정과 작업 분리/일정과 작업 분리 보완.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
## Task

- [x] 일정 삭제 시 연결된 작업 삭제 금지
- 작업 삭제 시 연결된 일정도 삭제는 있어야 하는 기능이지만,
- 일정 삭제 시 연결된 작업 삭제는 하지 않는다.
- [ ] 통계는 작업 타입에 따라 집계, 일정 누계 시간에 따라 추가
- 일정과 작업이 함께 사용되는 문제. 이걸 통계에서 어떻게 집계할지 고민 필요
- Recorder를 어떻게 처리할지...
- [x] ScheduleControllerAdvice에 Task 예외가 처리되고 있음
- 이 예외 처리는 전용 TaskControllerAdvice에 존재해야 함.
- [x] 작업의 조회 방식
1. 데드라인 기반 페이지네이션(정렬) 기능 지원
2. 사용자의 선택으로, "지금 시작할 수 있는 일정" 보기

- 작업 도메인에, 자신으로 들어오는(inbound) 의존 관계가 추가될 때마다 카운트하는 변수 추가
- 지금 시작할 수 있는 일정 조회 시, inbound 일정이 0개인 일정 조회

- [x] 작업 조회 페이지네이션
- 커서 기반 페이지네이션으로 변경 필요

## Task - Schedule

- [x] 일정과 작업은 일대일 관계임
- 실제 @OneToOne 관계로 바꾸는 건 아니지만, 유니크 제약 조건을 둬야 함
- [x] 작업의 내용을 복사해서 날짜 지정 후 일정 생성은 가능하지만, 반대 방향은 안 됨
- 일정에서 작업을 생성하는 건 불가능. 작업에서 일정을 생성하는 것만 가능

생각보다 일정-작업 연동은 강력한 기능이다.

- 작업에서 생성한 일정만 작업과 연동됨
- 연동이 끊긴 일정은 다시 작업과 연동 불가능
- 작업에서 생성한 일정이 완료되면 작업도 완료
- 작업이 완료되면 연동된 일정도 완료
- 일정 진행 중 연동된 작업이 완료되는 건 막아야 함.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,23 @@
import me.gg.pinit.pinittask.domain.dependency.model.Graph;
import me.gg.pinit.pinittask.domain.dependency.repository.DependencyRepository;
import me.gg.pinit.pinittask.domain.dependency.repository.FromToPair;
import me.gg.pinit.pinittask.domain.task.model.Task;
import me.gg.pinit.pinittask.domain.task.repository.TaskRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class DependencyService {
private DependencyRepository dependencyRepository;
private final DependencyRepository dependencyRepository;
private final TaskRepository taskRepository;

public DependencyService(DependencyRepository dependencyRepository) {
public DependencyService(DependencyRepository dependencyRepository, TaskRepository taskRepository) {
this.dependencyRepository = dependencyRepository;
this.taskRepository = taskRepository;
}

@Transactional(readOnly = true)
Expand All @@ -26,34 +32,54 @@ public boolean checkCycle(Long memberId, List<Dependency> removedDependencies, L


@Transactional(readOnly = true)
public List<Long> getNextScheduleIds(Long memberId, Long scheduleId) {
public List<Long> getNextTaskIds(Long memberId, Long taskId) {
List<Dependency> allByOwnerId = dependencyRepository.findAllByOwnerId(memberId);
Graph graph = Graph.of(allByOwnerId);
return graph.getNextScheduleIds(scheduleId);
return graph.getNextTaskIds(taskId);
}

@Transactional(readOnly = true)
public List<Long> getPreviousScheduleIds(Long memberId, Long scheduleId) {
public List<Long> getPreviousTaskIds(Long memberId, Long taskId) {
List<Dependency> allByOwnerId = dependencyRepository.findAllByOwnerId(memberId);
Graph graph = Graph.of(allByOwnerId);
return graph.getPreviousScheduleIds(scheduleId);
return graph.getPreviousTaskIds(taskId);
}

@Transactional
public void saveAll(List<Dependency> dependencies) {
updateInboundCount(dependencies, 1);
dependencyRepository.saveAll(dependencies);
}

@Transactional
public void deleteAll(List<Dependency> dependencies) {
updateInboundCount(dependencies, -1);
List<FromToPair> fromToPairs = dependencies.stream()
.map(dependency -> new FromToPair(dependency.getFromId(), dependency.getToId()))
.toList();
dependencyRepository.deleteByFromToPairs(fromToPairs);
}

@Transactional
public void deleteWithScheduleId(Long scheduleId) {
dependencyRepository.deleteAllRelatedToSchedule(scheduleId);
public void deleteWithTaskId(Long taskId) {
List<Dependency> outgoing = dependencyRepository.findAllByFromId(taskId);
updateInboundCount(outgoing, -1);
dependencyRepository.deleteAllRelatedToTask(taskId);
}

/**
* 추가되는 의존관계에 맞춰, 연결된 Task들의 inbound Count를 조정해준다.
*
* @param dependencies
* @param delta
*/
private void updateInboundCount(List<Dependency> dependencies, int delta) {
if (dependencies.isEmpty()) {
return;
}
Map<Long, Long> toCount = dependencies.stream()
.collect(Collectors.groupingBy(Dependency::getToId, Collectors.counting()));
List<Task> tasks = taskRepository.findAllByIdInWithOptimisticLock(toCount.keySet());
tasks.forEach(task -> task.adjustInboundDependencies(Math.toIntExact(toCount.get(task.getId()) * delta)));
}
}
Loading
Loading