UnrelateUserWhenArgumentNil used User :update which only accepts :email.
Switch to :update_user with member: nil so manage_relationship clears member_id.
- Member update_member: on_missing :unrelate → :ignore (no unlink when :user omitted)
- Test: normal_user update linked member without :user keeps link
- Doc: unlink only explicit (user: nil), admin-only; Actor.admin?(nil) note
- Check: defense-in-depth for "user" string key
- Forbid on :user argument presence (not value) to block unlink via nil/empty
- Defensive nil actor handling; policy restricted to create/update only
- Test: Ash.load with actor; test non-admin cannot unlink via user: nil
- Docs: unlink behaviour and policy split
- ActorPermissionSetIs check; bypass policy filters by member_id for own_data only.
- Admin with member_id still gets :all via HasPermission. Tests added.
- Group/MemberGroup/MembershipFeeType/MembershipFeeCycle: HasPermission policy
- normal_user: Group and MembershipFeeCycle create/update/destroy; pages /groups/new, /groups/:slug/edit
- Add policy tests for all four resources
Only admins or the linked user may change a linked member's email.
- New validation EmailChangePermission (uses Actor.admin?, Loader.get_linked_user).
- Register on Member update_member; docs and gettext.
- list_required_custom_fields: require actor (two clauses, no default)
- Member validation: use context.actor only, differentiate Forbidden vs transient errors
- stream_custom_fields: log + send flash on error instead of returning []
- GlobalSettingsLive: handle_info for custom_fields_load_error, put_flash
- Seeds: use Membership.update_member with actor, format
- Tests and UI pass actor for CustomField create/read/destroy; seeds use actor
- Member required-custom-fields validation uses context.actor only (no fallback)
- CODE_GUIDELINES: add rule forbidding system-actor fallbacks
- Authorizer and policies: bypass for read (member_id == actor.member_id),
CustomFieldValueCreateScope for create, HasPermission for read/update/destroy.
- HasPermission: pass authorizer into strict_check helper; document that create
must use a dedicated check (no filter).
- Add authorize?: false to all bootstrap operations in seeds.exs
- Fix user-linking validation to respect authorize? context flag
- Prevents authorization errors during initial setup when no actor exists yet
- Replace if actor, do: [actor: actor], else: [] with Mv.Helpers.ash_actor_opts/1
- Update email_sync/loader.ex, member validations, member.ex, cycle_generator.ex
- Consistent actor handling across non-LiveView modules
Replace after_action hooks with after_transaction to ensure async tasks only run after successful commit. Extract common cycle generation logic into handle_cycle_generation/2 to reduce duplication. Add structured error logging with context.