Skip to content

feat(plan): Routes API 기반 일정 경로 조회와 실시간 갱신 개선#114

Open
minbros wants to merge 8 commits into
mainfrom
codex/travel-mode-polyline-latest
Open

feat(plan): Routes API 기반 일정 경로 조회와 실시간 갱신 개선#114
minbros wants to merge 8 commits into
mainfrom
codex/travel-mode-polyline-latest

Conversation

@minbros

@minbros minbros commented Jul 16, 2026

Copy link
Copy Markdown
Member

변경 사항

  • Google Routes API 응답을 기반으로 일정 구간의 polyline, 거리, 소요 시간을 조회하도록 경로 처리를 개선했습니다.
  • 이동수단 변경과 일정 항목 생성·삭제·정렬·일차 간 이동 시 경로 캐시를 정확히 갱신합니다.
  • 서버가 내려주는 affectedRouteItemIds와 일정 생성 델타 응답을 사용해 영향받는 경로 구간만 무효화합니다.
  • 일정 일차 토글 버튼 겹침을 수정하고 경로 조회·캐시 갱신 회귀 테스트를 추가했습니다.

배경

STOMP 이벤트 수신 시 클라이언트 캐시만으로 영향받는 경로 구간을 추론하면, 항목 재조회 시점이나 일차 간 이동 순서에 따라 오래된 구간이 남을 수 있었습니다. 또한 이동수단별로 분리된 경로 쿼리와 지도 렌더링 상태를 함께 갱신할 필요가 있었습니다.

서버가 계산한 영향 범위를 단일 기준으로 사용하고, 항목 데이터 재조회 후 해당 구간의 쿼리와 지도 세그먼트를 갱신하도록 순서를 정리했습니다.

사용자 영향

  • 일정 편집 직후 지도와 이동 카드에 최신 경로가 일관되게 표시됩니다.
  • 불필요한 전체 경로 재조회 대신 영향받는 구간만 갱신합니다.
  • 일정 일차 토글 영역의 버튼 겹침이 해소됩니다.

검증

  • npm test: 20개 파일, 42개 테스트 통과
  • 변경 파일 ESLint: 통과
  • npm run build: 통과
  • npm run lint: 변경 범위 밖 기존 오류 37건으로 실패

Summary by CodeRabbit

  • 새 기능
    • 일정 항목을 원하는 위치(orderIndex)로 삽입하면 생성/변경 델타가 반환되어 클라이언트 캐시와 순서가 자동 동기화됩니다.
    • 일정 변경 시 서버가 지정한 범위만 경로를 갱신해 반영 속도와 정확도가 개선됩니다.
    • 저장된 “구간별 공유 이동수단” 기준으로 지도 경로가 표시됩니다.
  • 버그 수정
    • 일정 섹션 펼침/접힘 아이콘이 제목과 겹치지 않도록 정리되었습니다.
    • 지도 경로 계산 실패·무효화 상태에서 최신 경로를 안정적으로 다시 불러옵니다.
  • 테스트/문서
    • 관련 문서·회귀 테스트를 추가/확대했습니다.

minbros and others added 7 commits July 15, 2026 23:36
- 구간별 선택 이동수단을 지도 폴리라인 경로 조회에 연결
- 지도 경로 상태 및 단위 테스트 추가
- 무효화된 경로 캐시 재사용 방지
- 삭제 후 재추가 회귀 테스트 추가
- 생성 요청에 orderIndex를 전달하고 후속 재정렬 제거
- 생성·변경 항목 델타를 일정 캐시에 병합
- DirectionsService를 Route.computeRoutes로 교체
- Google Maps 타입 갱신 및 경로 조회 테스트 추가
- 펼침 아이콘을 헤더 오른쪽으로 정렬
- 레이아웃 회귀 테스트 추가
- 일정 생성·삭제·정렬·이동 시 서버의 affectedRouteItemIds를 사용
- 이동수단 변경 후 항목 재조회와 경로 무효화 순서를 보장
- 경로 캐시 갱신 회귀 테스트 추가
@vercel

vercel Bot commented Jul 16, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
frontend-server Ready Ready Preview, Comment Jul 16, 2026 3:16pm

@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 11720083-082d-4589-b08d-a9cc35efed90

