Project health — the hub's native status signal (P2b), Basecamp's
"Needle": a MANUAL three-state judgment (on_track / some_risk /
concerned) with a note, set by a human — never auto-computed (the
research's deliberate-omission lesson: progress math answers "how much",
health answers "how do we feel about it").
Stored in the project's settings["health"]
(%{"status", "note", "updated_at", "updated_by"}) — no migration.
History = the projects.health_updated activity rows; the current value
is just the latest judgment.
Summary
Functions
daisyUI badge/alert classes per status (whitelist — scanner-safe).
The project's current health map, or nil when never set.
Localizable label per status (call under the caller's gettext).
Sets the project's health. Unknown statuses are rejected
({:error, :invalid_status}); an empty note is stored as absent.
Valid health statuses, best first.
Functions
daisyUI badge/alert classes per status (whitelist — scanner-safe).
@spec get(PhoenixKitProjects.Schemas.Project.t() | map()) :: map() | nil
The project's current health map, or nil when never set.
Localizable label per status (call under the caller's gettext).
@spec set( PhoenixKitProjects.Schemas.Project.t(), String.t(), String.t() | nil, keyword() ) :: {:ok, PhoenixKitProjects.Schemas.Project.t()} | {:error, term()}
Sets the project's health. Unknown statuses are rejected
({:error, :invalid_status}); an empty note is stored as absent.
@spec statuses() :: [String.t()]
Valid health statuses, best first.