A task instance within a project. Copies description and duration from the task template at creation time — editable independently.
Tracks who completed the task via completed_by_uuid + completed_at.
Summary
Types
JSONB map of secondary-language overrides. Same shape as
Project.translations_map/Task.translations_map.
Functions
Form-facing changeset. Does NOT allow setting completed_by_uuid or
completed_at — those are server-owned fields (use status_changeset/2).
The display label for this assignment, locale-aware: the child project's
name for a sub-project, otherwise the task template's title. Requires the
relevant association (:child_project or :task) to be preloaded — both are
in Projects' @assignment_preloads. lang may be nil (primary value).
Returns the assignment's description in the requested language, with
primary-fallback semantics: empty/missing override → the primary
description column, which itself may be nil (in which case the
caller's typical pattern is to fall further back to the parent task's
localized_description/2). The double-fallback chain keeps existing
call sites like a.description || a.task.description working
locale-aware: Assignment.localized_description(a, lang) || Task.localized_description(a.task, lang).
Server-trusted changeset that also allows setting completion fields.
Use from context functions that own the completion transition, e.g.
progress updates, explicit complete_assignment/2, or reopen_assignment/1.
True when this assignment embeds a child project (a sub-project row).
Changeset for the parent-side linking assignment of a sub-project.
DB-column field names that participate in the translations JSONB.
Types
@type t() :: %PhoenixKitProjects.Schemas.Assignment{ __meta__: term(), assigned_department: PhoenixKitStaff.Schemas.Department.t() | Ecto.Association.NotLoaded.t() | nil, assigned_department_uuid: UUIDv7.t() | nil, assigned_person: PhoenixKitStaff.Schemas.Person.t() | Ecto.Association.NotLoaded.t() | nil, assigned_person_uuid: UUIDv7.t() | nil, assigned_team: PhoenixKitStaff.Schemas.Team.t() | Ecto.Association.NotLoaded.t() | nil, assigned_team_uuid: UUIDv7.t() | nil, child_project: PhoenixKitProjects.Schemas.Project.t() | Ecto.Association.NotLoaded.t() | nil, child_project_uuid: UUIDv7.t() | nil, completed_at: DateTime.t() | nil, completed_by: PhoenixKit.Users.Auth.User.t() | Ecto.Association.NotLoaded.t() | nil, completed_by_uuid: UUIDv7.t() | nil, counts_weekends: boolean() | nil, dependencies: [PhoenixKitProjects.Schemas.Dependency.t()] | Ecto.Association.NotLoaded.t(), dependents: term(), description: String.t() | nil, estimated_duration: integer() | nil, estimated_duration_unit: String.t() | nil, inserted_at: DateTime.t() | nil, position: integer() | nil, progress_pct: integer() | nil, project: PhoenixKitProjects.Schemas.Project.t() | Ecto.Association.NotLoaded.t() | nil, project_uuid: UUIDv7.t() | nil, status: String.t() | nil, task: PhoenixKitProjects.Schemas.Task.t() | Ecto.Association.NotLoaded.t() | nil, task_uuid: UUIDv7.t() | nil, track_progress: boolean() | nil, translations: translations_map(), updated_at: DateTime.t() | nil, uuid: UUIDv7.t() | nil }
JSONB map of secondary-language overrides. Same shape as
Project.translations_map/Task.translations_map.
Functions
@spec changeset(t(), map()) :: Ecto.Changeset.t()
Form-facing changeset. Does NOT allow setting completed_by_uuid or
completed_at — those are server-owned fields (use status_changeset/2).
The display label for this assignment, locale-aware: the child project's
name for a sub-project, otherwise the task template's title. Requires the
relevant association (:child_project or :task) to be preloaded — both are
in Projects' @assignment_preloads. lang may be nil (primary value).
Single source of truth so every render site (timeline title, comment header,
dependency badge, remove-confirm, activity metadata) handles the sub-project
case identically instead of dereferencing a nil task.
Returns the assignment's description in the requested language, with
primary-fallback semantics: empty/missing override → the primary
description column, which itself may be nil (in which case the
caller's typical pattern is to fall further back to the parent task's
localized_description/2). The double-fallback chain keeps existing
call sites like a.description || a.task.description working
locale-aware: Assignment.localized_description(a, lang) || Task.localized_description(a.task, lang).
@spec status_changeset(t(), map()) :: Ecto.Changeset.t()
Server-trusted changeset that also allows setting completion fields.
Use from context functions that own the completion transition, e.g.
progress updates, explicit complete_assignment/2, or reopen_assignment/1.
@spec statuses() :: [String.t()]
True when this assignment embeds a child project (a sub-project row).
@spec subproject_changeset(t(), map()) :: Ecto.Changeset.t()
Changeset for the parent-side linking assignment of a sub-project.
Used both to create the linking row (create_subproject/2) and to sync the
denormalized rollup fields whenever the child project changes
(sync_project_rollup/1). Unlike changeset/2 it:
- casts
child_project_uuidand the server-owned rollup fields (status/progress_pct/estimated_duration/completed_at/completed_by_uuid) but nevertask_uuid— so a sub-project row can't be flipped into a task-backed one via this path; - does NOT require
estimated_duration > 0— a child with no tasks rolls up to 0 planned hours, which is legitimate.
@spec translatable_fields() :: [String.t()]
DB-column field names that participate in the translations JSONB.