feat(members): implement DELETE/PATCH member + GET invites backend endpoints

- Add V006 migration: invalidated_at column + partial unique index on household_invite
- Add findByHouseholdIdAndInvalidatedAtIsNull, findByHouseholdIdAndUserId, countByHouseholdIdAndRole
- Add ChangeRoleRequest DTO
- HouseholdService: getActiveInvite, createInvite (regenerate), removeMember, changeMemberRole
- HouseholdController: GET /v1/households/mine/invites, DELETE/PATCH /v1/households/mine/members/{userId}

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-10 18:41:38 +02:00
parent 27163e3d72
commit d1e4b6c49e
9 changed files with 349 additions and 4 deletions

View File

@@ -9,6 +9,8 @@ import org.springframework.web.bind.annotation.*;
import java.security.Principal;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
@RestController
@RequestMapping("/v1")
@@ -40,12 +42,35 @@ public class HouseholdController {
return ResponseEntity.ok(members);
}
@GetMapping("/households/mine/invites")
public ResponseEntity<ApiResponse<InviteResponse>> getActiveInvite(Principal principal) {
Optional<InviteResponse> invite = householdService.getActiveInvite(principal.getName());
return invite
.map(r -> ResponseEntity.ok(ApiResponse.success(r)))
.orElse(ResponseEntity.noContent().build());
}
@PostMapping("/households/mine/invites")
public ResponseEntity<ApiResponse<InviteResponse>> createInvite(Principal principal) {
InviteResponse response = householdService.createInvite(principal.getName());
return ResponseEntity.status(HttpStatus.CREATED).body(ApiResponse.success(response));
}
@DeleteMapping("/households/mine/members/{userId}")
public ResponseEntity<Void> removeMember(Principal principal, @PathVariable UUID userId) {
householdService.removeMember(principal.getName(), userId);
return ResponseEntity.noContent().build();
}
@PatchMapping("/households/mine/members/{userId}")
public ResponseEntity<ApiResponse<MemberResponse>> changeMemberRole(
Principal principal,
@PathVariable UUID userId,
@Valid @RequestBody ChangeRoleRequest request) {
MemberResponse response = householdService.changeMemberRole(principal.getName(), userId, request.role());
return ResponseEntity.ok(ApiResponse.success(response));
}
@PostMapping("/invites/{code}/accept")
public ResponseEntity<ApiResponse<AcceptInviteResponse>> acceptInvite(
Principal principal,