PhoenixKitStaff.Employments (PhoenixKitStaff v0.6.0)

Copy Markdown View Source

Employment history for staff people (core V136) — the sole write path for PhoenixKitStaff.Schemas.Employment spans.

A person has a timeline of spans; the open span (no end date) is the current employment. This context:

  • keeps the one-open-span-per-person invariant — create/2 closes the prior open span when a new open one starts (the DB partial-unique index backstops it);
  • denormalizes the current span onto Person via sync_current/1, run in the same transaction as every mutation, so existing readers (overview org tree → primary_department_uuid, people list → job_title) need no join and stay consistent;
  • broadcasts :person_employment_changed on the person's topic so the profile view refreshes.

job_title is translatable; sync_current/1 mirrors the current span's job_title + its per-locale overrides onto Person without clobbering the person's other translated fields (bio, notes).

Summary

Functions

Creates an employment span for a person and denormalizes the current span onto Person. If the new span is open (no end date) and an open span already exists, the prior open span is closed at the new span's start date (today if it has none) so the one-open invariant holds.

The current span (open if any, else the latest by start), dept+team preloaded, or nil.

Deletes a span and re-denormalizes the current span onto Person.

Ends an open span by setting its end date (then re-syncs).

Fetches a span by uuid, or nil.

A person's employment spans, current/open first then newest-first, dept+team preloaded.

Recomputes the person's current span (open, else latest) and writes the denormalized mirror onto Person (employment_type, job_title + its translations, dates, primary_department_uuid, work_location) — clearing them when the person has no spans. Server-owned: never cast from the form. Call inside the mutating transaction.

Updates a span and re-denormalizes the current span onto Person.

Functions

create(person_uuid, attrs)

@spec create(UUIDv7.t() | String.t(), map()) ::
  {:ok, PhoenixKitStaff.Schemas.Employment.t()}
  | {:error, Ecto.Changeset.t(PhoenixKitStaff.Schemas.Employment.t())}
  | {:error, :person_trashed}

Creates an employment span for a person and denormalizes the current span onto Person. If the new span is open (no end date) and an open span already exists, the prior open span is closed at the new span's start date (today if it has none) so the one-open invariant holds.

current_for_person(person_uuid)

@spec current_for_person(UUIDv7.t() | String.t()) ::
  PhoenixKitStaff.Schemas.Employment.t() | nil

The current span (open if any, else the latest by start), dept+team preloaded, or nil.

delete(span)

Deletes a span and re-denormalizes the current span onto Person.

end_span(span, end_date)

Ends an open span by setting its end date (then re-syncs).

get(uuid)

Fetches a span by uuid, or nil.

list_for_person(person_uuid)

@spec list_for_person(UUIDv7.t() | String.t()) :: [
  PhoenixKitStaff.Schemas.Employment.t()
]

A person's employment spans, current/open first then newest-first, dept+team preloaded.

sync_current(person_uuid)

@spec sync_current(UUIDv7.t() | String.t()) :: :ok

Recomputes the person's current span (open, else latest) and writes the denormalized mirror onto Person (employment_type, job_title + its translations, dates, primary_department_uuid, work_location) — clearing them when the person has no spans. Server-owned: never cast from the form. Call inside the mutating transaction.

update(span, attrs)

Updates a span and re-denormalizes the current span onto Person.