📥 Commits

Reviewing files that changed from the base of the PR and between b48206b and 0631207.

📒 Files selected for processing (7)
  • src/lib/maps-routes.test.ts
  • src/lib/maps.ts
  • src/lib/plan/planItineraryMapSegments.test.ts
  • src/lib/plan/scheduleItemPlaces.create.test.ts
  • src/lib/plan/scheduleItemPlaces.ts
  • src/lib/stomp/schedules-dispatch.test.ts
  • src/lib/stomp/schedules-dispatch.ts
🚧 Files skipped from review as they are similar to previous changes (6)
  • src/lib/maps-routes.test.ts
  • src/lib/stomp/schedules-dispatch.test.ts
  • src/lib/plan/scheduleItemPlaces.create.test.ts
  • src/lib/maps.ts
  • src/lib/stomp/schedules-dispatch.ts
  • src/lib/plan/scheduleItemPlaces.ts

📝 Walkthrough

Walkthrough

일정 항목 생성이 서버 지정 위치와 델타 응답을 사용하도록 확장되었습니다. STOMP 경로 무효화가 서버 제공 ID 기반으로 정밀화되었고, 지도 경로 계산·이동수단 전달·일정 헤더 레이아웃이 수정되었습니다.

Changes

일정 델타 동기화

Layer / File(s) Summary
생성 계약과 캐시 병합
docs/superpowers/plans/..., src/lib/api/rooms/..., src/lib/plan/scheduleItemPlaces*
orderIndex와 생성 델타 응답을 추가하고, 결과를 캐시에 병합하거나 불일치 시 재조회합니다.
대상별 경로 무효화와 이벤트 처리
src/lib/stomp/schedules-dispatch*, src/lib/plan/scheduleItemPlaces*, src/lib/plan/scheduleItemRoutePersistedQuery*
STOMP 이벤트와 교차 일정 이동이 affectedRouteItemIds에 따라 전체 또는 소스별 경로를 무효화합니다.

지도 이동수단과 경로 계산

Layer / File(s) Summary
세그먼트 이동수단 전달
src/lib/plan/planItineraryMapSegments*, src/components/map/PlanItineraryMapRoutes.tsx
저장된 이동수단을 정규화해 세그먼트와 폴리라인 키에 반영합니다.
Google Maps 경로 좌표 계산
src/lib/maps*, src/lib/maps-routes.test.ts, package.json
Route.computeRoutes 기반 좌표 계산과 실패 시 빈 배열 반환을 구현하고 지도 타입을 추가합니다.

일정 섹션 토글 레이아웃

Layer / File(s) Summary
헤더 토글 정렬
src/app/(main)/plan/_components/itinerary/PlanDaySection*
Chevron 아이콘을 헤더 버튼 오른쪽으로 이동하고 렌더링 테스트를 추가했습니다.

개발 환경 설정

Layer / File(s) Summary
IDE 무시와 지도 타입
.gitignore, package.json
.idea/ 무시 규칙과 Google Maps 타입 의존성을 추가했습니다.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant PlanClient
  participant ScheduleItemsAPI
  participant QueryCache
  participant RouteInvalidation
  PlanClient->>ScheduleItemsAPI: orderIndex를 포함한 항목 생성
  ScheduleItemsAPI-->>PlanClient: 생성·변경·영향 라우트 델타 반환
  PlanClient->>QueryCache: 델타를 계획 장소 캐시에 병합
  PlanClient->>RouteInvalidation: 영향받은 경로 소스 무효화
Loading

Possibly related issues

  • how-about-us/backend-server#124: 일정 항목의 저장된 travelMode와 경로 무효화·브로드캐스팅 변경이 해당 이슈의 요구사항과 직접 연결됩니다.

Possibly related PRs

  • uttae/frontend-server#111: STOMP 이동수단 변경 이벤트와 일정 이동수단 동기화 경로를 함께 수정합니다.

Poem

당근 토끼가 새 위치를 심고
델타가 캐시에 살포시 앉네.
필요한 길만 다시 빛나고
이동수단도 제 빛을 찾지.
깡충, 말끔한 일정!

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed Routes API 기반 경로 조회와 일정 변경 시 실시간 갱신 개선이라는 핵심 변경점을 잘 요약합니다.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/lib/stomp/schedules-dispatch.ts (1)

