Club Membership
En bref
Club Membership manages the relationship between players and clubs independently of federation licenses, with a separate lifecycle, billing model, and category catalogue. It supports configurable membership categories per tenant, a strict single license-club constraint with optional support memberships in other clubs, family grouping with discounts, automated renewal reminders, per-club member directories with privacy controls, and competition-entry validation against the player's actual license club.
Comment ça fonctionne
Club membership is modelled separately from licensing because the two have distinct lifecycles and purposes — a player can be a paying member of several clubs but can hold competition rights through only one. The membership flow starts when a player submits an application to a club; the club then accepts or rejects through a workflow that records activated_at, expired_at, and full status-transition history. Each tenant configures its own MembershipCategory catalogue (full, associate, honorary, youth, family, support, etc.) and per-category membership fees, which are decoupled from license fees and billed by the club rather than the federation.
The license-club constraint is enforced at the system level: every player has exactly one ClubMembership flagged as is_license_club=true, and any category whose grants_competition_rights flag is set may only be assigned to that license-club membership. All other club memberships must use support categories. This lets a player play competitions for Club A while paying social membership at Club B without any conflict in license assignment. A dedicated player-summary endpoint exposes the full picture (license club + support clubs) for both admin and member-facing UIs.
Family grouping is handled through a FamilyGroup model: when two or more members from the same household join, the second and subsequent memberships receive a configurable family discount. A family-overview endpoint surfaces all members and their categories for billing and renewal. Renewal reminders run as a bulk job per club with a max_reminders threshold and per-player reminder count tracking, so members don't get spammed and clubs see who has been notified how many times. Membership cards are generated digitally and the per-club member directory respects privacy controls configured by both the club and individual members.
Finally, club-bound competition enforcement validates that players entering a competition under a specific club are actually license-club members of that club — using the per-player club mapping resolved at entry time — preventing accidental or fraudulent club affiliation in entry lists.
Capacités clés
- Membership application and acceptance/rejection workflow with full status history
- Configurable membership categories and per-category fees per tenant
- Single license-club constraint with optional support memberships in other clubs
- Family grouping with automatic discounts for second and subsequent members
- Automated bulk renewal reminders with per-player reminder count tracking
- Per-club member directory with privacy controls
- Club-bound competition entry validation against the player's license club
En pratique
A Swedish family of four signs up at BK Boule Stockholm. The parent registers first with a Full membership; the system creates a FamilyGroup, then applies a 25 percent family discount to the spouse's Full membership and to both children's Youth memberships. The club secretary accepts all four applications in one batch; activated_at timestamps are written and digital member cards are pushed.
Six months later the system runs the renewal-reminder job, which sees three of the four are renewed and the fourth has received only one of the three configured reminders, so a second reminder email goes out — but no new emails to the renewed members. When the parent registers as a support member at a second club, the system blocks the second club from assigning a Full category and offers only support categories instead.
Fonctionnalités de ce sous-système
17| ID | Status | Fonctionnalités |
|---|---|---|
| F03.02.01 | Livré | Membership application (player applies to join club) — PL-F0302a ✅ PL-F0302a |
| F03.02.02 | Livré | Club acceptance/rejection workflow — PL-F0302a ✅ PL-F0302a |
| F03.02.03 | Livré | Membership categories — configurable per tenant (full, associate, honorary, youth, family, support, etc.) — PL-F0302a ✅ PL-F0302a |
| F03.02.04 | Livré | Membership fee management per category — PL-F0302a ✅ PL-F0302a |
| F03.02.05 | Livré | Membership card generation — PL-F0302a ✅ PL-F0302a |
| F03.02.06 | Livré | Member directory per club (with privacy controls) — PL-F0302a ✅ PL-F0302a |
| F03.02.07 | Livré | Membership start/end dates and status tracking — status transition history, auto-expire endpoint, activated_at/expired_at timestamps — PL-F0302b ✅ PL-F0302b |
| F03.02.08 | Livré | License club vs support membership — player has exactly one license club (competition rights) but can be support member in other clubs (no competition rights). System enforces single license club constraint. Categories with grants_competition_rights require is_license_club=true. Player summary endpoint. — PL-F0302b ✅ PL-F0302b |
| F03.02.09 | Livré | Family membership grouping — FamilyGroup model, family discount for 2nd+ member, family membership overview endpoint — PL-F0302b ✅ PL-F0302b |
| F03.02.10 | Livré | Automatic membership renewal reminders — bulk reminder endpoint with max_reminders threshold, per-club filtering, reminder count tracking — PL-F0302b ✅ PL-F0302b |
| F03.02.11 | Livré | Club-bound competition enforcement — enhanced validation with expected club_id, per-player club mapping, club name resolution — PL-F0302b ✅ PL-F0302b |
| F03.02.12 | Livré | ClubInquiry inbox — shared inbox for prospect/visitor inquiries, status-FSM new/assigned/awaiting_reply/responded/converted/closed_no_response/spam, indices för (tenant_id, club_id, status) + (tenant_id, assigned_to, status) + (follow_up_due) — PL-T222 ✅ PL-T222 |
| F03.02.13 | Livré | InquiryAssignment — event-log per (re-)assignment, role-gated på role:club_secretary / role:membership_secretary, dispatchar inquiry.assigned-notification via F09.02 — PL-T222 ✅ PL-T222 |
| F03.02.14 | Livré | InquiryResponseTemplate — Jinja-style {{contact.name}}-substitution, per (club_id, inquiry_type, language)-default, okända variabler collapsar till tomt — PL-T222 ✅ PL-T222 |
| F03.02.15 | Livré | Inquiry follow-up reminder — 5-dagars default-SLA, inquiry_follow_up_tick (1 h-cron), single-fire via follow_up_reminder_sent_at-marker — PL-T222 ✅ PL-T222 |
| F03.02.16 | Livré | Convert-to-member — skapar ClubMember från inquiry, sätter inquiry.converted_to_member_id + status=converted, 409 vid email-kollision — PL-T222 ✅ PL-T222 |
| F03.02.17 | Livré | Public CMS inquiry-form-endpoint — POST /public/clubs/{id}/inquiries med rate-limit 10/h per IP, honeypot-fält website (left:-9999px), 5-min dedup på (email, subject), email lower-normaliserad — PL-T222 ✅ PL-T222 |
Parties prenantes qui ont besoin de ce sous-système
Apparaît dans 9 analyses de parties prenantes