Skip to content

Comments

[NUGUDI-181] 프로필 수정 화면 구현 #215

Merged
dydals3440 merged 4 commits intomainfrom
feature/NUGUDI-181-profile-update
Nov 13, 2025
Merged

[NUGUDI-181] 프로필 수정 화면 구현 #215
dydals3440 merged 4 commits intomainfrom
feature/NUGUDI-181-profile-update

Conversation

@hijjoy
Copy link
Member

@hijjoy hijjoy commented Nov 11, 2025

🌀 Issue Number

😵 As-Is

  • 프로필 수정 페이지 부재
  • 프로필 페이지 피그마 UI 변경
  • navbar 컴포넌트 수정으로 인한 포인트 페이지 UI 깨짐

🥳 To-Be

스크린샷 2025-11-11 12 59 22 스크린샷 2025-11-11 13 33 11 스크린샷 2025-11-11 13 33 15

85ef631 : 프로필 수정 페이지 구현

  • 단, 서버 dto와 api가 나오지 않은 부분이라 repository등 다른 파일을 생성하지 않았습니다.
  • 또한 프로젝트 구조가 한번 더 바뀔 것을 감안해 presentation/ui 부분만 구현하였습니다.
  • 이외에 유저dto에 키와 몸무게가 들어가는 것을 확인하여 UserAdapter와 entity에 두 필드는 추가하였습니다.

858a3e4 , a48ed2b : 두 부분은 이전에 있던 UI를 바탕으로 css만 수정하였습니다.

✅ Check List

  • 테스트가 전부 통과되었나요?
  • 빌드는 성공했나요?

📷 Test Screenshot (Optional)

👾 Additional Description (Optional)

Summary by CodeRabbit

  • New Features
    • 프로필 수정 페이지에서 닉네임, 키, 몸무게 정보 편집 가능
    • 닉네임 검증: 2-10자, 한글·영문·숫자만 허용, 공백 불가
    • 닉네임 중복 확인 기능 추가
    • 신체 정보 입력: 키(cm), 몸무게(kg) 단위로 선택적 입력 지원

@hijjoy hijjoy self-assigned this Nov 11, 2025
@hijjoy hijjoy added the apps/web apps/web 관련 작업 label Nov 11, 2025
@hijjoy hijjoy linked an issue Nov 11, 2025 that may be closed by this pull request
2 tasks
@vercel
Copy link
Contributor

vercel bot commented Nov 11, 2025

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

Project Deployment Preview Comments Updated (UTC)
nugudi Ready Ready Preview Comment Nov 13, 2025 6:26am

@github-actions
Copy link

Jira Issue: NUGUDI-181

  • 제목: 프로필 수정 화면 구현
  • 상태: To Do
  • 담당자: Yongmin Kim

@coderabbitai
Copy link

coderabbitai bot commented Nov 11, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

프로필 편집 기능을 구현하였습니다. 사용자 엔티티에 키와 체중 필드를 추가하고, 폼 유효성 검사 스키마를 정의한 후, 기본 정보와 체력 정보 입력 폼 컴포넌트를 작성하여 프로필 편집 뷰로 통합했습니다.

Changes

Cohort / File(s) Summary
도메인 엔티티 확장
apps/web/src/domains/user/domain/entities/user.entity.ts
UserProfile 인터페이스에 getHeight()와 getWeight() 메서드 시그니처 추가, UserProfileEntity에 _height와 _weight 개인 필드, 생성자 파라미터, 공개 게터 메서드 추가, toPlainObject() 업데이트
폼 유효성 검사 스키마
apps/web/src/domains/user/presentation/schemas/profile-edit.schema.ts
profileEditSchema Zod 스키마 정의 (닉네임, 키, 체중 필드 포함), ProfileEditFormData 타입 내보내기
폼 컴포넌트
apps/web/src/domains/user/presentation/ui/components/user-basic-info-form-component/index.tsx, apps/web/src/domains/user/presentation/ui/components/user-physical-info-form-component/index.tsx
닉네임 입력 및 중복 확인 버튼이 포함된 기본 정보 폼 컴포넌트, 키 및 체중 입력 필드가 있는 체력 정보 폼 컴포넌트 추가
폼 섹션 및 뷰
apps/web/src/domains/user/presentation/ui/sections/user-profile-edit-form-section-mock/index.tsx, apps/web/src/domains/user/presentation/ui/views/user-profile-edit-view/index.tsx
기본 정보 및 체력 정보 폼을 조합한 프로필 편집 폼 섹션 목(mock) 구현, NavBar와 함께 폼을 포함하는 프로필 편집 뷰 추가
페이지 통합
apps/web/app/(auth)/profile/edit/page.tsx
ProfileEditPage를 UserProfileEditView 컴포넌트로 업데이트

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Form as 프로필 편집 폼
    participant Validation as Zod 검증
    participant Entity as UserEntity
    participant Router as 라우터

    User->>Form: 닉네임/키/체중 입력
    Form->>Form: 필드 변경 감지
    Form->>Validation: 폼 데이터 검증
    alt 검증 성공
        Validation-->>Form: 유효함
        User->>Form: 수정 완료 버튼 클릭
        Form->>Entity: 프로필 데이터 저장
        Entity-->>Form: 저장 완료
        Form->>Router: /profile로 이동
        Router-->>User: 프로필 페이지 표시
    else 검증 실패
        Validation-->>Form: 오류 메시지
        Form->>User: 유효성 검사 오류 표시
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 분

  • 주의 필요 영역:
    • user.entity.ts에서 새로운 필드가 생성자, 게터, 직렬화에 일관되게 연결되었는지 확인
    • profile-edit.schema.ts의 닉네임 정규표현식 제약과 다국어 메시지 검증
    • 폼 컴포넌트들의 react-hook-form 통합과 오류 처리 로직
    • 타입 안정성 (ProfileEditFormData 타입 일관성)

