defmodule Mv.Membership.JoinRequest do @moduledoc """ Ash resource for public join requests (onboarding flow). Created only after email confirmation (double opt-in). Per concept ยง2.3.2: - email (dedicated field), payload, schema_version, status, submitted_at, source - approved_at, rejected_at, reviewed_by_user_id for audit (Step 2) - confirmation_token_hash for idempotency (unique constraint) """ use Ash.Resource, domain: Mv.Membership, data_layer: AshPostgres.DataLayer, authorizers: [Ash.Policy.Authorizer] postgres do table "join_requests" repo Mv.Repo end actions do defaults [:read, :destroy] create :create do primary? true accept [ :email, :confirmation_token_hash, :status, :submitted_at, :source, :schema_version, :payload, :approved_at, :rejected_at, :reviewed_by_user_id ] end create :confirm do description "Public action: create JoinRequest after confirmation link click (actor: nil)" accept [ :email, :confirmation_token_hash, :status, :submitted_at, :source, :schema_version, :payload ] end update :update do accept [:status, :approved_at, :rejected_at, :reviewed_by_user_id] require_atomic? false end end policies do policy action(:confirm) do description "Allow public confirmation (actor nil) for join flow" authorize_if Ash.Policy.Check.Builtins.actor_absent() end policy action_type(:read) do description "Allow read when actor nil (success page) or when user has permission" authorize_if Ash.Policy.Check.Builtins.actor_absent() authorize_if Mv.Authorization.Checks.HasPermission end policy action(:create) do description "Generic create only for authorized users; public uses :confirm" authorize_if Mv.Authorization.Checks.HasPermission end policy action_type([:update, :destroy]) do authorize_if Mv.Authorization.Checks.HasPermission end end attributes do uuid_v7_primary_key :id attribute :email, :string do allow_nil? false public? true end attribute :confirmation_token_hash, :string do allow_nil? false public? true end attribute :status, :string do allow_nil? false public? true default "submitted" end attribute :submitted_at, :utc_datetime_usec do allow_nil? false public? true end attribute :source, :string do allow_nil? false public? true end attribute :schema_version, :integer do allow_nil? false public? true end attribute :payload, :map do allow_nil? true public? true default %{} end attribute :approved_at, :utc_datetime_usec do allow_nil? true public? true end attribute :rejected_at, :utc_datetime_usec do allow_nil? true public? true end attribute :reviewed_by_user_id, :uuid do allow_nil? true public? true end timestamps() end identities do identity :unique_confirmation_token_hash, [:confirmation_token_hash] end end