feat: task 도메인 Supabase 연동 - #52
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (7)
📝 WalkthroughWalkthroughTask 도메인을 mock 데이터에서 Supabase 실데이터 기반으로 전환했습니다. 조회·생성·삭제·보드 갱신 API와 React Query 훅을 추가하고, 프로젝트 보드·진행률 차트·대시보드 위젯에 연결했습니다. ChangesTask 도메인 Supabase 연동
Signup 인증 클라이언트 수명주기
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant ProjectBoard
participant TaskQuery
participant TaskMutation
participant Supabase
ProjectBoard->>TaskQuery: workspaceId로 Task 조회
TaskQuery->>Supabase: tasks 조회
Supabase-->>TaskQuery: Task 목록 반환
ProjectBoard->>TaskMutation: 생성·삭제·정렬 요청
TaskMutation->>Supabase: server action 또는 RPC 실행
Supabase-->>TaskMutation: 변경 결과 반환
TaskMutation->>TaskQuery: 목록 query 무효화
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 11
🤖 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/entities/task/api/create-task.ts`:
- Around line 18-40: Replace the separate last-task lookup and insert flow in
the task creation function with an atomic database operation, preferably an RPC
that calculates the next workspace-level sort_order and inserts the task within
one transaction. Ensure concurrent creations cannot receive the same sort_order;
alternatively enforce a unique constraint and add retry handling for conflicts
while preserving the existing task payload fields.
In `@src/entities/task/api/get-tasks-by-workspace-id.ts`:
- Line 1: 브라우저 Supabase 클라이언트로 조회하는 getSupabaseBrowserClient 경로에 멤버십 기반 접근만
적용되도록 수정하세요. dev_full_access 정책을 제거하고 tasks, workspace_members, profiles에 대해
workspace 멤버십을 검증하는 RLS 정책만 유지·적용하세요.
In `@src/entities/task/api/update-task-board.ts`:
- Line 1: Replace the duplicated TaskStatus literal unions in the
update-task-board API parameter types and the use-update-task-board tasks status
type with TaskStatus. Import TaskStatus from ../model/task.types in
update-task-board.ts, and reuse the shared type in use-update-task-board.ts
while preserving the existing parameter shapes.
- Around line 24-39: Replace the per-task Promise.all updates in the task board
update flow with a single atomic database operation, preferably a batch upsert
using the existing task board payload and workspace scope. Preserve the current
failure logging and user-facing error behavior, and ensure the operation either
applies all task changes or none.
In `@src/entities/task/api/use-update-task-board.ts`:
- Around line 11-16: tasks 타입의 status에 중복 선언된 문자열 리터럴 유니온을 제거하고, 프로젝트에 이미 정의된
TaskStatus 타입을 재사용하도록 변경하세요. 기존 todo, in-progress, done 값에 대한 타입 계약은 그대로 유지하세요.
In `@src/entities/workspace-member/api/get-workspace-members-by-id.client.ts`:
- Around line 55-60: Update the membership mapping around profilesById.get in
the membershipRows.flatMap callback so a missing profile is not silently
omitted. Preserve the member in the returned list using the established fallback
or missing-profile representation, and keep the existing profile mapping
unchanged when a profile is available.
- Around line 25-49: Update the workspace member query in
getWorkspaceMembersById to join profiles through
profiles!workspace_members_user_id_fkey(email, real_name), returning the member
and profile fields in one request. Remove the separate userIds early-return flow
and profiles query, while preserving existing error handling and result mapping
behavior.
- Around line 62-70: Update the member mapping in getWorkspaceMembersById to
populate status from the actual member status column instead of always returning
'joined'. Include the status field in the query’s selected columns and map it
through so invited members retain their 'invited' status.
In `@src/features/project-board/ui/ProjectBoard.tsx`:
- Around line 62-68: Update the task creation handler containing
createTaskMutation.mutateAsync, likely createTask, to catch and consume mutation
errors locally so rejections do not propagate to handleComposerKeyDown as
unhandled Promise rejections. Preserve the existing hook toast behavior and
always reset isCreatingTaskRef.current in the finally block.
- Around line 80-90: handleDeleteTask가 전체 tasks 스냅샷을 복원하지 않도록 수정하세요. 중첩된 삭제·재정렬
요청에서 이전 실패가 이후 성공 변경을 덮어쓰지 않게 mutation별 cache context로 해당 삭제 변경분만 복구하거나 보드 쓰기를
직렬화하고, 기존 optimistic 삭제 동작은 유지하세요.
In `@src/widgets/team-project/dashboard-work-summary/ui/WorkSummary.tsx`:
- Around line 64-67: Update the task and member summary states in WorkSummary so
isError is handled separately from isPending instead of being rendered as "-".
For failed queries, show an explicit failure message and provide a retry action
using the query’s existing refetch behavior; preserve the loading placeholder
for pending queries and normal values for successful queries.
🪄 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: 915a9e1e-0f32-45b0-9202-3744d330e9fb
📒 Files selected for processing (24)
src/entities/project-column/ui/ProjectColumn.tsxsrc/entities/task/api/create-task.tssrc/entities/task/api/delete-task.tssrc/entities/task/api/get-tasks-by-workspace-id.tssrc/entities/task/api/update-task-board.tssrc/entities/task/api/use-create-task.tssrc/entities/task/api/use-delete-task.tssrc/entities/task/api/use-tasks-by-workspace-id.tssrc/entities/task/api/use-update-task-board.tssrc/entities/task/index.tssrc/entities/task/model/mock-tasks-by-workspace.tssrc/entities/task/model/task.db.types.tssrc/entities/task/model/task.mapper.tssrc/entities/task/model/task.schema.tssrc/entities/task/model/task.types.tssrc/entities/workspace-member/api/get-workspace-members-by-id.client.tssrc/entities/workspace-member/api/use-workspace-members-by-id.tssrc/entities/workspace-member/index.tssrc/features/manage-progress-chart/ui/ProgressChartView.tsxsrc/features/project-board/ui/ProjectBoard.tsxsrc/views/progress-chart/ui/ProgressChartPage.tsxsrc/views/signup/ui/SignupView.tsxsrc/widgets/team-project/dashboard-overall-progress/ui/OverallProgress.tsxsrc/widgets/team-project/dashboard-work-summary/ui/WorkSummary.tsx
💤 Files with no reviewable changes (1)
- src/entities/task/model/mock-tasks-by-workspace.ts
| @@ -0,0 +1,22 @@ | |||
| import { getSupabaseBrowserClient } from '@/shared/api/supabase/client'; | |||
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# RLS 정책 정의 파일(마이그레이션) 검색
rg -n "workspace_members|tasks|profiles" -g '*.sql' -C3
fd -e sql | xargs grep -l "ROW LEVEL SECURITY" 2>/dev/nullRepository: TeampleRun/syncly
Length of output: 155
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n## Files\n'
git ls-files 'src/entities/task/api/*' 'src/entities/workspace-member/api/*' 'supabase/*' '*.sql' | sed -n '1,200p'
printf '\n## Relevant source snippets\n'
for f in \
src/entities/task/api/get-tasks-by-workspace-id.ts \
src/entities/workspace-member/api/get-workspace-members-by-id.client.ts \
src/entities/task/api/update-task-board.ts \
src/entities/task/api/use-update-task-board.ts
do
if [ -f "$f" ]; then
echo "\n### $f"
ast-grep outline "$f" --view expanded || true
fi
done
printf '\n## Search for RLS / policies\n'
rg -n "ROW LEVEL SECURITY|create policy|alter table .* enable row level security|tasks|workspace_members|profiles" -g '*.sql' -g '*.ts' -g '*.tsx' -C 2 | sed -n '1,240p'Repository: TeampleRun/syncly
Length of output: 2397
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n## RLS migration snippets\n'
for f in \
supabase/migrations/20260709025820_add_auth_rls_policies.sql \
supabase/migrations/20260709034833_move_rls_helpers_to_private_schema.sql
do
echo "\n### $f"
wc -l "$f"
rg -n "ROW LEVEL SECURITY|create policy|alter table|tasks|workspace_members|profiles" "$f" -C 3
done
printf '\n## Core table definitions (for relation names / keys)\n'
rg -n "create table.*tasks|create table.*workspace_members|create table.*profiles|foreign key|references" \
supabase/migrations/20260709025327_create_enums_and_core_tables.sql \
supabase/migrations/20260709032015_add_constraints.sql -C 3Repository: TeampleRun/syncly
Length of output: 4327
🏁 Script executed:
#!/bin/bash
set -euo pipefail
for f in \
supabase/migrations/20260709025820_add_auth_rls_policies.sql \
supabase/migrations/20260709034833_move_rls_helpers_to_private_schema.sql \
supabase/migrations/20260709025327_create_enums_and_core_tables.sql
do
echo "\n===== $f ====="
sed -n '1,260p' "$f"
doneRepository: TeampleRun/syncly
Length of output: 14310
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "### add_auth_rls_policies"
nl -ba supabase/migrations/20260709025820_add_auth_rls_policies.sql | sed -n '1,260p'
echo "\n### create_enums_and_core_tables"
nl -ba supabase/migrations/20260709025327_create_enums_and_core_tables.sql | sed -n '1,260p'Repository: TeampleRun/syncly
Length of output: 221
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "### src/entities/workspace-member/api/get-workspace-members-by-id.client.ts"
cat -n src/entities/workspace-member/api/get-workspace-members-by-id.client.ts | sed -n '1,220p'
echo
echo "### src/entities/task/api/get-tasks-by-workspace-id.ts"
cat -n src/entities/task/api/get-tasks-by-workspace-id.ts | sed -n '1,220p'Repository: TeampleRun/syncly
Length of output: 3571
브라우저 조회가 현재는 멤버십으로 제한되지 않습니다. src/entities/task/api/get-tasks-by-workspace-id.ts와 src/entities/workspace-member/api/get-workspace-members-by-id.client.ts는 브라우저 Supabase 클라이언트로 직접 조회하지만, supabase/migrations/20260709025327_create_enums_and_core_tables.sql의 dev_full_access가 남아 있어 tasks/workspace_members/profiles 접근이 사실상 열려 있습니다. 브라우저 경로를 유지하려면 이 정책을 제거하고 멤버십 기반 RLS만 남겨야 합니다.
🤖 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/entities/task/api/get-tasks-by-workspace-id.ts` at line 1, 브라우저 Supabase
클라이언트로 조회하는 getSupabaseBrowserClient 경로에 멤버십 기반 접근만 적용되도록 수정하세요. dev_full_access
정책을 제거하고 tasks, workspace_members, profiles에 대해 workspace 멤버십을 검증하는 RLS 정책만
유지·적용하세요.
There was a problem hiding this comment.
동의합니다. 현재 브라우저 Supabase 클라이언트에서 tasks, workspace_members, profiles를 직접 조회하고 있으므로, RLS가 실질적인 접근 제어 역할을 해야 합니다. dev_full_access 정책을 제거하고 요청 사용자가 해당 워크스페이스의 멤버인지 검증하는 정책만 유지하도록 보완하면 좋겠습니다.
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "### create_enums_and_core_tables (tasks / workspace_members / profiles table defs)"
sed -n '1,400p' supabase/migrations/20260709025327_create_enums_and_core_tables.sql
echo
echo "### add_auth_rls_policies"
sed -n '1,400p' supabase/migrations/20260709025820_add_auth_rls_policies.sql
echo
echo "### move_rls_helpers_to_private_schema"
sed -n '1,400p' supabase/migrations/20260709034833_move_rls_helpers_to_private_schema.sql
echo
echo "### List all migrations for ordering"
fd -e sql . supabase/migrations | sortLength of output: 15359
@seongjinss555 네, 확인했습니다. 마이그레이션을 보니 실제로 필요한 멤버십 기반 정책은 이미 존재합니다:
profiles:profiles_select(로그인 유저 전체 조회 허용은 의도된 설계),profiles_insert_own,profiles_update_ownworkspace_members:members_select(private.is_workspace_member기반),members_insert_self등tasks:tasks_member_all(private.is_workspace_member(workspace_id)기반 CRUD)
문제는 20260709025327_create_enums_and_core_tables.sql에서 모든 public 테이블에 대해 for all using (true) with check (true)인 dev_full_access 정책이 여전히 남아 있고, RLS는 정책들을 OR로 평가하므로 이 정책 하나가 실질적으로 전체 접근을 허용해버립니다. 즉 is_workspace_member 검증 정책들이 이미 있음에도 dev_full_access가 살아있어 무력화되고 있는 상태입니다.
가장 간단하고 안전한 해결책은 새 마이그레이션을 추가해 모든 public 테이블의 dev_full_access 정책만 drop policy하는 것입니다(테이블 구조나 기존 정책은 그대로 유지). 아래와 같은 형태를 제안합니다.
-- supabase/migrations/<timestamp>_drop_dev_full_access.sql
-- dev_full_access 정책 제거: 실 RLS(auth.uid()/워크스페이스 멤버십 기반) 정책만 유효하도록 강제
do $$
declare t text;
begin
for t in select tablename from pg_tables where schemaname = 'public' loop
execute format('drop policy if exists dev_full_access on public.%I', t);
end loop;
end $$;이 마이그레이션만 추가하면 브라우저 클라이언트 조회 시(getTasksByWorkspaceId, getWorkspaceMembersByWorkspaceIdClient) private.is_workspace_member(workspace_id) 검증이 실제로 강제됩니다. 원하시면 이 변경을 이번 PR 범위로 반영할지, 별도 후속 이슈로 분리할지 알려주세요. 후속 이슈로 진행을 원하시면 GitHub 이슈를 생성해 드리겠습니다.
✏️ Learnings added
Learnt from: seongjinss555
Repo: TeampleRun/syncly PR: 52
File: src/entities/task/api/get-tasks-by-workspace-id.ts:1-1
Timestamp: 2026-07-14T05:30:47.536Z
Learning: Repository TeampleRun/syncly: `supabase/migrations/20260709025327_create_enums_and_core_tables.sql` applies a temporary `dev_full_access` policy (`for all using (true) with check (true)`) to every public table via a loop, intended as a placeholder until auth was wired up. `supabase/migrations/20260709025820_add_auth_rls_policies.sql` later added real membership-based RLS policies (e.g., `tasks_member_all`, `members_select` using `private.is_workspace_member(workspace_id)`) that coexist with `dev_full_access` via OR evaluation, so `dev_full_access` must be dropped (e.g., via a new migration looping `pg_tables` and running `drop policy if exists dev_full_access on public.%I`) before the membership-based policies actually take effect and browser-side Supabase client queries (like `src/entities/task/api/get-tasks-by-workspace-id.ts` and `src/entities/workspace-member/api/get-workspace-members-by-id.client.ts`) are properly restricted.
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.
There was a problem hiding this comment.
반영했습니다. 브라우저 직접 조회를 유지하는 대신 RLS를 실제 멤버십 기준으로 맞췄습니다. 새 migration에서 tasks / workspace_members / profiles의 dev_full_access를 제거했고, profiles 조회도 본인 또는 같은 워크스페이스 멤버의 프로필만 보이도록 정책을 좁혔습니다.
There was a problem hiding this comment.
Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!
| @@ -0,0 +1,40 @@ | |||
| 'use server'; | |||
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win
TaskStatus 리터럴 유니온 중복 정의. 두 파일 모두 'todo' | 'in-progress' | 'done'을 직접 정의하는 대신, barrel(src/entities/task/index.ts)이 이미 export하는 TaskStatus 타입을 재사용해야 합니다. 그대로 두면 상태값이 추가/변경될 때 한쪽만 갱신되어 타입이 어긋날 위험이 있습니다.
src/entities/task/api/update-task-board.ts#L8-14:status: 'todo' | 'in-progress' | 'done'을status: TaskStatus로 교체하고TaskStatus를../model/task.types에서 import하세요.src/entities/task/api/use-update-task-board.ts#L11-16:UpdateTaskBoardParams.tasks[].status도 동일하게TaskStatus로 교체하세요.
🤖 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/entities/task/api/update-task-board.ts` at line 1, Replace the duplicated
TaskStatus literal unions in the update-task-board API parameter types and the
use-update-task-board tasks status type with TaskStatus. Import TaskStatus from
../model/task.types in update-task-board.ts, and reuse the shared type in
use-update-task-board.ts while preserving the existing parameter shapes.
There was a problem hiding this comment.
지금 상황에서는 해당 status가 고정이라 큰 상관이 없어보이긴합니다. 다만 이후 코드 리펙토링 혹은 수정 시에 오류가 발생한 가능성이 있어서 고려하면 좋을 거 같습니다
There was a problem hiding this comment.
The PR description image shows the Syncly "프로젝트 관리" (Project Management) kanban board UI: a left sidebar with navigation items (대시보드, 프로젝트 관리 highlighted, 캘린더, 공지, 회의록, 자료실, 채팅, 진행률 차트, 설정) under a "캡스톤 디자인 팀" workspace label, a top header with search, "멤버 초대" button, notification bell, and a profile avatar "김". The main area shows three kanban columns — 대기 (1), 진행 중 (1), 완료 (1) — each with one task card ("대기 테스트", "진행중 테스트", "완료 테스트") showing assignee "JiWoongE" with a blue avatar and due date "7/14". A "+ 새업무" button sits top-right of the board.
@seongjinss555 이해했습니다. 현재는 status 값이 고정되어 있어 실제 리스크는 낮지만, 이후 리팩토링 시 참고할 수 있도록 기록해두겠습니다. 필요할 때 다시 짧게 짚어드리겠습니다. 🐇
✏️ Learnings added
Learnt from: seongjinss555
Repo: TeampleRun/syncly PR: 52
File: src/entities/task/api/update-task-board.ts:1-1
Timestamp: 2026-07-14T05:30:21.421Z
Learning: In `src/entities/task/api/update-task-board.ts` and `src/entities/task/api/use-update-task-board.ts`, the `status: 'todo' | 'in-progress' | 'done'` literal union is intentionally duplicated instead of reusing the shared `TaskStatus` type from `src/entities/task/model/task.types.ts` (per maintainer seongjinss555). This was deemed low risk since the status values are currently fixed, but should be revisited and reused if/when the task domain undergoes refactoring.
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.
There was a problem hiding this comment.
반영했습니다. update-task-board.ts와 use-update-task-board.ts에서 중복으로 선언하던 status 리터럴 유니온을 제거하고 TaskStatus 타입을 재사용하도록 정리했습니다.
There was a problem hiding this comment.
Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!
seongjinss555
left a comment
There was a problem hiding this comment.
리뷰 확인해주시고 해결하시고 머지해주세요~ 고생하셨습니다
| @@ -0,0 +1,22 @@ | |||
| import { getSupabaseBrowserClient } from '@/shared/api/supabase/client'; | |||
There was a problem hiding this comment.
동의합니다. 현재 브라우저 Supabase 클라이언트에서 tasks, workspace_members, profiles를 직접 조회하고 있으므로, RLS가 실질적인 접근 제어 역할을 해야 합니다. dev_full_access 정책을 제거하고 요청 사용자가 해당 워크스페이스의 멤버인지 검증하는 정책만 유지하도록 보완하면 좋겠습니다.
| @@ -0,0 +1,40 @@ | |||
| 'use server'; | |||
There was a problem hiding this comment.
지금 상황에서는 해당 status가 고정이라 큰 상관이 없어보이긴합니다. 다만 이후 코드 리펙토링 혹은 수정 시에 오류가 발생한 가능성이 있어서 고려하면 좋을 거 같습니다
There was a problem hiding this comment.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/entities/task/api/create-task.ts (1)
1-1: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
UntypedRpcClient타입이 두 파일에 중복 정의되어 있습니다. 근본 원인은 Supabase RPC 호출을 위한 공유 타입이 없어서 각 파일이 동일한 타입을 복제한 것입니다.
src/entities/task/api/create-task.ts#L8-14:UntypedRpcClient정의를 제거하고 공유 모듈(예:./rpc-client)에서 import하세요.src/entities/task/api/update-task-board.ts#L8-14: 동일하게 공유 모듈에서 import하도록 교체하세요.🤖 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/entities/task/api/create-task.ts` at line 1, Remove the duplicated UntypedRpcClient definitions from create-task and update-task-board, define the shared type in a common rpc-client module, and import it from both API modules.
♻️ Duplicate comments (1)
src/features/project-board/ui/ProjectBoard.tsx (1)
83-94: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
handleDeleteTask가 여전히 전체tasks스냅샷을 그대로 롤백합니다.
handleDropTask(161-182행)는 이전에 지적된 "중첩 요청 시 이전 실패가 이후 성공 변경을 덮어쓰는" 문제를 큐잉+invalidateQueries로 해결했지만,handleDeleteTask는 여전히previousTasks스냅샷을 그대로 복원하는 예전 패턴입니다. 두 핸들러가 동일한 쿼리 키(tasksByWorkspaceQueryKey(workspaceId))를 조율 없이 각자 갱신하므로:
- 삭제 A 시작 →
previousTasksA캡처, task A 낙관적 제거- 드래그/삭제 B가 A와 겹쳐 성공적으로 반영됨
- A가 실패 →
previousTasksA(B 반영 전 상태)로 전체 복원 → B의 성공한 변경이 화면에서 사라짐
handleDropTask와 동일하게 실패 시invalidateQueries로 서버 상태를 재동기화하도록 바꾸면 이 문제를 피할 수 있습니다.🛡️ 제안: invalidate로 전환
const handleDeleteTask = async (taskId: string) => { - const previousTasks = tasks; queryClient.setQueryData<Task[]>(tasksByWorkspaceQueryKey(workspaceId), (currentTasks) => (currentTasks ?? []).filter((task) => task.id !== taskId), ); try { await deleteTaskMutation.mutateAsync(taskId); } catch { - queryClient.setQueryData(tasksByWorkspaceQueryKey(workspaceId), previousTasks); + queryClient.invalidateQueries({ queryKey: tasksByWorkspaceQueryKey(workspaceId) }); } };이 정확한 패턴(중첩된 삭제·재정렬에서 전체 스냅샷 롤백)이 이전 리뷰에서 이미 지적되었고 "직렬화+invalidate로 변경했다"는 답변이 있었으나, 실제로는
handleDropTask만 수정되고handleDeleteTask는 그대로 남아있습니다.use-delete-task.ts의onSettled가 이미 invalidate를 수행하는지 확인해주시면 심각도 판단에 도움이 됩니다.🤖 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/project-board/ui/ProjectBoard.tsx` around lines 83 - 94, Update handleDeleteTask to remove the full previousTasks snapshot rollback; when deleteTaskMutation.mutateAsync fails, invalidate the tasksByWorkspaceQueryKey(workspaceId) query to resynchronize with the server, matching the coordination pattern used by handleDropTask. Preserve the existing optimistic task removal and avoid restoring stale data that could overwrite concurrent successful changes.
🤖 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/entities/task/api/create-task.ts`:
- Around line 24-25: Update the dueDate calculation in the task creation flow to
use the current Asia/Seoul calendar date instead of today.toISOString(),
ensuring tasks created between KST midnight and 09:00 retain the correct local
date regardless of server timezone.
- Around line 8-14: Extract the duplicated UntypedRpcClient type from
create-task.ts and update-task-board.ts into a shared task API module, then
import and reuse that single definition in both files. Preserve the existing rpc
signature and behavior; use generated Supabase Database function types only if
they can be adopted without changing the current API contract.
In `@src/entities/task/api/update-task-board.ts`:
- Around line 8-14: Extract the duplicated UntypedRpcClient type into a shared
module, then update the UntypedRpcClient references in create-task.ts and
update-task-board.ts to import and reuse that shared definition. Remove both
local type declarations while preserving the existing rpc signature.
In `@src/entities/workspace-member/api/get-workspace-members-by-id.ts`:
- Around line 18-45: 중복된 조회·매핑 로직을 공유 함수로 통합하세요.
src/entities/workspace-member/api/get-workspace-members-by-id.ts:18-45에서는 select
쿼리와 WorkspaceMemberQueryRow→WorkspaceMember 변환을 mapWorkspaceMemberRows 같은 공유 함수로
추출하고 서버 클라이언트 결과에 적용하세요.
src/entities/workspace-member/api/get-workspace-members-by-id.client.ts:18-46에서도
동일한 공유 매핑 함수를 사용하도록 변경하며, 프로필 폴백 값과 status: 'joined' 동작은 유지하세요.
In
`@supabase/migrations/20260714100000_create_task_rpcs_and_restrict_browser_rls.sql`:
- Around line 3-22: Remove the legacy dev_full_access policy from every affected
public table, not only public.tasks, public.workspace_members, and
public.profiles; update the migration’s policy cleanup to include any other
public tables where the initial migration created this permissive policy, while
preserving the existing auth-specific policies.
- Around line 24-115: Restrict EXECUTE privileges for the public.create_task and
public.update_task_board RPCs by revoking access from PUBLIC and granting it
only to authenticated. Add these explicit privilege statements in the migration
after the function definitions, leaving the function logic unchanged.
---
Outside diff comments:
In `@src/entities/task/api/create-task.ts`:
- Line 1: Remove the duplicated UntypedRpcClient definitions from create-task
and update-task-board, define the shared type in a common rpc-client module, and
import it from both API modules.
---
Duplicate comments:
In `@src/features/project-board/ui/ProjectBoard.tsx`:
- Around line 83-94: Update handleDeleteTask to remove the full previousTasks
snapshot rollback; when deleteTaskMutation.mutateAsync fails, invalidate the
tasksByWorkspaceQueryKey(workspaceId) query to resynchronize with the server,
matching the coordination pattern used by handleDropTask. Preserve the existing
optimistic task removal and avoid restoring stale data that could overwrite
concurrent successful changes.
🪄 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: 7ef711db-b758-4a9f-9930-f6539c473314
📒 Files selected for processing (9)
src/entities/task/api/create-task.tssrc/entities/task/api/update-task-board.tssrc/entities/task/api/use-update-task-board.tssrc/entities/workspace-member/api/get-workspace-members-by-id.client.tssrc/entities/workspace-member/api/get-workspace-members-by-id.tssrc/features/project-board/ui/ProjectBoard.tsxsrc/widgets/team-project/dashboard-overall-progress/ui/OverallProgress.tsxsrc/widgets/team-project/dashboard-work-summary/ui/WorkSummary.tsxsupabase/migrations/20260714100000_create_task_rpcs_and_restrict_browser_rls.sql
Pull Request
작업 내용
업무 요약,전체 진행률위젯도 실제 task / workspace member 데이터를 기준으로 보이도록 변경했습니다.작업 결과
업무 요약,전체 진행률위젯이 실데이터 기준으로 표시됩니다.변경 사항
Added
src/entities/task/api/create-task.tssrc/entities/task/api/delete-task.tssrc/entities/task/api/get-tasks-by-workspace-id.tssrc/entities/task/api/update-task-board.tssrc/entities/task/api/use-create-task.tssrc/entities/task/api/use-delete-task.tssrc/entities/task/api/use-tasks-by-workspace-id.tssrc/entities/task/api/use-update-task-board.tssrc/entities/task/model/task.db.types.tssrc/entities/task/model/task.mapper.tssrc/entities/task/model/task.schema.tssrc/entities/workspace-member/api/get-workspace-members-by-id.client.tssrc/entities/workspace-member/api/use-workspace-members-by-id.tsChanged
src/entities/task/index.tssrc/entities/task/model/task.types.tssrc/features/project-board/ui/ProjectBoard.tsxsrc/features/manage-progress-chart/ui/ProgressChartView.tsxsrc/views/progress-chart/ui/ProgressChartPage.tsxsrc/widgets/team-project/dashboard-overall-progress/ui/OverallProgress.tsxsrc/widgets/team-project/dashboard-work-summary/ui/WorkSummary.tsxsrc/entities/project-column/ui/ProjectColumn.tsxsrc/entities/workspace-member/index.tssrc/views/signup/ui/SignupView.tsxFixed
invalid uuid에러가 나던 문제를 정리했습니다.스크린샷
테스트
리뷰 체크리스트
feature/*->develop, 배포 시develop또는release/*->main)Type/#issue-number/description형식을 따릅니다.console.log, 주석, 임시 코드를 제거했습니다.리뷰 요청사항
관련 이슈
Closes #49
Summary by CodeRabbit