Skip to content

Conversation

@salmonco
Copy link
Contributor

@salmonco salmonco commented Jan 28, 2026

๐Ÿ”— 1. ์—ฐ๊ด€ ์ด์Šˆ

๐Ÿ›  2. ์ž‘์—… ๋‚ด์šฉ

  • edit photo note

๐Ÿ“Œ 3. ์ฐธ๊ณ  ์‚ฌํ•ญ

ํ”ผ๊ทธ๋งˆ

๐Ÿ‘€ 4. ๋ฆฌ๋ทฐ ์ค‘์  ์‚ฌํ•ญ

  • ๋ถ„๋ฆฌ๋ฅผ ์ ์ ˆํžˆ ํ–ˆ๋Š”์ง€

๐Ÿงช 5. ํ…Œ์ŠคํŠธ

  • ์‚ฌ์ง„ ๊ธฐ๋ก ์ˆ˜์ •

ํ…Œ์ŠคํŠธ ๋ฐฉ๋ฒ•

  1. http://localhost:3000/photo/1
  2. ์ƒ๋‹จ ๋ฉ”๋‰ด > ๊ธฐ๋ก ์ˆ˜์ •ํ•˜๊ธฐ
2026-01-29.1.40.08.mov

Summary by CodeRabbit

  • ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ

    • ์‚ฌ์ง„ ์ƒ์„ธ์—์„œ ๋ฉ”๋ชจ, ์•จ๋ฒ”, ์œ„์น˜๋ฅผ ํ•œ ํ™”๋ฉด์—์„œ ํŽธ์ง‘ํ•˜๊ณ  ์ €์žฅํ•  ์ˆ˜ ์žˆ๋Š” ํŽธ์ง‘ ์˜ค๋ฒ„๋ ˆ์ด๊ฐ€ ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
    • ํŽธ์ง‘ ์ค‘ ๋กœ๋”ฉ ์ƒํƒœ์™€ ๋ณ€๊ฒฝ ์ƒํƒœ๋ฅผ ํ‘œ์‹œํ•˜๋Š” ํˆดํŒ ๋ฐ ๋งต ๋ฏธ๋ฆฌ๋ณด๊ธฐ/์œ„์น˜ ํŽธ์ง‘ ์ปจํŠธ๋กค์ด ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.
  • ์Šคํƒ€์ผ

    • ๋ฉ”๋‰ด ๋“œ๋กญ๋‹ค์šด๊ณผ ํ•ญ๋ชฉ์˜ ์‹œ๊ฐ ๋””์ž์ธ(๋ฐฐ๊ฒฝ, ๋‘ฅ๊ทผ ๋ชจ์„œ๋ฆฌ, ๋ธ”๋Ÿฌ, ๊ธ€๊ผด ๋“ฑ)์„ ๊ฐœ์„ ํ–ˆ์Šต๋‹ˆ๋‹ค.
    • ์œ„์น˜ ์„ ํƒ ๋ฐ ์ฒดํฌ ์•„์ด์ฝ˜ ๋“ฑ ์ผ๋ถ€ UI ์•„์ด์ฝ˜ ํฌ๊ธฐ ๋ฐ ์Šคํฌ๋กค ๋™์ž‘์„ ์กฐ์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.

โœ๏ธ Tip: You can customize this high-level summary in your review settings.

@salmonco salmonco self-assigned this Jan 28, 2026
@salmonco salmonco requested a review from H0ngJu as a code owner January 28, 2026 16:42
@netlify
Copy link

netlify bot commented Jan 28, 2026

โœ… Deploy Preview for timely-pudding-5af14b ready!

Name Link
๐Ÿ”จ Latest commit dcd07b1
๐Ÿ” Latest deploy log https://app.netlify.com/projects/timely-pudding-5af14b/deploys/697a40bc6b4c730008a02321
๐Ÿ˜Ž Deploy Preview https://deploy-preview-49--timely-pudding-5af14b.netlify.app
๐Ÿ“ฑ Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai
Copy link

coderabbitai bot commented Jan 28, 2026

์›Œํฌ์Šค๋ฃจ

์‚ฌ์ง„ ๊ธฐ๋ก ํŽธ์ง‘ ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. PhotoEditOverlay ์ปดํฌ๋„ŒํŠธ์™€ usePhotoEdit ํ›…์„ ๋„์ž…ํ•ด ๋ฉ”๋ชจยท์•จ๋ฒ”ยท์œ„์น˜ ํŽธ์ง‘ UI๋ฅผ ์ œ๊ณตํ•˜๊ณ  ํŽ˜์ด์ง€์— ํ†ตํ•ฉํ–ˆ์œผ๋ฉฐ, ๊ด€๋ จ ์Šคํƒ€์ผยทํ›…ยท๋ชฉ ๋ฐ์ดํ„ฐ ๋ฐ ์ผ๋ถ€ UI ์ปดํฌ๋„ŒํŠธ๋ฅผ ์—…๋ฐ์ดํŠธํ–ˆ์Šต๋‹ˆ๋‹ค.