155-189: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

비동기 GET 시작 전에 route 버킷을 캡처하고 제거하세요.

현재 GET 진행 중 새 이벤트가 같은 mapKey에 버킷을 추가하면, 이전 요청이 그 신규 버킷까지 삭제합니다. 이후 두 번째 조회는 route 무효화 없이 끝나 지도 경로가 stale 상태로 남을 수 있으며, catch 경로도 신규 버킷을 지웁니다.

타이머 콜백 시작 시 버킷을 읽고 즉시 삭제한 뒤, 캡처한 값만 해당 비동기 작업에서 처리하세요.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/stomp/schedules-dispatch.ts` around lines 155 - 189, In the
setTimeout callback within the schedule-place sync flow, capture the current
value from syncSchedulePlacesRouteInvalidationPending using mapKey and delete
that entry before starting the asynchronous getScheduleItems request. Use only
the captured route bucket for scope checks, source invalidation, and map
updates, and ensure the catch path does not delete a newer bucket added while
the request is running.
🧹 Nitpick comments (2)
src/app/(main)/plan/_components/itinerary/PlanDaySection.test.tsx (1)

8-27: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

@testing-library/react 사용을 고려해 보세요.

정규식을 이용해 정적 HTML 문자열을 파싱하고 검사하는 방식은 마크업 구조가 약간만 변경되어도 테스트가 깨지기 쉽습니다.

React 생태계의 표준적인 테스트 도구인 @testing-library/react를 활용해 DOM 노드를 직접 탐색하고 검증하는 방식으로 리팩터링하는 것을 추천합니다. (단, Vitest 설정에 jsdom 또는 happy-dom 환경이 구성되어 있어야 합니다.)

🛠 제안하는 리팩터링
-import { createElement } from "react";
-import { renderToStaticMarkup } from "react-dom/server";
+import { render, screen } from "`@testing-library/react`";
 import { describe, expect, it } from "vitest";

 import { PlanDaySection } from "./PlanDaySection";

 describe("PlanDaySection", () => {
   it("펼침 토글 아이콘을 제목과 겹치지 않게 버튼 오른쪽에 배치한다", () => {
-    const html = renderToStaticMarkup(
-      createElement(
-        PlanDaySection,
-        {
-          title: "1일차",
-          subtitle: "7월 16일 (목)",
-        },
-        createElement("div", null, "일정"),
-      ),
-    );
-
-    const triggerMarkup = html.match(
-      /<button[^>]*aria-expanded="true"[^>]*>([\s\S]*?)<\/button>/,
-    )?.[1];
-
-    expect(triggerMarkup).toContain("ml-auto");
-    expect(triggerMarkup).toContain("shrink-0");
-    expect(html).not.toContain("absolute left-1/2");
+    const { container } = render(
+      <PlanDaySection title="1일차" subtitle="7월 16일 (목)">
+        <div>일정</div>
+      </PlanDaySection>
+    );
+
+    const button = screen.getByRole("button", { expanded: true });
+    const iconContainer = button.querySelector("span[aria-hidden='true']");
+
+    expect(iconContainer?.className).toContain("ml-auto");
+    expect(iconContainer?.className).toContain("shrink-0");
+    expect(container.innerHTML).not.toContain("absolute left-1/2");
   });
 });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/app/`(main)/plan/_components/itinerary/PlanDaySection.test.tsx around
lines 8 - 27, Refactor the PlanDaySection test to use `@testing-library/react`
rendering and DOM queries instead of renderToStaticMarkup and regular-expression
parsing. Locate the expanded button through its accessible state, assert its
class list contains ml-auto and shrink-0, and verify no matching centered
absolute element exists; ensure the test environment provides jsdom or
happy-dom.
src/lib/plan/planItineraryMapSegments.test.ts (1)

5-22: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

정규화와 기본값 폴백도 회귀 테스트로 고정해 주세요.

