Commit Graph

269 Commits

Author SHA1 Message Date
3914765f90 feat(tenancy): add Season current-season lookup and year name
Complete the Season model:

- name property renders the start/end years as a "YY-YY" label (e.g.
  "25-26") via strftime %y, and __str__ now returns it.
- get_current(date) returns the active club's season covering the given
  date (today by default), inclusive of both boundaries, scoped through
  the tenant queryset so it never crosses clubs.

Rename the tenant queryset's current() to current_club() for clarity and
update callers/tests. Cover the new behaviour; tenancy modules stay at
100%.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-12 15:38:06 +02:00
cda4960ffc docs: revise shop order-level discount design
Replace the ad-hoc manual order discount with a per-club catalogue of
named OrderDiscountType presets snapshotted onto AppliedDiscount rows,
with stacking, retirement, and an optional value override. Regenerate
ARCHITECTURE.pdf.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-12 15:32:23 +02:00
3575d8f7b1 chore: document dev environment variables
Add .env.example covering the required settings plus the multi-tenant
dev config (DJANGO_ALLOWED_HOSTS=.localhost and CLUBMANAGER_BASE_DOMAIN),
so *.localhost subdomains resolve to clubs without editing /etc/hosts.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-12 15:32:23 +02:00
e85a5f6300 test(tenancy): cover club resolution, context, and scoping
Exercise subdomain resolution (base-domain and generic hosts, unknown
slug, www, port stripping, contextvar cleanup), slug derivation and
uniqueness, the require_current_club/current() context helpers, and
ClubScopedModel save/for_club/current via Season. Add a with_club test
helper. Tenancy modules reach 100% coverage.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-12 15:32:23 +02:00
72e7b5e070 feat(tenancy): resolve active club from request subdomain
Add row-based multi-tenancy plumbing keyed on Club as the tenant root:

- ClubTenantMiddleware maps the request's subdomain to a Club by slug,
  storing it on request.club and in a contextvar so service-layer code
  and management commands can read it via get_current_club(). Resolution
  honours CLUBMANAGER_BASE_DOMAIN (e.g. ajax-united.clubmanager.app),
  falling back to generic slug.example.com hosts, and ignores the bare
  base domain, www, and unknown slugs.
- Club gains a unique slug (auto-derived from name on save) plus a
  ClubManager.current() accessor for the active tenant.
- ClubScopedModel gets a TenantQuerySet (.for_club()/.current()) and
  auto-fills club from the active context on save.

Contextvar helpers live in club.tenancy; Club is imported lazily there
and in clubmanager.base to avoid an import cycle with club.models.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-12 15:32:05 +02:00
919a68ed3a build: add coverage dev dependency; drop contextvars backport
Add coverage 7.15 to the dev group for test-coverage reporting. Remove
the erroneous contextvars>=2.4 runtime dependency: contextvars is part of
the standard library on Python 3.14, and the PyPI backport (with its
immutables dependency) would shadow it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-12 15:31:55 +02:00
638f85fa07 Remove redundant user re-link branch in CSV importer
update_or_create already persists member.user via defaults, so the
follow-up `if create_account and member.user_id is None` block was
unreachable dead code. Removing it brings importer coverage to 100%
with no behavior change (existing link-existing-user test still passes).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-12 00:21:48 +02:00
4165729d61 Add tests for uncovered members code paths
Close the small coverage gaps left after the members app move:
- FamilyMembership.__str__ string representation
- FamilyAdmin.member_count display (with and without members)
- CSV import skips a row with an empty required field (was only
  exercising the invalid-date path)
- MemberImportResult.successful_rows property

Coverage 98% -> 99% (69 tests). The only remaining uncovered lines are
the redundant re-link branch in MemberCsvImporter.import_row (131-132),
which is unreachable because update_or_create already sets member.user.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-12 00:20:27 +02:00
f3b1ae7e82 Complete people-domain move into members app; keep names on Member
Finish relocating Member/Family/FamilyMembership from authentication into
a dedicated members app, and revert the half-applied move of member names
onto the global User.

- members: add first_name/last_name back to Member (the whole codebase —
  tests, CSV importer, club app, admin — assumes them, and login-less
  children in families need a name); restore local ordering/index and the
  member__last_name lookups in Family.__str__ and FamilyMembership.
- authentication: drop first_name/last_name from User; get_full_name/
  get_short_name delegate to the linked member, else fall back to email.
