PhoenixKitProjects.People (PhoenixKitProjects v0.23.3)

Copy Markdown View Source

The ONE doorway to people/team/department data for this module — the staff-optional seam (Phase B of the hub rework, panel-approved design).

Why shadow schemas, not a bridge

The staff DB tables are created by CORE's migrations (V100), not by the phoenix_kit_staff package — staff ships no migrations; it is the admin UI + context over core-owned tables. So the tables (and projects' SQL FKs to them) exist on every install, and projects can keep its belongs_to graph, preloads, authz relationship grants, and direct assignee queries by mapping its OWN minimal read-only schemas (PhoenixKitProjects.People.{Person,Team,Department,TeamMembership}) over those tables. The staff PACKAGE is optional: it is the people ADMIN surface, not the data's owner.

Rules

  • Read-only: no changesets, no writes — people are managed in staff.
  • Filter semantics COPIED from staff, not imported: soft-deleted rows are status == "trashed" and excluded from listings by default.
  • Label semantics mirrored from staff: display_name/1 resolves name → user's first/last name → user email → "Unnamed"; team/department names localize via the row's translations map.
  • staff_admin_available?/0 gates ONLY admin-UI affordances (manage- people links, the "Me" chip's person resolution when staff adds value) — data reads never require the staff package.

Summary

Functions

name → user's first/last → user email → "Unnamed" (staff parity).

A person by uuid with [:user, :primary_department] preloaded, or nil.

The person linked to a core user, or nil. STAFF-PARITY: resolves trashed people too (soft-delete keeps assignments/memberships live so restore is clean — filtering here blanked My Tasks and the Me chip for the whole trash→restore window; panel round). Only LISTINGS exclude trashed.

All departments, name-ordered.

A person's team memberships with team: [:department] preloaded.

Non-trashed people ordered by display name source, [:user] preloaded (the option loaders read the user email). Mirrors staff's default trashed-exclusion.

All teams with their department preloaded, name-ordered.

A team/department's localized name: translations[lang]["name"] else the primary.

The names of a set of teams or departments in one read, %{uuid => name} — the members page labels its group grants this way (it read one row per grant). Unknown uuids are simply absent.

Whether the staff PACKAGE (the people admin surface) is installed and enabled — for UI affordances only; the data paths below never need it.

Functions

display_name(arg1)

@spec display_name(PhoenixKitProjects.People.Person.t() | nil) :: String.t()

name → user's first/last → user email → "Unnamed" (staff parity).

get_person(uuid, opts \\ [])

@spec get_person(binary(), keyword()) :: PhoenixKitProjects.People.Person.t() | nil

A person by uuid with [:user, :primary_department] preloaded, or nil.

get_person_by_user_uuid(user_uuid, opts \\ [])

@spec get_person_by_user_uuid(binary(), keyword()) ::
  PhoenixKitProjects.People.Person.t() | nil

The person linked to a core user, or nil. STAFF-PARITY: resolves trashed people too (soft-delete keeps assignments/memberships live so restore is clean — filtering here blanked My Tasks and the Me chip for the whole trash→restore window; panel round). Only LISTINGS exclude trashed.

list_departments()

@spec list_departments() :: [PhoenixKitProjects.People.Department.t()]

All departments, name-ordered.

list_memberships_for_person(person_uuid)

@spec list_memberships_for_person(binary()) :: [
  PhoenixKitProjects.People.TeamMembership.t()
]

A person's team memberships with team: [:department] preloaded.

list_people(opts \\ [])

@spec list_people(keyword()) :: [PhoenixKitProjects.People.Person.t()]

Non-trashed people ordered by display name source, [:user] preloaded (the option loaders read the user email). Mirrors staff's default trashed-exclusion.

list_teams()

@spec list_teams() :: [PhoenixKitProjects.People.Team.t()]

All teams with their department preloaded, name-ordered.

localized_name(arg1, lang)

@spec localized_name(
  PhoenixKitProjects.People.Team.t()
  | PhoenixKitProjects.People.Department.t()
  | nil,
  String.t() | nil
) :: String.t() | nil

A team/department's localized name: translations[lang]["name"] else the primary.

names_by_uuid(kind, uuids)

@spec names_by_uuid(:team | :department, [binary()]) :: %{
  required(binary()) => String.t()
}

The names of a set of teams or departments in one read, %{uuid => name} — the members page labels its group grants this way (it read one row per grant). Unknown uuids are simply absent.

staff_admin_available?()

@spec staff_admin_available?() :: boolean()

Whether the staff PACKAGE (the people admin surface) is installed and enabled — for UI affordances only; the data paths below never need it.