SDLC-372 · Detailed design · One of two directions under consideration

Alternative A
Rail + Context

One project on screen at a time. A permanent 52 px rail for everything global, a 236 px panel for the project you're in, and a top bar that finally says which board you're looking at. This document takes that idea all the way down — anatomy, behaviour at fifty projects, the multi-project reviewer, the icon and emoji system, every breakpoint down to mobile web, and what it costs to build.

Sibling doc
Alternative B →
Overview
Main doc →
Status
Ideation — no code changes
Date
2026-08-09
00

Decisions this design is built on

Your answers to the open questions, now treated as fixed constraints. Everything below obeys them.

Cross-project work
Occasional for you — frequent for people who sit across several products. Both must be first-class.
Scale
15–20 today, growing. Projects are products; old ones never wash out. Design for 50+.
Project icon
Keep colour emoji — but the palette expands well past today's eight.
Boards & views
Monochrome glyphs. Colour survives only as the board's identity dot.
Viewport width
Current content width is fine. No full-bleed requirement — this is what retired Alternative C.
Page header
Remove it on project screens. The top bar absorbs identity, view switch and Create.
Pinned projects
In scope. Client-side acceptable, server-side welcome — see §07.
Responsive
Mandatory. Web, mobile web, and a planned Electron desktop app share this shell.

One interpretation I want confirmed

You said "monogram" for boards and views. I've read that as monochrome — single-colour line glyphs, no per-board hue on the glyph itself — because that's the proposal it was answering and because a literal two-letter monogram on a board row (CP for "Core Platform") would be less scannable than a shape, not more.

If you did mean literal letter monograms for boards, say so and I'll redraw §06 — it's a contained change, but it changes every board row in both alternatives.

01

The premise, and the two people it has to serve

A's whole bet is that the sidebar should render one project, not all of them. That's what makes its height constant as you go from 20 products to 50. The cost is obvious and has to be paid for explicitly: the person who checks in on six products every morning can no longer see six trees at once.

PERSONA 01 — THE RESIDENT

Lives in one product all day

Opens Janus on their board, works tickets, occasionally hits Backlog or the Roadmap. Wants the fastest possible path to their boards and nothing else on screen. A serves this natively — the panel is their project and nothing but.

PERSONA 02 — THE REVIEWER

Sits across six products

An EM, a QA lead, a PM. Needs a morning sweep: what moved, what's blocked, what's in review — across everything. A serves this not by showing six trees but by three dedicated affordances: cross-project My Work, pinned project tiles in the rail, and ⌘P. §04 is entirely about this persona.

A — resident view · /project/SDLC?board=CORE
Rail carries global destinations plus pinned project tiles. Panel is one project. Top bar carries the breadcrumb with an inline board switcher — and there is no page header beneath it.
02

Anatomy

Every slot, its size, and why it's there. The rail is fixed and never scrolls; the panel scrolls only when a project has an unusual number of boards.

rail + panel, annotated
  1. Workspace mark — 26 px

    Click returns Home. In a multi-tenant future this is where a workspace switcher would live; today it's a logo and nothing more.

  2. Global destinations — six, capped

    Home · My Work · Search · Agents · Reports · Config. Six is the ceiling: past that the rail stops being scannable and starts being a list. Anything new goes inside one of these six, never beside them.

  3. Pinned project tiles — up to six

    The reviewer's shortcut. Each is the project's colour tile; one click swaps the whole panel. Separated from the global block by a hairline so the two never read as one list. Overflow beyond six goes to ⌘P.

  4. Rail footer — theme + account

    Avatar opens the account menu that now absorbs Preferences, Admin Management and Application Preferences — the three rows that used to compete with projects for vertical space.

  5. Project switcher — 40 px

    Colour tile + name + key + the up/down chevron pair that signals "this swaps". The single most-clicked control in the panel, so it gets the top slot and a distinct raised surface.

  6. BOARDS group

    Monochrome glyph, board name, and a 5 px dot carrying board.color. The dot is the only place per-board colour appears. Sprint boards get no special glyph — mode is shown in the top bar where it's actionable.

  7. VIEWS group

    One step quieter than boards — 60% opacity glyph, dimmer label. That weight difference is what encodes "lens over work" vs "place work lives" without adding chrome.

  8. QUALITY group — conditional

    Only rendered when project.qa_enabled. Splitting it out of VIEWS stops a QA project's sub-tree reading as a ten-item wall.

  9. Panel footer — project admin

    Settings and Members, gated on the same project.role === 'project_admin' || isSuperAdmin check the current cog uses. Moving them here kills the per-row cog entirely.