- migrations: create members.0001_initial, repoint club.ClubMembership FK
  (club.0005), delete the models from authentication (0004, rewritten to
  plain DeleteModel ops in child-first order to avoid a SQLite table-remake
  crash).
- fix stale imports across apps (authentication/club tests, CSV importer)
  and missing imports/URLs in members tests; add missing _ import in
  members/admin.py; export MemberCsvImporter from members.services.

Full suite green (64 tests), ruff clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-12 00:16:41 +02:00
19b92d61f7 Add ARCHITECTURE.md to define domain and model architecture
- Introduce a comprehensive architecture document outlining the app's domain model, design principles, and shared conventions.
- Establish the foundation for multi-tenancy and tenant scoping via `Club` as the tenant root and `ClubScopedModel`.
- Detail the decomposition of the app into planned sub-apps and their responsibilities.
- Define model structure, relationships, and access control mechanisms (RBAC) through `ClubRole` and service-layer authorization.
- Provide a roadmap for tenant-aware features: seasons, rosters, events, shop, and dynamic forms.
2026-07-11 23:23:36 +02:00
89c12c12b1 Add ClubMembership enhancements, CSV import command, and related tests
- Extend the ClubMembership model with `club`, `member`, and optional `license` fields, along with relevant constraints and ordering.
- Implement verbose names for Club and ClubMembership models and update admin configurations for better display and filtering.
- Add a `import_members_csv` management command for batch importing members, clubs, and memberships from a CSV file.
- Include extensive tests for the `import_members_csv` command, ClubMembership model, and Club model.
- Refactor related migrations, services, and test structure.
2026-07-05 23:51:35 +02:00
44fe658efa Localize authentication models with verbose names and update corresponding migration 2026-07-05 15:50:54 +02:00
b30522d3d0 Extend admin, migrations, and tests for authentication and club apps
- Implement admin configurations for User, Member, Family, and FamilyMembership, with specialized inlines and filtered displays.
- Introduce `UserCreationForm` and `UserChangeForm` for streamlined user management.
- Enhance Family model with improved string representation and made name optional.
- Add `Member.contact_email` property for prioritized email retrieval.
- Include tests for the updated Family string logic, contact email functionality, and admin integration.
- Add initial migration for club models (Club, ClubMembership) and updated migration for Family in the authentication app.
- Configure IntelliJ IDEA for local SQLite database access.
2026-07-02 16:37:56 +02:00
8f71bb74c0 Refactor accounts app into authentication and club apps
- Split the accounts app into new authentication and club apps for better separation of concerns.
- Migrate the custom User, Member, and Family models to the authentication app.
- Introduce Club and ClubMembership models in the club app.
- Refactor Family model to use UUID as the primary key and consolidate family-role relationships into a new FamilyMembership model.
- Update tests, managers, and migrations to align with the new structure.
2026-07-02 09:40:06 +02:00
aa2c6329b9 Simplify family model and add Member.contact_email
- Replace the Guardianship through-model + self-referential M2M with a simple
  is_guardian flag on Member. Guardians in a family look after the family's
  dependents; guardians/dependents are now derived properties.
- Add Member.contact_email: own contact email, falling back to the linked
  user's login email, so a linked member need not store their email twice.
- Update admin (is_guardian in list/filter/inline; drop guardianship inline).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 00:18:35 +02:00
2ead824c5d Add accounts app: custom User, Member, families & guardianship
Introduce the foundational accounts app:
- Custom email-as-username User (AbstractBaseUser + PermissionsMixin) set
  as AUTH_USER_MODEL, decoupled from membership so children can be members
  without a login.
- Member model holding personal/roster data (names, contact email, phone +
  emergency phone via django-phonenumber-field, license number, DOB) with an
  optional link to a User.
- Family household grouping and directional Guardianship (guardian -> child)
  with uniqueness and no-self-guardian constraints.
- Custom UserAdmin plus Member/Family admin with inlines and autocomplete.
- Settings: register apps, AUTH_USER_MODEL, phonenumber defaults (BE/E164).
- Add CLAUDE.md and a tracked static/ directory.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 00:08:51 +02:00
537c023258 Update project dependencies, settings, and environment configuration 2026-06-17 22:37:32 +02:00
e654311321 Basic app skeleton 2026-06-17 21:40:21 +02:00
3b941b5a3e Initial commit 2026-06-17 21:40:10 +02:00