Pipeline funnel v2: 4-stage enum + migration 0007 + derived grid signals
Collapse the inherited 6-stage opportunity funnel to the locked 4-stage
per-investor funnel (lead -> engaged -> diligence -> commitment), terminal at
commitment. Migration 0007 remaps existing stage values (outreach/meeting ->
engaged, due_diligence -> diligence, committed/funded -> commitment) and
archives the stray 'lost' value (the grid row is left intact). Inject read-only
existing_investor (total_invested>0), last_activity_at, and staleness
(''/'aging'>=30d/'stale'>=60d) into the grid GET, stripped on write. Frontend:
4-stage chip tints + Pipeline board / opp-form / mock on the new enum.
The visible desktop existing-investor star + staleness recency column + the
Stale saved view are deferred to mobile Phase 3 (data is injected + test-locked
now, so that phase stays pure-frontend). Longshot was already retired by prior
cleanup -- no-op.
Tests: test_pipeline_stages_v2.py (migration remap + derivation boundaries) +
updated grid-pipeline-link / soft-delete / nl_query; 36/36 green, render-smoke
green, fresh-DB migrate clean.
This commit is contained in:
+65
-27
@@ -274,42 +274,80 @@ Items 3–6 are cheap (derived/read-time/frontend, reuse `last_activity_at`, no
|
||||
(`design/DESIGN.md` §8 + the `mobile` token group), provenance + per-surface interaction model
|
||||
are in `design/_imports/2026-06-19/`, and the input brief is `design/BRIEF.md`. This is the gap
|
||||
between that contract and the current desktop-only `frontend/index.html` — the implementation
|
||||
backlog. **Not yet started; scope/plan to be developed next (the user's stated next step).**
|
||||
backlog. **Scoped 2026-06-19 (plan below); not yet started.**
|
||||
The comps are signed-off prototypes, **not drop-in** (Claude Design runtime, seed data) — each
|
||||
surface is re-authored in the app's React idiom and wired to the **real API**.*
|
||||
|
||||
**Hard prerequisite — inline-style→CSS migration.** Responsive layout cannot live in the
|
||||
~1,300 inline `style={{}}` objects (they can't carry media queries). Mobile-first means
|
||||
authoring a 375px base + `min-width` enhancements in the CSS `<style>` block / utility classes.
|
||||
This migration is **large and not yet scoped** — it gates everything below and is the first
|
||||
thing the implementation plan must size. (Precedent for a mechanical sweep: the design guide's
|
||||
inline-hex→`var()` field notes; this is bigger — structural layout, not just values.)
|
||||
**Prerequisite — inline-style→CSS migration: SCOPED 2026-06-19 — much smaller/divisible than
|
||||
the "~1,300 inline styles" framing suggested.** Ground truth from `index.html`: **370** total
|
||||
`style={{}}` objects (not 1,300), against an existing **1,861-line `<style>` block** (with
|
||||
`:root` vars + ~all the `.nav-item`/`.sidebar`/`.table` classes + **4 media queries already**,
|
||||
incl. a `min-width` one) and **1,088 `className=` usages** — the app is already majority
|
||||
class-based. Two consequences:
|
||||
- **The responsive migration that gates mobile is only ~114 inline styles**, confined to the four
|
||||
mobile surfaces + shell: FundraisingGrid **70**, Reminders **18**, Contacts **17**, Pipeline **7**,
|
||||
App shell **2**. The other **240** inline styles live on desktop-only pages (Settings 104,
|
||||
Outreach/Email/Status 57, Thesis 44, Comms 31, Dashboard 4) that are **absent on mobile**, so they
|
||||
never block it. → **Not a monolithic blocker; it divides per-surface** and folds into each surface's
|
||||
build (no upfront sweep).
|
||||
- **Two separable axes, not one.** (1) *Responsive* = layout-bearing inline styles → CSS classes +
|
||||
`min-width` queries (the ~114 above; gates mobile layout). (2) *Theming* = inline **hex → `var()`**
|
||||
so `[data-theme="light"]` can re-bind them — **183 hex literals** in the JSX region, app-wide but
|
||||
mechanical (precedent: the design guide's inline-hex→`var()` field notes); gates the **light theme**
|
||||
only. Sequence them apart.
|
||||
|
||||
**Data-layer dependency — the locked pipeline-stages/flags spec** (see the section above) lands
|
||||
**first or together**: the mobile cards render the 4-stage chip, the auto-derived
|
||||
**first, standalone (Phase 0 below)**: the mobile cards render the 4-stage chip, the auto-derived
|
||||
Existing-Investor star, and the staleness overlay, all of which need the stage enum + migration +
|
||||
`total_invested>0` derivation + the `last_activity_at` ramp. Building the cards before the data
|
||||
layer means hardcoding against a model that's about to change.
|
||||
|
||||
**UI workstreams (rough order; real sequencing comes with the plan):**
|
||||
1. **Responsive shell + nav:** viewport-gated mobile shell, the safe-area-aware **4-tab bottom
|
||||
bar** (Grid·Pipeline·Reminders·Contacts), the top-bar account/logout control, the bottom-sheet
|
||||
primitive, and the type/touch bump — the chrome every surface shares.
|
||||
2. **Grid (do first — canonical + the crux):** card list + bottom-sheet **view picker** + search;
|
||||
full-screen detail with per-field bottom-sheet edits (name, contact pills, stage, reminder, log
|
||||
note) + the `+`-create flow with client-side dedup typeahead. **Writes go through the targeted
|
||||
one-row `POST /api/fundraising/log-communication` path + the pipeline link→`PATCH stage` flow —
|
||||
never whole-grid `PUT /state`** (the `BRIEF.md` §3a "Backend reality"). Commitments read-only.
|
||||
3. **Contacts (lowest-risk validator):** read-only A–Z list + full-screen detail; proves the
|
||||
list+detail+sheet pattern before the heavier surfaces.
|
||||
4. **Pipeline:** swipe-between-stages (snap-scroll + segmented control + dots), per-card stage move
|
||||
sharing the same opportunities endpoints as the Grid detail.
|
||||
5. **Reminders:** urgency-grouped list, swipe complete/snooze, add/edit sheets on `/api/reminders`.
|
||||
6. **Light theme + toggle (adopted as a planned feature, 2026-06-19).** Ship the light palette
|
||||
(`tokens.tokens.json` `color.light`) behind a `[data-theme]` switch + a top-bar toggle; dark
|
||||
stays the default. Naturally co-lands with the inline-style→CSS migration (theming wants CSS
|
||||
custom properties, not per-element inline values). Per-component light tints (stage/staleness/
|
||||
note badges) are in `_imports/2026-06-19/GridApp.dc.html`.
|
||||
**Implementation plan (sequenced; decisions confirmed with Grant 2026-06-19) — fold the per-surface
|
||||
migration into each surface's build, behind one shared foundation step. No upfront sweep.**
|
||||
|
||||
- **Phase 0 — Pipeline-stages/flags data layer — BUILT + tested locally 2026-06-19 (deploy pending).**
|
||||
The locked spec above. **Shipped:** enum → `['lead','engaged','diligence','commitment']`
|
||||
(`server.py`) + all mirror sites (report CASEs/filters, `total_funded`→`commitment`,
|
||||
`nl_query/intents.py`); reversible migration **`0007_pipeline_stages_v2`** (outreach/meeting→engaged,
|
||||
due_diligence→diligence, committed/funded→commitment, stray `lost`→archived; up+down verified on
|
||||
synthetic data — the live DB has 0 opps so it's a real no-op there); backend injection of
|
||||
`existing_investor` (`total_invested>0`), `last_activity_at`, and `staleness` (`''`/`aging`≥30d/
|
||||
`stale`≥60d, boundaries inclusive) into the grid GET + stripped on write (`_computed_row_values` +
|
||||
frontend `stripComputedRows`); frontend enum sites (Pipeline board, opp-form, mock) + a 4-stage
|
||||
`pipeline_stage` chip with DESIGN tints. **Drop Longshot (spec item 4) was already done** by prior
|
||||
cleanup (vestigial empty column + strip code) — left as-is (still cleans legacy blobs). Tests:
|
||||
`test_pipeline_stages_v2.py` (migration remap + derivation values/boundaries) + updated
|
||||
`test_grid_pipeline_link`/`test_soft_delete_reads`/`nl_query`; **36/36 suite green, render-smoke
|
||||
green, fresh-DB migrate clean**. **Deferred to Phase 3 (co-lands with the mobile cards, where the
|
||||
card design specifies them):** the *visible* desktop rendering of the existing-investor star + the
|
||||
staleness-colored recency column + the seeded "Stale" saved view — the data is injected and
|
||||
test-locked now, so Phase 3 is pure frontend. W1b nudge specialization is a separate fast-follow.
|
||||
**Deploy:** needs an s9pk build + install (**authorize first**).
|
||||
- **Phase 1 — Shared mobile foundation (the only do-once part of the migration).** Extend `:root` with
|
||||
the missing tokens (semantic colors + the `mobile` token group + a `[data-theme="light"]` block); add
|
||||
CSS for the bottom-tab-bar, the bottom-sheet primitive, `env(safe-area-inset-bottom)`, and the 13→15px
|
||||
type bump; build the viewport-gated shell in `App` (bottom 4-tab bar <768px, hide sidebar, top-bar
|
||||
account/logout control). Touches ~2 inline styles.
|
||||
- **Phase 2 — Contacts (pattern-validator spike, BEFORE the Grid).** ~17 inline styles; read-only A–Z
|
||||
list + segmented tabs + search → full-screen read-only detail. Proves the list→detail→sheet pattern
|
||||
and the per-surface migration mechanics on the lowest-risk surface before the crux. *(Reorders the
|
||||
earlier "Grid first" draft — de-risk the pattern cheaply, then attack the Grid.)*
|
||||
- **Phase 3 — Fundraising Grid (the crux).** ~70 inline styles → classes. Card list + bottom-sheet view
|
||||
picker + search; full-screen detail with per-field bottom-sheet edits (name, contact pills, stage,
|
||||
reminder, log note) + the `+`-create flow with client-side dedup typeahead. **Writes per `BRIEF.md`
|
||||
§3a "Backend reality":** single-investor edits → `POST /api/fundraising/log-communication` (one-row,
|
||||
no version race; can create investor+contact); stage → `POST /api/fundraising/pipeline/link` (needs ≥1
|
||||
contact) then `PATCH /api/opportunities/{id}/stage`; commitments/amounts read-only; **never whole-grid
|
||||
`PUT /state`**. Renders Phase 0's stage chip + Existing-Investor star + staleness ramp.
|
||||
- **Phase 4 — Pipeline.** ~7 inline styles. Swipe-between-stages (snap-scroll + segmented control +
|
||||
dots), per-card stage move sharing the Grid detail's opportunities endpoints.
|
||||
- **Phase 5 — Reminders.** ~18 inline styles. Urgency-grouped list, swipe complete/snooze, add/edit
|
||||
sheets on `/api/reminders`.
|
||||
- **Phase 6 — Light theme + toggle (adopted as a planned feature, 2026-06-19).** The inline-hex→`var()`
|
||||
axis (183 literals) + ship the light palette (`tokens.tokens.json` `color.light`) behind a
|
||||
`[data-theme]` switch + a top-bar toggle; dark stays the default. Mechanical; co-lands after the
|
||||
surfaces. Per-component light tints (stage/staleness/note badges) are in
|
||||
`_imports/2026-06-19/GridApp.dc.html`.
|
||||
|
||||
**Note on `design-checker`:** not run for this round-trip — it audits *existing* UI conformance,
|
||||
and the desktop UI still conforms to §1–7 (unchanged). The mobile gap is greenfield
|
||||
|
||||
Reference in New Issue
Block a user