# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Added
- **GDPR/DSGVO join-form description** – Custom fields can carry a "join form description" that is shown as the field's label on the public join form, with clickable external links (whole URLs and Markdown `[text](url)`). Useful for presenting a GDPR confirmation with a link to an externally hosted privacy declaration before sign-up.
- **Join-form description tooltip in member details** – Custom fields that have a join-form description show an info tooltip (prefixed "Beitrittsformular:") on their label in the member detail view.
- **Editable join-form description** – Admins can set a field's join-form description in the custom-field settings, with an inline hint about the supported link syntax.
- **CSV import – groups column** – Members can be assigned to groups during CSV import via a `Groups`/`Gruppen` column; group names that do not exist yet are created automatically, and re-importing the same file does not create duplicate groups.
- **CSV import – membership fee type column** – A `Fee Type`/`Beitragsart` column assigns each member's membership fee type; an unknown name falls back to the default fee type and is flagged in the preview with a link to create it.
- **CSV import – mapping preview** – After uploading a file, a preview shows how every column maps (with sample rows and warnings for ignored or unknown columns) and the import only starts once you confirm.
- **Dynamic CSV import templates** – The EN and DE import-template downloads now include the association's current custom fields instead of a fixed column set.
- **Deactivate and reactivate members** – Members can be deactivated directly from the member page: a dialog picks the exit date (prefilled to today, future dates allowed); deactivated members can be reactivated, which clears the exit date.
- **Tooltips and OIDC explanation** – Icon-only action buttons (including the Vereinfacht sync control) now carry tooltips and accessible labels, and the OIDC settings section explains that it enables single sign-on.

### Changed
- **Member bulk actions in one menu** – The actions above the member overview (open in email program, copy email addresses, export to CSV, export to PDF) are now collected in a single "Aktionen" dropdown instead of separate buttons. Without a selection they apply to all members, or to the currently filtered members; the trigger shows the active scope. Opening the email program is disabled when too many recipients are selected, with a hint to copy the addresses or use the export instead.
- **Dropdown buttons** – Dropdown buttons (actions, filter, column visibility) now show a chevron so they are recognizable as menus.
- **Default GDPR custom field** – The seeded GDPR field was shortened from "Datenschutzerklärung akzeptiert" to "DSGVO" and now ships with a default join-form description (with a placeholder link to replace).

### Fixed
- **CSV date round-trip** – Date custom-field values are now exported as ISO-8601 (`YYYY-MM-DD`), so an exported CSV can be re-imported without date-parsing errors.
- **CSV import – fee-status columns ignored** – Columns such as `Bezahlstatus` / `Membership Fee Status` are always ignored on import and never stored as a custom-field value, even when a custom field of the same name exists.
- **Column-header tooltips clipped** – Tooltips on the members-overview column headers are no longer clipped by the sticky table header.
- **Text selection opens member** – Dragging to select text in a members-overview row (for example to copy an email) no longer opens the member details; a plain click still opens them.
- **Sort by custom date** – Sorting the member list or member export by a custom date field now orders rows chronologically instead of like text, so e.g. 29.01.1981 correctly comes before 01.03.1982.

## [1.2.0] - 2026-05-08

### Changed
- **Clickable table row highlights** – The new hover/focus-visible row highlight behavior is now the CoreComponents default across clickable tables. Sticky-first-column tables keep zebra striping and show selection through the sticky-column accent stripe (checkboxes keep their default style).
- **Members overview scrolling** – The members table scrollbar now scrolls inside the table container instead of moving with the full page.
- **Join request display and settings workflow** – Improved join request rendering and related settings behavior in one cohesive update:
  - Join request fields now respect their configured field types in the details view.
  - Custom field labels in join request views were standardized.
  - Join request field formatting was corrected for more consistent output.
  - Join link settings now include a direct "Open" action in addition to copy/share workflows.

### Fixed
- **Runtime ENV handling** – Empty or invalid environment variables (e.g. `SMTP_PORT=`, `PORT=`, `POOL_SIZE=`, `DATABASE_PORT=`) no longer cause `ArgumentError` at boot. Instead raises clear errors for required vars set but empty (e.g. DATABASE_HOST, PHX_HOST/DOMAIN, SECRET_KEY_BASE).
- **PostgreSQL 18 Docker volume path** – Corrected the database volume path to match PostgreSQL 18 expectations.
- **Association name ENV handling** – `ASSOCIATION_NAME` is now treated as source of truth; the field is read-only in Global Settings when managed via ENV.
- **Association name consistency after updates** – Layout now prefers explicitly assigned `club_name` values to avoid stale cached values right after settings changes.
- **SMTP ENV/UI source selection** – SMTP now follows a strict single-source policy: ENV-only when `SMTP_HOST` is set, otherwise Settings-only.
- **SMTP settings UI in ENV mode** – SMTP fields are read-only, save action is hidden, and missing required ENV keys are shown as a warning.

### Dependency updates
- Mix dependencies were updated.
- Renovate Docker image was updated to `v43.165`.
- Rauthy Docker image was updated to `v0.35.1`.
- `just` was updated to `v1.50.0`.

## [1.1.1] - 2026-03-16

