# [웹] app_schedule 미완료 할일 이동(지연일자) — 작업 안내 (미적용)

- 날짜: 2026-09-28 (KST)
- 대상: modam_doc 웹 `app_schedule` (**사용자가 직접 작업 예정, 이 문서는 안내만**)
- 앱 반영 내용: `20260928_0537_미완료할일_오늘로_이동_지연표시.md` (auto_schedule_app / day_plan_app)

## 1. 서버 DB · 동기화 (먼저)
- `tb_todo`에 `delay_date` 컬럼을 추가한다(DATE 또는 VARCHAR(10), NULL 허용).
- `sql_statement.py`의 조회, INSERT, UPDATE와 앱 동기화 병합(`/schedule/api/todos/sync/`)에 `delay_date`를 포함한다.
  - 서버가 이 값을 돌려주지 않아도 앱은 로컬 값을 유지하고, 불러올 때 다시 계산한다. 다만 웹 화면이 같은 결과를 보이려면 서버 저장이 필요하다.
- `created_at`은 만들 때 한 번만 쓴다. 이동 처리로 UPDATE 하지 않는다.

## 2. 이동(지연) 갱신 — 웹에서 화면을 불러올 때도 실행
앱만 갱신하면 앱을 안 연 날 웹 화면이 어긋나므로 웹에서도 같은 갱신을 한다.
- 비반복 미완료 할일:
  ```sql
  UPDATE tb_todo SET delay_date = :today, updated_at = UTC_TIMESTAMP()
  WHERE user_id = :u AND is_todo = 1 AND is_done = 0 AND is_deleted = 0
    AND (repeat_unit IS NULL OR repeat_unit = '')
    AND COALESCE(NULLIF(delay_date, ''), DATE(created_at), due_date) < :today
  ```
- 반복 미완료 할일(앱 `_carryRepeatTodo`와 동일):
  - 오늘 이하 최근 회차가 생성일(현재 회차)과 같고 생성일이 오늘 이전이면 `delay_date = 오늘`
  - 최근 회차가 생성일보다 뒤(다음 회차 도래)이면 분리:
    - 기존 행: `repeat_unit = NULL`, `repeat_until = NULL`, `delay_date = 오늘`, 회차 메모를 `note`로
    - 새 행: 같은 내용으로 `created_at = 최근 회차`, `due_date = 최근 회차 + (원래 기한 − 생성일)`, 미완료, 새 `sync_uid`, `delay_date = (최근 회차 < 오늘 ? 오늘 : NULL)`
- 반복 완료 회차: 완료 기록으로 보존할 때 `done_date`는 실제 완료일을 유지한다(회차 날로 덮지 않음).

## 3. 표시 규칙 (한 할일은 한 칸에만)
```
놓이는 날 = done_date            (완료)
          = delay_date           (미완료이면서 delay_date 있음)
          = DATE(created_at)     (그 외, 없으면 due_date)
```
- 월 달력 칸, 날짜 상세 목록: 조회 날짜와 놓이는 날이 같은 건만 표시한다.
- 반복 전개: 지연 중인 반복 할일은 기준일(생성일) 회차를 전개에서 빼고, 오늘 칸에 표시한다.
- 오늘 목록: `is_done = 0 AND (due_date <= 오늘 OR is_my_day = 1 OR delay_date = 오늘 OR (비반복 AND DATE(created_at) = 오늘))`
- "지연" 표시와 지연 목록: 미완료이면서 `delay_date`가 있거나 `due_date < 오늘`.
- 편집 저장 시: 미완료 할일의 생성일이 오늘 이전이면 `delay_date = 오늘`, 오늘·미래면 NULL.
