Prototype handoff · 31 August 2026

Project Types — Prototype Spec

A clickable prototype of Project Types running the real app with no backend and no login. This document is the build spec: what each screen does, which rules it encodes, and exactly which parts are real UI versus mocked data. There is no branch and no PR to read — the prototype plus this page is the whole handoff.

Prototype thrive-ui-nxgen, local branch prototype/local Base c45ffe408 on origin/main Head 1ead0de89

01The link

Open the prototype

https://project-types.thrive-ui-prototype.pages.dev

Sign in with your @thrivetrm.com Google account — the site sits behind Cloudflare Access and is not reachable otherwise.

It runs entirely in your browser against mock data. Nothing you do is saved, nothing reaches a real environment, and no analytics events are emitted. Click freely; a reload resets everything.

02The four types

Every surface reads one canonical order, defined once in src/core/types/ProjectType.ts. It is a reading order: the work with a client and a clock on it first, then the type that behaves most like it, then the two cultivated pools that are rarely urgent.

Searches

search

Client mandates with a fee and a contract.

  • Off limits · yes — the only type with an engagement behind it
  • Statuses · the tenant's full configurable list
  • Incumbent · no

Succession Plans

succession_plan

A named executive's replacement plan.

  • Off limits · no
  • Statuses · Not Started / Open / On Hold / Closed
  • Incumbent · yes — the only type that has one

Pipelines

pipeline

A cultivated pool for a function or role family.

  • Off limits · no
  • Statuses · Not Started / Open / On Hold / Closed
  • Incumbent · no

Talent Pools

talent_pool

Vetted people kept on deck for future roles.

  • Off limits · no
  • Statuses · Not Started / Open / On Hold / Closed
  • Incumbent · no

Pipelines, Succession Plans and Talent Pools share one capability profile — no fee, no contract, no client mandate. Wherever a screen behaves differently “on a Talent Pool, Pipeline or Succession Plan”, it is that one set being tested, not three separate branches (POOL_LIKE_PROJECT_TYPES).

03Screen by screen

Each screenshot is the prototype as deployed. The components underneath are the real ones, edited in place — that edit is the design spec.

Projects index — one type at a time

The index shows exactly one project type at a time, chosen from the header picker. That single-select rule is what makes the rest of the index coherent: stage positions are only comparable inside one type's stage set, so “highest stage reached” can only be filtered or sorted once the list is narrowed to one type. Per-type columns, per-type status options and the incumbent filter all follow from the same premise.

Projects index with the project type picker open showing Searches, Succession Plans, Pipelines and Talent Pools
The picker lists all four types in canonical order, each with the one-line description that is the only place the product explains what separates them. A user who picks the wrong type gets the wrong stage set, so this copy carries real weight.
Projects index showing Talent Pools
Switching type re-titles the page, swaps the description, and re-scopes the list. Status, company, tags and dates survive the switch; the stage and incumbent filters are cleared — they are scoped to the type that was showing when they were set, and carrying them across would return zero results with a populated filter badge, which reads as a broken list rather than an empty filter.
Projects index on a VC/PE tenant, defaulting to Pipelines
First visit has no stored preference, so the tenant decides: VC and Private Equity workspaces open on Pipelines, everyone else on Searches. VC/PE firms run their recruiting out of pipelines, so defaulting them to Searches would open the index on a near-empty list. After that, the last type viewed wins, kept in localStorage per device.

Create Project

Create Project panel with Project type as the first required field
Project type is the first field and it is required. It has to be chosen before anything else because it determines the stage set the project is created with, and there is no sanctioned path to change it afterwards.

Admin → Customization → Project Workflow → Stages

Each project type edits its own stage set, so the tab renders one section per type rather than one table. Editing one does not affect the others.

