# 쌍둥이 앱 차이점 기록 (auto ↔ day_plan)

- 날짜: 2026-09-28 (KST)
- 대상: `auto_schedule_app`, `day_plan_app`
- **기준 앱: `day_plan_app`** (두 앱이 다르면 day_plan 쪽이 기준)
- 상태: **기록만 함. 코드 수정 없음** (사용자 지시: "일단 수정하지 말라")

## 배경
2026-09-27 작업 이후 두 앱의 `lib/`를 비교했다. 앱 고유 부분은 빼고 봤다.
- auto 전용: 서버 동기화(`services/sync.dart`, 홈 폴링 등)
- day_plan 전용: 예시 데이터(`demo/`, `childSyncUid`의 `demo-` 접두어, `calendarShowAll` 등)
- `dart format` 줄바꿈 차이

그 결과 로직이 다른 곳이 아래 2군데 나왔다. 둘 다 **auto 쪽이 기준(day_plan)과 다르다**.

---

## 1. 반복 일정의 지난 회차 분리 — 회차 메모 처리 (`lib/db/app_db.dart`)

함수: `detachPastRepeatEvent(Todo base, DateTime yesterday)`
반복 일정의 지난 회차들을 개별 행으로 떼어내고 반복 기준행은 소프트 삭제한다.
두 앱이 다른 부분은 이렇게 만든 회차 행의 메모 처리다.

| | day_plan (기준) | auto |
|--|--|--|
| `note` | 기준행 `note`를 그대로 복사 | `base.noteFor(회차날짜)`: 그 회차 개별 메모가 있으면 그것, 없으면 공통 메모 |
| `occ_notes` | 기준행 값을 그대로 복사 | `null`로 비움 |

day_plan (기준):
```dart
          ..['remind_day'] = null
          ..['sync_uid'] = AppDb.childSyncUid(base.syncUid)
          ..['updated_at'] = stamp
```

auto:
```dart
          ..['remind_day'] = null
          ..['note'] = base.noteFor(_isoDate(o))
          ..['occ_notes'] = null
          ..['sync_uid'] = genUuid()
          ..['updated_at'] = stamp
```

- `sync_uid`가 `genUuid()`인지 `childSyncUid()`인지는 앱 고유 차이(예시 데이터)라 이 항목과 무관하다.
- 참고: 같은 파일의 반복 할일 쪽 처리(`'note': t.noteFor(createdDay)`, `'occ_notes': null`)는 **두 앱이 같다**.
  다른 곳은 반복 일정의 지난 회차를 분리하는 위 부분뿐이다.

### auto에만 있는 서버 동기화 관련 처리 (앱 고유)
```dart
        // 서버에 occ_notes 가 없으면 로컬 회차 메모를 덮지 않는다.
        if (!m.containsKey('occ_notes')) map.remove('occ_notes');
```
서버 동기화 병합 코드라 auto 전용이다. 이식 대상이 아니다.

---

## 2. 반복 보기의 완료 기록 날짜 (`lib/screens/calendar_tab.dart`)

반복 보기에서 완료 기록(그 날짜만 완료된 회차)을 달력의 어느 날짜에 표시하는지가 다르다.

| | day_plan (기준) | auto |
|--|--|--|
| 표시 날짜 | `dueDate` (기한) | `doneDate` → 없으면 `createdAt` 날짜 → 없으면 `dueDate` |
| 날짜 없음 처리 | 없음(`dueDate!` 강제) | 비어 있으면 건너뜀 |

day_plan (기준):
```dart
      if (!repContents.contains(t.content)) continue; // 반복과 무관한 완료 제외
      doneRec.putIfAbsent(t.content, () => <String>{}).add(t.dueDate!);
      doneCounts[t.dueDate!] = (doneCounts[t.dueDate!] ?? 0) + 1;
```

auto:
```dart
      if (!repContents.contains(t.content)) continue; // 반복과 무관한 완료 제외
      final home = t.doneDate ??
          ((t.createdAt != null && t.createdAt!.length >= 10)
              ? t.createdAt!.substring(0, 10)
              : t.dueDate);
      if (home == null || home.isEmpty) continue;
      doneRec.putIfAbsent(t.content, () => <String>{}).add(home);
      doneCounts[home] = (doneCounts[home] ?? 0) + 1;
```

(같은 파일 셀 높이 부분은 주석 문구만 다르고 로직은 같다.)

---

## 아이폰 앱 반영 시
- **day_plan(기준) 동작으로 구현**한다.
  1. 반복 일정의 지난 회차를 분리할 때 `note`·`occ_notes`는 기준행 값을 그대로 복사한다.
  2. 반복 보기의 완료 기록은 `dueDate` 날짜에 표시한다.
- auto를 day_plan에 맞출지는 **아직 결정하지 않았다**. 결정되면 이 문서를 갱신한다.
