CommunityPro / CommunityPro/community-pro-api
Mentorship: mentor profiles + availability model (Phase 6.1, 6.2)
- Dominant language
- C#
- Stars
- 0
- Forks
- 0
- PR merge metrics
- No merged PRs in 30d
Description
## Scope
New `CommunityPro.Mentorship` module (schema `mentorship`): mentor opt-in and weekly availability. This is the foundation ticket — model + timezone groundwork; requests/booking build on it.
## Data model
```csharp
public sealed class MentorProfile
{
public Guid MemberId { get; set; } // == AppUser.Id
public string Headline { get; set; }
public string TimezoneId { get; set; } // IANA id, e.g. "Africa/Lagos" — validate against NodaTime TZDB
public List ExpertiseTags { get; set; }
public int Capacity { get; set; } // max concurrent mentees
public bool IsAcceptingMentees { get; set; } // auto-false at capacity, manual toggle too
}
public sealed class AvailabilitySlot
{
public Guid Id { get; set; }
public Guid MentorId { get; set; }
public DayOfWeek Day { get; set; }
public TimeOnly Start { get; set; } // local to MentorProfile.TimezoneId
public TimeOnly End { get; set; }
}
```
## Endpoints (prefix `/mentorship`, active-member policy)
| Method | Path | Notes |
|---|---|---|
| PUT | `/mentorship/mentors/me` | upsert opt-in: headline, timezone, tags, capacity, accepting toggle |
| PUT | `/mentorship/mentors/me/availability` | replace-all slot list |
## Rules
- **Use NodaTime** for all timezone work — validate `TimezoneId` against the TZDB; do not hand-roll DST math (this module's #1 gotcha; Lagos is UTC+1 year-round but mentors/mentees won't all be).
- Slot validation: `End > Start`, no overlapping slots on the same day, sane bounds (e.g. 15-min granularity).
- Capacity ≥ 1, tags length-capped and deduped (mirror the skills validation in `MemberProfileService`).
- Mentor is a **flag in this module**, not an Identity role.
## Error codes
`mentorship.invalid_profile`, `mentorship.invalid_timezone`, `mentorship.invalid_slots`
## Acceptance criteria
- [ ] Invalid IANA id rejected; valid exotic ones (e.g. `Pacific/Chatham`) accepted
- [ ] Overlapping/inverted slots rejected
- [ ] Availability replace-all is transactional
- [ ] xUnit coverage for validation matrix
### 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
Assessment
This issue has not been assessed yet.