PhoenixKitStaff.Staff (PhoenixKitStaff v0.2.0)

Copy Markdown View Source

Context for staff (people) and team memberships.

Staff are linked 1:1 to a PhoenixKit user (decision A for MVP). A person can belong to multiple teams via TeamMembership.

Summary

Functions

Adds a person to a team and broadcasts :team_person_added.

Returns a changeset for the given person.

Total number of people.

Inserts a person and broadcasts :person_created on success.

Find-or-create a user by email, then create a staff person linked to that user. If the person creation fails AND we just created a brand-new placeholder user, delete the placeholder so we don't leave orphans.

Deletes a person and broadcasts :person_deleted on success.

Users who don't yet have a staff profile. When exclude_person_uuid is passed (edit mode), that person's linked user is kept in the list.

Returns the regex used to validate emails throughout the staff module.

Finds an existing user by email, or creates a placeholder user with no usable password. When the person later registers or logs in via OAuth with the same email, PhoenixKit's built-in lookup links them automatically.

Fetches a person by uuid, or nil if not found.

Fetches a person by uuid. Raises if not found.

Fetches a person by the linked user's uuid, or nil if no staff profile exists.

All memberships a given person belongs to, with team and department preloaded.

Lists people. Accepts :preload, :status filter, and :search (matches user email).

Memberships on a given team, preloaded with staff_person and user.

Returns the full org tree: %{ departments: [%{department: ..., teams: [...], dept_only_people: [...]}], unassigned_people: [...] }

People not already on this team (for the add-to-team picker).

Removes a team membership (by struct or by team/person uuids) and broadcasts :team_person_removed.

Renames the email of an unclaimed placeholder user directly in place. Safe only for users we created via find_or_create_user_by_email/1 that nobody has signed up for yet. Refuses if another user already exists with the new email.

Returns upcoming birthdays within the given window (default 30 days), sorted by days-until-birthday.

Updates a person and broadcasts :person_updated on success.

Whether the given string looks like a valid email.

Functions

add_team_person(team_uuid, staff_person_uuid)

Adds a person to a team and broadcasts :team_person_added.

change_person(p, attrs \\ %{})

Returns a changeset for the given person.

count_people()

@spec count_people() :: non_neg_integer()

Total number of people.

create_person(attrs)

Inserts a person and broadcasts :person_created on success.

create_person_with_user(email, person_attrs)

Find-or-create a user by email, then create a staff person linked to that user. If the person creation fails AND we just created a brand-new placeholder user, delete the placeholder so we don't leave orphans.

Returns {:ok, person, user_status} or {:error, reason}.

delete_person(p)

Deletes a person and broadcasts :person_deleted on success.

eligible_users(opts \\ [])

@spec eligible_users(keyword()) :: [PhoenixKit.Users.Auth.User.t()]

Users who don't yet have a staff profile. When exclude_person_uuid is passed (edit mode), that person's linked user is kept in the list.

email_regex()

@spec email_regex() :: Regex.t()

Returns the regex used to validate emails throughout the staff module.

find_or_create_user_by_email(email)

@spec find_or_create_user_by_email(String.t()) ::
  {:ok, PhoenixKit.Users.Auth.User.t(), :created | :existing}
  | {:error, PhoenixKitStaff.Errors.error_atom() | Ecto.Changeset.t()}

Finds an existing user by email, or creates a placeholder user with no usable password. When the person later registers or logs in via OAuth with the same email, PhoenixKit's built-in lookup links them automatically.

get_person(uuid, opts \\ [])

@spec get_person(
  UUIDv7.t() | String.t() | any(),
  keyword()
) :: PhoenixKitStaff.Schemas.Person.t() | nil

Fetches a person by uuid, or nil if not found.

get_person!(uuid, opts \\ [])

@spec get_person!(
  UUIDv7.t() | String.t(),
  keyword()
) :: PhoenixKitStaff.Schemas.Person.t()

Fetches a person by uuid. Raises if not found.

get_person_by_user_uuid(user_uuid, opts \\ [])

@spec get_person_by_user_uuid(
  UUIDv7.t() | String.t(),
  keyword()
) :: PhoenixKitStaff.Schemas.Person.t() | nil

Fetches a person by the linked user's uuid, or nil if no staff profile exists.

list_memberships_for_person(person_uuid)

@spec list_memberships_for_person(UUIDv7.t() | String.t()) :: [
  PhoenixKitStaff.Schemas.TeamMembership.t()
]

All memberships a given person belongs to, with team and department preloaded.

list_people(opts \\ [])

@spec list_people(keyword()) :: [PhoenixKitStaff.Schemas.Person.t()]

Lists people. Accepts :preload, :status filter, and :search (matches user email).

list_team_memberships(team_uuid)

@spec list_team_memberships(UUIDv7.t() | String.t()) :: [
  PhoenixKitStaff.Schemas.TeamMembership.t()
]

Memberships on a given team, preloaded with staff_person and user.

org_tree()

@spec org_tree() :: %{
  departments: [
    %{
      department: PhoenixKitStaff.Schemas.Department.t(),
      teams: [
        %{
          team: PhoenixKitStaff.Schemas.Team.t(),
          people: [PhoenixKitStaff.Schemas.Person.t()]
        }
      ],
      dept_only_people: [PhoenixKitStaff.Schemas.Person.t()]
    }
  ],
  unassigned_people: [PhoenixKitStaff.Schemas.Person.t()]
}

Returns the full org tree: %{ departments: [%{department: ..., teams: [...], dept_only_people: [...]}], unassigned_people: [...] }

people_not_on_team(team_uuid)

@spec people_not_on_team(UUIDv7.t() | String.t()) :: [
  PhoenixKitStaff.Schemas.Person.t()
]

People not already on this team (for the add-to-team picker).

remove_team_person(tm)

Removes a team membership (by struct or by team/person uuids) and broadcasts :team_person_removed.

remove_team_person(team_uuid, staff_person_uuid)

@spec remove_team_person(UUIDv7.t() | String.t(), UUIDv7.t() | String.t()) ::
  {:ok, PhoenixKitStaff.Schemas.TeamMembership.t()}
  | {:error, Ecto.Changeset.t(PhoenixKitStaff.Schemas.TeamMembership.t())}
  | {:error, :not_found}

rename_placeholder_email(user, new_email)

@spec rename_placeholder_email(PhoenixKit.Users.Auth.User.t(), String.t()) ::
  :ok
  | {:ok, PhoenixKit.Users.Auth.User.t()}
  | {:error, PhoenixKitStaff.Errors.error_atom() | Ecto.Changeset.t()}

Renames the email of an unclaimed placeholder user directly in place. Safe only for users we created via find_or_create_user_by_email/1 that nobody has signed up for yet. Refuses if another user already exists with the new email.

upcoming_birthdays(window_days \\ 30)

@spec upcoming_birthdays(non_neg_integer()) :: [
  %{
    person: PhoenixKitStaff.Schemas.Person.t(),
    next_birthday: Date.t(),
    days_until: non_neg_integer()
  }
]

Returns upcoming birthdays within the given window (default 30 days), sorted by days-until-birthday.

update_person(p, attrs)

Updates a person and broadcasts :person_updated on success.

valid_email?(email)

@spec valid_email?(any()) :: boolean()

Whether the given string looks like a valid email.