현재 테스트는 이미 canonical한 값만 검증하므로, 소문자 입력과 누락된 이동수단이 각각 WALKING, DRIVING으로 변환되는지 추가 검증하는 편이 안전합니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/plan/planItineraryMapSegments.test.ts` around lines 5 - 22, Extend
the test around flattenPlanItinerarySegmentsFromPlaces with cases covering
lowercase travelMode input and an omitted travel mode. Assert that normalization
produces “WALKING” for the lowercase value and the default fallback produces
“DRIVING” when the value is missing, while preserving the existing
canonical-value assertion.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/lib/maps.ts`:
- Around line 267-281: Update fetchPlanSegmentPathLatLng in src/lib/maps.ts to
use DRIVING when segmentTravelMode is omitted, matching
SCHEDULE_TRAVEL_MODE_DEFAULT instead of the current WALKING fallback. Add or
update the omitted-mode test in src/lib/maps-routes.test.ts around lines 48-65
to assert that computeRoutes receives travelMode: "DRIVING".

In `@src/lib/plan/scheduleItemPlaces.ts`:
- Around line 731-753: Separate the post-creation cache synchronization from the
mutation success path around getScheduleItems,
mergeOrRefetchSchedulePlanPlacesFromItems,
invalidateScheduleItemRouteForSources, and bumpPlanMapRouteSegments. Handle
synchronization failures as best-effort: mark the affected schedule/route caches
stale or invalidate them, then return response.createdItem instead of rejecting
after the POST has succeeded.

---

Outside diff comments:
In `@src/lib/stomp/schedules-dispatch.ts`:
- Around line 155-189: In the setTimeout callback within the schedule-place sync
flow, capture the current value from syncSchedulePlacesRouteInvalidationPending
using mapKey and delete that entry before starting the asynchronous
getScheduleItems request. Use only the captured route bucket for scope checks,
source invalidation, and map updates, and ensure the catch path does not delete
a newer bucket added while the request is running.

---

Nitpick comments:
In `@src/app/`(main)/plan/_components/itinerary/PlanDaySection.test.tsx:
- Around line 8-27: Refactor the PlanDaySection test to use
`@testing-library/react` rendering and DOM queries instead of renderToStaticMarkup
and regular-expression parsing. Locate the expanded button through its
accessible state, assert its class list contains ml-auto and shrink-0, and
verify no matching centered absolute element exists; ensure the test environment
provides jsdom or happy-dom.

In `@src/lib/plan/planItineraryMapSegments.test.ts`:
- Around line 5-22: Extend the test around
flattenPlanItinerarySegmentsFromPlaces with cases covering lowercase travelMode
input and an omitted travel mode. Assert that normalization produces “WALKING”
for the lowercase value and the default fallback produces “DRIVING” when the
value is missing, while preserving the existing canonical-value assertion.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 50240381-ccfb-455e-8055-e802cea993ff

📥 Commits

Reviewing files that changed from the base of the PR and between db23c91 and b48206b.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (19)
  • .gitignore
  • docs/superpowers/plans/2026-07-16-schedule-item-insert-delta.md
  • package.json
  • src/app/(main)/plan/_components/itinerary/PlanDaySection.test.tsx
  • src/app/(main)/plan/_components/itinerary/PlanDaySection.tsx
  • src/components/map/PlanItineraryMapRoutes.tsx
  • src/lib/api/rooms/index.ts
  • src/lib/api/rooms/schedule-items.ts
  • src/lib/maps-routes.test.ts
  • src/lib/maps.ts
  • src/lib/plan/planItineraryMapSegments.test.ts
  • src/lib/plan/planItineraryMapSegments.ts
  • src/lib/plan/scheduleItemPlaces.create.test.ts
  • src/lib/plan/scheduleItemPlaces.test.ts
  • src/lib/plan/scheduleItemPlaces.ts
  • src/lib/plan/scheduleItemRoutePersistedQuery.test.ts
  • src/lib/plan/scheduleItemRoutePersistedQuery.ts
  • src/lib/stomp/schedules-dispatch.test.ts
  • src/lib/stomp/schedules-dispatch.ts

Comment thread src/lib/maps.ts
Comment thread src/lib/plan/scheduleItemPlaces.ts Outdated
- 생성 성공 이후 캐시 동기화 실패를 stale fallback으로 처리
- STOMP 경로 버킷 경쟁 조건 방지
- 이동수단 기본값과 정규화 회귀 테스트 보강
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.

1 participant