CONTRACT PARITY ANALYSIS: SHIFT vs TASK SELF-ASSIGNMENT ======================================================== SHIFT SELF-ASSIGNMENT MUTATION PATH: ------------------------------------ Hook: useSignUpShift() in frontend/src/hooks/useShifts.ts:104-120 Endpoint: POST /api/shifts/{shiftId}/signup Method: Server-side inference of current member via session Body: Empty (no explicit memberId sent) Permission: Member role (inferred from endpoint access control) Pattern: shift.signups.some((s) => s.memberId === session?.user?.id) TASK UPDATE MUTATION PATH: --------------------------- Hook: useUpdateTask() in frontend/src/hooks/useTasks.ts:109-116 Endpoint: PATCH /api/tasks/{id} Interface: UpdateTaskRequest (lines 41-47) with assigneeId?: string Method: Client explicitly sends assigneeId in request body Permission: Assumed member role (no explicit gate observed) Existing usage: assigneeId field exists in Task, CreateTaskRequest, UpdateTaskRequest ASSIGNMENT SEMANTICS COMPARISON: --------------------------------- Shift: Implicit self-assignment via POST to /signup endpoint Task: Explicit assigneeId field update via PATCH with assigneeId in body MEMBER ROLE PERMISSION ASSUMPTION: ----------------------------------- Both flows assume member role can: 1. Sign up for shifts (POST /api/shifts/{id}/signup) 2. Update task assigneeId field (PATCH /api/tasks/{id} with assigneeId) DETECTION PATTERN FOR "ASSIGN TO ME" BUTTON: -------------------------------------------- Shift: isSignedUp = shift.signups.some((s) => s.memberId === session?.user?.id) Task equivalent: task.assigneeId === session?.user?.id CONTRACT COMPATIBILITY: ----------------------- ✓ UpdateTaskRequest.assigneeId field exists and accepts string ✓ useUpdateTask mutation supports arbitrary UpdateTaskRequest fields ✓ Task model includes assigneeId: string | null ✓ No observed frontend restrictions on member role updating assigneeId DECISION: --------- PARITY CONFIRMED: Task self-assignment flow should use: - Mutation: useUpdateTask({ id: taskId, data: { assigneeId: session.user.id } }) - Detection: task.assigneeId === session?.user?.id - Button label: "Assign to Me" (when not assigned) / "Unassign Me" (when assigned) BACKEND VERIFICATION REQUIRED: ------------------------------- Backend policy must permit member role to: 1. PATCH /api/tasks/{id} with assigneeId field 2. Set assigneeId to self (current member id) (Deferred to T8 - conditional backend policy adjustment task)