Skip to content

Feat: 워크스페이스 설정페이지 api연동 - #53

Merged
Kwon812 merged 11 commits into
developfrom
feat/#47/workspace-setting-page
Jul 14, 2026
Merged

Feat: 워크스페이스 설정페이지 api연동 #53
Kwon812 merged 11 commits into
developfrom
feat/#47/workspace-setting-page

Conversation

@Kwon812

@Kwon812 Kwon812 commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Pull Request

작업 내용

  • 기존 목업 기반이던 워크스페이스 설정 페이지를 실 Supabase API로 연동 (정보/멤버/현재 사용자 조회, 정보·닉네임 수정)
  • 초대 링크 생성 → 이메일 발송 → 링크 참여로 이어지는 초대 플로우 구현 (RPC 2종 + /invite/[code] 라우트)
  • 조회/수정 모두 RLS 기반으로 동작 (인가 주체는 앱 레이어가 아닌 DB auth.uid())

작업 결과

  • 설정 페이지에서 워크스페이스 정보/닉네임 수정이 실 DB에 반영됨 (소유자만 정보 편집 노출)
  • 초대 링크 활성화 후 이메일로 초대 발송 → 수신 링크(/invite/[code])로 워크스페이스 참여 가능
  • 이미 멤버인 사용자가 초대 링크 접속 시 재참여 없이 입장 (멱등)

변경 사항

Added

  • updateWorkspaceInfo / updateMyNickname 서버액션 (정보·닉네임 수정, RLS 기반)
  • 초대 RPC 2종 supabase/migrations/20260713010000_create_invite_rpcs.sql
    • get_invite_preview(p_code) — 활성·유효 코드일 때만 워크스페이스 요약 반환
    • join_workspace_by_invite_code(p_user_id, p_code)security definer로 RLS 우회, 멱등 참여
  • /invite/[code] 라우트 및 InviteAcceptView (초대 미리보기·참여 UI)
  • set-workspace-invite-enabled — 초대 링크 활성/비활성 토글
  • send-invite-email 서버액션 — Resend로 초대 이메일 발송 (멤버만 발송 가능)
  • .env.exampleRESEND_API_KEY, INVITE_EMAIL_FROM 추가, resend 패키지 도입

