Unified Client Work
Tasks are the delivery system's source of truth for work. A blocker, a file request, and a client request are not parallel kinds of project work: they are states or collaboration records attached to that work.
Product model
The model has four layers:
- A task describes the outcome the organization is responsible for.
- A client action describes exactly what the client must provide or decide before work can continue.
- Comments record asynchronous back-and-forth around the task or a specific action. Mentions route a comment to an organization member without creating another copy of the conversation.
- A work request is client-originated intake. It can be discussed and resolved without a project, or accepted into a chosen project as a task.
File requests remain owned by the Files domain because they need upload, storage, review, and audit behavior. When created from a task, the task client action and file request are linked and advance as one lifecycle.
A task is an openable work record, not only an editable row. Its internal context can accumulate as structured notes and links without changing the task description or exposing working material to the client. This is the intended home for copied conversation details, decisions, source links, and other information needed to complete the work.
Task workflow
An open task has one derived workflow state:
| State | Meaning |
|---|---|
ready | The organization can continue the work. |
in_progress | Work has started and is not waiting on the client. |
waiting_on_client | At least one blocking client action is requested or needs changes. |
ready_for_review | The client has submitted a response that the organization must review. |
paused | Work is intentionally paused for an internal reason. |
Task completion remains a separate terminal state. A task cannot be completed while it has active client actions.
Client actions use draft → requested → submitted → completed. The organization may instead request changes, which returns the action to the client, or cancel it. Blocking is explicit per action; non-blocking requests do not stop work.
Visibility and permissions
- Tasks inherit the client-facing project container and do not repeat a visibility decision.
- A client action can be sent only from a portal-visible project task.
- Organization members can configure, per client, whether portal users may request work or request a new project.
- Client-originated requests are intake records until an authorized organization member accepts them.
- Accepting a work request creates one linked task and is idempotent.
- Portal users only read and mutate records inside an active grant for the owning client account.
User experience
The organization project workspace has one Tasks surface. There is no separate Blockers tab.
From a task, an organization member can:
- open the task to review its full description and metadata
- add internal notes and links as additional information
- ask for a file, content, an answer, approval, or an action
- mark the request blocking or non-blocking
- set instructions and a due date
- review a response, request changes, or complete the action
- exchange contextual comments and mention eligible organization members
The portal project page promotes outstanding actions into a concise “What you should do now” section. Linked file actions open the existing file-request submission flow. Text, approval, and action responses use the task response flow. Submitted items clearly move to organization review.
Portal users may also submit “Request work” or “Request a project” from Projects when the client policy allows it. Work requests remain useful without a project; organization staff choose a project only if and when the request becomes structured delivery work.
Notifications
Sending a client action creates a communication thread projection for active portal grants with delivery access. Client submissions and comments create personal organization Inbox entries for the task assignee, project owner, requester, or explicitly mentioned members. Organization comments notify mentioned members and relevant portal users. The Inbox drawer is backed by shared threads with per-person read and archive state; it is not a second task system or a shared-read mailbox. It opens with B; opening an entry opens the owning conversation and marks only the viewer's projection read. The complete participant, authorization, email, and lifecycle contract lives in communications-inbox-spec.md.
Legacy blocker transition
The migration is additive and reversible:
- Existing task and client-policy defaults are backfilled.
- Each legacy blocker receives one idempotent task/action projection.
- Client-visible open blockers become blocking client actions; internal blockers become paused tasks.
- Legacy rows are retained for audit and rollback.
- Read models hide a legacy blocker once its projection exists, preventing duplicate UI and Today/Overview signals.
- Completing or cancelling a projected action resolves its legacy blocker and restores the project's prior lifecycle state when no open legacy blockers remain.
The migration supports dry runs, resumable execution, and a verifier. The schema remains widened until the projection is confirmed in every deployed environment.
Release gates
- task, action, file-request, comment, mention, and Inbox lifecycles pass backend tests
- organization and portal authorization is tested at the mutation boundary
- legacy projections are idempotent and do not duplicate operational signals
- locale validation passes for every supported locale
- application and Convex typechecks pass
- the development deployment migration is dry-run, executed, and verified before production rollout