Skip to content

feat: task 도메인 Supabase 연동 - #52

Merged
JiWoongE merged 4 commits into
developfrom
Feat/#49/task-supabase-integration
Jul 14, 2026
Merged

feat: task 도메인 Supabase 연동#52
JiWoongE merged 4 commits into
developfrom
Feat/#49/task-supabase-integration

Conversation

@JiWoongE

@JiWoongE JiWoongE commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Pull Request

작업 내용

  • 프로젝트 관리, 진행률 차트, 팀 프로젝트 대시보드 위젯에서 사용하던 task mock 데이터를 Supabase 실데이터 조회로 전환했습니다.
  • 프로젝트 관리 페이지에서 업무 생성/삭제/상태 이동 및 정렬 변경이 실제 DB에 반영되도록 연결했습니다.
  • 팀 프로젝트 대시보드의 업무 요약, 전체 진행률 위젯도 실제 task / workspace member 데이터를 기준으로 보이도록 변경했습니다.

작업 결과

  • 프로젝트 관리 페이지가 workspace 기준 실제 task 목록을 렌더링합니다.
  • 새 업무 생성 시 DB에 실제 row가 생성되고, 삭제/이동/정렬 변경도 DB에 반영됩니다.
  • 진행률 차트가 mock이 아닌 실제 task 집계값으로 표시됩니다.
  • 팀 프로젝트 대시보드 업무 요약, 전체 진행률 위젯이 실데이터 기준으로 표시됩니다.
  • 업무 생성 중복 요청 방지, 맨 아래 드롭 영역 보완, 보드 이동 시 ID 검증 오류를 함께 정리했습니다.

변경 사항

Added

  • src/entities/task/api/create-task.ts
  • src/entities/task/api/delete-task.ts
  • src/entities/task/api/get-tasks-by-workspace-id.ts
  • src/entities/task/api/update-task-board.ts
  • src/entities/task/api/use-create-task.ts
  • src/entities/task/api/use-delete-task.ts
  • src/entities/task/api/use-tasks-by-workspace-id.ts
  • src/entities/task/api/use-update-task-board.ts
  • src/entities/task/model/task.db.types.ts
  • src/entities/task/model/task.mapper.ts
  • src/entities/task/model/task.schema.ts
  • src/entities/workspace-member/api/get-workspace-members-by-id.client.ts
  • src/entities/workspace-member/api/use-workspace-members-by-id.ts

Changed

  • src/entities/task/index.ts
  • src/entities/task/model/task.types.ts
  • src/features/project-board/ui/ProjectBoard.tsx
  • src/features/manage-progress-chart/ui/ProgressChartView.tsx
  • src/views/progress-chart/ui/ProgressChartPage.tsx
  • src/widgets/team-project/dashboard-overall-progress/ui/OverallProgress.tsx
  • src/widgets/team-project/dashboard-work-summary/ui/WorkSummary.tsx
  • src/entities/project-column/ui/ProjectColumn.tsx
  • src/entities/workspace-member/index.ts
  • src/views/signup/ui/SignupView.tsx

Fixed

  • 업무 생성 시 Enter 중복 입력으로 동일 업무가 2번 생성되던 문제를 방지했습니다.
  • 업무 이동 시 프론트 UUID 검증으로 invalid uuid 에러가 나던 문제를 정리했습니다.
  • 컬럼 맨 아래로 드래그 이동이 잘 안 잡히던 문제를 드롭 영역 보완으로 수정했습니다.

스크린샷

image

테스트

  • 로컬 실행 확인
  • 주요 시나리오 확인
  • 영향 범위 확인

리뷰 체크리스트

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

리뷰 요청사항

  • task 실데이터 연동 범위를 프로젝트 관리 / 진행률 차트 / 팀 프로젝트 대시보드 위젯까지 우선 연결한 상태입니다.
  • 보드 정렬/이동 시 DB 반영 흐름과, 팀 프로젝트 위젯에서 client query로 member 수를 읽어오는 방식이 현재 구조와 맞는지 함께 봐주시면 좋겠습니다.

