Skip to main content

Client Visibility Model

Status: decided
Updated: 2026-07-30 Scope: org product behavior, portal projections, and all client-facing publication/file-sharing flows

Purpose

This document defines how client exposure follows the purpose of each record.

The product should stop mixing multiple mental models such as:

  • client visible versus internal only
  • shared versus internal
  • feature-specific visibility rules that feel unrelated

The product should answer the exposure question through structure wherever it can. Operators should not have to repeatedly classify every record as private or client-facing.

Core model

There are two outcomes:

  1. Client visible
  2. Internal

They are not a universal field that every record must expose. A record either:

  • inherits exposure from its client-facing parent;
  • is internal by its record type and purpose; or
  • offers an explicit exposure choice because both outcomes are legitimate.

This makes the safe behavior predictable without adding a switch to every form.

Client-visible records can appear in a client-facing surface such as:

  • the portal;
  • a client-facing project timeline;
  • a client-facing contract view;
  • a shared file workspace; or
  • a notification/email flow that exists to inform the client.

Internal means the record is for agency operators only.

Internal records must never be casually repurposed into client-facing records by a buried toggle or ambiguous copy. They should be represented by an internal record type such as a note or task context item.

Feature Rules

Projects

Projects are client-facing delivery containers.

  • a project is not an internal task bucket;
  • a project exists to represent delivery state in a way that can be communicated outward;
  • new projects should default to client-visible;
  • publishing a project update is a client-facing act; and
  • agencies that want private work tracking should use notes, time, internal files, or external PM tools instead of turning projects into hidden internal containers.

Product consequence:

Projects are client-visible whenever the client has portal access. Projects and tasks do not expose a visibility control in normal product UI.

Project tasks and blockers inherit the project's exposure. They do not ask the operator to repeat the visibility decision for each child record. Notes, time entries, and internal files keep their feature-level rules because they are agency working material rather than project delivery content.

Project ownership is also the default work-assignment context:

  • new projects default to their creator, with owner and initial status chosen in the project form when a different setup is needed;
  • new tasks default to the project owner while still allowing an explicit unassigned state; and
  • new blockers default to the project owner.

Project updates

Project updates are never a separate visibility system.

  • drafts are internal because they are drafts;
  • published updates are client-visible because they are published project communication;
  • update publication should inherit the project's client-facing nature rather than introduce another parallel visibility toggle.

Files

File items can be either client-visible or internal.

  • client-visible drive items are part of the shared client workspace;
  • internal drive items are agency-only support material;
  • file requests, upload links, and portal file browsing should operate only on the client-visible side unless a clearly internal agency workflow is involved.

Important:

shared is an implementation/storage term. In product language, it means client visible.

Contracts

Contracts can be client-visible or internal.

  • published/shared contract records can appear in the client relationship surface;
  • internal contract drafts, prep copies, or support material remain agency-only.

Important:

Contract visibility should use the same user-facing terms as Files, even if both currently reuse the same underlying validator.

Notes

Notes are internal.

  • notes are working memory;
  • notes are not a client-facing publishing tool;
  • if note content should become client-facing, create a project update or client-facing document from it.

Time

Time entries are internal.

  • the record itself is internal;
  • summaries derived from time may influence billing or client reporting later;
  • raw time logs are not a client-facing visibility surface by default.

Billing and commercial records

Invoices, subscriptions/retainers, and quotes are inherently client-related records, but they are not governed by the same binary visibility toggle used by file collaboration.

They follow their own commercial lifecycle and portal exposure rules.

The portal presents client-facing commercial documents through one Agreements destination. Quotes retain their billing ownership and contracts retain their contract ownership; the combined destination is a projection, not a new parallel record type. Delivery-scoped portal grants may see published contracts but not quotes. Billing and full grants may see both.

Client decisions and feedback

Acknowledgement, approval, change-request, and feedback records do not change an artifact's visibility. They are client relationship signals attached to an already client-visible project update, file, or contract. The agency and portal must read the same response record.

UI Rules

Do not show an exposure label or control when the behavior follows directly from the record type or parent. In particular, project lists, project forms, task forms, and task detail do not repeat a visibility decision.

Where an explicit choice is materially necessary, the UI uses:

  • Client visible
  • Internal

Do not mix the following in equivalent places:

  • Shared when the real meaning is client-visible
  • Client workspace in one area and Client visible in another for the same underlying rule
  • Internal only on one feature and Internal on another unless the distinction is materially important

Preferred guidance for those explicit choices:

  • use Client visible for labels, badges, filters, and fields;
  • use Internal for agency-only records;
  • reserve descriptive helper text for cases where the consequence is not obvious.

Current Implementation Mapping

The current codebase still stores multiple values:

  • projects and project tasks: legacy client_visible and internal_only values are temporarily retained for compatibility, but normal application writes and migration normalize them to client_visible
  • drive items: shared and internal
  • contracts: shared and internal

Until storage is unified, the app should map them like this:

Storage valueProduct meaning
client_visibleClient visible
sharedClient visible
internal_onlyInternal
internalInternal

Migration Direction

The product direction is not to add more visibility variants.

The direction is:

  1. derive exposure from record purpose before asking the user;
  2. make projects and their tasks inherit client delivery exposure;
  3. keep internal agency work in notes, task context, time, and internal artifacts;
  4. retain explicit exposure only for artifacts such as Files and contracts where both states are meaningful; and
  5. remove redundant badges, columns, and switches so operators can predict what a record does without rereading the screen.