Possibly related issues

Possibly related PRs

Suggested labels

feat

Suggested reviewers

  • dydals3440
  • yewonahn

Poem

🐰 프로필 수정의 마법을 펼쳐,
키와 몸무게를 담아내고,
형식을 갖춰 검증하며,
컴포넌트로 조화롭게 엮어,
새로운 프로필이 빛나네! ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목은 구현된 주요 변경사항인 프로필 수정 화면 구현을 명확하게 요약하고 있으며, 이슈 번호를 포함하여 추적 가능합니다.
Description check ✅ Passed PR 설명은 템플릿의 모든 필수 섹션을 포함하고 있으며, 변경사항에 대한 상세한 설명과 스크린샷, 커밋별 변경 내용이 기술되어 있습니다.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/NUGUDI-181-profile-update

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bc783a8 and 1aee6e2.

⛔ Files ignored due to path filters (1)
  • apps/web/public/images/intern-nuguri.png is excluded by !**/*.png
📒 Files selected for processing (1)
  • apps/web/app/(auth)/profile/edit/page.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/web/app/(auth)/profile/edit/page.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: deploy

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 @hijjoy, 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은 사용자 프로필 수정 기능을 도입하고, 기존 프로필 및 포인트 관련 UI를 전반적으로 개선합니다. 사용자 엔티티에 키와 몸무게 필드를 추가하고, 프로필 편집을 위한 유효성 검사 스키마를 정의하며, 관련 UI 컴포넌트를 새로 추가하거나 수정하여 사용자 경험을 향상시키는 것을 목표로 합니다. 서버 API가 아직 준비되지 않아 UI/프레젠테이션 계층에 집중하여 구현되었습니다.

Highlights

  • 프로필 수정 화면 구현: 사용자 프로필을 편집할 수 있는 새로운 페이지가 구현되었습니다. 이 페이지는 닉네임과 신체 정보(키, 몸무게)를 입력할 수 있는 UI 컴포넌트를 포함합니다.
  • 사용자 엔티티 및 어댑터 업데이트: 사용자 프로필 엔티티와 어댑터에 키(height)와 몸무게(weight) 필드가 추가되어, 사용자 DTO 변경 사항을 반영했습니다.
  • 프로필 편집 유효성 검사 스키마 추가: 닉네임, 키, 몸무게 필드에 대한 유효성 검사 규칙을 정의하는 Zod 스키마가 새로 추가되었습니다.
  • UI/UX 개선 및 버그 수정: 기존 프로필 섹션의 UI가 새로운 이미지, 레벨 배지, 닉네임 레이아웃 등으로 시각적으로 개선되었으며, 네비게이션 바 컴포넌트 수정으로 인한 포인트 페이지 UI 깨짐 현상이 수정되었습니다.
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 잘 보았습니다. 전반적으로 새로운 기능 구현과 기존 UI 개선이 잘 이루어졌습니다. 코드의 유지보수성과 견고성을 높이기 위한 몇 가지 제안 사항을 리뷰 코멘트로 남겼습니다. 주로 zod 스키마 유효성 검사 강화, react-hook-form의 올바른 사용, 그리고 컴포넌트 구조 단순화에 대한 내용입니다. 확인 부탁드립니다.

@github-actions
Copy link

This pull request (commit a48ed2b) has been deployed to Vercel ▲ - View GitHub Actions Workflow Logs

Name Link
🌐 Unique https://nugudi-9ah24mzfr-dydals3440s-projects.vercel.app
🔍 Inspect https://vercel.com/dydals3440s-projects/nugudi/Gi8o3uVc2AUwG82LqNvqc2BdonaY

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: 4

Caution

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

⚠️ Outside diff range comments (1)
apps/web/src/domains/user/domain/entities/user.entity.ts (1)

33-40: toPlainObject 반환 타입이 구현과 일치하지 않습니다.

인터페이스의 toPlainObject 반환 타입(33-40줄)에는 heightweight가 포함되어 있지 않지만, 실제 구현(240-241줄)에서는 이 필드들을 반환하고 있습니다. 이는 TypeScript 타입 안정성 문제를 일으킵니다.

다음 diff를 적용하여 인터페이스의 반환 타입을 수정하세요:

   toPlainObject(): {
     id: number;
     nickname: string;
     email?: string;
     profileImageUrl?: string;
+    height?: number;
+    weight?: number;
     createdAt?: string;
     updatedAt?: string;
   };

Also applies to: 240-241

🧹 Nitpick comments (5)
apps/web/src/domains/user/presentation/schemas/profile-edit.schema.ts (2)

8-14: 공백 검증 로직이 중복됩니다.

Line 8-11의 정규식 /^[a-zA-Z0-9가-힣ㄱ-ㅎㅏ-ㅣ]+$/이 이미 공백을 허용하지 않으므로, Line 12-14의 .refine() 검증은 불필요합니다.

다음과 같이 refine을 제거할 수 있습니다:

  nickname: z
    .string()
    .min(2, "닉네임은 최소 2자 이상이어야 합니다")
    .max(10, "닉네임은 최대 10자까지 가능합니다")
    .regex(
      /^[a-zA-Z0-9가-힣ㄱ-ㅎㅏ-ㅣ]+$/,
      "닉네임은 영문, 한글, 숫자만 사용할 수 있습니다",
-   )
-   .refine((val) => !val.includes(" "), {
-     message: "닉네임에 공백을 포함할 수 없습니다",
-   }),
+   ),

15-16: 신체 정보 필드에 대한 검증 추가를 고려해 주세요.

heightweight에 대한 범위 검증이 없습니다. 실제 운영 환경에서는 음수나 비현실적인 값을 방지하기 위한 검증이 필요할 수 있습니다.

예시:

height: z.number().positive().min(100).max(250).optional(),
weight: z.number().positive().min(20).max(300).optional(),

또는 Zod 4의 새로운 통합 에러 커스터마이징을 활용할 수도 있습니다:

height: z.number({
  error: (issue) => {
    if (issue.code === 'too_small') return '키는 100cm 이상이어야 합니다';
    if (issue.code === 'too_big') return '키는 250cm 이하여야 합니다';
  }
}).positive().min(100).max(250).optional(),
apps/web/src/domains/user/presentation/ui/sections/user-profile-edit-form-section-mock/index.tsx (1)

32-35: 실제 API 연동 시 수정이 필요합니다.

console.log와 단순 라우팅만 수행하고 있습니다. 실제 프로필 업데이트 API 호출, 에러 처리, 로딩 상태 관리 등이 필요합니다.

향후 구현 시 다음 항목들을 고려해 주세요:

  • 프로필 업데이트 API 호출
  • 로딩/에러 상태 관리 (React Query mutation 활용)
  • 성공/실패 토스트 메시지
  • 낙관적 UI 업데이트 (useOptimistic 활용 가능)

API 연동을 위한 mutation hook 구조를 생성해 드릴까요?

apps/web/src/domains/user/presentation/ui/components/user-basic-info-form-component/index.tsx (1)

64-76: onChange 핸들러 패턴을 개선할 수 있습니다.

Line 69-72의 onChange 핸들러에서 register("nickname").onChange를 수동으로 호출하는 것은 비표준 패턴입니다. {...register("nickname")}가 이미 onChange를 포함하고 있으므로 중복될 수 있습니다.

react-hook-form의 watch를 사용하는 것이 더 명확합니다:

// 컴포넌트 상단에서
const nickname = watch("nickname");

useEffect(() => {
  if (nickname) {
    onNicknameChange({ target: { value: nickname } } as any);
  }
}, [nickname, onNicknameChange]);

// Input에서는
<Input
  label="닉네임"
  variant="filled"
  {...register("nickname")}
  defaultValue={defaultNickname}
  // onChange 제거
  placeholder="정조이"
  isError={!!errors.nickname}
  errorMessage={errors.nickname?.message}
/>

또는 커스텀 onChange가 꼭 필요하다면:

<Input
  {...register("nickname", {
    onChange: (e) => onNicknameChange(e)
  })}
  // 나머지 props...
/>
apps/web/src/domains/user/domain/entities/user.entity.ts (1)

59-60: 신체 정보 값에 대한 유효성 검증을 추가하는 것을 고려하세요.

생성자에서 heightweight 값을 검증 없이 그대로 할당하고 있습니다. 음수, 0, 또는 비정상적으로 큰 값(예: 키 300cm, 몸무게 500kg)이 엔티티에 저장될 수 있습니다. 엔티티 레벨에서 기본적인 범위 검증을 추가하면 데이터 무결성을 보장할 수 있습니다.

생성자에 다음과 같은 검증 로직 추가를 고려하세요:

constructor(params: {
  id: number;
  nickname: string;
  email?: string;
  profileImageUrl?: string;
  height?: number;
  weight?: number;
  createdAt?: string;
  updatedAt?: string;
}) {
  // 기존 검증...
  
  if (params.height !== undefined && (params.height <= 0 || params.height > 300)) {
    throw new Error("Height must be between 0 and 300 cm");
  }
  
  if (params.weight !== undefined && (params.weight <= 0 || params.weight > 500)) {
    throw new Error("Weight must be between 0 and 500 kg");
  }
  
  // 필드 할당...
}

Also applies to: 75-76

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f0056a5 and a48ed2b.

⛔ Files ignored due to path filters (1)
  • apps/web/public/images/intern-nuguri.png is excluded by !**/*.png