관련 이슈

Closes #49

Summary by CodeRabbit

  • 새 기능
    • 워크스페이스별 업무를 실제 데이터로 조회하고 생성·삭제·보드 정렬 변경을 저장합니다.
    • 빈 열의 맨 끝에 전용 드롭 영역이 제공되어(시각적 강조) 마지막 위치로 드래그가 더 정확해졌습니다.
  • 버그 수정
    • 진행률/업무 요약 화면이 올바른 워크스페이스 데이터를 기반으로 표시됩니다.
    • 업무/멤버 데이터 조회 시 로딩·오류 상태가 안내되고, 요약 화면은 “다시 시도”로 재조회할 수 있습니다.
    • 삭제·정렬 저장 실패 시 화면 상태가 롤백됩니다.

@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 166313bc-d562-43c2-a0d3-b481c6dec2dc

📥 Commits

Reviewing files that changed from the base of the PR and between 5210c45 and 89aa588.

📒 Files selected for processing (7)
  • src/entities/task/api/create-task.ts
  • src/entities/task/api/rpc-client.ts
  • src/entities/task/api/update-task-board.ts
  • src/entities/workspace-member/api/get-workspace-members-by-id.client.ts
  • src/entities/workspace-member/api/get-workspace-members-by-id.ts
  • src/entities/workspace-member/api/shared.ts
  • supabase/migrations/20260714100000_create_task_rpcs_and_restrict_browser_rls.sql

📝 Walkthrough

Walkthrough

Task 도메인을 mock 데이터에서 Supabase 실데이터 기반으로 전환했습니다. 조회·생성·삭제·보드 갱신 API와 React Query 훅을 추가하고, 프로젝트 보드·진행률 차트·대시보드 위젯에 연결했습니다.

Changes

Task 도메인 Supabase 연동

