These member/group/custom-field LiveView tests stay async: false. With the
foreign keys now deferrable the create_member deadlock no longer forces it, so
the rationale is updated: they remain synchronous as a deferred scope decision,
and index_groups_url_params/member_filter_component additionally have separate
async-isolation issues that must be fixed before they can run in parallel.
Concurrent create_member transactions took FK FOR KEY SHARE (MultiXact) locks
on shared rows across members/users/membership_fee_types and could form a
cross-transaction cycle, producing intermittent PostgreSQL deadlocks (40P01)
under load. Making the three foreign keys DEFERRABLE INITIALLY DEFERRED moves
the check to commit time and breaks the cycle, without weakening integrity
(NOT NULL and ON DELETE RESTRICT are unaffected).
The bound-pair generator filtered out ~1/4 of generated values, so unlucky
seeds hit StreamData's FilterTooNarrowError under full property runs.
Construct an at-least-one-bound-set pair directly instead, preserving the
exact domain with no rejection.
Replace the fixed Process.sleep waits in the import, members-PDF and
field-visibility tests with event-based / bounded-poll waits on the
observable condition, removing a known flakiness vector.
Replace :sys.get_state assertions on the LiveView socket with assertions on
rendered output, so the tests pin user-visible behavior rather than internal
state; the few sites with no observable equivalent are kept and annotated.
Replace the create_fee_type/create_cycle helpers duplicated across 18/8
membership-fee test files with a single shared definition in Mv.Fixtures,
reconciling the divergent local signatures (including the reversed
argument order) into one superset so behavior is unchanged.
Several isolated stacks can now coexist: host ports come from DB_PORT/RAUTHY_PORT/MAILCRAB_PORT (defaulting to today's values) and the container namespace from COMPOSE_PROJECT_NAME. Drops the fixed rauthy-dev container_name that blocked a second stack.
Custom :date values are real Date structs; sorting them by Erlang term
order compares day, then month, then year, so the member list ordered
them like day-first text instead of chronologically. Derive the sort key
from a single shared helper that maps a date to its Gregorian day count,
leaving the other value types at their already-correct natural order.
Integrate current main (CSV import, GDPR join-form description, dependency and
tooling bumps) into the bulk-actions-dropdown feature. Gettext catalogs were
reconciled with mix gettext.extract --merge; the CHANGELOG Unreleased entries
of both sides were combined.
The growing row of bulk-action buttons above the member overview is replaced
by one "Aktionen" dropdown holding all four actions (open in email program,
copy addresses, export CSV, export PDF). With no selection the actions operate
on all — or the currently filtered — members; the email-program action is
disabled past a recipient cap, because the browser cannot reliably hand a very
long mailto over to the mail client. The trigger shows the active scope as a
badge: an emphasized count when members are selected, a muted "alle"/"gefiltert"
otherwise.
Dropdown openers were visually indistinguishable from ordinary buttons. A
trailing chevron now marks every dropdown trigger — both the shared
dropdown_menu component and the bespoke member-filter trigger — and an
optional badge slot lets a trigger show a status indicator beside its label.