ElementSizeScrollCollapsed behaviour
Rail52px fixedneveralways visible — this is the point
Context panel236px, resizable 200–320only the group blockhides entirely; board access moves to the top-bar switcher
Top bar44pxstickyunchanged
Total chrome288px → 52pxvs. 256px → 64px today
03

Fifty products, and none of them ever retire

This is the constraint that decides the whole design. Because the panel renders one project, the sidebar's height is independent of project count — twenty products and two hundred cost the same pixels. What has to be designed is not the list, it's the switch.

⌘P — the switcher at 18 projects
Type-to-filter over name and key. Pinned first, then Recent by last visit, then everything else alphabetical. Archived collapsed at the bottom.
Rail pins — the reviewer's six
Hovering a pinned tile shows name + key. One click swaps the panel — no menu, no scroll. This is what replaces "see six trees at once".

Archiving is the missing primitive

You said old products stay on the board rather than washing out. At 50 that is fine if there's a way to say "this one is dormant" — otherwise the switcher's alphabetical tail grows forever and ⌘P starts returning three things you don't want above the one you do.

The cheapest version is a per-user Hide from my sidebar toggle, which needs no schema change if pins are client-side and no policy debate. A real project.status = active | archived field is better but is a product decision beyond this ticket. I'd ship the per-user hide with A and raise archiving separately.

04

The multi-project reviewer

The persona A is weakest for, so it gets a dedicated answer rather than a hand-wave. The insight: this person doesn't actually want six navigation trees — they want six answers. Trees are how they get them today because nothing better exists.

A — My Work, cross-project
Grouped by project, not by status. Every row carries its project tile so provenance is never ambiguous. This is the morning sweep — one screen instead of six trees.
AFFORDANCE 01

My Work

Assigned to me · reviewing · blocked · mentioned — across every project the user can see. Replaces the act of visiting six boards to check whether anything needs them.

AFFORDANCE 02

Pinned tiles

For the sweeps that genuinely need the board itself. Six one-click destinations in the rail, always in the same pixels, no menu in between.

AFFORDANCE 03

⌘P and ⌘K

⌘P swaps project, ⌘K searches tickets and boards globally. For power users this beats any tree, and it's the same muscle memory as every other tool they use.

05

The top bar, and deleting the page header

You approved removing the per-screen project header. That returns roughly 73 px on every project screen and ends the duplicated identity. Everything it carried has to land somewhere, so here is the full accounting, route by route.

RouteBreadcrumbRight sideSecond row
Boardtile · project · board switcherBoard/Sheet toggle · Filter · Createsprint strip (sprint mode + active sprint only)
Backlogtile · project · BacklogFilter · Createnone
Future Sprintstile · project · Future SprintsCreate sprintnone
Roadmaptile · project · Roadmapcycle range · Create initiativenone
Test Casestile · project · Test CasesFilter · New test casefolder path (when inside a folder)
Ticket /browse/KEYtile · project · board · KEYstatus · assignee · ⋯none
Reports · Agentssection · pagepage-specific controlsnone
Today — two bars, 117px
A — one bar + conditional strip
The sprint strip is the one thing that earns a second row, and only when there is an active sprint. On a kanban board the top bar is a single 44 px line.
06

The icon and emoji system

You asked for a much wider palette. Today's reality: eight hardcoded emoji for projects (📋 🚀 🦞 🧪 ⚡ 🎯 🔧 💎 in CreateProjectDialog.tsx) and thirteen lucide icons for boards in boardIconCatalog.ts. At fifty products, eight emoji means every seventh project looks identical.

OPTION 01 — RECOMMENDED

Full native emoji, searchable

Ship a real picker over the platform's own emoji set — categories, search by name, recently-used. Zero curation forever, users already know it, and it renders identically to what they type elsewhere. The stored value stays a single emoji string, so nothing migrates.

OPTION 02

Curated 100

A hand-picked grid of ~100. More visually consistent, and safe from someone picking an emoji that renders as a black-and-white glyph on one OS — but it is a list somebody has to own and extend, forever, and it will still be too small for someone.

Project icon picker — native set + colour
Search, category tabs, recents. Colour is a separate row — it drives the tile, not the glyph.
Board icon picker — 13 → ~60, monochrome
Categorised and searchable. All rendered monochrome in the picker because that's how they render in the panel — the picker shouldn't lie.

Why boards don't get emoji too

It's tempting to give boards the same expanded emoji set. Don't: emoji are full-colour by definition, and Rule 02 says colour identifies rather than decorates. A panel with four colour emoji stacked under a colour project tile is exactly the noise this ticket was filed about — just at a different depth.

Projects earn colour because there are fifty of them and they're the top-level identity. Boards sit inside an already-identified project, so a shape plus a colour dot is sufficient and much calmer.

