CommunityPro / CommunityPro/community-pro-api

Admin: policy-based authorization + member management endpoints (Phase 8.1, 8.2, 2.6)

Open
#1 0 comments 0 reactions 0 assignees View on GitHub
admin
Dominant language
C#
Stars
0
Forks
0
PR merge metrics
No merged PRs in 30d

Description

## Scope
Foundation for everything `/admin/*`: an admin authorization policy, plus the member-management endpoints. Also closes deferred item 2.6 (hide deactivated members) since deactivation is introduced here.

The `admin` role already exists in Identity (Phase 1). This ticket adds:
1. An `AdminPolicy` (role `admin`, checked server-side on every request — DB-backed like `ActiveMemberPolicy`, not stale claims) and a reusable route-group pattern so other modules can mount `/admin/*` endpoints with the policy applied at group level.
2. Member management endpoints (Identity/Members owned, `/admin/*` paths):

| Method | Path | Notes |
|---|---|---|
| GET | `/admin/members` | paginated; filter by status; search by login/display name |
| POST | `/admin/members/{id}/activate` | manual activation — fallback for the orphan-PR edge case; runs the same pipeline as the webhook (publishes `MemberActivated`) |
| POST | `/admin/members/{id}/feature` | toggle `MemberProfile.IsFeatured` (drives spotlight) |
| POST | `/admin/members/{id}/deactivate` | sets `Deactivated`, revokes refresh-token families, publishes `MemberDeactivated` |

3. **Deferred item 2.6:** Members module subscribes to `MemberDeactivated` → profile is removed from the Meilisearch index and excluded from `/members`, `/members/{id}`, and `/members/spotlight` at query level (not UI level).

## Error codes
`admin.forbidden`, `members.not_found`, `members.already_active`, `members.already_deactivated`

## Acceptance criteria
- [ ] Admin policy rejects non-admin active members (403) and is applied at the route-group level
- [ ] Manual activation is idempotent and fires the same events as webhook activation
- [ ] Deactivation revokes all refresh tokens for the user
- [ ] Deactivated members disappear from list/detail/spotlight endpoints and from the search index (test each)
- [ ] xUnit coverage for policy, each endpoint, and the `MemberDeactivated` handler

### Conventions (project-wide, non-negotiable)
- .NET 9, records for immutable shapes, file-scoped namespaces, primary constructors where they read well. Minimal-API endpoints grouped per module via `IEndpointModule.MapEndpoints`.
- `Result` (SharedKernel) instead of exception-driven control flow. Endpoint results map failures to ProblemDetails with the stable error codes listed above — the frontend keys off them.
- Module owns its EF Core `DbContext` mapped to its own Postgres schema. Modules never reference each other's internals — cross-module needs go through a public contract interface or an in-process domain event (`IEventPublisher`).
- All external calls (GitHub, Stripe, Brevo, Cloudinary, Meilisearch) behind interfaces owned by the consuming module.
- Every list endpoint paginated (offset is fine). xUnit tests in `tests/CommunityPro.Tests//` following the existing harness patterns (see `Members/MembersTestHarness.cs`).

Contributor guide

No contributing guide indexed for this repository

Research direction

Start by reading the existing IEndpointModule.MapEndpoints convention and the harness at tests/CommunityPro.Tests/Members/MembersTestHarness.cs. Trace the public contracts and event paths for Identity/Members, refresh tokens, profiles, and search before implementing the admin group and endpoints. Done means every acceptance criterion passes with xUnit coverage, including policy, endpoint behavior, deactivation filtering, and index removal.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp, postgres
Domain
api, authorization, backend, databases, search, testing
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.