๋ณ€๊ฒฝ์‚ฌํ•ญ

Cohort / File(s) ์š”์•ฝ
์‚ฌ์ง„ ํŽธ์ง‘ ์˜ค๋ฒ„๋ ˆ์ด ์Šคํƒ€์ผ
apps/web/src/app/photo/[photoId]/_components/PhotoEditOverlay.styles.ts
Emotion์œผ๋กœ ์ž‘์„ฑ๋œ ๋‹ค์ˆ˜(์•ฝ 22๊ฐœ)์˜ ์Šคํƒ€์ผ ์ปดํฌ๋„ŒํŠธ ์ถ”๊ฐ€: ์ปจํ…Œ์ด๋„ˆ, ์˜ค๋ฒ„๋ ˆ์ด, ํˆดํŒ, ๋ฒ„ํŠผ ๋“ฑ UI ๊ตฌ์„ฑ ์š”์†Œ ์ •์˜
์‚ฌ์ง„ ํŽธ์ง‘ ์˜ค๋ฒ„๋ ˆ์ด ์ปดํฌ๋„ŒํŠธ
apps/web/src/app/photo/[photoId]/_components/PhotoEditOverlay.tsx
ํด๋ผ์ด์–ธํŠธ ์ „์šฉ React ์ปดํฌ๋„ŒํŠธ ์ถ”๊ฐ€: photoDetail ์กฐํšŒ, ๋ฉ”๋ชจ/์•จ๋ฒ”/์œ„์น˜ ๋ชจ๋‹ฌ ์—ฐ๋™, ์ €์žฅ ์ฝœ๋ฐฑ(onSave) ํ˜ธ์ถœ ๋กœ์ง ํฌํ•จ
์‚ฌ์ง„ ํŽธ์ง‘ ํ›… ๋ฐ ์ธ๋ฑ์Šค
apps/web/src/app/photo/[photoId]/_hooks/usePhotoEdit.ts
apps/web/src/app/photo/[photoId]/_hooks/index.ts
ํŽธ์ง‘ ์ƒํƒœ ๊ด€๋ฆฌ ํ›… ์ถ”๊ฐ€(usePhotoEdit) ๋ฐ ํ›… ๋ฐ”๋ ์— ์žฌ๋‚ด๋ณด๋‚ด๊ธฐ ์ถ”๊ฐ€ (open/close/save ๊ธฐ๋Šฅ ์ œ๊ณต)
ํŽ˜์ด์ง€ ํ†ตํ•ฉ ๋ฐ ์Šคํƒ€์ผ
apps/web/src/app/photo/[photoId]/page.tsx
apps/web/src/app/photo/[photoId]/page.styles.ts
ํŽ˜์ด์ง€์— usePhotoEdit ๋ฐ PhotoEditOverlay ํ†ตํ•ฉ(AnimatePresence ์‚ฌ์šฉ), "๊ธฐ๋ก ์ˆ˜์ •ํ•˜๊ธฐ" ์•ก์…˜ ์ถ”๊ฐ€, HeaderWrapper z-index ์ƒํ–ฅ(10โ†’30)
๋ฉ”๋ชจ ๋ชจ๋‹ฌ ํ›… ๊ฐœ์„ 
apps/web/src/app/photo/add/note/_hooks/useMemoModal.ts
initialMemo ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฐ useEffect ๋™๊ธฐํ™” ์ถ”๊ฐ€; setMemo๋ฅผ ๋ฐ˜ํ™˜๊ฐ’์œผ๋กœ ๋…ธ์ถœ
์œ„์น˜ ์„ ํƒ UI ์กฐ์ •
apps/web/src/app/photo/add/note/_components/LocationSelectOverlay.styles.ts
apps/web/src/app/photo/add/note/_components/LocationSelectOverlay.tsx
์ฒดํฌ ์•„์ด์ฝ˜ ํฌ๊ธฐ ์ถ•์†Œ(22โ†’16) ๋ฐ ์Šคํฌ๋กค๋ฐ” ์Šคํƒ€์ผ ์กฐ์ •
๋ฉ”๋‰ด ํ—ค๋” API/์Šคํƒ€์ผ ๋ณ€๊ฒฝ
apps/web/src/components/header/menu/MenuHeader.styles.ts
apps/web/src/components/header/menu/MenuHeader.tsx
apps/web/src/app/test-menu/page.tsx
apps/web/src/components/header/menu/MenuHeader.stories.tsx
MenuItem prop์„ color?: string โ†’ `variant?: 'default'
๋ชฉ(mock) ํ—ฌํผ ๊ฐœ์„ 
apps/web/src/mocks/createHandler.ts
createHandler๊ฐ€ ์˜ต์…˜ ๊ฐ์ฒด(validator, dataResolver) ๋˜๋Š” ๊ธฐ์กด validator ํ˜ธํ™˜ ํ—ˆ์šฉ; dataResolver๋กœ ๋™์  ์‘๋‹ต ์ƒ์„ฑ ๊ฐ€๋Šฅ
๋ชฉ ๋ฐ์ดํ„ฐ ํ™•์žฅ ๋ฐ ๋™์  ์‘๋‹ต
apps/web/src/mocks/handlers/photos/getPhotoDetail/mockData.ts
apps/web/src/mocks/handlers/photos/index.ts
์‚ฌ์ง„ ์ƒ์„ธ ๋ฐ์ดํ„ฐ๋ฅผ 5๊ฐœ ํ•ญ๋ชฉ์˜ ๋งต์œผ๋กœ ํ™•์žฅ; ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ์š”์ฒญ photoId์— ๋”ฐ๋ผ ๋™์ ์œผ๋กœ ์‘๋‹ตํ•˜๋„๋ก ๋ณ€๊ฒฝ

์‹œํ€€์Šค ๋‹ค์ด์–ด๊ทธ๋žจ

sequenceDiagram
    actor User
    participant Page as ์‚ฌ์ง„ ์กฐํšŒ ํŽ˜์ด์ง€
    participant Hook as usePhotoEdit ํ›…
    participant Overlay as PhotoEditOverlay
    participant MemoModal as MemoModal
    participant AlbumModal as AlbumSelectOverlay
    participant LocationModal as LocationSelectOverlay

    User->>Page: "๊ธฐ๋ก ์ˆ˜์ •ํ•˜๊ธฐ" ํด๋ฆญ
    Page->>Hook: openEditOverlay(photoId)
    Hook-->>Page: isEditing = true
    Page->>Overlay: ๋ Œ๋”(AnimatePresence, photoId)
    
    User->>Overlay: ๋ฉ”๋ชจ ํŽธ์ง‘ ํด๋ฆญ
    Overlay->>MemoModal: open()
    MemoModal->>User: ๋ฉ”๋ชจ ์ž…๋ ฅ UI
    User->>MemoModal: ์ €์žฅ
    MemoModal-->>Overlay: memo ์ œ์ถœ

    User->>Overlay: ์•จ๋ฒ” ์„ ํƒ ํด๋ฆญ
    Overlay->>AlbumModal: open()
    AlbumModal->>User: ์•จ๋ฒ” ์„ ํƒ UI
    User->>AlbumModal: ์„ ํƒ
    AlbumModal-->>Overlay: albumId ์ œ์ถœ

    User->>Overlay: ์œ„์น˜ ์„ ํƒ ํด๋ฆญ
    Overlay->>LocationModal: open()
    LocationModal->>User: ์œ„์น˜ ์„ ํƒ UI
    User->>LocationModal: ์„ ํƒ
    LocationModal-->>Overlay: location ์ œ์ถœ

    User->>Overlay: ์ €์žฅ ํด๋ฆญ
    Overlay->>Hook: saveEdit({photoId,memo,albumId,location})
    Hook-->>Page: onSave ์ฝœ๋ฐฑ
    Page->>Hook: closeEditOverlay()
    Hook-->>Page: isEditing = false
    Page->>User: ์˜ค๋ฒ„๋ ˆ์ด ๋‹ซํž˜
Loading

์ถ”์ • ์ฝ”๋“œ ๋ฆฌ๋ทฐ ๋…ธ๋ ฅ

๐ŸŽฏ 3 (์ค‘๊ฐ„) | โฑ๏ธ ~25๋ถ„

์‹œ

๐Ÿฐ ์ƒˆ ๊ธฐ๋ก์„ ๊พน๊พน ๋ˆŒ๋Ÿฌ ๋‹ด์•„
๋ฉ”๋ชจ์™€ ์•จ๋ฒ”, ์œ„์น˜ ํ•œ ์คŒ์”ฉ
์˜ค๋ฒ„๋ ˆ์ด์— ์ˆจ์€ ์†๊ธธ๋กœ ๊ณ ์ณ ์“ฐ๋„ค
์ €์žฅ ๋ฒ„ํŠผ ๋ˆŒ๋Ÿฌ ์ถ”์–ต์„ ์ž ๊ถˆ์š” ๐Ÿ“ธโœจ

๐Ÿšฅ Pre-merge checks | โœ… 3 | โŒ 2
โŒ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage โš ๏ธ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Out of Scope Changes check โ“ Inconclusive MenuHeader ์ปดํฌ๋„ŒํŠธ์˜ color์—์„œ variant๋กœ์˜ ๋ณ€๊ฒฝ๊ณผ LocationSelectOverlay์˜ ์ฒดํฌ๋งˆํฌ ์•„์ด์ฝ˜ ํฌ๊ธฐ ์กฐ์ •์€ ์‚ฌ์ง„ ๊ธฐ๋ก ์ˆ˜์ • ๊ธฐ๋Šฅ๊ณผ์˜ ์ง์ ‘์  ์—ฐ๊ด€์„ฑ์ด ๋ช…ํ™•ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. color์—์„œ variant๋กœ์˜ ๋ณ€๊ฒฝ๊ณผ ์ฒดํฌ๋งˆํฌ ํฌ๊ธฐ ๊ฐ์†Œ๊ฐ€ ์‚ฌ์ง„ ์ˆ˜์ • UI์™€์˜ ํ•„์ˆ˜์  ์—ฐ๊ด€์„ฑ์„ ๋ช…์‹œํ•ด ์ฃผ๊ฑฐ๋‚˜, ๋ฒ”์œ„ ์™ธ ๋ณ€๊ฒฝ์œผ๋กœ ๋ถ„๋ฆฌํ•˜๋Š” ๊ฒƒ์„ ๊ฒ€ํ† ํ•˜์„ธ์š”.
โœ… Passed checks (3 passed)
Check name Status Explanation
Description Check โœ… Passed Check skipped - CodeRabbitโ€™s high-level summary is enabled.
Title check โœ… Passed PR ์ œ๋ชฉ 'feat: edit photo note'๋Š” ์‚ฌ์ง„ ๊ธฐ๋ก ์ˆ˜์ • ๊ธฐ๋Šฅ ์ถ”๊ฐ€๋ผ๋Š” ํ•ต์‹ฌ ๋ณ€๊ฒฝ์‚ฌํ•ญ์„ ๋ช…ํ™•ํ•˜๊ณ  ๊ฐ„๊ฒฐํ•˜๊ฒŒ ์š”์•ฝํ•ฉ๋‹ˆ๋‹ค.
Linked Issues check โœ… Passed PR์—์„œ ๊ตฌํ˜„ํ•œ ์‚ฌ์ง„ ๊ธฐ๋ก ์ˆ˜์ • ๊ธฐ๋Šฅ์ด #48 ์ด์Šˆ์˜ ์š”๊ตฌ์‚ฌํ•ญ(์ˆ˜์ • ๋ถˆ๊ฐ€๋Šฅํ•œ ์ƒํƒœ์—์„œ ์ˆ˜์ • ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋ณ€๊ฒฝ)์„ ์ถฉ์กฑํ•ฉ๋‹ˆ๋‹ค.

โœ๏ธ Tip: You can configure your own custom pre-merge checks in the settings.

โœจ Finishing touches
  • ๐Ÿ“ Generate docstrings

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 and usage tips.

@gemini-code-assist
Copy link

Summary of Changes

Hello @salmonco, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

์ด PR์€ ์‚ฌ์šฉ์ž๊ฐ€ ์‚ฌ์ง„ ์ƒ์„ธ ํŽ˜์ด์ง€์—์„œ ์‚ฌ์ง„์˜ ๋ฉ”๋ชจ, ์•จ๋ฒ”, ์œ„์น˜ ์ •๋ณด๋ฅผ ์ง์ ‘ ํŽธ์ง‘ํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์„ ๋„์ž…ํ•ฉ๋‹ˆ๋‹ค. ์ƒˆ๋กœ์šด ํŽธ์ง‘ ์˜ค๋ฒ„๋ ˆ์ด ์ปดํฌ๋„ŒํŠธ์™€ ์ด๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ํ›…์„ ํ†ตํ•ด ๊ธฐ์กด ์‚ฌ์ง„ ์ •๋ณด์— ๋Œ€ํ•œ ์ˆ˜์ • ์ ‘๊ทผ์„ฑ์„ ๋†’์ด๊ณ , ์‚ฌ์šฉ์ž์—๊ฒŒ ๋”์šฑ ์œ ์—ฐํ•œ ๋ฐ์ดํ„ฐ ๊ด€๋ฆฌ ๊ฒฝํ—˜์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ, ๊ฐœ๋ฐœ ํŽธ์˜์„ฑ์„ ์œ„ํ•ด ๋ชฉ(mock) ๋ฐ์ดํ„ฐ ํ•ธ๋“ค๋ง ๋กœ์ง๋„ ๊ฐœ์„ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

Highlights

  • ์‚ฌ์ง„ ๊ธฐ๋ก ์ˆ˜์ • ๊ธฐ๋Šฅ ์ถ”๊ฐ€: ์‚ฌ์ง„ ์ƒ์„ธ ํŽ˜์ด์ง€์—์„œ ๋ฉ”๋ชจ, ์•จ๋ฒ”, ์œ„์น˜ ์ •๋ณด๋ฅผ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๋Š” PhotoEditOverlay ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
  • ์ƒˆ๋กœ์šด ํ›… usePhotoEdit ๋„์ž…: ์‚ฌ์ง„ ํŽธ์ง‘ ์˜ค๋ฒ„๋ ˆ์ด์˜ ์ƒํƒœ ๊ด€๋ฆฌ ๋ฐ ์ €์žฅ ๋กœ์ง์„ ๋‹ด๋‹นํ•˜๋Š” usePhotoEdit ์ปค์Šคํ…€ ํ›…์ด ๊ตฌํ˜„๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
  • MSW ํ•ธ๋“ค๋Ÿฌ ๊ฐœ์„ : MSW(Mock Service Worker)์˜ createHandler๊ฐ€ dataResolver ์˜ต์…˜์„ ์ง€์›ํ•˜๋„๋ก ํ™•์žฅ๋˜์–ด, photoId์— ๋”ฐ๋ผ ๋™์ ์œผ๋กœ ์‚ฌ์ง„ ์ƒ์„ธ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
  • ๋ฉ”๋ชจ ๋ชจ๋‹ฌ ํ›… ์ดˆ๊ธฐํ™” ๋กœ์ง ๊ฐœ์„ : useMemoModal ํ›…์ด ๋น„๋™๊ธฐ์ ์œผ๋กœ ๋กœ๋“œ๋˜๋Š” ์ดˆ๊ธฐ ๋ฉ”๋ชจ ๊ฐ’์„ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ฒ˜๋ฆฌํ•˜๋„๋ก useEffect์™€ useRef๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ดˆ๊ธฐํ™” ๋กœ์ง์ด ๊ฐœ์„ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
  • UI/UX ๊ฐœ์„  ๋ฐ ์Šคํƒ€์ผ ์กฐ์ •: ๋ฉ”๋‰ด ํ—ค๋” ๋“œ๋กญ๋‹ค์šด์˜ ์Šคํƒ€์ผ(๋ฐฐ๊ฒฝ, ํ…Œ๋‘๋ฆฌ, ๋ธ”๋Ÿฌ ํšจ๊ณผ)๊ณผ ์œ„์น˜ ์„ ํƒ ์˜ค๋ฒ„๋ ˆ์ด์˜ ์ฒดํฌ ์•„์ด์ฝ˜ ํฌ๊ธฐ ๋ฐ ์ƒ‰์ƒ์ด ์กฐ์ •๋˜์–ด ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์ด ํ–ฅ์ƒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๐Ÿง  New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with ๐Ÿ‘ and ๐Ÿ‘Ž on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. โ†ฉ

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

์‚ฌ์ง„ ๊ธฐ๋ก์„ ์ˆ˜์ •ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•œ PR ์ž˜ ๋ณด์•˜์Šต๋‹ˆ๋‹ค. ์ „๋ฐ˜์ ์œผ๋กœ ์ƒˆ๋กœ์šด PhotoEditOverlay ์ปดํฌ๋„ŒํŠธ์™€ ๊ด€๋ จ ํ›…๋“ค์ด ์ž˜ ๊ตฌํ˜„๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ฝ”๋“œ์˜ ์•ˆ์ •์„ฑ๊ณผ ๊ฐ€๋…์„ฑ์„ ๋†’์ผ ์ˆ˜ ์žˆ๋Š” ๋ช‡ ๊ฐ€์ง€ ์ œ์•ˆ ์‚ฌํ•ญ์„ ๋ฆฌ๋ทฐ์— ๋‚จ๊ฒผ์Šต๋‹ˆ๋‹ค.

ํŠนํžˆ, useMemoModal ํ›…์˜ ์ƒํƒœ ๋™๊ธฐํ™” ๋กœ์ง๊ณผ onSave ํ•ธ๋“ค๋Ÿฌ์˜ ์˜ต์…”๋„ ์†์„ฑ ์ฒ˜๋ฆฌ ๋ถ€๋ถ„์€ ์ž ์žฌ์ ์ธ ๋ฒ„๊ทธ๋ฅผ ์œ ๋ฐœํ•  ์ˆ˜ ์žˆ์–ด ํ™•์ธ์ด ํ•„์š”ํ•ด ๋ณด์ž…๋‹ˆ๋‹ค. ๋˜ํ•œ, ์Šคํƒ€์ผ ๊ฐ€์ด๋“œ์— ๋”ฐ๋ผ ๋งค์ง ๋„˜๋ฒ„์™€ ํ•˜๋“œ์ฝ”๋”ฉ๋œ ์ƒ‰์ƒ ๊ฐ’์„ ํ…Œ๋งˆ ์ƒ์ˆ˜๋กœ ๋Œ€์ฒดํ•˜๋Š” ๊ฒƒ์„ ๊ณ ๋ คํ•ด๋ณด์‹œ๋ฉด ์ข‹๊ฒ ์Šต๋‹ˆ๋‹ค.


const saveEdit = (data: EditData) => {
// TODO: ์‚ฌ์ง„ ์ˆ˜์ • API ์—ฐ๋™
console.log('Save photo edit:', data);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

์ถ”ํ›„ API ์—ฐ๋™ ์˜ˆ์ •์ด์—์š”

Comment on lines +54 to +56
svg path {
fill: ${({ theme }) => theme.colors.gray[100]};
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

์œ„์น˜์„ ํƒ ์˜ค๋ฒ„๋ ˆ์ด์˜ ๋””์ž์ธ์ด ์ˆ˜์ •๋˜์–ด ๋ฐ˜์˜ํ–ˆ์–ด์š”

Image

ํ”ผ๊ทธ๋งˆ

Comment on lines +144 to +152
<AnimatePresence>
{isEditing && editingPhotoId && (
<PhotoEditOverlay
photoId={editingPhotoId}
onClose={closeEditOverlay}
onSave={saveEdit}
/>
)}
</AnimatePresence>
Copy link
Contributor Author

Choose a reason for hiding this comment

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

์‚ฌ์ง„ ์ƒ์„ธ๋ณด๊ธฐ ํ™”๋ฉด์—์„œ ์˜ค๋ฒ„๋ ˆ์ด๋ฅผ ๋„์›Œ์„œ ์‚ฌ์ง„ ๊ธฐ๋ก ์ˆ˜์ • ๊ฐ€๋Šฅํ•˜๊ฒŒ๋” ํ–ˆ์–ด์š”

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

๐Ÿค– Fix all issues with AI agents
In `@apps/web/src/app/photo/`[photoId]/_components/PhotoEditOverlay.tsx:
- Around line 83-85: The code in PhotoEditOverlay.tsx uses non-null assertions
on selectedLocation.latitude! and selectedLocation.longitude!, which can throw
at runtime; update the logic where location is built (the object using
selectedLocation) to first check that selectedLocation.latitude and
selectedLocation.longitude are not null/undefined (e.g., guard with if/&& or a
helper like isFinite number check) and only set location to { latitude:
selectedLocation.latitude, longitude: selectedLocation.longitude } when both
values are valid; otherwise set location to undefined or handle the missing
coordinates appropriately to avoid using the ! operator.
- Around line 120-123: The isModified check incorrectly treats any non-null
selectedAlbum/selectedLocation as a change; update it to compare actual values:
compute whether memo.trim() differs from (photoDetail.description || '').trim(),
and for albums/locations compare selectedAlbum?.id (or selectedAlbum) against
photoDetail.albumId (or photoDetail.album?.id) and selectedLocation?.id against
photoDetail.locationId (or photoDetail?.id) instead of checking !== null; then
set isModified to true only if any of those comparisons show a real difference
(use optional chaining and null-safe checks like selectedAlbum?.id !==
photoDetail.albumId).

In `@apps/web/src/app/photo/`[photoId]/_hooks/usePhotoEdit.ts:
- Around line 24-28: The saveEdit function currently logs EditData to the
console which can leak sensitive info; remove the raw console.log and instead
either (a) guard debug logging behind a runtime dev check (e.g., only log when
process.env.NODE_ENV === 'development' or an app-level isDebug flag) or (b)
replace with a structured logger that redacts sensitive fields before emitting;
update the saveEdit implementation (refer to saveEdit, EditData, setIsEditing,
setEditingPhotoId) to stop unguarded console output and ensure any retained logs
explicitly omit or redact memo/location fields.

In `@apps/web/src/app/photo/`[photoId]/page.tsx:
- Line 87: The "์‚ฌ์ง„ ์‚ญ์ œํ•˜๊ธฐ" MenuHeader.Item is missing an onClick handler; add an
onClick prop that calls a delete handler (e.g., handleDeletePhoto) similar to
the edit item at line 84. Implement handleDeletePhoto to call the photo deletion
API (or mutation) for the current photoId, handle errors, and then update UI
(navigate away or call router.refresh / revalidate) and close any open menus.
Attach this handler to the MenuHeader.Item (MenuHeader.Item
onClick={handleDeletePhoto}) and reuse any existing modal/confirmation logic if
present.

In `@apps/web/src/app/photo/add/note/_hooks/useMemoModal.ts`:
- Around line 3-16: The current useEffect guard with isInitialized prevents
subsequent changes to initialMemo from syncing into the hook; update the
synchronization so useMemoModal reacts to new initialMemo values instead of
permanently blocking after the first setโ€”e.g., remove or adjust the
isInitialized ref and add a useEffect that compares initialMemo to memo/tempMemo
(or runs when isOpen changes) and sets memo and tempMemo when initialMemo
differs; touch the useMemoModal function, the isInitialized ref, and the
existing useEffect to ensure memo and tempMemo are updated on relevant
initialMemo updates.

In `@apps/web/src/mocks/handlers/photos/index.ts`:
- Around line 10-14: The dataResolver in createHandler(mockGetPhotoDetail...)
may produce id: NaN because Number(params.photoId) can return NaN for undefined
or string[]; update the resolver to safely extract and parse photoId (e.g., if
Array.isArray(params.photoId) take first element, if missing treat as fallback
id or return ์‚ฌ์ง„_์ƒ์„ธ_์กฐํšŒ_์„ฑ๊ณต) and only use the parsed numeric id when
Number.isFinite(parsedId); otherwise return the safe default object
(์‚ฌ์ง„_์ƒ์„ธ_์กฐํšŒ_์„ฑ๊ณต) or a fallback id so ์‚ฌ์ง„_์ƒ์„ธ_๋ชฉ๋ก lookup never receives NaN.
๐Ÿงน Nitpick comments (3)
apps/web/src/mocks/createHandler.ts (1)

6-28: dataResolver ๋ฐ˜ํ™˜ ํƒ€์ž…์„ ์‘๋‹ต ํƒ€์ž…๊ณผ ์—ฐ๊ฒฐํ•ด ์ฃผ์„ธ์š”.
ํ˜„์žฌ CreateHandlerOptions<JsonBodyType>๋กœ ๊ณ ์ •๋˜์–ด ์žˆ์–ด resolver๊ฐ€ ์‹ค์ œ ์‘๋‹ต ์Šคํ‚ค๋งˆ์™€ ๋‹ค๋ฅธ ํ˜•ํƒœ๋ฅผ ๋ฐ˜ํ™˜ํ•ด๋„ ํƒ€์ž…์ด ํ†ต๊ณผํ•ฉ๋‹ˆ๋‹ค. responseKey์— ๋Œ€์‘ํ•˜๋Š” responseItem.data ํƒ€์ž…๊ณผ ์—ฐ๊ฒฐํ•˜๋ฉด ์•ˆ์ „์„ฑ์ด ์˜ฌ๋ผ๊ฐ‘๋‹ˆ๋‹ค.

โ™ป๏ธ ์ œ์•ˆ ๋ณ€๊ฒฝ (ํƒ€์ž… ์—ฐ๊ฒฐ)
-export const createHandler = <T extends MockApiResponse<string, JsonBodyType>>(
-  config: T,
-  responseKey: ResponseKey<T>,
-  options?: CreateHandlerOptions<JsonBodyType> | ((request: Request) => string | null)
-) => {
+export const createHandler = <
+  T extends MockApiResponse<string, JsonBodyType>,
+  K extends ResponseKey<T>
+>(
+  config: T,
+  responseKey: K,
+  options?: CreateHandlerOptions<T['response'][K]['data']> | ((request: Request) => string | null)
+) => {
apps/web/src/app/photo/[photoId]/_components/PhotoEditOverlay.tsx (2)

202-207: MapPreviewButton์— onClick ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

"์ง€๋„๋ทฐ ๋ฏธ๋ฆฌ๋ณด๊ธฐ" ๋ฒ„ํŠผ์— ํด๋ฆญ ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ๊ตฌํ˜„๋˜์–ด ์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํ–ฅํ›„ ๊ตฌํ˜„ ์˜ˆ์ •์ธ์ง€ ํ™•์ธ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

์ด ๊ธฐ๋Šฅ ๊ตฌํ˜„์„ ์ถ”์ ํ•˜๊ธฐ ์œ„ํ•œ ์ด์Šˆ๋ฅผ ์ƒ์„ฑํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?


91-110: ์ธ๋ผ์ธ ์Šคํƒ€์ผ์„ styled-component๋กœ ์ถ”์ถœํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.

๋กœ๋”ฉ ์ƒํƒœ์™€ ๋ฉ”์ธ ์˜ค๋ฒ„๋ ˆ์ด์—์„œ ์œ ์‚ฌํ•œ ์ธ๋ผ์ธ ์Šคํƒ€์ผ์ด ๋ฐ˜๋ณต๋˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. PhotoEditOverlay.styles.ts์— styled-component๋กœ ์ถ”์ถœํ•˜๋ฉด ์ผ๊ด€์„ฑ๊ณผ ์œ ์ง€๋ณด์ˆ˜์„ฑ์ด ํ–ฅ์ƒ๋ฉ๋‹ˆ๋‹ค.

Comment on lines 120 to 123
const isModified =
memo !== (photoDetail.description || '') ||
selectedAlbum !== null ||
selectedLocation !== null;
Copy link

Choose a reason for hiding this comment

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

โš ๏ธ Potential issue | ๐ŸŸก Minor

isModified ๋กœ์ง์ด ์‹ค์ œ ๋ณ€๊ฒฝ ์—ฌ๋ถ€๋ฅผ ์ •ํ™•ํžˆ ๋ฐ˜์˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

ํ˜„์žฌ ๋กœ์ง์€ selectedAlbum !== null ๋˜๋Š” selectedLocation !== null์ธ ๊ฒฝ์šฐ ์ˆ˜์ •๋œ ๊ฒƒ์œผ๋กœ ํŒ๋‹จํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์‚ฌ์šฉ์ž๊ฐ€ ๊ธฐ์กด๊ณผ ๋™์ผํ•œ ์•จ๋ฒ”์ด๋‚˜ ์œ„์น˜๋ฅผ ์„ ํƒํ•ด๋„ ์ˆ˜์ •๋œ ๊ฒƒ์œผ๋กœ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.

โ™ป๏ธ ๊ฐœ์„  ์ œ์•ˆ
   const isModified =
     memo !== (photoDetail.description || '') ||
-    selectedAlbum !== null ||
-    selectedLocation !== null;
+    (selectedAlbum !== null && selectedAlbum.id !== photoDetail.albumId) ||
+    (selectedLocation !== null && selectedLocation.placeName !== photoDetail.address);
๐Ÿ“ Committable suggestion

โ€ผ๏ธ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const isModified =
memo !== (photoDetail.description || '') ||
selectedAlbum !== null ||
selectedLocation !== null;
const isModified =
memo !== (photoDetail.description || '') ||
(selectedAlbum !== null && selectedAlbum.id !== photoDetail.albumId) ||
(selectedLocation !== null && selectedLocation.placeName !== photoDetail.address);
๐Ÿค– Prompt for AI Agents
In `@apps/web/src/app/photo/`[photoId]/_components/PhotoEditOverlay.tsx around
lines 120 - 123, The isModified check incorrectly treats any non-null
selectedAlbum/selectedLocation as a change; update it to compare actual values:
compute whether memo.trim() differs from (photoDetail.description || '').trim(),
and for albums/locations compare selectedAlbum?.id (or selectedAlbum) against
photoDetail.albumId (or photoDetail.album?.id) and selectedLocation?.id against
photoDetail.locationId (or photoDetail?.id) instead of checking !== null; then
set isModified to true only if any of those comparisons show a real difference
(use optional chaining and null-safe checks like selectedAlbum?.id !==
photoDetail.albumId).

Comment on lines +24 to +28
const saveEdit = (data: EditData) => {
// TODO: ์‚ฌ์ง„ ์ˆ˜์ • API ์—ฐ๋™
console.log('Save photo edit:', data);
setIsEditing(false);
setEditingPhotoId(null);
Copy link

Choose a reason for hiding this comment

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

โš ๏ธ Potential issue | ๐ŸŸก Minor

ํŽธ์ง‘ ๋ฐ์ดํ„ฐ console.log๋Š” ํ”„๋กœ๋•์…˜์—์„œ ์ œ๊ฑฐ/๊ฐ€๋“œ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.
๋ฉ”๋ชจ/์œ„์น˜๊ฐ€ ์ฝ˜์†”์— ๋‚จ์œผ๋ฉด ๋””๋ฒ„๊ทธ ๋…ธ์ด์ฆˆ + ๋ฏผ๊ฐ ์ •๋ณด ๋…ธ์ถœ ์šฐ๋ ค๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ› ๏ธ ์ œ์•ˆ ์ˆ˜์ •
-    console.log('Save photo edit:', data);
+    if (process.env.NODE_ENV !== 'production') {
+      console.log('Save photo edit:', data);
+    }
๐Ÿ“ Committable suggestion

โ€ผ๏ธ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const saveEdit = (data: EditData) => {
// TODO: ์‚ฌ์ง„ ์ˆ˜์ • API ์—ฐ๋™
console.log('Save photo edit:', data);
setIsEditing(false);
setEditingPhotoId(null);
const saveEdit = (data: EditData) => {
// TODO: ์‚ฌ์ง„ ์ˆ˜์ • API ์—ฐ๋™
if (process.env.NODE_ENV !== 'production') {
console.log('Save photo edit:', data);
}
setIsEditing(false);
setEditingPhotoId(null);
๐Ÿค– Prompt for AI Agents
In `@apps/web/src/app/photo/`[photoId]/_hooks/usePhotoEdit.ts around lines 24 -
28, The saveEdit function currently logs EditData to the console which can leak
sensitive info; remove the raw console.log and instead either (a) guard debug
logging behind a runtime dev check (e.g., only log when process.env.NODE_ENV ===
'development' or an app-level isDebug flag) or (b) replace with a structured
logger that redacts sensitive fields before emitting; update the saveEdit
implementation (refer to saveEdit, EditData, setIsEditing, setEditingPhotoId) to
stop unguarded console output and ensure any retained logs explicitly omit or
redact memo/location fields.

Copy link
Contributor

@H0ngJu H0ngJu left a comment

Choose a reason for hiding this comment

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

๋น ๋ฅธ ์ž‘์—… ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค ใ…Žใ…Ž!! ์ˆ˜๊ณ ํ•˜์…จ์Šต๋‹ˆ๋‹ค~!

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.

feat: ์‚ฌ์ง„ ๊ธฐ๋ก ์ˆ˜์ •

3 participants