0. 이 문서에서 빼는 것
아래는 이미 됐다고 보고 손대지 않는다.
- 엔드포인트 · JSON 봉투 ·
sync_uid/updated_at/is_deleted - 병합·스냅샷 컬럼 (
_CONTENT_ORDER,_SYNC_COLS,_content_vals) - 강제 Push/Pull 경로
20260923_1350_예시데이터_지우기— 폰 설정 버튼. 웹에 없음
원문 규칙: 할일일정기록_날짜규칙.html.
동기화 배포 순서·병합 필드는 서버동기화_날짜규칙.html 에 남아 있으나
이번 작업의 범위가 아니다.
1. 지금 웹 (2026-09-23 확인)
조회와 화면이 아직 기한 칸이다. 앱과 같은 항목이 다른 날에 보이거나, 별표 미래 할일이 오늘 목록에 들어간다.
| 곳 | 지금 | 앱(목표) |
|---|---|---|
list_events_only · cal_events_in_range |
due_date 로 칸을 찾음 |
일정 칸 = DATE(created_at) |
cal_todos_in_range · list_todos |
비반복 할일도 due_date |
비반복 칸 = 생성일(없으면 기한 폴백) |
_today_where |
기한≤오늘 OR 나의하루 OR 별표 미래 | 별표 조건 없음. 생성일=오늘을 넣음 |
enrich_todo 오늘 상태 |
별표 + 기한≥오늘 이면 오늘 | 별표만으로는 오늘이 아님 |
todo_add_event |
고른 날을 due_date 에 넣음 |
고른 날 = 생성일. 기한은 비움 |
| 달력 칸 줄 | 공휴일 → 일정 → 기록 → 할일 | 공휴일 → 기록 → 일정 → 할일 |
| 선택일 패널 목록 | 일정 블록 → 기록 블록 → 할일 | 기록 → 일정 → 할일 |
| 사이드 「중요」 | 항상 보임. 이름 「중요」 | 이름 「별표」. 개수 있을 때만 |
| 일정 타일 | 「기한 {{ date }}」 | 기한 줄 없음. 날은 생성일 |
달력 아래 .sch-todo |
고정 높이. 앱 시트 0.6/0.9 없음 | 1050 + 1213 높이 규칙 |
기록 칸은 지금처럼 due_date 다. 바꾸지 않는다.
2. 맞출 날짜 의미
| 필드 | 할일 | 일정 | 기록 |
|---|---|---|---|
created_at |
달력·목록에 놓는 날 | 일정 그 날. 기한을 대신함 | 만든 시각. 칸에 안 씀 |
due_date |
마감. 비울 수 있음. 칸이 아님 | 없음. 저장 때 비움 | 기록한 날. 칸 위치 |
- 할일 예: 생성 9/25 · 기한 9/27 → 9/25에만 보인다.
- 생성일이 빈 옛 할일만 기한 날로 폴백.
- 반복 할일 회차는 계속
due_date. 반복 기준일을 생성일로 바꾸지 않는다. - 지연 = 미완료이고 기한이 오늘보다 전. 기한 없으면 생성일이 지나도 지연이 아니다. 기한=오늘은 지연이 아니다.
- 일정: 지난 날=완료, 오늘=오늘, 미래=예정. 지연 없음.
- 생성일 ≤ 기한. 어기면 저장 거부. 문구: 「기한은 생성일보다 빠를 수 없습니다.」
오늘 목록 (할일만)
- 기한 ≤ 오늘
is_my_day = 1- 비반복이고
DATE(created_at) = 오늘
_today_where 의
is_star = 1 AND due_date >= today 를 지운다.
enrich_todo 의 오늘 판정에서도 같은 별표 분기를 지운다.
3. 조회 SQL
파일: app_schedule/pkg_sql_statement/sql_statement.py. 병합 함수는 그대로 둔다.
| 함수 | 바꿀 점 |
|---|---|
list_events_only |
due_date = %s → DATE(created_at) = %s |
cal_events_in_range · events_in_range_full |
구간을 생성일 날짜로. 반환 키를 뷰가 칸 묶기에 쓰게 맞춘다 |
list_todos · cal_todos_in_range |
비반복: COALESCE(DATE(created_at), due_date). 반복은 기한 전개 유지 |
_today_where |
별표 조건 삭제. 생성일=오늘 추가 |
list_repeating |
할일: 기한 있음. 일정: 생성일 있음. 일정을 기한 필수로 두면 기한 지운 뒤 반복 일정이 빠진다 |
| 기록 조회 | 그대로 due_date |
뷰 views_schedule.py:
- 달력 셀
setdefault— 일정·할일을 생성일 날짜로 묶는다. _month_events의e['date']— 생성일. 지난/오늘 비교도 그 날짜.- 반복 전개 시작일 — 일정은 생성일, 할일은 기한. (
mdl_recur.py가 기한만 보면 일정도 생성일로) - 목록 묶음: 오늘 → 예정 → 지연 → 완료. 일정에는 지연 묶음 없음. 오름/내림은 묶음 안에서만.
기존 일정 기한 (한 번)
앱 dropEventDueDates() 와 같다. 순수 일정만. updated_at 은 건드리지 않는다. 동기화 병합이 아니다.
UPDATE tb_todo
SET created_at = CONCAT(due_date, ' 00:00:00')
WHERE on_calendar = 1 AND is_todo = 0 AND is_record = 0 AND is_deleted = 0
AND due_date IS NOT NULL AND due_date != ''
AND (created_at IS NULL OR DATE(created_at) > due_date);
UPDATE tb_todo
SET due_date = NULL
WHERE on_calendar = 1 AND is_todo = 0 AND is_record = 0 AND is_deleted = 0
AND due_date IS NOT NULL;
init_schema() 끝, 또는 배포 시 1회.
4. 웹에서 저장할 때
동기화 API가 아니라 todo_add / todo_add_event / todo_edit 폼이다.
- 일정:
due_date = None. 고른 칸(또는 생성일 입력)을created_at로 저장. hiddendue_date에 칸 날짜를 넣지 않는다. - 할일: 고른 칸이 생성일. 기한은 사용자가 넣을 때만. 기한 < 생성일이면 거절.
- 「오늘」 체크를 켜면 생성일을 오늘로 이동. 떠나려는 날이 기한과 같으면 기한을 비운다. 끄면 고른 칸으로 되돌린다.
- 기록: 지금처럼 hidden
due_date= 그 날. 신규는 미래 기한 불가. - 달력 제목의 날짜 이동 폼(
todo_due): 할일·일정은 생성일을 옮긴다. 기록만 기한을 옮긴다.
5. 화면
템플릿: app_schedule/templates/app_schedule/
5.1 폼 _todo_fields.html
- 일정 모드: hidden
due_date를 칸 날짜로 채우지 않는다. 생성일 칸을 보여 주거나, 달력 선택일을 생성일로만 쓴다. - 할일: 생성일 입력을 둔다. 기한 선택 시작일 = 생성일.
- 기록: hidden
due_date유지. 기록 시간 탭은 시간 창을 바로. 새 기록 기본 시간은 현재HH:mm.
5.2 타일
schedule.html이달 일정: 「기한 {{ e.date }}」 를 뺀다. 날은 생성일. 지난 일정은 완료 태그·취소선(이미is_past있음)._todo_item.html: 일정 행에는 기한 라벨을 그리지 않는다. 별은 제목 글자 바로 뒤.
5.3 달력 칸 · 선택일 목록 순서
schedule.html 칸(cal_only 가 비어 있을 때)과 .sch-todo-scroll 블록 순서:
- 날짜 숫자
- 공휴일 이름
- 기록
- 일정
- 할일
- 구글 점
지금은 칸이 일정→기록, 패널도 일정→기록이다. 둘 다 기록→일정으로 바꾼다.
5.4 사이드 · 제목
- 필터 이름 「중요」 → 별표.
star_cnt가 있을 때만 링크를 그린다. 0이면 숨기고, 그 보기에 머무르면 오늘 할 일로 돌린다. - 할일·일정·기록 화면 제목 옆에 오늘. 예:
할 일 9월 23일 (수). 달력 제목에는 안 붙인다.
6. 달력 아래 패널 (1050 + 1213)
앱 바텀시트와 같은 높이 규칙이다.
원문: 20260923_1050_바텀시트_안드로이드웹이식.html 4절.
날짜+건수 토글은 1050의 「최대일 때만 접기」가 아니라
20260923_1213_날짜건수_올라온시트접기.html 이다.
지금 웹 .sch-todo 는 달력 아래 문서 흐름이다.
앱과 맞추려면 달력 영역 안에서 아래를 덮는 패널로 바꾼다.
데스크톱에서 레이아웃을 유지하려면, 좁은 화면(또는 폰 웹)에만 시트를 적용해도 된다.
높이 식은 화면 너비와 무관하다.
| 조작 | 결과 |
|---|---|
| 날짜칸 클릭 | 목록 맨 위. 높이 = 내용 + 여유 24px + 헤더 48px. 0.6 미만 금지, 0.9 초과 금지. 이전 높이·스크롤을 재사용하지 않음. |
| 접힌 패널에서 날짜+건수(제목 줄) | 최대 높이 0.9 |
| 이미 올라온 패널에서 날짜+건수 | 바로 접는다. 0.6 → 0.9 로 한 단 더 올리지 않는다. (1213) |
| 휠 | 패널 높이는 그대로. 목록만 스크롤 |
| 핸들 드래그 | 높이만. 접힘(약 84px) ~ 90% |
.cal-sheet {
position: absolute; left: 0; right: 0; bottom: 0;
display: flex; flex-direction: column; overflow: hidden;
background: #f7f9fc;
border-radius: 16px 16px 0 0;
box-shadow: 0 -2px 8px rgba(0, 0, 0, .15);
height: 84px;
max-height: 90%;
}
.cal-sheet .head { flex: 0 0 auto; text-align: center; font-weight: 700; }
.cal-sheet .list { flex: 1 1 auto; overflow-y: auto; min-height: 0; }
var SHEET_RAISED = 0.6, SHEET_MAX = 0.9;
var SHEET_HEADER_H = 48, SHEET_SLACK = 24;
function sheetSizeOnDayTap(contentHeight, bodyHeight) {
if (!(bodyHeight > 0) || !(contentHeight > 0)) return SHEET_RAISED;
var size = (contentHeight + SHEET_SLACK + SHEET_HEADER_H) / bodyHeight;
if (size <= SHEET_RAISED) return SHEET_RAISED;
if (size >= SHEET_MAX) return SHEET_MAX;
return size;
}
function openDaySheet(sheet, list, body) {
list.scrollTop = 0;
var size = sheetSizeOnDayTap(list.scrollHeight, body.clientHeight);
var px = Math.round(size * body.clientHeight);
var minPx = Math.round(SHEET_RAISED * body.clientHeight);
var maxPx = Math.round(SHEET_MAX * body.clientHeight);
if (px < minPx) px = minPx;
if (px > maxPx) px = maxPx;
sheet.style.height = px + 'px';
}
/* 1213: 올라가 있으면 접고, 접혀 있으면 0.9 */
function onDateCountClick(sheet, body) {
var collapsed = 84;
var raised = sheet.offsetHeight > collapsed + 24;
var maxPx = Math.round(SHEET_MAX * body.clientHeight);
sheet.style.height = (raised ? collapsed : maxPx) + 'px';
}
날짜 목록을 그린 다음 프레임에 openDaySheet 를 부른다.
1050 원문의 atMax 토글은 쓰지 않는다.
20260923_1313_바텀시트_아래화살표 는 시트가 0.9 이고 목록을 더 내릴 수 있을 때만
목록 다음 줄에 아래 화살표를 둔다. 글자 위에 겹치지 않는다.
시트를 넣은 뒤에만 붙인다.
7. 손볼 파일
| 파일 | 할 일 |
|---|---|
pkg_sql_statement/sql_statement.py |
조회 SQL, 오늘 WHERE, 일정 기한 마이그레이션. 병합·스냅샷은 금지 |
pkg_views/views_schedule.py |
칸 묶기, 이달 일정 날짜, 정렬, 저장 시 일정 기한 비우기·생성일 |
pkg_mdl_common/mdl_recur.py |
일정 반복 앵커 = 생성일 |
pkg_mdl_common/mdl_todo_display.py |
오늘/지연 판정에서 별표 제거. 일정은 생성일로 완료/예정 |
templates/.../_todo_fields.html |
일정 기한 hidden 제거, 할일 생성일, 오늘 이동 |
templates/.../schedule.html |
칸·패널 순서, 일정 타일, 별표 칩, 제목 옆 오늘, 시트 마크업 |
templates/.../_todo_item.html |
일정 기한 라벨 제거, 별은 제목 뒤 |
static/app_schedule/schedule.css (+ 달력 JS) |
시트 높이·스크롤·날짜+건수 토글 |
8. 확인
- 생성 9/25 · 기한 9/27 할일이 웹 달력 9/25에만 있다. 9/27에는 없다.
- 내일 칸에 일정 저장 → 내일 칸. 기한 필드 없음. 오늘 칸에 안 나온다.
- 기한을 생성일보다 이르게 저장할 수 없다.
- 「오늘」을 켜면 원래 칸에서 사라지고 오늘 칸으로 이동한다.
- 기한 없고 생성일만 지난 할일은 지연이 아니다. 오늘 목록에도 없다.
- 별표만 있는 미래 할일은 오늘 목록에 없다.
- 어제 일정은 완료, 내일 일정은 예정. 내림차순이어도 묶음은 오늘 → 예정 → 완료.
- 칸과 선택일 목록이 기록 → 일정 → 할일 이다.
- 사이드가 「별표」이고, 별이 없으면 그 링크가 없다.
- (시트) 적은 날 0.6, 중간은 최대 미만, 많은 날은 0.9 + 목록 스크롤. 올라온 제목을 누르면 접힌다.