Changed

  • settings/page.tsx — RSC에서 워크스페이스·멤버·현재 사용자를 실 API로 조회해 주입
  • SettingsView — 현재 사용자 역할(owner) 기준으로 정보 편집 권한 판단
  • WorkspaceInfoForm / MemberProfileForm — 실 서버액션 연결 및 저장 상태 UI 반영
  • manage-workspace-members/** — 멤버 관리·초대 UI 실 데이터 연동
  • get-workspace-by-id — invite_code, invite_enabled 컬럼 추가

Fixed

  • 닉네임 수정 시 (workspace_id, workspace_nickname) 유니크 제약 위반을 사용자 친화 메시지로 처리

실행화면

스크린샷 2026-07-14 오후 12 24 11 스크린샷 2026-07-14 오후 12 24 56

테스트

  • 로컬 실행 확인
  • 주요 시나리오 확인 (정보/닉네임 수정, 초대 발송·참여, 멱등 입장, 무효 코드 안내)
  • 영향 범위 확인

리뷰 체크리스트

  • PR base branch가 올바릅니다. (feature/* -> develop, 배포 시 develop 또는 release/* -> main)
  • 브랜치명이 Type/#issue-number/description 형식을 따릅니다.
  • 커밋 메시지가 컨벤션을 따릅니다.
  • 불필요한 console.log, 주석, 임시 코드를 제거했습니다.
  • 타입 에러와 린트 에러를 확인했습니다.
  • CodeRabbit 1차 리뷰를 확인했습니다.
  • CodeRabbit 리뷰 반영 후 Discord에 공유했습니다.
  • 최소 1명 이상의 approve 후 merge합니다.

리뷰 요청사항

  • 초대 RPC의 security definer / search_path 설정과 멱등·닉네임 충돌 재시도 로직이 안전한지

관련 이슈

Closes #47

Summary by CodeRabbit

Summary by CodeRabbit

  • 새로운 기능

    • 워크스페이스 초대 코드로 가입 화면과 참여 전 워크스페이스 미리보기가 제공됩니다.
    • 초대 링크 생성/활성화(복사 포함)와 이메일 초대 발송이 지원됩니다.
    • 닉네임을 서버에 저장하고, 워크스페이스 페이지에서 업데이트가 반영됩니다.
  • 개선 사항

    • 초대 설정/편집은 권한이 있는 경우에만 가능하며, 비활성/무효 초대에 대한 안내가 표시됩니다.
    • 워크스페이스 설정 페이지가 실제 멤버 및 현재 사용자 정보를 기준으로 표시됩니다.

@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

워크스페이스 설정을 실제 Supabase 서버 액션으로 전환하고, 소유자 전용 수정과 본인 닉네임 저장을 구현했습니다. 초대 링크 프리뷰·참여·활성화 및 Resend 이메일 발송 흐름도 추가했습니다.

Changes

워크스페이스 설정 및 초대 백엔드

Layer / File(s) Summary
설정 저장 서버 계약
src/entities/workspace/..., src/entities/workspace-member/...
워크스페이스 정보, 멤버 닉네임, 초대 활성 상태를 검증하고 저장하는 서버 액션과 초대 필드를 추가했습니다.
초대 RPC와 발송 API
supabase/migrations/..., src/entities/workspace/api/..., src/shared/api/email/..., .env.example, package.json
초대 프리뷰·참여 RPC, 호출 권한, Resend 이메일 발송과 환경 설정을 추가했습니다.

설정 및 초대 UI

Layer / File(s) Summary
설정 데이터와 저장 UI
src/app/workspaces/..., src/views/settings/..., src/features/manage-workspace-info/..., src/features/manage-member-profile/...
실제 멤버·현재 사용자 조회를 연결하고, 소유자 권한과 서버 저장 상태를 폼에 반영했습니다.
멤버 초대 관리 UI
src/features/manage-workspace-members/...
초대 활성화 토글, 소유자 권한, 링크 복사 제한, 이메일 발송 상태를 서버 API와 연결했습니다.
초대 코드 참여 화면
src/app/invite/..., src/views/invite/...
초대 프리뷰를 조회하고 유효한 초대의 참여 화면을 표시하며, 참여 후 워크스페이스로 이동하도록 구현했습니다.

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

Sequence Diagram(s)

sequenceDiagram
  participant Browser
  participant InvitePage
  participant SupabaseRPC
  participant InviteAcceptView
  Browser->>InvitePage: 초대 코드 접근
  InvitePage->>SupabaseRPC: get_invite_preview(code)
  SupabaseRPC-->>InvitePage: 프리뷰 반환
  InvitePage->>InviteAcceptView: 초대 정보 전달
  InviteAcceptView->>SupabaseRPC: join_workspace_by_invite_code(code)
  SupabaseRPC-->>InviteAcceptView: workspaceId 반환
  InviteAcceptView-->>Browser: 워크스페이스 이동
Loading

Possibly related PRs

  • TeampleRun/syncly#33 — 설정 페이지의 멤버·현재 사용자 데이터 흐름과 직접 연결됩니다.

Suggested reviewers: jiwoonge, 0011810, seongjinss555

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning 워크스페이스 초대 범위와 무관한 create_work_shift_type_and_ensure_weekly_entries 타입 제거가 포함되어 있습니다. 해당 타입 삭제가 의도된 스키마 정리인지 확인하고, 아니라면 관련 없는 변경은 되돌리세요.
Docstring Coverage ⚠️ Warning Docstring coverage is 15.38% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed 제목이 워크스페이스 설정 페이지의 API 연동이라는 핵심 변경을 간결하게 요약합니다.
Description check ✅ Passed 템플릿의 주요 섹션과 필요한 정보가 대부분 채워져 있어 설명이 충분합니다.
Linked Issues check ✅ Passed 설정 페이지 실 API 연동, 권한 분리, 초대 링크·이메일·참여 플로우가 이슈 #47의 완료 기준과 일치합니다.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/#47/workspace-setting-page

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

Caution

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

⚠️ Outside diff range comments (1)
src/features/manage-member-profile/ui/MemberProfileForm.tsx (1)

59-67: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

닉네임 입력에 서버와 동일한 글자 수 제한을 클라이언트에도 반영 권장.

서버 스키마(update-my-nickname.ts)는 닉네임을 20자로 제한하는데, input에는 대응하는 maxLength가 없어 초과 입력 시 서버 왕복 후에야 오류를 알게 됩니다.

♻️ 제안
           <input
             value={nickname}
             onChange={(event) => {
               setNickname(event.target.value);
               setIsSaved(false);
             }}
+            maxLength={20}
             placeholder="닉네임을 입력하세요."
🤖 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/features/manage-member-profile/ui/MemberProfileForm.tsx` around lines 59
- 67, Update the nickname input in MemberProfileForm to enforce the server’s
20-character limit by adding the corresponding maxLength constraint, while
preserving the existing value, change handler, placeholder, and styling.
🤖 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/app/invite/`[code]/page.tsx:
- Around line 16-36: Extract the invalid or expired invitation UI from the
page-level conditional in the invite page into a new InviteInvalidView component
under the invite views UI layer. Export InviteInvalidView through the invite
view barrel alongside InviteAcceptView, then import and render it from the
!preview branch so the page only composes views.

In `@src/entities/workspace-member/index.ts`:
- Around line 12-14: Update the comment above the `updateMyNickname` barrel
export so it accurately states that this Server Action can be safely exposed
through the barrel, removing the contradictory claim that
`next/headers`-dependent functions are excluded. Keep the `updateMyNickname`
export unchanged.

In `@src/entities/workspace/api/set-workspace-invite-enabled.ts`:
- Around line 25-33: Update the Supabase update chain in
setWorkspaceInviteEnabled to select the updated workspace id with maybeSingle(),
destructure the returned data alongside error, and treat !data as failure by
logging and throwing the existing user-facing error, preserving the current
error handling.

In `@src/entities/workspace/api/update-workspace-info.ts`:
- Around line 22-29: Update both workspace update
sites—src/entities/workspace/api/update-workspace-info.ts lines 22-29 and
src/entities/workspace-member/api/update-my-nickname.ts lines 28-33—by chaining
select('id') after update and capturing the returned data. Treat an empty result
as a permission error and throw it instead of reporting success; preserve
existing handling for database errors.

In `@src/features/manage-workspace-members/model/use-member-management.ts`:
- Line 82: Update the canInvite calculation in the member-management hook to
require isInviteEnabled alongside the existing email, duplicate, and
sending-state checks, so the invite action remains disabled when workspace
invitations are disabled.
- Line 35: Remove the unused useState wrapper around members in the
member-management hook and use initialMembers directly so updates from the
caller are reflected in the latest member list. Clean up the now-unneeded
state-related import if applicable, while preserving all existing
member-management behavior.

In `@src/shared/api/email/env.ts`:
- Line 5: Update the from initialization in the email environment configuration
to treat an empty INVITE_EMAIL_FROM value as unset and use the existing default
sender instead. Preserve the configured sender when it contains a non-empty
value.

In `@supabase/migrations/20260713010000_create_invite_rpcs.sql`:
- Around line 54-78: Update the insert exception handling in the invite RPC so a
unique_violation caused by an existing (workspace_id, user_id) membership is
rechecked and returns v_workspace_id as an idempotent success. Only apply the
nickname suffix retry for an actual workspace_nickname conflict, and ensure the
retry cannot treat a user-membership conflict as a nickname collision.
- Around line 30-38: Update the security-definer function
join_workspace_by_invite_code to derive the acting user exclusively from
auth.uid() instead of trusting p_user_id. Reject or otherwise prevent execution
when auth.uid() is null, and ensure all membership and invitation updates use
the authenticated ID so callers cannot act on behalf of another user.
- Line 63: Update the profile lookup in the invite RPC so a missing row is
caught and converted to a clear custom exception message before the error
reaches join-workspace-by-invite-code.ts. Preserve the existing nickname
assignment for found profiles and ensure the custom message is suitable for the
caller’s error.message fallback.

---

Outside diff comments:
In `@src/features/manage-member-profile/ui/MemberProfileForm.tsx`:
- Around line 59-67: Update the nickname input in MemberProfileForm to enforce
the server’s 20-character limit by adding the corresponding maxLength
constraint, while preserving the existing value, change handler, placeholder,
and styling.
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 4876e497-9f0c-416d-b577-255496fbc92c

📥 Commits

Reviewing files that changed from the base of the PR and between 269b17c and 9da2861.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json, !package-lock.json
📒 Files selected for processing (24)
  • .env.example
  • package.json
  • src/app/invite/[code]/page.tsx
  • src/app/workspaces/[workspaceId]/settings/page.tsx
  • src/entities/workspace-member/api/update-my-nickname.ts
  • src/entities/workspace-member/index.ts
  • src/entities/workspace/api/get-invite-preview.ts
  • src/entities/workspace/api/get-workspace-by-id.ts
  • src/entities/workspace/api/join-workspace-by-invite-code.ts
  • src/entities/workspace/api/send-invite-email.ts
  • src/entities/workspace/api/set-workspace-invite-enabled.ts
  • src/entities/workspace/api/update-workspace-info.ts
  • src/entities/workspace/index.ts
  • src/entities/workspace/model/workspace.types.ts
  • src/features/manage-member-profile/ui/MemberProfileForm.tsx
  • src/features/manage-workspace-info/ui/WorkspaceInfoForm.tsx
  • src/features/manage-workspace-members/model/use-member-management.ts
  • src/features/manage-workspace-members/ui/MemberInviteSection.tsx
  • src/features/manage-workspace-members/ui/MemberManagementPanel.tsx
  • src/shared/api/email/env.ts
  • src/views/invite/index.ts
  • src/views/invite/ui/InviteAcceptView.tsx
  • src/views/settings/ui/SettingsView.tsx
  • supabase/migrations/20260713010000_create_invite_rpcs.sql

Comment thread src/app/invite/[code]/page.tsx
Comment thread src/entities/workspace-member/index.ts
Comment thread src/entities/workspace/api/set-workspace-invite-enabled.ts
Comment thread src/entities/workspace/api/update-workspace-info.ts
Comment thread src/shared/api/email/env.ts Outdated
Comment thread supabase/migrations/20260713010000_create_invite_rpcs.sql
Comment thread supabase/migrations/20260713010000_create_invite_rpcs.sql
Comment thread supabase/migrations/20260713010000_create_invite_rpcs.sql

@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/shared/model/database.types.ts (1)

778-779: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

create_work_shift_type_and_ensure_weekly_entries RPC를 타입에 복구하세요 src/shared/model/database.types.ts:778-779

이 RPC는 아직 supabase/migrations/20260714024702_make_work_shift_creation_atomic.sql에 정의돼 있고 src/entities/work-schedule/api/work-schedule-actions.ts에서도 호출합니다. Database['public']['Functions']에서 빠지면 생성 타입이 실제 스키마와 어긋납니다.

🤖 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/shared/model/database.types.ts` around lines 778 - 779, Restore the
create_work_shift_type_and_ensure_weekly_entries entry in the Database public
Functions type alongside create_workspace. Match its argument and return types
to the RPC definition and its usage in work-schedule-actions.ts so the generated
type reflects the existing schema.
🤖 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 `@supabase/migrations/20260714030000_harden_invite_rpcs.sql`:
- Line 5: Remove the explicit transaction boundaries from the migration by
deleting the begin statement at the top and the commit statement near the end.
Leave the migration statements themselves unchanged so the migration tool
controls atomicity and migration recording.
- Around line 41-65: Update the membership insertion logic in the invite RPC
around the existing workspace_members existence check and insert exception block
to handle concurrent requests for the same (workspace_id, user_id) idempotently.
Distinguish user-membership unique violations from nickname conflicts, recheck
or otherwise return the existing workspace membership for the same user, and
only apply the generated nickname suffix for genuine nickname collisions.

---

Outside diff comments:
In `@src/shared/model/database.types.ts`:
- Around line 778-779: Restore the
create_work_shift_type_and_ensure_weekly_entries entry in the Database public
Functions type alongside create_workspace. Match its argument and return types
to the RPC definition and its usage in work-schedule-actions.ts so the generated
type reflects the existing schema.
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 62b22caf-6f41-4f03-8b0c-42c2888612aa

📥 Commits

Reviewing files that changed from the base of the PR and between 9da2861 and 746062d.

📒 Files selected for processing (3)
  • src/entities/workspace/api/join-workspace-by-invite-code.ts
  • src/shared/model/database.types.ts
  • supabase/migrations/20260714030000_harden_invite_rpcs.sql

Comment thread supabase/migrations/20260714030000_harden_invite_rpcs.sql Outdated
Comment thread supabase/migrations/20260714030000_harden_invite_rpcs.sql Outdated

@seongjinss555 seongjinss555 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

고생하셨습니다~

@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: 1

🤖 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 `@supabase/migrations/20260714030000_harden_invite_rpcs.sql`:
- Around line 41-42: Update the profile lookup in the invite RPC to handle both
unique_violation and no_data_found exceptions. When the strict profiles query
for v_nickname finds no row, route it through the same safe handling path as the
existing conflict case so accounts without profiles do not abort the RPC.
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 5ed6aea0-2c8a-4d65-9173-f7dd0739a851

📥 Commits

Reviewing files that changed from the base of the PR and between 746062d and f3f4e99.

📒 Files selected for processing (2)
  • src/shared/api/email/env.ts
  • supabase/migrations/20260714030000_harden_invite_rpcs.sql

Comment on lines +41 to +42
-- 이미 참여한 멤버면 재참여 없이 그대로 입장한다(멱등 — 빠른 경로).
-- 정합성은 아래 on conflict가 보장하므로 이 체크는 프로필 조회를 아끼는 최적화일 뿐이다.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# 마이그레이션 파일에서 exists 체크와 strict select 부분(43-52라인)을 확인
fd 'harden_invite_rpcs' | xargs cat -n | sed -n '30,60p'

# 프로필 생성이 트리거 등으로 보장되는지 확인
rg -n 'insert into (public\.)?profiles' supabase/migrations

Repository: TeampleRun/syncly

Length of output: 1613


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== migrations mentioning profiles table or inserts =="
rg -n -i 'create table .*profiles|profiles\s*\(|insert into (public\.)?profiles|trigger.*profiles|profiles.*trigger|handle_new_user|on auth\.users' supabase/migrations

echo
echo "== files related to profiles =="
fd -a 'profiles' supabase/migrations supabase || true

Repository: TeampleRun/syncly

Length of output: 2157


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== auth.users 관련 트리거/함수 =="
rg -n -i 'auth\.users|new_user|handle_new_user|create.*profile|profiles.*from auth|insert.*profiles' supabase/migrations supabase --glob '*.sql'

echo
echo "== profiles 테이블 정의 =="
rg -n -i 'create table .*profiles|alter table .*profiles|primary key.*profiles|references .*profiles' supabase/migrations --glob '*.sql'

Repository: TeampleRun/syncly

Length of output: 4974


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== any trigger/function mentioning profiles or auth.users anywhere =="
rg -n -i 'create\s+trigger|create\s+function|returns\s+trigger|auth\.users|public\.profiles|insert into (public\.)?profiles|new_user|handle_new_user' . --glob '*.sql' --glob '*.ts' --glob '*.js' --glob '*.md'

echo
echo "== core profiles table / policies excerpts =="
sed -n '1,60p' supabase/migrations/20260709025327_create_enums_and_core_tables.sql
echo
sed -n '1,80p' supabase/migrations/20260709025820_add_auth_rls_policies.sql

Repository: TeampleRun/syncly

Length of output: 10418


strict 조회의 no_data_found도 처리하세요. profiles 자동 생성이 보장되지 않아서, select real_name into strict v_nickname from profiles where id = v_user_id; 는 프로필이 없는 계정에서 RPC를 중단시킬 수 있습니다. unique_violation와 함께 no_data_found도 잡는 쪽이 안전합니다.

🤖 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 `@supabase/migrations/20260714030000_harden_invite_rpcs.sql` around lines 41 -
42, Update the profile lookup in the invite RPC to handle both unique_violation
and no_data_found exceptions. When the strict profiles query for v_nickname
finds no row, route it through the same safe handling path as the existing
conflict case so accounts without profiles do not abort the RPC.

@Kwon812
Kwon812 merged commit d33361c into develop Jul 14, 2026
1 check passed
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: 설정페이지 mock -> api 전환

2 participants