Projects module for PhoenixKit.
Provides a reusable task library, projects that pull tasks in as assignments (with team/department/person assignees), and task dependency chains within each project.
Summary
Functions
One-time data repairs for installs that predate a change here. Core calls this on every boot, so each repair carries its own "already done" flag and runs exactly once.
Notification preference types (Step 7 of the hub rework): the actions
below fan out through core's activity→notification bridge whenever their
entries carry a target_uuid (the affected user — assignees on task
actions, the member on membership actions). Users tune each sub-type —
and its Email/Telegram routing — in their notification preferences.
Places a dashboard may be shown inside this module — the duck-typed
phoenix_kit_dashboard_slots/0 contract (no dependency on
phoenix_kit_dashboards, no @impl, exactly like phoenix_kit_widgets/0).
Resolves "my project" for a viewer — the viewer bind source in the
dashboards package.
Functions
One-time data repairs for installs that predate a change here. Core calls this on every boot, so each repair carries its own "already done" flag and runs exactly once.
projects.admin_allis granted to every role that already holds the baseprojectskey, preserving the pre-split behavior.- Projects carrying the old, incomplete "simple to-do list" preset get the three flags that preset should always have turned off.
Both are deliberately one-way and one-time: re-deciding on every boot would fight the Owner, handing back a permission they revoked or re-disabling a feature they turned on.
Notification preference types (Step 7 of the hub rework): the actions
below fan out through core's activity→notification bridge whenever their
entries carry a target_uuid (the affected user — assignees on task
actions, the member on membership actions). Users tune each sub-type —
and its Email/Telegram routing — in their notification preferences.
@spec phoenix_kit_dashboard_slots() :: [map()]
Places a dashboard may be shown inside this module — the duck-typed
phoenix_kit_dashboard_slots/0 contract (no dependency on
phoenix_kit_dashboards, no @impl, exactly like phoenix_kit_widgets/0).
Declaring these is CONSENT. The dashboards package is able to inject a sub-tab under any module's sidebar entry without asking — core groups sub-tabs by parent id with no ownership check — and deliberately does not. Nothing appears under Projects that is not declared right here.
Two places:
- Projects dashboard — a sidebar sub-tab beside the list and the Overview. Context-free: it is about the whole module, so widgets bound to "the project this page is about" have nothing to read and say so. A widget bound to the viewer's own project resolves fine here, which is what makes one shared board work for every project manager.
- Project page — the Dashboard tab inside a project. It supplies
projects.project, so one shared board serves every project instead of needing a copy each. It is the SAME tab this module's dashboard extension contributes, and the two settle by specificity: a project that picks its own board in its Modules panel overrides the placement, everything else follows it.
The list stays the project list: neither slot is a landing page. The boss's rule that "an overview and a dashboard are different things" is why Dashboard sits next to Overview rather than replacing it.
Resolves "my project" for a viewer — the viewer bind source in the
dashboards package.
This is the half of the design that a page subject cannot supply: a shared "Project managers" dashboard in the sidebar has no current project, yet each manager needs their own. Only this module can answer that question, so the dashboards package asks rather than guessing.
Deliberately conservative. It answers only when there is exactly ONE project
the viewer can reach, and otherwise nil — which renders as "pick a project"
rather than a confident wrong answer. Guessing "most recently visited" was
considered and rejected: it is wrong every Monday morning, and being silently
shown the wrong project's numbers is worse than being shown none.