Skip to content

feat: #68 복구안 비교 및 미리보기 화면 구현 - #82

Merged
borissal1207 merged 5 commits into
devfrom
feature/#68-recovery
Aug 8, 2026
Merged

feat: #68 복구안 비교 및 미리보기 화면 구현#82
borissal1207 merged 5 commits into
devfrom
feature/#68-recovery

Conversation

@borissal1207

@borissal1207 borissal1207 commented Aug 7, 2026

Copy link
Copy Markdown
Collaborator

배경

하루 종료(#65) 후 계획이 위험하거나 불가능해졌을 때 보여주는 화면이다.
PLAN B의 핵심 가치인 "실패 이후의 재계산"이 사용자에게 드러나는 지점으로,
두 복구안을 비교하고 승인해야만 미래 계획이 바뀐다.

구현 대상

  • planner/templates/planner/recovery_compare.html — 복구안 비교
  • planner/templates/planner/recovery_result.html — 미리보기 및 적용
  • planner/templates/planner/includes/recovery_card.html — 복구안 카드 (신규)
  • static/css/planner.css, static/css/tokens.css — 스타일/유틸리티 클래스 추가
  • static/js/planner.js — 복구안 선택 토글
  • templates/includes/icons.html — 아이콘 추가

화면 구성

  1. 복구안 비교
    • 왜 복구가 필요한지 — 못한 분량, 속도 보정, 남은 가능시간
    • 복구안 2개 — 분량 유지형(maintain_volume) / 핵심 집중형(core_focus), 같은 축의 Fit Bar로 비교
    • 제외되는 작업 수와 목록(항상 펼쳐진 상태로 노출), 추가로 필요한 시간
    • 하단 고정 바 — 선택한 안 표시 + 적용 버튼
  2. 미리보기 및 적용
    • 날짜별 공부량 변화 (지금 계획 vs 복구 후, before만 가능시간 초과 표시)
    • 유지 / 이동 / 제외 작업 수
    • "적용해도 나중에 다시 바꿀 수 있습니다" 안내
    • 적용 버튼

리뷰 반영 (셀프 체크 중 발견)

  • #i-clock, .sr-only, .ico-lg 클래스/심볼이 참조만 되고 정의가 없던 것 추가 (.ico-lg는 기존 task_row.html도 쓰고 있던 걸 이번에 같이 고침)
  • 하단 바의 기본 선택 표시가 plans.1로 인덱스 하드코딩되어 있던 것 → {% with selected_plan=plans|last %}로 루프의 forloop.last 기준과 일치시킴 (분량 유지형/핵심 집중형 중 하나가 용량 부족으로 생성되지 않아 plans가 1개만 내려오는 케이스가 실제로 존재해서, 인덱스 하드코딩 시 빈 텍스트가 뜰 수 있었음)
  • recovery_compare.html 상단에 남아있던 디자인 툴 복붙 잔재 텍스트 제거

주요 원칙 (기준안)

  • 복구안은 생성 즉시 적용하지 않고, 사용자 승인 후에만 미래 계획을 변경한다
  • 제외되는 작업을 명확히 보여주고, 승인 없이 제외하지 않는다
  • 복구 유형은 2개다 (깊이 조절형은 MVP 제외)

이번 PR 범위 밖

  • View/URL 연결 (BE 담당) — 더미 데이터로 마크업만 진행

확인 기준

  • 복구안 2개가 같은 눈금의 Fit Bar로 렌더
  • 제외되는 작업 목록이 접히지 않고 보임
  • 선택한 복구안이 하단 바에 표시됨 (복구안이 1개만 내려오는 경우도 포함)
  • 미리보기에서 날짜별 변화가 before/after로 비교됨
  • 320 / 375 / 767 / 1440 레이아웃 정상

Close #68

@wngjs8114

Copy link
Copy Markdown
Collaborator

확인했습니다! recovery_card.html에 plan context 필드를 comment로 문서화해주신 게 특히 좋았어요. View 만들 때 계약으로 바로 참고할 수 있을 것 같습니다. 인덱스 하드코딩이나 누락된 아이콘/클래스를 셀프 체크해주신 부분도 확인했습니다.

병합 전에 네 가지만 확인 부탁드려요.

1. messages 루프가 빠졌습니다

recovery_compare.html, recovery_result.html 둘 다 {% block body %}를 통째로 재정의하면서 base.html의 messages 루프가 빠집니다.

복구안 적용 시 가용시간 변경 등으로 적용에 실패하면 View에서 messages.error()로 안내할 예정이라, 두 화면 모두 messages 출력 영역을 추가 부탁드립니다.

{% for message in messages %}
  <div class="banner">{{ message }}</div>
{% endfor %}

2. RecoveryPlan PK를 전달할 수 있어야 합니다

현재 recovery_card.html의 radio value는 plan.recovery_type이고, recovery_result.html의 적용 버튼에도 plan 식별자가 없습니다.

하지만 실제 적용은 특정 RecoveryPlan을 대상으로 해야 하고, maintain_volume / core_focus 같은 recovery_type만으로는 어느 복구 그룹의 계획인지 특정할 수 없습니다.

라디오와 적용 버튼 모두 plan.id를 기준으로 연결할 수 있도록 부탁드립니다.

<input type="radio" name="recovery" value="{{ plan.id }}" ...>

<button class="btn btn-accent btn-lg"
        type="button"
        data-plan-id="{{ plan.id }}">
  {{ plan.type_label }} 적용
</button>

recovery_card.html 상단의 plan context 필드 목록에도 id를 추가해주시면 좋을 것 같습니다.

3. 복구안이 0개 생성되는 경우도 처리 부탁드립니다

현재 1개만 생성되는 경우는 잘 처리되어 있는데, 실제 복구 로직에서는 분량 유지형과 핵심 집중형이 둘 다 생성되지 않을 수도 있습니다.

이 경우 현재 템플릿에서는 카드가 하나도 없는데 하단의 선택한 복구안미리보기 버튼은 그대로 남게 됩니다.

plans가 비어 있을 경우 별도 empty state를 보여주고 미리보기 버튼은 노출되지 않도록 처리 부탁드립니다.

예시 문구는
현재 남은 가용시간으로 적용 가능한 복구안을 만들 수 없습니다.
정도면 될 것 같습니다.

4. 오늘 못한 분량에 PARTIAL 잔여분도 포함되어야 합니다

현재 화면은 reason.not_done_minutes, reason.not_done_count 기준인데, 실제 복구 로직은 NOT_DONE뿐 아니라 PARTIAL 작업의 남은 분량도 복구 대상으로 계산합니다.

예를 들어 50% 일부완료한 작업은 남은 50%가 복구 대상으로 넘어갑니다.

따라서 오늘 못한 분량보다는 오늘 남은 분량 또는 오늘 미완료 분량으로 표현하고, context도 PARTIAL 잔여분까지 포함할 수 있는 형태로 잡아주시면 좋을 것 같습니다.

위 네 가지 반영되면 화면 구현 범위에서는 승인하겠습니다!

@borissal1207

Copy link
Copy Markdown
Collaborator Author

피드백 4가지 모두 반영했습니다.

  1. recovery_compare.html, recovery_result.html에 messages 출력 영역({% for message in messages %}<div class="banner">...) 추가
  2. 라디오 value·적용 버튼 모두 plan.id(RecoveryPlan PK) 기준으로 변경, recovery_card.html 필드 주석에도 id 추가
  3. plans가 비어있는 경우 empty state("현재 남은 가용시간으로 적용 가능한 복구안을 만들 수 없습니다.")로 분기, 이 경우 선택/미리보기 바는 노출 안 함
  4. reason.not_done_*reason.remaining_*로 변경, 라벨도 "오늘 남은 분량"으로 수정해 일부완료 잔여분 포함되는 걸 반영

확인 부탁드립니다!

@wngjs8114

Copy link
Copy Markdown
Collaborator

추가 반영 확인했습니다! 기존에 말씀드린 4가지(messages, RecoveryPlan PK, 0개 empty state, PARTIAL 잔여분)는 모두 잘 반영된 것 확인했습니다.

실제 복구 로직과 연결해서 다시 보니 두 가지만 추가로 확인 부탁드릴게요.

1. 학습 속도 보정이 단일 과목/단일 speed_factor 기준으로 되어 있습니다

현재 화면은 reason.speed_factor, reason.speed_subject, reason.speed_added_minutes 하나씩 받도록 되어 있는데, 실제 speed_factor는 과목(Exam)별 값이고 복구 로직도 미완료 작업마다 해당 과목의 최신 speed_factor를 사용해 예상시간을 다시 계산합니다.

따라서 오늘 미완료 작업이 여러 과목에 걸쳐 있으면 하나의 speed_factor / speed_subject로 표현하기 어렵습니다.

MVP에서는 과목 하나를 특정하기보다 예를 들어

학습 속도 보정 반영
재추정된 공부량 +30분

처럼 전체 증가분만 보여주도록 context/문구를 단순화하는 방향이 좋을 것 같습니다.
과목별로 보여주려면 speed_adjustments[] 형태가 필요합니다.

2. 선택한 RecoveryPlan PK가 미리보기 버튼까지는 연결되지 않습니다

라디오 value="{{ plan.id }}" 반영은 확인했습니다.

다만 현재 미리보기 버튼은 아직 href="#"이고, planner.js에서도 선택 시 카드 스타일과 recLabel만 변경해서 실제 선택된 plan.id가 미리보기 액션 쪽에는 전달되지 않습니다.

View/URL 연결 자체는 BE 범위이므로 실제 URL 연결까지는 필요 없고, 선택된 radio의 plan.id를 미리보기 버튼의 data-plan-id 등에 동기화할 수 있게만 준비 부탁드립니다. 그러면 이후 BE에서 해당 PK 기준으로 미리보기 View를 바로 연결할 수 있을 것 같습니다.

이 두 가지까지 반영되면 화면 구현 범위에서는 머지해도 될 것 같습니다!

추가로 병합 차단 사항은 아니지만 sidebar.html에서 기존 today_counttitle 속성이 이번 작업과 무관하게 제거되어 있어서 가능하면 원복 부탁드립니다.

@borissal1207

Copy link
Copy Markdown
Collaborator Author
  1. 학습 속도 보정 단순화 (recovery_compare.html)
    reason.speed_factor / speed_subject / speed_added_minutes 세 필드 조합 → reason.speed_added_minutes 하나만 사용
    문구: 라벨 "학습 속도 보정 반영" / 값 "+N분" / 서브 "재추정된 공부량"으로 단순화
    과목별로 보여줘야 할 일이 생기면 speed_adjustments[] 형태로 나중에 확장하면 될 것 같습니다 !

  2. 선택된 RecoveryPlan PK를 미리보기 버튼까지 동기화
    recovery_compare.html: 미리보기 버튼에 id="previewBtn" data-plan-id="{{ selected_plan.id }}" 추가 (초기값은 기본 선택된 카드 기준)
    planner.js: 라디오 선택 바뀔 때마다 previewBtn.dataset.planId = input.value로 동기화 (라디오 value는 이미 plan.id라 그대로 씀)
    URL 연결은 안 했고, BE가 data-plan-id 읽어서 붙이면 되는 상태로만 준비했습니다 !

  3. sidebar.html의 today_count title 속성 복구
    title="오늘 계획된 작업 {{ today_count }}개" 되돌려놨습니다 !
    (이 브랜치 히스토리 어딘가에서 실수로 빠졌던 것 같습니다)

@wngjs8114

Copy link
Copy Markdown
Collaborator

최종 반영 확인했습니다!
학습 속도 보정 단순화, 선택된 RecoveryPlan PK의 previewBtn 동기화, sidebar today_count title 복구 모두 확인했습니다.

병합 전에 두 가지만 추가 확인 부탁드려요.

  1. .claude/settings.json 제거 부탁드립니다.
    이번 커밋에 Claude 로컬 권한 설정 파일이 같이 추가됐는데, 이번 복구 화면 작업과 무관한 파일이라 PR에서는 제외하는 게 좋을 것 같습니다.

  2. recovery_card.html context 계약 변경 확인 부탁드립니다.
    기존 desc/status/status_label이 이번 커밋에서 summary/feasibility_status/feasibility_status_label로 변경됐습니다. feasibility_status로 분리한 방향은 RecoveryPlan의 status(pending/applied/discarded)와 헷갈리지 않아서 좋은 것 같습니다. 이 계약으로 확정하면 BE feat: #81 복구안 비교 View 연결 (recovery_compare) #88 쪽을 제가 맞추겠습니다.

다만 현재 RecoveryPlan.summary는 복구안 생성 시 저장하지 않고 있어서 summary를 모델 필드 그대로 사용하면 빈 값입니다. summary는 RecoveryPlan.summary라고 명시하기보다 View에서 구성해서 넘기는 한 줄 설명으로 주석만 수정 부탁드립니다.

추가로 병합 차단 사항은 아니지만 recovery_result.html의 “적용해도 나중에 다시 바꿀 수 있습니다”는 되돌리기 기능으로 오해할 수 있어서, “공부가 다시 밀리면 새 복구안을 만들 수 있습니다” 정도가 실제 정책에는 더 정확할 것 같습니다.

위 부분만 확인되면 화면 구현 PR은 머지해도 될 것 같습니다!

- .claude/settings.json을 트래킹에서 제외하고 .gitignore에 추가
- recovery_card.html: summary가 RecoveryPlan.summary 그대로가 아니라
  View에서 구성해서 넘겨야 함을 주석에 명시
- recovery_result.html: "적용해도 나중에 다시 바꿀 수 있습니다"가
  되돌리기로 오해될 수 있어 "공부가 다시 밀리면 새 복구안을 만들 수
  있습니다"로 수정
dev에 이미 .cph/가 추가돼 있어서 같은 자리에 .claude/를 추가하면
머지 충돌이 남. gitignore는 건드리지 않고 .claude 폴더 자체를
로컬에서 삭제하는 방식으로 정리.
@borissal1207
borissal1207 merged commit 3ab07bf into dev Aug 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[planner/FE] 복구안 비교 및 미리보기 화면 구현

2 participants