Admin Stages tab with one section per project type
Sections are stacked alphabetically — the one documented exception to the canonical order. A configuration page is scanned by name (an admin arrives looking for a specific type's stages), so alphabetical is what makes a section findable. Note the per-type differences: Off limits and Hide candidates by default appear only on Search, because both presuppose an engagement and a client who can see the project.

Project panel — candidate board

Candidate kanban board showing Identified, Contacted and Screened columns
The kanban board, unchanged in structure, now driven by the stage set of the project's own type.

Project panel — candidate table (new)

A third view alongside kanban and list. Rows are grouped into collapsible stage buckets, so the stage set stays legible as a spine while the row data becomes scannable and sortable in a way the cards never were.

Candidate table view grouped by stage bucket
Stage buckets carry their own counts and selection checkbox. Stage is editable inline; rows drag between buckets the same way cards drag between columns. Off Limits appears only on a Search.
Configure Columns popover over the candidate table
Columns are user-configurable — reorder by dragging the table headers, toggle from the picker. Name and Off Limits are locked; the rest are optional. The chosen set persists per user.

Person panel — Projects tab

Person panel Projects tab with Searches, Succession Plans, Pipelines, Talent Pools and Lists sub-tabs
The tab used to stack every association into one scroll: an “Associated Projects” grid holding all four types mixed together, then Associated Lists below it. It is now one sub-tab per type — derived from the canonical order, so reordering the types is a one-line change and this strip follows. Lists is last rather than interleaved: it is not a project type, its rows have no type and no stage, and it keeps its own columns.

Hub

Hub page with projects grouped into a Searches section
Hub projects are grouped into one section per type, in canonical order, each with its own count.

04Rules the prototype encodes

These are invariants, not pixels. They are the part most likely to be lost in translation, so they are stated explicitly.

// src/core/types/ProjectType.ts

export const PROJECT_TYPE_ORDER: readonly TProjectTypeTag[] = [
  'search',
  'succession_plan',
  'pipeline',
  'talent_pool',
];

export const POOL_LIKE_PROJECT_TYPES: readonly TProjectTypeTag[] = [
  'pipeline',
  'succession_plan',
  'talent_pool',
];

export const DEFAULT_PROJECT_TYPE_TAG: TProjectTypeTag = 'search';

/** The incumbent is the only field that genuinely separates the pool-like types. */
export function hasIncumbent(tag: TProjectTypeTag): boolean {
  return tag === 'succession_plan';
}

export function defaultProjectTypeForTenant(isVcPeCustomer: boolean): TProjectTypeTag {
  return isVcPeCustomer ? 'pipeline' : 'search';
}
// admin Stages: a section reads its config instead of branching on the tag inline.
// src/legacy/pages/admin/customization/project-workflow/components/projectTypesData.ts

export type TProjectTypeConfig = {
  tag: TProjectTypeTag;
  showOffLimits: boolean;            // Search only: presupposes an engagement
  showHideCandidatesToggle: boolean; // Search only: presupposes a client who can see it
};

// Section order here is ALPHABETICAL — the one exception to PROJECT_TYPE_ORDER.
export const PROJECT_TYPES: readonly TProjectTypeConfig[] = [
  { tag: 'pipeline',        showOffLimits: false, showHideCandidatesToggle: false },
  { tag: 'search',          showOffLimits: true,  showHideCandidatesToggle: true  },
  { tag: 'succession_plan', showOffLimits: false, showHideCandidatesToggle: false },
  { tag: 'talent_pool',     showOffLimits: false, showHideCandidatesToggle: false },
];

05What's real and what's faked

The prototype runs the actual application bundle. Everything you see rendered is the real component tree; everything it asks the network for is intercepted.

LayerStatusWhat that means for you
Components, layout, styling real Real files in src/legacy/ and src/app/, edited in place. Spacing, states and responsive behaviour are what the app will do.
Interactions & local state real Drag and drop, sorting, filtering, tab and view switching, column reordering, form validation — all real client-side logic.
Routing real The real router. One caveat below on deep links.
Every network response mocked Intercepted by MSW and served from typed fixtures in src/prototype/. That directory is scaffolding — ignore it when building. Fixtures are typed against the real types in src/core/types/, which is what stands in for a backend.
Persistence mocked Nothing survives a reload except the localStorage preferences (chosen project type, board/table view, column set). Creating or editing a project appears to work and is then gone.
The project-type taxonomy mocked The four types, their labels, descriptions and per-type stage sets are fixture data. The rules in section 04 are the spec; the specific stage names are illustrative.
Permissions & feature flags mocked One fixture user, an Administrator on an Executive Search Firm tenant. Role gating is not exercised.
Telemetry off by design PostHog, Pendo and Intercom keys are blanked; New Relic no-ops. A prototype session emits nothing.

06Known gaps in the prototype

Artefacts of the mock layer, not intended design. Flagged so nobody builds them.

07Where the code is

These are the files the prototype actually changed. There is no diff to read, so this list is the map.

SurfaceFiles
Canonical rules src/core/types/ProjectType.ts
Admin stages admin/customization/project-workflow/components/ProjectTypeStagesSection.tsx, projectTypesData.ts, tabs/StagesPage.tsx, ProjectStagesTable.tsx
Create project jobs/index/JobCreateQvp.tsx, jobs/index/ProjectTypeSelect.tsx
Projects index jobs/index/useProjectTypeView.ts, JobFilterPopover.tsx, JobsPage.tsx, JobListView.tsx, data-grid/columnUtils.ts, store/ui/indexPageSlice.ts
Hub hub/components/ProjectTypeSection.tsx, hub/components/JobList.tsx
Project panel jobs/profile/PageHeader.tsx, routing/panel/jobs/job/tabs/useGetJobTabs.ts, jobs/profile/qvp/JobOverviewInfoEdit.tsx, jobs/profile/JobEditOverviewForm.tsx
Candidate table (new) jobs/profile/manage-candidacies/table/CandidateTableView.tsx, candidacyColumnDefs.tsx, CandidacyColumnPicker.tsx, StageBucketLoader.tsx, rows.ts, sortCandidacies.ts, cells/
Person panel components/shared/associations/associationTabs.ts, routing/panel/people/person/tabs/associations/loaders.ts
Search & autocompletes GlobalSearchAutocompleteOption.tsx, option-renderer/renderProjectOption.tsx, forms/FormRelatedToAutocomplete.tsx, shared/projects/cards/ProjectCardHeader.tsx
Prototype scaffolding (ignore) src/prototype/, .env.prototype, the *:proto package scripts

08Related documents