📒 Files selected for processing (18)
  • apps/web/app/(auth)/profile/edit/page.tsx (1 hunks)
  • apps/web/src/domains/user/domain/entities/user.entity.ts (6 hunks)
  • apps/web/src/domains/user/presentation/adapters/user.adapter.ts (2 hunks)
  • apps/web/src/domains/user/presentation/schemas/profile-edit.schema.ts (1 hunks)
  • apps/web/src/domains/user/presentation/types/user.type.ts (1 hunks)
  • apps/web/src/domains/user/presentation/ui/components/user-basic-info-form-component/index.tsx (1 hunks)
  • apps/web/src/domains/user/presentation/ui/components/user-physical-info-form-component/index.tsx (1 hunks)
  • apps/web/src/domains/user/presentation/ui/components/user-points-balance/index.css.ts (1 hunks)
  • apps/web/src/domains/user/presentation/ui/components/user-points-balance/index.tsx (1 hunks)
  • apps/web/src/domains/user/presentation/ui/sections/user-points-history-section/index.css.ts (1 hunks)
  • apps/web/src/domains/user/presentation/ui/sections/user-points-history-section/index.tsx (1 hunks)
  • apps/web/src/domains/user/presentation/ui/sections/user-profile-edit-form-section-mock/index.tsx (1 hunks)
  • apps/web/src/domains/user/presentation/ui/sections/user-profile-section/index.css.ts (2 hunks)
  • apps/web/src/domains/user/presentation/ui/sections/user-profile-section/index.tsx (4 hunks)
  • apps/web/src/domains/user/presentation/ui/views/user-points-view/index.css.ts (1 hunks)
  • apps/web/src/domains/user/presentation/ui/views/user-points-view/index.tsx (1 hunks)
  • apps/web/src/domains/user/presentation/ui/views/user-profile-edit-view/index.tsx (1 hunks)
  • apps/web/src/domains/user/presentation/ui/views/user-profile-view/index.tsx (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (9)
apps/web/src/domains/user/presentation/ui/views/user-profile-edit-view/index.tsx (2)
apps/web/src/core/ui/components/nav-bar/index.tsx (1)
  • NavBar (16-48)
apps/web/src/domains/user/presentation/ui/sections/user-profile-edit-form-section-mock/index.tsx (1)
  • UserProfileEditFormSectionMock (21-69)
apps/web/src/domains/user/presentation/ui/sections/user-points-history-section/index.css.ts (2)
apps/web/src/domains/user/presentation/ui/components/user-points-balance/index.css.ts (1)
  • container (3-7)
apps/web/src/domains/user/presentation/ui/views/user-points-view/index.css.ts (1)
  • container (4-7)
apps/web/src/domains/user/presentation/ui/components/user-basic-info-form-component/index.tsx (1)
apps/web/src/domains/user/presentation/schemas/profile-edit.schema.ts (1)
  • ProfileEditFormData (19-19)
apps/web/src/domains/user/presentation/ui/sections/user-profile-edit-form-section-mock/index.tsx (3)
apps/web/src/domains/user/presentation/schemas/profile-edit.schema.ts (2)
  • ProfileEditFormData (19-19)
  • profileEditSchema (3-17)
apps/web/src/domains/user/presentation/ui/components/user-basic-info-form-component/index.tsx (1)
  • UserBasicInfoFormComponent (16-37)
apps/web/src/domains/user/presentation/ui/components/user-physical-info-form-component/index.tsx (1)
  • UserPhysicalInfoFormComponent (13-30)
apps/web/src/domains/user/presentation/ui/components/user-physical-info-form-component/index.tsx (1)
apps/web/src/domains/user/presentation/schemas/profile-edit.schema.ts (1)
  • ProfileEditFormData (19-19)
apps/web/src/domains/user/presentation/adapters/user.adapter.ts (2)
apps/web/src/domains/user/domain/entities/user.entity.ts (1)
  • UserProfile (5-42)
apps/web/src/domains/user/presentation/types/user.type.ts (1)
  • UserProfileItem (1-10)
apps/web/src/domains/user/presentation/ui/views/user-profile-view/index.tsx (2)
apps/web/src/domains/user/presentation/ui/sections/user-profile-section/index.tsx (1)
  • UserProfileSection (15-23)
apps/web/src/domains/user/presentation/ui/sections/user-profile-point-section/index.tsx (1)
  • UserProfilePointSection (7-26)
apps/web/app/(auth)/profile/edit/page.tsx (1)
apps/web/src/domains/user/presentation/ui/views/user-profile-edit-view/index.tsx (1)
  • UserProfileEditView (5-12)
apps/web/src/domains/user/presentation/ui/views/user-points-view/index.tsx (2)
apps/web/src/core/ui/components/nav-bar/index.tsx (1)
  • NavBar (16-48)
apps/web/src/domains/user/presentation/ui/sections/user-points-balance-section/index.tsx (1)
  • UserPointsBalanceSection (5-10)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: deploy
🔇 Additional comments (24)
apps/web/src/domains/user/presentation/ui/components/user-points-balance/index.tsx (1)

20-20: 레이아웃 변경사항 확인됨

VStack에 pX={16} 수평 패딩이 추가되어 일관된 레이아웃을 제공합니다. 관련 CSS 파일에서 boxSizing: "border-box"가 추가되어 패딩이 전체 너비 계산에 올바르게 포함됩니다.

apps/web/src/domains/user/presentation/ui/components/user-points-balance/index.css.ts (1)

6-6: 적절한 box-sizing 설정

boxSizing: "border-box" 추가로 패딩과 테두리가 요소의 전체 너비/높이에 포함되어 예측 가능한 레이아웃을 보장합니다. 컴포넌트에 추가된 수평 패딩과 잘 조화됩니다.

apps/web/app/(auth)/profile/edit/page.tsx (1)

1-7: 프로필 수정 페이지 구현 확인

페이지 구조가 깔끔하고 뷰 컴포넌트로 적절히 위임하고 있습니다. PR 설명에 따르면 현재는 UI만 구현된 상태이며 서버 DTO 및 API가 아직 준비되지 않았습니다. 향후 실제 데이터 연동 시 repository 레이어와 API 통합이 필요합니다.

서버 통합 작업이 예정되어 있는지 확인하세요. 현재는 프레젠테이션 레이어만 구현되어 있어 실제 프로필 수정 기능이 동작하지 않습니다.

apps/web/src/domains/user/presentation/ui/views/user-points-view/index.css.ts (1)

6-6: 배경색 추가 확인

컨테이너에 테마 변수를 사용한 배경색이 추가되어 일관된 UI를 제공합니다. 기존 boxSizing: "border-box"와 함께 적절한 스타일링이 적용되었습니다.

apps/web/src/domains/user/presentation/ui/sections/user-points-history-section/index.tsx (2)

8-8: 스타일링 통합 확인

CSS 모듈을 import하고 VStack에 적절한 레이아웃 속성(pY={16}, grow={1}, className)을 추가하여 일관된 UI를 구현했습니다.

Also applies to: 15-15


11-11: 향후 API 통합 필요

TODO 코멘트와 mock 데이터 훅이 존재합니다. 현재는 UI 레이어만 구현된 상태로, 향후 실제 API 호출로 대체가 필요합니다.

실제 포인트 히스토리 데이터를 가져오는 API 엔드포인트가 준비되면 usePointsData 훅을 실제 데이터 페칭 로직으로 교체해야 합니다.

Also applies to: 22-41

apps/web/src/domains/user/presentation/ui/views/user-profile-view/index.tsx (1)

2-2: 레이아웃 구조 개선

UserProfileSectionUserProfilePointSectionVStack으로 감싸 수직 레이아웃을 명확하게 구성했습니다. 로직 변경 없이 순수하게 프레젠테이션 레이어만 개선되었습니다.

Also applies to: 13-16

apps/web/src/domains/user/presentation/types/user.type.ts (1)

6-7: UserProfileItem 인터페이스 확장

heightweight 필드가 옵셔널 속성으로 추가되어 프로필 수정 기능을 지원합니다. 모든 사용자가 이 데이터를 제공하지 않을 수 있으므로 옵셔널로 정의한 것이 적절합니다. 관련 파일들(entity, adapter, schema)에서도 일관되게 이 필드들을 처리하고 있습니다.

apps/web/src/domains/user/presentation/ui/sections/user-points-history-section/index.css.ts (1)

1-6: 새 CSS 모듈 구현

포인트 히스토리 섹션을 위한 새로운 스타일 모듈이 추가되었습니다. 테마 변수를 사용하여 배경색을 설정하고 있어 일관된 디자인 시스템을 유지합니다.

apps/web/src/domains/user/presentation/ui/views/user-points-view/index.tsx (1)

18-19: 레이아웃 구조 개선이 잘 적용되었습니다.

불필요한 중첩 VStack을 제거하여 컴포넌트 구조가 더 명확해졌습니다. NavBar의 background="transparent" 속성도 UI 요구사항에 적합하게 설정되었습니다.

apps/web/src/domains/user/presentation/ui/sections/user-profile-section/index.css.ts (3)

7-8: 테마 토큰 사용이 잘 적용되었습니다.

고정 픽셀 값 대신 vars.box.spacing[4]를 사용하여 일관된 디자인 시스템을 유지하고 있습니다.


14-14: objectFit 변경 의도를 확인해 주세요.

"cover"에서 "contain"으로 변경하면 이미지가 잘리지 않지만, 컨테이너를 완전히 채우지 못할 수 있습니다. 이것이 의도된 디자인인지 확인이 필요합니다.


34-51: 클릭 영역 확장 패턴이 잘 구현되었습니다.

::before 가상 요소를 사용하여 작은 아이콘의 클릭 영역을 확장한 것은 모바일 접근성 향상에 도움이 됩니다. inset: "-12px"를 통해 최소 44x44px의 터치 타겟 크기를 확보하고 있습니다.

apps/web/src/domains/user/presentation/ui/views/user-profile-edit-view/index.tsx (1)

1-12: 프로필 수정 뷰가 깔끔하게 구현되었습니다.

프레젠테이션 레이어 컴포넌트로서 역할이 명확하고, minH="100dvh"를 사용하여 모바일 브라우저의 동적 뷰포트 높이를 올바르게 처리하고 있습니다.

apps/web/src/domains/user/presentation/ui/sections/user-profile-edit-form-section-mock/index.tsx (2)

15-19: 목 데이터가 적절하게 구성되었습니다.

개발 단계에서 UI 테스트를 위한 목 데이터로 적합합니다.


47-54: 닉네임 검증 핸들러가 구현되지 않았습니다.

Line 51의 닉네임 중복 체크와 Line 52의 onChange 핸들러가 구현되지 않아 실제 검증이 동작하지 않습니다.

현재는 목 구현이지만, 실제 구현 시:

  1. 닉네임 변경 시 중복 체크 버튼 활성화
  2. API를 통한 중복 검증
  3. 검증 결과에 따른 에러 표시

이러한 로직이 필요합니다. 이 부분의 구현 계획을 확인해 주세요.

apps/web/src/domains/user/presentation/ui/components/user-basic-info-form-component/index.tsx (1)

1-108: 폼 컴포넌트가 잘 구성되었습니다.

컴포넌트 분리와 타입 정의가 명확하며, 에러 처리와 로딩 상태 관리가 적절하게 구현되어 있습니다.

apps/web/src/domains/user/presentation/ui/sections/user-profile-section/index.tsx (2)

29-41: 스켈레톤 UI가 개선되었습니다.

실제 콘텐츠 구조와 더 유사한 스켈레톤을 제공하여 레이아웃 이동(CLS)을 최소화하고 있습니다.


57-72: 하드코딩된 값들을 확인해 주세요.

"Lv.1", "인턴 너구리", "손님" 등의 값이 하드코딩되어 있습니다. 이 값들이 실제 데이터로 교체될 예정인지 확인이 필요합니다.

다음 사항들을 확인해 주세요:

  1. 레벨 정보는 API에서 제공될 예정인가요?
  2. "인턴 너구리"는 고정된 타이틀인가요, 아니면 레벨에 따라 변경되나요?
  3. 사용자 역할/타이틀 정보가 UserProfileItem에 추가되어야 하나요?
apps/web/src/domains/user/presentation/adapters/user.adapter.ts (2)

11-12: UI 아이템에 신체 정보 필드가 올바르게 추가되었습니다.

엔티티의 getHeight()getWeight() 메서드를 통해 안전하게 값을 가져오고 있습니다.


53-62: 프로필 완성도 계산에서 신체 정보를 제외한 것이 의도된 것인지 확인해 주세요.

getProfileCompletionPercentage 메서드가 nickname, email, profileImage만 카운트하고 height/weight는 고려하지 않습니다. 이것이 의도된 설계인지 확인이 필요합니다.

만약 신체 정보도 프로필 완성도에 포함되어야 한다면:

getProfileCompletionPercentage(profile: UserProfile): number {
  let completedFields = 0;
  const totalFields = 5; // nickname, email, profileImage, height, weight

  if (profile.getNickname()) completedFields++;
  if (profile.getEmail()) completedFields++;
  if (profile.getProfileImageUrl()) completedFields++;
  if (profile.getHeight()) completedFields++;
  if (profile.getWeight()) completedFields++;

  return Math.round((completedFields / totalFields) * 100);
}

또는 필수/선택 필드를 구분하여 계산할 수도 있습니다.

apps/web/src/domains/user/presentation/ui/components/user-physical-info-form-component/index.tsx (1)

6-30: 컴포넌트 구조가 잘 구성되어 있습니다.

Props 인터페이스가 명확하고, 컴포넌트 분해가 적절하게 이루어졌습니다.

apps/web/src/domains/user/domain/entities/user.entity.ts (2)

11-12: 인터페이스 확장이 적절합니다.

getHeight()getWeight() 메서드 시그니처가 다른 선택적 필드들과 일관성 있게 정의되었습니다.


98-104: getter 구현이 올바릅니다.

getHeight()getWeight() 메서드가 private 필드를 올바르게 반환하고 있습니다.

Comment on lines 92 to 94
{...register("height", {
setValueAs: (v) => (v === "" ? undefined : Number(v)),
})}
Copy link

@coderabbitai coderabbitai bot Nov 11, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

신체 정보 입력값의 범위 검증을 확인하세요.

현재 type="number"를 사용하지만, 음수나 비정상적으로 큰 값(예: 키 999cm, 몸무게 -10kg)을 방지하는 클라이언트 측 검증이 보이지 않습니다. ProfileEditFormData 스키마에 적절한 min/max 검증이 포함되어 있는지 확인하시기 바랍니다.

다음 스크립트를 실행하여 스키마에 검증 로직이 있는지 확인하세요:

Also applies to: 119-121


🏁 Script executed:

#!/bin/bash
# Description: profile-edit.schema.ts의 height와 weight 검증 규칙 확인

# profile-edit.schema.ts 파일에서 height와 weight의 검증 로직 찾기
rg -A 10 -B 2 'height|weight' apps/web/src/domains/user/presentation/schemas/profile-edit.schema.ts

Length of output: 185


신체 정보 입력값의 범위 검증이 누락되어 있습니다.

스키마 검증 결과, heightweightz.number().optional()으로만 정의되어 있으며, 음수, 0, 또는 비정상적으로 큰 값(예: 키 999cm, 몸무게 -10kg)을 방지하는 min/max 제약이 없습니다.

apps/web/src/domains/user/presentation/schemas/profile-edit.schema.ts에서 다음과 같이 범위 검증을 추가하세요:

height: z.number().min(50).max(300).optional(),
weight: z.number().min(10).max(500).optional(),

적절한 범위값은 프로젝트의 요구사항에 맞게 조정하시기 바랍니다.

Also applies to: 119-121

🤖 Prompt for AI Agents
In
apps/web/src/domains/user/presentation/ui/components/user-physical-info-form-component/index.tsx
around lines 92-94 and 119-121, the schema validation for height and weight
lacks range checks; update the corresponding schema definitions in
apps/web/src/domains/user/presentation/schemas/profile-edit.schema.ts by
replacing z.number().optional() for height and weight with
z.number().min(50).max(300).optional() and
z.number().min(10).max(500).optional() respectively (or adjust the min/max to
match project requirements), ensuring the form parsing still maps empty strings
to undefined.

⚠️ Potential issue | 🟠 Major

setValueAs에서 NaN 처리가 누락되었습니다.

빈 문자열은 undefined로 변환하지만, 유효하지 않은 숫자 입력(예: 공백, 문자 등)은 Number(v)NaN을 반환합니다. NaN은 서버로 전송되거나 유효성 검사를 우회할 수 있습니다.

다음 diff를 적용하여 NaN 처리를 추가하세요:

       {...register("height", {
-        setValueAs: (v) => (v === "" ? undefined : Number(v)),
+        setValueAs: (v) => {
+          if (v === "" || v == null) return undefined;
+          const num = Number(v);
+          return Number.isNaN(num) ? undefined : num;
+        },
       })}
📝 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
{...register("height", {
setValueAs: (v) => (v === "" ? undefined : Number(v)),
})}
{...register("height", {
setValueAs: (v) => {
if (v === "" || v == null) return undefined;
const num = Number(v);
return Number.isNaN(num) ? undefined : num;
},
})}
🤖 Prompt for AI Agents
In
apps/web/src/domains/user/presentation/ui/components/user-physical-info-form-component/index.tsx
around lines 92-94, the setValueAs handler currently converts empty string to
undefined but calls Number(v) for other inputs which can produce NaN for invalid
numeric input; update setValueAs to parse the value into a number, then return
undefined when the parsed result is NaN (e.g., const n = Number(v); return
isNaN(n) ? undefined : n) so invalid inputs don’t become NaN and aren’t sent to
the server or bypass validation.

Copy link
Member Author

Choose a reason for hiding this comment

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

height: z.number().min(50).max(300).optional(),
weight: z.number().min(10).max(500).optional(),
해당 부분은 아직 고민인 부분입니다. 키와 몸무게를 과연 적당한 min 값을 정해야한다고 생각하지만, 적당한 값을 정하지 못했습니다
일단 제안한 방법대로 변경해보고 의미 있는 값으로 설정해보도록하겠습니다.

Copy link

Choose a reason for hiding this comment

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

@hijjoy, 좋은 접근 방식입니다! 사용자의 실제 데이터를 고려하여 적절한 범위를 설정하는 것이 중요하겠네요.

참고로, 일반적인 범위 설정 시 고려사항:

  • 키(height): 일반적으로 성인 기준 최소 130-140cm, 최대 210-220cm 정도가 합리적입니다
  • 몸무게(weight): 최소 30-40kg, 최대 200-250kg 정도를 고려할 수 있습니다

서비스의 타겟 사용자층과 실제 사용 케이스를 반영하여 결정하시면 됩니다. 추가로 NaN 처리 로직도 함께 적용해주시면 더욱 안전한 구현이 될 것 같습니다. 👍

Copy link
Member Author

Choose a reason for hiding this comment

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

setValueAs 정리

setValueAs는 react-hook-form에서 폼 값을 최종 저장하기 직전에 변환하는 함수
실행 시점: 사용자가 입력할 때마다 (onChange), getValues(), handleSubmit() 호출 시 등..

  1. HTML input의 값은 항상 string입니다 - type="number"여도 e.target.value는 문자열로 반환
  2. Zod 스키마는 number 타입을 기대합니다: height: z.number().min(130, "...").max(220, "...").optional()
  3. 빈 값 처리 - 사용자가 input을 비우면 "" (빈 문자열)이 되는데, 이를 undefined로 변환해야 optional 필드가 제대로 작동합니다.
  4. 잘못된 입력 처리 - 사용자가 숫자가 아닌 값을 입력하면 Number(v)가 NaN을 반환하는데, 이를 undefined로 처리해야 validation이 올바르게 동작합니다.

Copy link

Choose a reason for hiding this comment

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

@hijjoy, 정확히 이해하셨습니다! 👍

설명해주신 setValueAs의 동작 방식과 네 가지 핵심 포인트가 모두 정확합니다. 특히 다음 두 가지가 중요합니다:

  1. 빈 값 → undefined: optional 필드가 제대로 동작하려면 필수적
  2. NaN → undefined: 잘못된 입력이 validation을 우회하는 것을 방지

제안드린 코드 패턴은 이 두 케이스를 모두 안전하게 처리합니다:

setValueAs: (v) => {
  if (v === "" || v == null) return undefined;
  const num = Number(v);
  return Number.isNaN(num) ? undefined : num;
}

height와 weight 범위값과 함께 적용해주시면 안전한 폼 구현이 완성될 것 같습니다! 🙂


✏️ Learnings added
Learnt from: hijjoy
Repo: Nugudi/websites PR: 215
File: apps/web/src/domains/user/presentation/ui/components/user-physical-info-form-component/index.tsx:92-98
Timestamp: 2025-11-11T05:19:24.613Z
Learning: In React Hook Form with Zod validation for optional numeric fields (like height, weight), use setValueAs to safely convert string inputs to numbers by checking for empty strings, null, and NaN, and returning undefined for all invalid cases. This ensures optional fields work correctly and invalid inputs don't bypass validation. Pattern: setValueAs: (v) => { if (v === "" || v == null) return undefined; const num = Number(v); return Number.isNaN(num) ? undefined : num; }

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

Comment on lines +96 to 111
<Badge tone="positive" size="xs" variant="weak">
Lv.1
</Badge>
<Flex direction="column" gap={4}>
<Title fontSize="t3" color="main" colorShade={800}>
인턴 너구리
</Title>
<HStack gap={4} align="center">
<Body fontSize="b3b" colorShade={700}>
{nickname}
</Body>
<Link href="/profile/edit" className={styles.editButton}>
<PencilIcon width={16} height={16} />
</Link>
</HStack>
</Flex>
Copy link

@coderabbitai coderabbitai bot Nov 11, 2025

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

에러 상태와 콘텐츠 상태의 UI가 중복됩니다.

Line 57-72의 에러 UI와 Line 96-111의 실제 콘텐츠 UI가 거의 동일한 구조입니다. 공통 컴포넌트로 추출하여 코드 중복을 제거할 수 있습니다.

다음과 같이 공통 컴포넌트로 추출할 수 있습니다:

interface UserProfileDisplayProps {
  profileImageUrl: string;
  nickname: string;
  level?: string;
  title?: string;
}

const UserProfileDisplay = ({
  profileImageUrl,
  nickname,
  level = "Lv.1",
  title = "인턴 너구리"
}: UserProfileDisplayProps) => {
  return (
    <Flex className={styles.container}>
      <Image
        priority
        src={profileImageUrl}
        alt="profile"
        width={165}
        height={130}
        className={styles.profileImage}
      />
      <Flex className={styles.infoWrapper}>
        <Badge tone="positive" size="xs" variant="weak">
          {level}
        </Badge>
        <Flex direction="column" gap={4}>
          <Title fontSize="t3" color="main" colorShade={800}>
            {title}
          </Title>
          <HStack gap={4} align="center">
            <Body fontSize="b3b" colorShade={700}>
              {nickname}
            </Body>
            <Link href="/profile/edit" className={styles.editButton}>
              <PencilIcon width={16} height={16} />
            </Link>
          </HStack>
        </Flex>
      </Flex>
    </Flex>
  );
};

// 그리고 각 컴포넌트에서:
const UserProfileSectionError = () => (
  <UserProfileDisplay
    profileImageUrl="/images/intern-nuguri.png"
    nickname="손님"
  />
);

const UserProfileSectionContent = () => {
  const { data: profileData } = useSuspenseQuery(userProfileQueryClient);
  return (
    <UserProfileDisplay
      profileImageUrl={profileData.profileImageUrl ?? "/images/intern-nuguri.png"}
      nickname={profileData.nickname ?? "손님"}
    />
  );
};
🤖 Prompt for AI Agents
In
apps/web/src/domains/user/presentation/ui/sections/user-profile-section/index.tsx
around lines 57-72 and 96-111, the error-state UI and the real-content UI are
duplicated; extract a shared presentational component (e.g., UserProfileDisplay)
that accepts profileImageUrl, nickname, level, and title props and use it for
both the error and content variants; update the error variant to pass default
placeholder values and the content variant to pass values from profileData (with
fallbacks), and replace the duplicated JSX blocks with calls to the new shared
component while keeping existing className/style/props intact.

Copy link
Member Author

Choose a reason for hiding this comment

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

현재 브랜치는 프로필 수정 컴포넌트와 관련되어있으므로, 이 부분은 추후 실제로 프로필 연결 과정에서 수정하도록 하겟습니다.

Copy link

Choose a reason for hiding this comment

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

@hijjoy, 이해했습니다! 현재 PR의 범위를 고려하면 합리적인 결정입니다.

추후 프로필 연결 작업 시 이 리팩토링을 잊지 않도록 후속 이슈를 생성하시겠습니까? 원하신다면 제가 이슈를 만들어 드릴 수 있습니다.

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: 0

🧹 Nitpick comments (1)
apps/web/src/domains/user/presentation/ui/components/user-basic-info-form-component/index.tsx (1)

62-66: onChange 핸들러 패턴을 더 간결하게 개선할 수 있습니다.

현재 패턴은 올바르게 동작하지만, spread 연산자로 포함된 onChange를 오버라이드한 후 수동으로 다시 호출하는 방식이 다소 장황합니다. 구조 분해를 사용하면 더 명확하게 표현할 수 있습니다.

다음 diff를 적용하여 패턴을 개선하세요:

+      const { onChange, ...registration } = register("nickname");
       <Input
         label="닉네임"
         variant="filled"
-        {...register("nickname")}
+        {...registration}
         onChange={(e) => {
-          register("nickname").onChange(e);
+          onChange(e);
           onNicknameChange(e);
         }}
         placeholder="정조이"
         isError={!!errors.nickname}
         errorMessage={errors.nickname?.message}
       />
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a48ed2b and bc783a8.

📒 Files selected for processing (4)
  • apps/web/src/domains/user/presentation/schemas/profile-edit.schema.ts (1 hunks)
  • apps/web/src/domains/user/presentation/ui/components/user-basic-info-form-component/index.tsx (1 hunks)
  • apps/web/src/domains/user/presentation/ui/components/user-physical-info-form-component/index.tsx (1 hunks)
  • apps/web/src/domains/user/presentation/ui/sections/user-profile-edit-form-section-mock/index.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • apps/web/src/domains/user/presentation/ui/sections/user-profile-edit-form-section-mock/index.tsx
  • apps/web/src/domains/user/presentation/schemas/profile-edit.schema.ts
  • apps/web/src/domains/user/presentation/ui/components/user-physical-info-form-component/index.tsx
🧰 Additional context used
🧬 Code graph analysis (1)
apps/web/src/domains/user/presentation/ui/components/user-basic-info-form-component/index.tsx (1)
apps/web/src/domains/user/presentation/schemas/profile-edit.schema.ts (1)
  • ProfileEditFormData (27-27)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: deploy
🔇 Additional comments (1)
apps/web/src/domains/user/presentation/ui/components/user-basic-info-form-component/index.tsx (1)

86-102: 잘 구현되었습니다!

중복 체크 버튼이 올바르게 구현되었습니다. type="button"으로 폼 제출을 방지하고, 로딩 상태를 isLoadingdisabled 속성에 모두 연결하여 적절한 사용자 경험을 제공합니다.

@hijjoy hijjoy requested a review from dydals3440 November 11, 2025 05:19
@github-actions
Copy link

This pull request (commit bc783a8) has been deployed to Vercel ▲ - View GitHub Actions Workflow Logs

Name Link
🌐 Unique https://nugudi-5c9xdqvl4-dydals3440s-projects.vercel.app
🔍 Inspect https://vercel.com/dydals3440s-projects/nugudi/6YreyfydRNW79PAWHjgvXQrGh3NW

- 사용자 엔티티와 어댑터에 키·몸무게 속성 추가
- 프로필 수정 폼 스키마와 기본 정보/신체 정보 컴포넌트 구현
- 프로필 수정 페이지에서 신규 뷰 컴포넌트 렌더링
- 인턴 너구리 이미지를 추가하고 기본 프로필 이미지를 교체
- 배지와 타이포그래피 컴포넌트로 프로필 정보 표현을 재구성
- 프로필 뷰에 스택 레이아웃을 적용해 섹션 배치를 정리했습니다
- 수정 버튼 범위 클릭 범위 확장
- navbar 변경으로 인한 깨진 UI 수정
- 키/몸무게 필드에 범위 검증 추가 (키: 130-220cm, 몸무게: 30-250kg)
- Number.isNaN() 사용하여 타입 안정성 강화
- 빈 값 및 잘못된 입력 처리를 위한 setValueAs 핸들러 개선
- react-hook-form defaultValues와 중복되는 defaultValue props 제거
@hijjoy hijjoy force-pushed the feature/NUGUDI-181-profile-update branch from bc783a8 to 1aee6e2 Compare November 13, 2025 06:23
@github-actions
Copy link

This pull request (commit 1aee6e2) has been deployed to Vercel ▲ - View GitHub Actions Workflow Logs

Name Link
🌐 Unique https://nugudi-k8ff8si47-dydals3440s-projects.vercel.app
🔍 Inspect https://vercel.com/dydals3440s-projects/nugudi/5ggoJspEkupJDgxWhrqawm6kSq9r

@hijjoy
Copy link
Member Author

hijjoy commented Nov 13, 2025

@dydals3440 이 UI만 마지막으로 마무리하고(아직 dto없는 화면), 이제 클린아키텍쳐에 맞춰 api 나온 화면들 연결하려고합니다 🐿️
아마 이 페이지도 다시 하게 되겠죠..

@dydals3440 dydals3440 merged commit 9c9f2e3 into main Nov 13, 2025
5 checks passed
@dydals3440 dydals3440 deleted the feature/NUGUDI-181-profile-update branch November 13, 2025 13:27
@dydals3440
Copy link
Contributor

@dydals3440 이 UI만 마지막으로 마무리하고(아직 dto없는 화면), 이제 클린아키텍쳐에 맞춰 api 나온 화면들 연결하려고합니다 🐿️ 아마 이 페이지도 다시 하게 되겠죠..

고생하셨습니당 팟탱 나머지도..

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

apps/web apps/web 관련 작업

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[NUGUDI-181] 프로필 수정 화면 구현

2 participants