- Remove Process.sleep calls from integration tests (tests run synchronously in SQL sandbox)
- Improve error handling: membership_fee_type_not_found now returns changeset error instead of just logging
- Clarify partial_failure documentation: successful_cycles are not persisted on rollback
- Update documentation: joined_at → join_date, left_at → exit_date
- Document PostgreSQL advisory locks per member (not whole table lock)
- Document gap handling: explicitly deleted cycles are not recreated
- Use return_notifications?: true when creating cycles within transaction
- Collect notifications and send them after transaction commits
- Prevents 'Missed notifications' warnings in test output
- Notifications are now properly sent via Ash.Notifier.notify/1
- Add create_member_with_cycles helper that uses fixed 'today' date
- Update tests to use explicit 'today:' option instead of Date.utc_today()
- Prevents test failures when current date changes (e.g., in 2026+)
- Tests now explicitly delete and regenerate cycles with fixed dates
- Ensures consistent test behavior regardless of execution date
- Change algorithm to start from last existing cycle instead of start_date
- Deleted cycles (gaps) are no longer automatically filled
- Add test to verify gaps remain unfilled
- Update documentation to clarify gap handling behavior
- Replace weak assertions (>= 0, if length > 0) with concrete expectations
- Remove unnecessary Process.sleep calls (tests run synchronously)
- Add get_member_cycles helper for direct cycle verification
- Tests now validate actual generated cycles instead of relying on async behavior
- Handle Task crashes in async_stream with {:exit, reason}
- Return {:error, {:partial_failure, successes, errors}} when some cycles fail
- Previously returned {:ok, successful} even on partial failures
- Improves debuggability and allows callers to handle partial failures
- Remove exit_date filter from generate_cycles_for_all_members query
- Inactive members now get cycles generated up to their exit_date
- Add tests for inactive member processing and exit_date boundary
- Document exit_date == cycle_start behavior (cycle still generated)
- Add warning logging for unexpected errors (not missing prerequisites)
- Use CalendarCycles.interval() type instead of generic atom()
- Update moduledoc to reflect actual usage (no where clause needed)
- Log warnings when cycle generation fails in Member create/update
- Extract generate_fn to reduce code duplication
- Improves debuggability of silent failures
- Replace Application.get_env(:mv, :env) with :sql_sandbox config
- Remove redundant :env config from test.exs
- More explicit and less error-prone for test environment detection
Change 'Save Custom field' to 'Save Custom Field' and
'Save Custom field value' to 'Save Custom Field Value' for consistency.
Update gettext files accordingly.
Add tests to verify that copy and open-email buttons are disabled
when no members are selected and enabled after selection.
Also verify that the counter shows the correct count.
Use URI.encode_www_form() instead of URI.encode() for mailto query parameters.
This is the safer choice for query parameter encoding.
Add comment about mailto URL length limits that vary by email client.
Calculate selected_count, any_selected? and mailto_bcc once in assigns
instead of recalculating Enum.any? and Enum.count multiple times in template.
This improves render performance and makes the template code more readable.
Remove navigation attributes (href, navigate, patch) when disabled=true
to prevent 'Open in new tab' and 'Copy link' from working on disabled links.
This makes the disabled state semantically stronger and independent of CSS themes.
- Escape SQL LIKE wildcards (% and _) to prevent pattern injection
- Limit search query length to 100 characters
- Apply sanitization in both :search action and linking filters
- FTS and fuzzy search use unsanitized query (wildcards not special there)
Custom field LIKE queries on JSONB are expensive (no index).
User linking only needs name/email search for autocomplete.
Custom fields are still searchable via main member search (uses FTS index).
Remove unnecessary credo:disable as function complexity is now acceptable.
The fields parameter was accepted but never used in the :search action.
Simplify API to only accept the query parameter.
Update @doc to reflect the actual functionality.
Explain the two-tier matching approach:
- % operator with server-wide threshold (0.3) for fast index scans
- similarity functions with configurable threshold (0.2) for edge cases
Add rationale for threshold value based on German name testing