### Added
- **FORCE_SEEDS** – Environment variable. When set to `"true"`, bootstrap (and optionally dev) seeds are run even when the admin user already exists, so you can re-apply changed seed data (e.g. new roles or custom fields) without deleting the admin user.
- **Improved OIDC-only mode** – Admin can enable “Only OIDC sign-in” in settings; when enabled, direct registration is disabled and sign-in page redirects to OIDC when configured.
- **Success toast auto-dismiss** – Success flash messages (e.g. “Settings saved”) hide automatically after 5 seconds instead of requiring the user to close them.

### Changed
- **Seeds run only when needed** – Bootstrap and dev seeds are skipped on application start when the admin user already exists (`Mv.Release.bootstrap_seeds_applied?/0`). This avoids duplicate data and speeds up startup in dev and production after the first run. Set `FORCE_SEEDS=true` to override and re-run.
- **Unauthenticated access** – Users who are not logged in are redirected to sign-in without showing a “no permission” message; the message is only shown to logged-in users who lack access.

### Fixed
- **SMTP configuration** – Repaired so that both port 587 (TLS/STARTTLS) and 465 (SSL) work correctly.

## [1.1.0] - 2026-03-13

### Added
- **Browser timezone for datetime display** – Date/time values (e.g. join request submitted at, approved at, rejected at) are shown in the user’s local timezone.
- **Registration toggle** – New global setting to disable direct registration (`/register`). When disabled, visitors are redirected to sign-in and the register link is hidden; join form remains available.
- **Configurable SMTP in global settings** – SMTP host, port, user, password, and TLS options configurable via Admin → Global Settings. Test-email action to verify delivery. Join confirmation and other transactional emails use this configuration.
- **Theme and language selector on unauthenticated pages** – Sign-in and join pages now offer theme (light/dark) and locale (e.g. German/English) controls in the header.
- **Duplicate-email handling for join form** – If an applicant’s email is already a member or already has a pending join request, the system sends a clarifying email (already-member or already-pending) and shows the same success message (anti-enumeration).
- **Reviewed-by display for join requests** – Approval UI shows who reviewed a request via a dedicated display field, without loading the User record.
- **Improved field order and seeds for join request approval** – Approval screen field order improved; seed data updated for join-form and approval flows.
- **Tests for SMTP mailer configuration** – Tests for SMTP config and for join confirmation email delivery failure (domain and LiveView).

### Changed
- **SMTP settings layout** – SMTP options reordered and grouped in global settings for clearer configuration.
- **Join confirmation mail** – Uses configurable SMTP from settings; on delivery failure the join form shows an error and no success message.
- **i18n** – Gettext catalogs updated for new and changed strings.

### Fixed
- **Login page translation** – Corrected translation/locale handling on the sign-in page.

---

## [1.0.0] and earlier

### Added
- **Roles and Permissions System (RBAC)** - Complete implementation (#345, 2026-01-08)
  - Four hardcoded permission sets: `own_data`, `read_only`, `normal_user`, `admin`
  - Database-backed roles with permission set references
  - Member resource policies with scope filtering (`:own`, `:linked`, `:all`)
  - Authorization checks via `Mv.Authorization.Checks.HasPermission`
  - System role protection (critical roles cannot be deleted)
  - Role management UI at `/admin/roles`
- **Membership Fees System** - Full implementation
  - Membership fee types with intervals (monthly, quarterly, half_yearly, yearly)
  - Individual billing cycles per member with payment status tracking
  - Cycle generation and regeneration
  - Global membership fee settings
  - UI components for fee management
- **Global Settings Management** - Singleton settings resource
  - Club name configuration (with environment variable support)
  - Member field visibility settings
  - Membership fee default settings
- **Sidebar Navigation** - Replaced navbar with standard-compliant sidebar (#260, 2026-01-12)
- **CSV Import Templates** - German and English templates (#329, 2026-01-13)
  - Template files in `priv/static/templates/`
  - CSV specification documented
- User-Member linking with fuzzy search autocomplete (#168)
- PostgreSQL trigram-based member search with typo tolerance
- WCAG 2.1 AA compliant autocomplete dropdown with ARIA support
- Bilingual UI (German/English) for member linking workflow
- **Bulk email copy feature** - Copy email addresses of selected members to clipboard (#230)
  - Email format: "First Last <email>" with semicolon separator (compatible with email clients)
  - CopyToClipboard JavaScript hook with fallback for older browsers
  - Button shows count of visible selected members (respects search/filter)
  - German/English translations
- Docker secrets support via `_FILE` environment variables for all sensitive configuration (SECRET_KEY_BASE, TOKEN_SIGNING_SECRET, OIDC_CLIENT_SECRET, DATABASE_URL, DATABASE_PASSWORD)

### Changed
- **Actor Handling Refactoring** (2026-01-09)
  - Standardized actor access with `current_actor/1` helper function
  - `ash_actor_opts/1` helper for consistent authorization options
  - `submit_form/3` wrapper for form submissions with actor
  - All Ash operations now properly pass `actor` parameter
- **Error Handling Improvements** (2026-01-13)
  - Replaced `Ash.read!` with proper error handling in LiveViews
  - Consistent flash message handling for authorization errors
  - Early return patterns for unauthenticated users

### Fixed
- Email validation false positive when linking user and member with identical emails (#168 Problem #4)
- Relationship data extraction from Ash manage_relationship during validation
- Copy button count now shows only visible selected members when filtering
- Language headers in German `.po` files (corrected from "en" to "de")
- Critical deny-filter bug in authorization system (2026-01-08)
- HasPermission auto_filter and strict_check implementation (2026-01-08)