Layer / File(s) Summary
Task 계약과 매핑
src/entities/task/model/*, src/entities/task/index.ts
DB/UI 타입, 매핑 함수, 입력 검증 스키마와 공개 export를 추가했습니다.
Task와 멤버 조회 흐름
src/entities/task/api/get-tasks-by-workspace-id.ts, src/entities/task/api/use-tasks-by-workspace-id.ts, src/entities/workspace-member/api/*
워크스페이스 기준 Task·멤버 조회와 React Query 훅을 구현했습니다.
Task 변경 API와 무효화
src/entities/task/api/create-task.ts, src/entities/task/api/delete-task.ts, src/entities/task/api/update-task-board.ts, src/entities/task/api/use-*.ts
생성·삭제·보드 갱신 server action과 mutation 훅을 추가했습니다.
Task RPC와 접근 정책
supabase/migrations/20260714100000_create_task_rpcs_and_restrict_browser_rls.sql
Task RPC와 프로필 조회 RLS 정책을 추가했습니다.
프로젝트 보드와 대시보드 연결
src/features/project-board/ui/ProjectBoard.tsx, src/entities/project-column/ui/ProjectColumn.tsx, src/features/manage-progress-chart/..., src/widgets/team-project/...
보드·차트·대시보드가 실데이터와 조회 상태를 사용하도록 변경했습니다.

Signup 인증 클라이언트 수명주기

Layer / File(s) Summary
Signup 인증 클라이언트 처리
src/views/signup/ui/SignupView.tsx
Supabase 클라이언트 보관 방식과 인증 응답 처리를 변경했습니다.

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 무효화
Loading

Possibly related PRs

  • TeampleRun/syncly#17: ProjectColumn.tsx의 열 끝 드롭 처리와 관련된 변경을 포함합니다.
  • TeampleRun/syncly#32: Task DB 타입과 Supabase 스키마 연동에 직접 연결됩니다.
  • TeampleRun/syncly#40: 진행률 차트의 Task 조회 연결과 같은 구현 흐름을 다룹니다.

Suggested reviewers: kwon812, 0011810, seongjinss555

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning SignupView의 Supabase/의존성 수정은 task 도메인 연동 목표와 직접 관련이 없어 범위를 벗어납니다. 해당 SignupView 변경은 별도 PR로 분리하거나, task 연동과의 직접적 필요성을 설명할 수 없으면 제거하세요.
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.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed 제목은 task 도메인의 Supabase 연동이라는 핵심 변경을 간결하게 잘 요약합니다.
Description check ✅ Passed 필수 섹션과 주요 항목이 대부분 갖춰져 있어 템플릿 요구를 충족합니다.
Linked Issues check ✅ Passed task 조회·생성·삭제·보드 업데이트와 차트/대시보드 연결이 이슈 #49의 요구와 일치합니다.
✨ 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/#49/task-supabase-integration

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

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 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

📥 Commits

Reviewing files that changed from the base of the PR and between 269b17c and 8ca6eda.

📒 Files selected for processing (24)
  • src/entities/project-column/ui/ProjectColumn.tsx
  • src/entities/task/api/create-task.ts
  • src/entities/task/api/delete-task.ts
  • src/entities/task/api/get-tasks-by-workspace-id.ts
  • src/entities/task/api/update-task-board.ts
  • src/entities/task/api/use-create-task.ts
  • src/entities/task/api/use-delete-task.ts
  • src/entities/task/api/use-tasks-by-workspace-id.ts
  • src/entities/task/api/use-update-task-board.ts
  • src/entities/task/index.ts
  • src/entities/task/model/mock-tasks-by-workspace.ts
  • src/entities/task/model/task.db.types.ts
  • src/entities/task/model/task.mapper.ts
  • src/entities/task/model/task.schema.ts
  • src/entities/task/model/task.types.ts
  • src/entities/workspace-member/api/get-workspace-members-by-id.client.ts
  • src/entities/workspace-member/api/use-workspace-members-by-id.ts
  • src/entities/workspace-member/index.ts
  • src/features/manage-progress-chart/ui/ProgressChartView.tsx
  • src/features/project-board/ui/ProjectBoard.tsx
  • src/views/progress-chart/ui/ProgressChartPage.tsx
  • src/views/signup/ui/SignupView.tsx
  • src/widgets/team-project/dashboard-overall-progress/ui/OverallProgress.tsx
  • src/widgets/team-project/dashboard-work-summary/ui/WorkSummary.tsx
💤 Files with no reviewable changes (1)
  • src/entities/task/model/mock-tasks-by-workspace.ts

Comment thread src/entities/task/api/create-task.ts Outdated
@@ -0,0 +1,22 @@
import { getSupabaseBrowserClient } from '@/shared/api/supabase/client';

@coderabbitai coderabbitai Bot Jul 14, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 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/null

Repository: 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 3

Repository: 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"
done

Repository: 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.tssrc/entities/workspace-member/api/get-workspace-members-by-id.client.ts는 브라우저 Supabase 클라이언트로 직접 조회하지만, supabase/migrations/20260709025327_create_enums_and_core_tables.sqldev_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 정책만
유지·적용하세요.

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.

동의합니다. 현재 브라우저 Supabase 클라이언트에서 tasks, workspace_members, profiles를 직접 조회하고 있으므로, RLS가 실질적인 접근 제어 역할을 해야 합니다. dev_full_access 정책을 제거하고 요청 사용자가 해당 워크스페이스의 멤버인지 검증하는 정책만 유지하도록 보완하면 좋겠습니다.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧩 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 | sort

Length of output: 15359


@seongjinss555 네, 확인했습니다. 마이그레이션을 보니 실제로 필요한 멤버십 기반 정책은 이미 존재합니다:

  • profiles: profiles_select(로그인 유저 전체 조회 허용은 의도된 설계), profiles_insert_own, profiles_update_own
  • workspace_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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

반영했습니다. 브라우저 직접 조회를 유지하는 대신 RLS를 실제 멤버십 기준으로 맞췄습니다. 새 migration에서 tasks / workspace_members / profiles의 dev_full_access를 제거했고, profiles 조회도 본인 또는 같은 워크스페이스 멤버의 프로필만 보이도록 정책을 좁혔습니다.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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';

@coderabbitai coderabbitai Bot Jul 14, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 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.

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.

지금 상황에서는 해당 status가 고정이라 큰 상관이 없어보이긴합니다. 다만 이후 코드 리펙토링 혹은 수정 시에 오류가 발생한 가능성이 있어서 고려하면 좋을 거 같습니다

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

반영했습니다. update-task-board.ts와 use-update-task-board.ts에서 중복으로 선언하던 status 리터럴 유니온을 제거하고 TaskStatus 타입을 재사용하도록 정리했습니다.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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!

Comment thread src/entities/task/api/update-task-board.ts Outdated
Comment thread src/entities/task/api/use-update-task-board.ts
Comment thread src/entities/workspace-member/api/get-workspace-members-by-id.client.ts Outdated
Comment thread src/entities/workspace-member/api/get-workspace-members-by-id.client.ts Outdated
Comment thread src/features/project-board/ui/ProjectBoard.tsx
Comment thread src/features/project-board/ui/ProjectBoard.tsx
Comment thread src/widgets/team-project/dashboard-work-summary/ui/WorkSummary.tsx 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.

리뷰 확인해주시고 해결하시고 머지해주세요~ 고생하셨습니다

Comment thread src/entities/task/api/update-task-board.ts Outdated
@@ -0,0 +1,22 @@
import { getSupabaseBrowserClient } from '@/shared/api/supabase/client';

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.

동의합니다. 현재 브라우저 Supabase 클라이언트에서 tasks, workspace_members, profiles를 직접 조회하고 있으므로, RLS가 실질적인 접근 제어 역할을 해야 합니다. dev_full_access 정책을 제거하고 요청 사용자가 해당 워크스페이스의 멤버인지 검증하는 정책만 유지하도록 보완하면 좋겠습니다.

Comment thread src/entities/task/api/create-task.ts Outdated
@@ -0,0 +1,40 @@
'use server';

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.

지금 상황에서는 해당 status가 고정이라 큰 상관이 없어보이긴합니다. 다만 이후 코드 리펙토링 혹은 수정 시에 오류가 발생한 가능성이 있어서 고려하면 좋을 거 같습니다

@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: 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))를 조율 없이 각자 갱신하므로:

  1. 삭제 A 시작 → previousTasksA 캡처, task A 낙관적 제거
  2. 드래그/삭제 B가 A와 겹쳐 성공적으로 반영됨
  3. 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.tsonSettled가 이미 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

📥 Commits

Reviewing files that changed from the base of the PR and between 8ca6eda and 5210c45.

📒 Files selected for processing (9)
  • src/entities/task/api/create-task.ts
  • src/entities/task/api/update-task-board.ts
  • src/entities/task/api/use-update-task-board.ts
  • src/entities/workspace-member/api/get-workspace-members-by-id.client.ts
  • src/entities/workspace-member/api/get-workspace-members-by-id.ts
  • src/features/project-board/ui/ProjectBoard.tsx
  • src/widgets/team-project/dashboard-overall-progress/ui/OverallProgress.tsx
  • src/widgets/team-project/dashboard-work-summary/ui/WorkSummary.tsx
  • supabase/migrations/20260714100000_create_task_rpcs_and_restrict_browser_rls.sql

Comment thread src/entities/task/api/create-task.ts Outdated
Comment thread src/entities/task/api/create-task.ts Outdated
Comment thread src/entities/task/api/update-task-board.ts Outdated
Comment thread src/entities/workspace-member/api/get-workspace-members-by-id.ts
Comment thread supabase/migrations/20260714100000_create_task_rpcs_and_restrict_browser_rls.sql Outdated
@JiWoongE
JiWoongE merged commit 5a61bea into develop Jul 14, 2026
1 check passed
@JiWoongE
JiWoongE deleted the Feat/#49/task-supabase-integration branch July 14, 2026 06:51
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] task 도메인 Supabase 연동

2 participants