07

Every width, down to a phone

Today mobile is useIsMobile() at 768 px swapping the sidebar for an 18 rem drawer — containing the same overloaded tree. That isn't a mobile design, it's the desktop one in a narrower box. A translates unusually well because a rail of six global destinations is already the shape of a bottom tab bar.

WidthRailPanelTop bar
≥ 128052px, persistent236px, persistentfull breadcrumb + search field + Create
1024 – 127952px, persistent236px, collapsible — remembers choicesearch collapses to an icon
768 – 102352px, persistentoverlay — slides over content, dismisses on navbreadcrumb truncates to board name
< 768becomes a bottom tab barbecomes a bottom sheet off the project chip40px: project chip · title · search · avatar
Mobile — board
Mobile — project sheet
Tablet — panel as overlay
Rail stays. Panel slides over and closes on navigation, so a tap never leaves the user in a half-covered board.
MOBILE 01

Rail → bottom tabs

Home · My Work · Create · Boards · More. Thumb-reachable, and the same six global destinations minus Search (which moves into the top bar) and Config (which moves into More).

MOBILE 02

Panel → bottom sheet

Tapping the project chip or the Boards tab raises the same BOARDS / VIEWS / QUALITY groups as a sheet, with the project switcher at its head. Identical information architecture — different container.

MOBILE 03

Kanban → single column

Out of scope for this ticket but worth flagging: a five-column board on a 390 px screen needs a status-picker-plus-list treatment, not horizontal scroll. Raise separately.

08

Where pins live

You said client-side is preferred and server-side is a nice-to-have — and in the same breath that people will use web, mobile web, and a planned Electron app. Those two pull in opposite directions, so it's worth being explicit rather than picking quietly.

CLIENT — localStorage

Ships immediately, forgets on every new device

Zero backend, zero migration, works offline, lands in the same PR as the UI. But pins are per-browser: the same person gets a different rail on their laptop, their phone, and the Electron app — and clearing site data wipes them silently.

SERVER — user preference

One extra endpoint, correct everywhere

A small per-user key/value on the existing preferences surface. Pins follow the person across web, mobile web and Electron, which is precisely the multi-platform story you described. Costs one table or one JSON column and one endpoint.

Recommendation

Build the UI against a tiny pins interface — read, toggle, reorder — and back it with localStorage on day one. Because every call goes through that interface, swapping in a server implementation later is a one-file change with no UI churn.

That gives you the client-side answer you preferred without painting the multi-device story into a corner. If the Electron app is close, skip straight to server-side — the interface is the same either way.

09

What it takes to build

Sequenced so each phase is independently shippable and independently revertible. Phase 1 closes the literal ticket on its own.

PHASE 1

Icon grammar + expanded palettes

Monochrome board glyphs with colour dots, emoji-in-tile for projects, icons for the seven bare view rows, native emoji picker, board catalog to ~60. Touches AppSidebar, BoardIcon, boardIconCatalog, CreateProjectDialog, BoardFormDialog. No shell change, no route change.

PHASE 2

Top bar + page-header removal

Breadcrumb with board switcher, global search entry, Create. Delete ProjectBoard's sticky header and the equivalent block on every other project screen. Highest-value phase, and it's shared with Alternative B — do it regardless of which shell wins.

PHASE 3

The shell — rail + panel

New AppRail and ProjectPanel, App.tsx layout change, active-project resolution on every route. The /browse/<KEY> lookup already does this via the ["ticket", key] cache, so the hard case is solved.

PHASE 4

Switcher, pins, My Work

⌘P switcher, pin interface, cross-project My Work page. My Work is the only one needing new backend query work.

PHASE 5

Responsive

Bottom tab bar, project sheet, tablet overlay. Replaces the current mobile Sheet wholesale.

Risks worth naming now
RISK

"Which project am I in" on non-project routes

Reports, Agents and Config have no project. The panel needs a defined empty state — most likely it collapses and the content goes full width, which incidentally recovers some of what Alternative C offered.

RISK

Deep links from Slack and email

A /browse/KEY link must resolve the project and populate the panel before first paint, or the panel flashes empty. The query cache makes this solvable but it needs deliberate handling, not luck.

RISK

Muscle memory

Everyone currently scans a vertical list of project names. The rail is tiles. Expect a fortnight of "where did Payments go" — mitigated by keeping names on hover and shipping ⌘P at the same time, not after.

RISK

Six-item rail ceiling

The design forbids a seventh global destination. If a new top-level product area is coming, it has to nest inside one of the six — decide that before building, not after.

SDLC-372 · ALTERNATIVE A · IDEATION ONLY SDLC Wiki · Main doc · Alternative B