9777fe6e25
Drop 'type badge'/INVESTOR-PROSPECT category and the create-flow 'type' field (no investor type — Existing-Investor is auto-derived from committed $). Card now specs the existing-investor star/accent, Priority as the only corner badge, the 4-stage chip shown only when in pipeline, and last-contact staleness (grey->amber->red, 'Nd stale').
265 lines
18 KiB
Markdown
265 lines
18 KiB
Markdown
# Design brief — Ten31 CRM mobile-first redesign
|
||
|
||
*The input packet for a Claude Design (or equivalent) round-trip. Goal: make the phone a
|
||
first-class, **preferred** surface for the Ten31 CRM without losing the existing look. This
|
||
is a **layout / information-architecture / interaction** redesign — the visual language is
|
||
captured in `design/DESIGN.md` + `design/tokens.tokens.json` and is **preserved**. Posture:
|
||
**preserve-but-refine** — keep the brand DNA; small mobile-warranted tweaks (type scale,
|
||
density, touch sizing) are welcome, a visual reskin is not.*
|
||
|
||
---
|
||
|
||
## 0. The one instruction that matters most
|
||
|
||
**Preserve the visual language; redesign only layout, navigation, and touch interaction.**
|
||
The current app is already a coherent, deliberate dark venture-CRM look (see `DESIGN.md`).
|
||
Do **not** reinvent the palette, typography, or component styling. Where mobile genuinely
|
||
warrants it, you may refine — bump body type from 13px toward 15–16px, loosen touch density,
|
||
add bottom-sheet patterns — but the colors, the IBM Plex faces, the bordered-panel +
|
||
tinted-badge idiom, and the single `#3b82c4` accent stay.
|
||
|
||
## 1. Goal
|
||
|
||
The Ten31 CRM is the fund's system of record (~150 LPs, 250+ prospects, the capital-raise
|
||
pipeline), used by a ~5-person team. Today it's desktop-first; the team increasingly works
|
||
from phones — before/after investor meetings, on the move. Make **mobile the primary,
|
||
preferred surface**: every common on-the-go task is thumb-reachable and fast, and desktop
|
||
becomes the wide-screen enhancement rather than the baseline.
|
||
|
||
**Mobile is a focused subset, not the whole app** (decided 2026-06-18). Mobile carries only
|
||
the on-the-go core; everything else stays desktop-only.
|
||
|
||
- **Mobile surfaces — the only four:** **Fundraising Grid** (with fast switching between its
|
||
saved *views*), **Pipeline**, **Reminders**, **Contacts**. Every other screen — Dashboard,
|
||
Thesis, Thesis Workshop, Outreach, Communications, Email Capture, System Status, Feedback,
|
||
Instructions, Settings — is **desktop-only and simply absent** from the mobile UI (keep only
|
||
a minimal account/logout control).
|
||
- **Mobile editing — core records + quick capture (expanded 2026-06-18):** read everything;
|
||
editable on mobile is **investor name**, **contacts (name + email)**, **notes / communication
|
||
/ outreach log** (logging activity, not composing/sending — see §3a Backend reality),
|
||
**pipeline stage**, and **reminders** — *and* **creating a new investor**
|
||
(name + one or more contacts; no type field — Existing-Investor is auto-derived, pipeline stage
|
||
optional). Still **desktop-only**: commitments/amounts, the
|
||
full 20+ column set, column structure, bulk ops, and CSV. So mobile is "create and manage the
|
||
core investor record + log activity," not the full spreadsheet.
|
||
- **Create/edit investors go through the Grid — the canonical write path — never Contacts.**
|
||
Per the app's model, the `fundraising_*` grid is the system of record (investor row → contact
|
||
"pills" → commitments) and the **Contacts tab is a read-only directory auto-populated from
|
||
it**. So the **"+ add investor"** entry point and all name/contact/email edits live on the
|
||
**Grid** (its card list and detail); **Contacts stays read-only** on mobile — do not put an
|
||
add/edit affordance there.
|
||
- **Guard against duplicate investors on create.** Adding an investor from a phone is a
|
||
dupe-generation risk; the app already has entity resolution/merge. The mobile "+ add
|
||
investor" flow should **check for an existing match first** (search-as-you-type on name)
|
||
before creating a new row.
|
||
- **The Grid is card/detail on a phone, never a spreadsheet.** A row is one investor; mobile
|
||
shows an investor card list → full-screen detail with the editable set above, plus a create flow.
|
||
|
||
## 2. Layout (global, mobile-first)
|
||
|
||
- **Base = mobile; enhance up.** Author layout for a 375px column first, then add `min-width`
|
||
breakpoints for tablet/desktop. (Implementation note for later: the app's ~1300 inline
|
||
`style={{}}` objects can't respond to media queries — responsive layout must live in the
|
||
CSS `<style>` block / utility classes. The design tool doesn't need to solve this, but the
|
||
brief should assume layout, not inline style, carries responsiveness.)
|
||
- **Navigation → a 4-tab bottom bar; everything else is desktop-only.** Replace the 250px
|
||
sidebar with a **bottom tab bar of exactly four**: **Grid · Pipeline · Reminders ·
|
||
Contacts**. The other ten destinations are **not** present on mobile — there is no "More"
|
||
feature menu. Keep only a minimal **account control** (e.g. a top-bar avatar/menu) for
|
||
profile + logout. The bar respects `env(safe-area-inset-bottom)`.
|
||
- **Grid views are a first-class mobile control (high priority — second only to the tabs).**
|
||
The Grid's saved *views* (Main, Follow-up, All Investors, … and a growing set of
|
||
filter-based cuts) are how the team reads the investor list different ways. Surface a **view
|
||
picker at the top of the Grid screen** — a tappable current-view header that opens a
|
||
**bottom-sheet list of views**. Use a sheet/dropdown, not a fixed segmented control, because
|
||
the set of views grows over time. Switching a view re-filters the card list in place.
|
||
- **Overlays → bottom sheets.** Today's centered modal (500px) and right slide-over (400px,
|
||
which overflows a phone) become **drag-to-dismiss bottom sheets** or full-screen detail
|
||
views on mobile.
|
||
- **Touch + safe areas.** 44px minimum touch targets; sticky bottom nav respects
|
||
`env(safe-area-inset-bottom)`; content gets bottom padding so the nav never overlaps it.
|
||
|
||
## 3. Per-screen briefs
|
||
|
||
Take the design tool through these **one screen at a time** (mobile re-layout is screen-by-
|
||
screen, not a global token swap). Ordered by value and difficulty.
|
||
|
||
### 3a. Fundraising Grid — the crux (do first)
|
||
The core feature and system of record: a 20+ column, ~3,000px-wide editable table. A row =
|
||
**one investor** (contact "pills" + per-fund commitments). On a phone it is a **card list**,
|
||
never a wide table.
|
||
- **View switching, up top (high priority):** a tappable current-view name → **bottom-sheet
|
||
view picker** (Main / Follow-up / All Investors / … a growing set), plus search. Switching
|
||
re-filters the card list in place.
|
||
- **Card:** at-a-glance — **name · committed amount · pipeline stage · last contact**, plus two
|
||
derived indicators below. Tap → **full-screen investor detail** (today's slide-over, promoted).
|
||
*(Card model is locked — see ROADMAP "Pipeline stages + investor flags/labels — LOCKED SPEC.")*
|
||
- **Existing-Investor indicator** (auto-derived from any committed $): a quiet **star by the name
|
||
or a thin left accent edge** — *not* a per-card banner. Existing LPs are special; unmistakable
|
||
but restrained, in the blue accent.
|
||
- **Priority** is the **only top-right corner badge** — a star/pill when flagged, empty otherwise.
|
||
Graveyard is not a corner badge (those rows filter out / render muted). Priority + Graveyard are
|
||
the only two disposition flags; there is **no investor "type"** — drop any INVESTOR/PROSPECT chip.
|
||
- **Pipeline stage** chip shows **only when the row is in the pipeline** (`Lead → Engaged →
|
||
Diligence → Commitment`); most rows have none.
|
||
- **Last contact** carries staleness: grey when fresh → **amber → red** by age, appending "stale"
|
||
past one global threshold (e.g. "35d stale"). Derived from one server value, so grid + mobile
|
||
color-code identically.
|
||
- **Detail + edit:** the full field set is grouped into sections and **read-only**, *except*
|
||
the editable set: **investor name**, **contacts (name + email — the contact "pills")**,
|
||
**notes / communication / outreach** (a text area or "log a note" entry), **pipeline stage**
|
||
(a picker / segmented control), and **set/update a reminder** (date + note). Each edit happens
|
||
in a **bottom sheet**, one field at a time — no spreadsheet grid. Commitments/amounts and the
|
||
rest of the columns stay read-only on mobile.
|
||
- **Add investor (`+` on the Grid):** a create flow capturing **investor name + one or more
|
||
contacts (name, email)** — the minimum to start a record (no "type" to choose — Existing-Investor
|
||
is auto-derived from committed $; pipeline stage is optional, set only if adding to the pipeline);
|
||
the rest is filled later on desktop. **Search-as-you-type on name first** and offer existing matches before
|
||
creating, so a phone-added investor doesn't duplicate one already in the grid.
|
||
- The full multi-column spreadsheet (commitments/amounts, column reorder, bulk/CSV) stays
|
||
**desktop-only**.
|
||
|
||
> **Backend reality (read before designing the edit interactions — the write layer is not
|
||
> what "edit a field in a sheet" implies):**
|
||
> - **There is no field-level write. The grid is one JSON blob saved wholesale.**
|
||
> `PUT /api/fundraising/state` takes the *entire* grid and rejects with **409** if the global
|
||
> `version` moved under you (5 people edit live). So a naive "edit one field" = load the whole
|
||
> grid → mutate one row → PUT it all back → race everyone else. **Mobile single-investor edits
|
||
> (name, pills, add-investor, log-note) should instead go through the targeted, server-side,
|
||
> one-row path** `POST /api/fundraising/log-communication` (it finds/creates a single row,
|
||
> appends a note, and can create a new investor + first contact in one call via
|
||
> `create_investor_if_missing`, with no whole-grid version race) — or a new narrow per-row
|
||
> PATCH. Do **not** model these as whole-grid saves. The Matrix bot already uses this path.
|
||
> - **"Pipeline stage" is not a grid field** — it lives on the separate `opportunities` table and
|
||
> editing it is a **two-call flow with a precondition**: the row must first be *linked* to a
|
||
> pipeline opp (`POST /api/fundraising/pipeline/link`, which **requires ≥1 contact on the row**),
|
||
> *then* `PATCH /api/opportunities/{id}/stage`. The grid only *displays* stage read-only. So the
|
||
> detail-sheet "change stage" control needs a "not in pipeline yet → add to pipeline" state, and
|
||
> it shares the *same* opportunities endpoint as the Pipeline tab (3c) — consistent with that, not
|
||
> with the grid blob.
|
||
> - **Removing a contact pill has no tombstone/undo** — the `fundraising_*` tables are rebuilt on
|
||
> every save; the JSON blob is canonical. Don't promise soft-delete/undo semantics for pill
|
||
> removal (unlike comms/reminders, which *are* soft-deleted).
|
||
> - **Dedup typeahead is client-side** — filter the already-loaded rows; there is no investor-search
|
||
> endpoint, and the app's `entity_merge` is an admin-only *after-the-fact* reconciliation, not a
|
||
> create-time guard.
|
||
> - **"Notes / communication" = the `log-communication` path above (immediate write).** **Outreach
|
||
> *composition*** is a different, **gated** feature (agent drafts → human edits → human sends; the
|
||
> Outreach screen is desktop-only) — only the investor's outreach *log/notes* belong on mobile.
|
||
> - All of these are **plain-authenticated immediate writes** — a human **member** can do them on a
|
||
> phone; there is no draft→approve gate on a *human's own* edit (that gate is for *agent*-originated
|
||
> actions). "Agents draft, humans send" constrains the bot, not this UI.
|
||
|
||
### 3b. Contacts — lowest-risk transform (good pattern validator)
|
||
A **read-only** per-person directory (auto-populated from the Grid — no create/edit here),
|
||
today a table + tabs (All / Investors / Prospects) + a detail slide-over.
|
||
- **Mobile pattern:** a **list of contact rows** (initial/avatar · name · organization · type
|
||
badge · last contact) with the tabs as a top segmented control and search pinned → tap →
|
||
**full-screen read-only detail** (contact info, linked investor, communication history).
|
||
- Pure browse→detail, no edit — validate the list+detail+sheet pattern here before the Grid.
|
||
|
||
### 3c. Pipeline (Kanban) — re-think the horizontal board
|
||
Today: horizontal kanban columns, one per stage (count + total per column), tap card → edit.
|
||
Horizontal columns don't work on a phone.
|
||
- **Mobile pattern (lead option):** **swipe between stage columns** — one full-width stage at
|
||
a time, snap-scrolling, a stage indicator/segmented control at top, vertical list of
|
||
investor cards within each stage. (Alternative to weigh: a vertical accordion of collapsible
|
||
stages.) Tap a card → the same investor detail sheet as the Grid. **Editing pipeline stage**
|
||
is one of the mobile-editable fields, so make stage changeable here too (a stage picker on the
|
||
card, or drag/swipe a card to the next stage).
|
||
|
||
### 3d. Reminders — a primary tab + an edit surface
|
||
A follow-up/tickler list tied to investors (one of the mobile-editable areas).
|
||
- **Mobile pattern:** a **list grouped by urgency** (overdue → due-soon → later), each row
|
||
showing title, investor, due date (urgency-colored: overdue `#e06c6c`, due-soon `#e0b341`),
|
||
and assignee. **Quick actions** (done / snooze / edit) via swipe or a row menu; a **`+`**
|
||
creates one. Tap → a **bottom-sheet edit** (title, investor, due date, note, assignee). This
|
||
is also the editor reached from an investor detail's "set a reminder" action.
|
||
|
||
## 4. Brand description (~120 words)
|
||
|
||
Ten31's CRM is a *trustworthy instrument* — a dense, dark, data-forward venture-fund
|
||
workspace for a small team handling sensitive LP relationships. The voice is serious,
|
||
discreet, and precise: cool blue-greys, a single confident blue accent, IBM Plex's
|
||
engineered-but-humane type, monospace for every number and date. It feels like a well-made
|
||
financial terminal, not a consumer app — restraint and legibility over decoration. The
|
||
mobile version should feel like the *same instrument in your pocket*: calmer and roomier for
|
||
touch, but unmistakably the same tool. It is **not** playful, colorful, skeuomorphic, or
|
||
trend-chasing; **not** a second bright color or a borderless/flat reskin. Quiet confidence,
|
||
information density made thumb-friendly.
|
||
|
||
## 5. Inputs to bring to the cloud tool
|
||
|
||
- **Point at:** `frontend/` (the single `index.html` holds the whole UI — point at the
|
||
directory, not the repo root).
|
||
- **Upload:** `design/DESIGN.md`, `design/tokens.tokens.json`, `design/brand/ten31-logo-white.svg`,
|
||
`design/brand/ten31-favicon.svg`, and **screenshots of each screen** below at desktop width
|
||
(Fundraising Grid, Contacts, Pipeline, Dashboard, a modal, the slide-over) so the tool sees
|
||
the as-built look it must preserve.
|
||
- **Web-capture:** the running app URL if convenient (it's behind auth on the Start9 box; a
|
||
set of screenshots is the reliable path).
|
||
|
||
## 6. Prompt blocks (paste into the design tool, one per screen)
|
||
|
||
**Global frame (paste first):**
|
||
> Redesign this dark venture-CRM web app to be mobile-first and mobile-preferred. **Preserve
|
||
> the existing visual language exactly** (see the uploaded DESIGN.md + tokens: dark blue-grey
|
||
> palette, single `#3b82c4` accent, IBM Plex Sans/Mono, bordered panels, tinted badges) —
|
||
> change only **layout, navigation, and touch interaction**. Small mobile-warranted refinements
|
||
> (body type 13→15–16px, looser touch density, bottom sheets) are welcome; no visual reskin.
|
||
> Mobile carries only **four surfaces in a bottom tab bar — Grid, Pipeline, Reminders,
|
||
> Contacts**; every other screen is desktop-only and absent here (keep just a minimal top-bar
|
||
> account/logout menu). Convert centered modals and the right slide-over into **drag-to-dismiss
|
||
> bottom sheets / full-screen detail views**. 44px touch targets, safe-area-aware sticky bottom
|
||
> nav. Design for a 375px phone first.
|
||
|
||
**Fundraising Grid:**
|
||
> This is a 20+ column editable data table; each row is one investor (contact pills + per-fund
|
||
> commitments) — unusable as a wide table on a phone. Design a mobile **investor card list**:
|
||
> card shows name, committed amount, pipeline stage (only if in the pipeline), and last contact
|
||
> (which color-shifts grey→amber→red as it goes stale); plus an auto-derived Existing-Investor star
|
||
> and a Priority corner badge — there is **no** investor/prospect type chip. At the top, a
|
||
> **tappable current-view name that opens a bottom-sheet list of saved views** (Main, Follow-up,
|
||
> All Investors, and a growing set of filtered cuts) plus search; switching a view re-filters
|
||
> the list. Tapping a card opens a **full-screen detail**: most fields read-only **except** the
|
||
> editable set — **investor name**, **contacts (name + email)**, **notes/communication/outreach**,
|
||
> **pipeline stage**, and **set a reminder** — each edited in a bottom sheet. Add a **`+` to
|
||
> create a new investor** (name + one or more contacts with name/email; no type, pipeline stage
|
||
> optional), with
|
||
> search-as-you-type on name to surface existing matches before creating (avoid duplicates).
|
||
> Commitments/amounts and the full column set stay read-only / desktop-only.
|
||
|
||
**Contacts:**
|
||
> A read-only people directory (no create/edit here). Today it's a table with All/Investors/
|
||
> Prospects tabs and a detail panel. Design a mobile **contact list** (initial, name,
|
||
> organization, type badge, last contact), tabs as a top segmented control, search pinned;
|
||
> tapping a row opens a **full-screen read-only detail** with contact info, linked investor,
|
||
> and communication history.
|
||
|
||
**Pipeline (Kanban):**
|
||
> A kanban board of pipeline stages (one column per stage, each showing count + total),
|
||
> cards are investors. Horizontal columns don't fit a phone. Design a **swipe-between-stages**
|
||
> mobile view: one full-width stage at a time with snap-scrolling and a stage segmented
|
||
> control at top, a vertical list of investor cards within each stage; tapping a card opens
|
||
> the investor detail sheet. Stage is editable here (a stage picker on the card, or drag a card
|
||
> to the next stage). Also sketch a vertical-accordion alternative for comparison.
|
||
|
||
**Reminders:**
|
||
> A follow-up/tickler list tied to investors. Design a mobile **reminders list grouped by
|
||
> urgency** (overdue, due-soon, later); each row shows title, investor, due date (urgency-
|
||
> colored), assignee, with quick actions (done / snooze / edit) via swipe or a row menu and a
|
||
> `+` to create. Tapping a row opens a **bottom-sheet edit** (title, investor, due date, note,
|
||
> assignee).
|
||
|
||
---
|
||
|
||
## 7. After the round-trip (Phase C reminder)
|
||
|
||
Export the **"Handoff to Claude Code" bundle** + screenshots, drop them in
|
||
`design/_imports/<date>/`, then distill back into the contract: update `DESIGN.md` §8
|
||
(Responsive behavior) with the real mobile-first system, add mobile component states (bottom
|
||
nav, sheets, card list) to §4, and bump the mobile type scale in `tokens.tokens.json` if it
|
||
changed. The gap between the new contract and the current `index.html` is the implementation
|
||
backlog → capture it to `ROADMAP.md` (incl. the inline-style→CSS migration that makes
|
||
responsive layout possible at all). Do not silently reskin existing code in the same pass.
|