ETS-backed cache of the machine_type / operation / defect_reason
phoenix_kit_entities records, keyed by kind + uuid, with per-locale
title resolution. Subscribes to PhoenixKitEntities.Events and reloads
on any entity/entity-data change. Concurrent readers always see a
consistent snapshot.
Modeled 1:1 on Andi.Orders.StatusRegistry. The three "blueprint"
entities (machine_type/operation/defect_reason) are provisioned
idempotently by provision_blueprints/0, retried until all three are
confirmed present. Two retry paths run in parallel:
- Event-driven: every reload (triggered by a PubSub event or an
explicit
reload/0call) retries provisioning at the top ofdo_reload/1. - Timer-driven: while
blueprints_provisionedisfalse,init/1and each failed attempt schedule aProcess.send_after(self(), :retry_provision, @retry_provision_interval)(default 30 s).handle_info(:retry_provision, ...)retries and reschedules if still not provisioned, and is a no-op once provisioned. This guarantees the subtabs become available even on a host that boots with no users and receives no entities PubSub events for a long time.
See dev_docs/ENTITIES_MIGRATION_SPEC.md for the original design rationale.
Not wired into children/0 by this module alone — see
PhoenixKitManufacturing.children/0 for supervision-tree wiring.
Record shape
Every cached record is a plain map:
%{
uuid: "01…",
entity_name: "machine_type",
status: "published",
position: 0,
metadata: %{"field_template" => [...], "legacy_uuid" => "…"},
primary_title: "CNC Mill",
titles: %{"en-US" => "CNC Mill", "et-EE" => "CNC-frees"},
name: "CNC Mill",
unit: nil,
base_time_norm_seconds: nil
}titles only carries the locale keys actually present on that
record's data — it is not restricted to the host's currently
"enabled" languages, so a translation someone filled in survives even
while that language is temporarily disabled site-wide.
name is a convenience field: the record's primary-language title by
default (as returned by get/2), or the title resolved for the
locale requested via list/3 / label/3. unit /
base_time_norm_seconds only carry a value for :operation records —
they are read once from the primary-language data block and never
locale-overridden, even though the generic entities form technically
allows editing them on secondary language tabs (see
dev_docs/ENTITIES_MIGRATION_SPEC.md §5 — a known, accepted
limitation of the generic-UI approach). metadata is passed through
raw so callers (e.g. Machines.merged_field_template/2, which reads
metadata["field_template"]) can access machine_type-specific keys
this registry itself doesn't interpret.
Locale handling
Callers pass this module's own bare Gettext locale codes ("en",
"et", "ru"); phoenix_kit_entities stores translations under
BCP-47 dialect codes ("en-US", …). normalize_locale/1 bridges the
two by mapping a bare or dialect code to an enabled PhoenixKit
Language sharing its prefix, falling back to the primary language for
nil or an unmatched code. On a fresh host with the Languages module
disabled, only the primary language's own prefix resolves distinctly —
every other requested locale falls back to the primary title, which is
the intended graceful-degradation behavior.
Summary
Functions
Returns a specification to start this module under a supervisor.
Fetches a single cached record by uuid, or nil if unknown. nil is
accepted as uuid (returns nil) so callers can pass an optional
linked-record uuid straight through without a separate nil-check.
Resolves the title for uuid in locale, or "Unknown" if the uuid
isn't cached (including nil).
Lists cached records for kind, with :name resolved for locale
(a bare Gettext code or BCP-47 dialect; nil resolves to the primary
language — see normalize_locale/1).
Normalizes a bare Gettext locale ("en") or BCP-47 dialect
("en-US") to the dialect code of an enabled PhoenixKit Language
sharing its prefix. nil and codes with no enabled match fall back
to the primary language.
True once the registry has completed its initial ETS load.
Forces an immediate synchronous reload from the database.
Types
@type kind() :: :machine_type | :operation | :defect_reason
Functions
Returns a specification to start this module under a supervisor.
See Supervisor.
Fetches a single cached record by uuid, or nil if unknown. nil is
accepted as uuid (returns nil) so callers can pass an optional
linked-record uuid straight through without a separate nil-check.
Unlike list/3, this does not take a locale — :name on the
returned record is the primary-language title (see label/3 for
locale-specific resolution of a single record).
Resolves the title for uuid in locale, or "Unknown" if the uuid
isn't cached (including nil).
Lists cached records for kind, with :name resolved for locale
(a bare Gettext code or BCP-47 dialect; nil resolves to the primary
language — see normalize_locale/1).
Options
:status— when given, only records with this exact status are returned (e.g."published"). Defaults to all cached (i.e. all non-trashed — trashed rows are never cached in the first place) statuses; callers that previously filteredstatus: "active"should now passstatus: "published"explicitly.
Normalizes a bare Gettext locale ("en") or BCP-47 dialect
("en-US") to the dialect code of an enabled PhoenixKit Language
sharing its prefix. nil and codes with no enabled match fall back
to the primary language.
@spec ready?() :: boolean()
True once the registry has completed its initial ETS load.
@spec reload() :: :ok
Forces an immediate synchronous reload from the database.