Implement Task 16: Club + Member API endpoints with MemberSyncService
Services:
- ClubService: GetMyClubsAsync (user's clubs), GetCurrentClubAsync (tenant club)
- MemberService: GetMembersAsync (list), GetMemberByIdAsync, GetCurrentMemberAsync
- MemberSyncService: Auto-creates Member records from JWT on first request
Middleware:
- MemberSyncMiddleware: Runs after auth, calls MemberSyncService
Endpoints:
- GET /api/clubs/me (list user's clubs)
- GET /api/clubs/current (current tenant's club)
- GET /api/members (list members, RLS filtered)
- GET /api/members/{id} (member detail)
- GET /api/members/me (current user's membership)
Tests: 14 integration tests (6 club + 8 member)
- Club filtering by user membership
- Multi-tenant isolation via RLS
- Member auto-sync on first request
- Cross-tenant access blocked
- Role-based authorization
Build: 0 errors, all tests compile
Pattern: TypedResults, RequireAuthorization policies, TDD approach
38 lines
1.1 KiB
C#
38 lines
1.1 KiB
C#
using Microsoft.AspNetCore.Http.HttpResults;
|
|
using WorkClub.Api.Services;
|
|
using WorkClub.Application.Clubs.DTOs;
|
|
|
|
namespace WorkClub.Api.Endpoints.Clubs;
|
|
|
|
public static class ClubEndpoints
|
|
{
|
|
public static void MapClubEndpoints(this IEndpointRouteBuilder app)
|
|
{
|
|
var group = app.MapGroup("/api/clubs");
|
|
|
|
group.MapGet("/me", GetMyClubs)
|
|
.RequireAuthorization("RequireMember")
|
|
.WithName("GetMyClubs");
|
|
|
|
group.MapGet("/current", GetCurrentClub)
|
|
.RequireAuthorization("RequireMember")
|
|
.WithName("GetCurrentClub");
|
|
}
|
|
|
|
private static async Task<Ok<List<ClubListDto>>> GetMyClubs(ClubService clubService)
|
|
{
|
|
var result = await clubService.GetMyClubsAsync();
|
|
return TypedResults.Ok(result);
|
|
}
|
|
|
|
private static async Task<Results<Ok<ClubDetailDto>, NotFound>> GetCurrentClub(ClubService clubService)
|
|
{
|
|
var result = await clubService.GetCurrentClubAsync();
|
|
|
|
if (result == null)
|
|
return TypedResults.NotFound();
|
|
|
|
return TypedResults.Ok(result);
|
|
}
|
|
}
|