Practical-usefulness slice: /uses hub + demand-side use-case pages (what's in demand, buy/sell, arbitrage, shop-check) - follow-up F from #98 #99

Closed
opened 2026-07-07 06:37:27 +00:00 by coilysiren · 2 comments
Owner

Ship the first slice of the practical-usefulness layer: the /uses hub plus the demand-side, task-focused use-case pages. This is follow-up F (and the shared hub it needs) from the design on #98. Kai asked to start here because it depends on zero new data - every panel reads data eco-app already hydrates and the /trade page already renders.

Do NOT build anything recipe-shaped or cost/margin-based here. Those (the recipes page, cost engine, value-per-profession, and the "how to price X" page) are follow-ups A-E on #98 and are gated on the recipe exporter. This ticket is the no-dependency slice only.

1. The shared /uses hub

  • Add a /uses route (App.tsx) and one homepage card in Home.tsx (data-testid in the dir-* family). This is the ONLY homepage card the whole use-case family gets - the individual use-case pages are URL-only, reached from the hub, mirroring how /item is only reached from /items.
  • /uses is a single page that lists the use cases as cards, each linking to its page. It is NOT the recipes page (that is a separate data hub on #98).
  • List the four demand-side pages below as live cards. Optionally show the recipe-dependent use cases (from #98's Tier B/C list) as muted "coming soon" cards so the hub reads as the full roadmap, but do not build them.

2. The demand-side use-case pages (all buildable now)

Each is a task-framed page with a hero stating the job, one primary input (an item picker where relevant, deep-linkable via ?item=<id>), then panels composed from existing typed clients. Each panel degrades on its own via fetchJsonOrNull so one dead source never blanks the page (the /preview/logistics.json sibling can 404 on a reset-gated shelf - fetchLogistics already resolves to null). Reuse formatCount / prettifyEcoName from lib/format.ts.

  • /uses/demand - "What's in demand right now." Rank LogisticsBoard.supplyGaps (lib/logisticsApi.ts) by demandQty, showing the item, the reason tag (no_supply / thin_supply / overpriced) with a glyph+label+color severity treatment (never color alone), buyerCount, and who needs it (buyers[]: owner, store, quantity, price). This is the Supply-gaps signal Kai likes, given its own focused page.
  • /uses/buy-sell - "Where to buy X cheapest / sell X highest." For a picked item, show the cheapest sell offers (LogisticsBoard.cheapest -> PricedBoardRow.offers, cheapest price) and the best buy offers (resale, best price), each row naming the store, owner, price, quantity, and source (live / history).
  • /uses/arbitrage - "Buy low here, sell high there." Render LogisticsBoard.arbitrage (ArbitrageSpread): buyFrom store, sellTo store, spread / spreadPct, volume, and opportunity, ranked by opportunity.
  • /uses/shop-check - "Is my shop priced right?" Pick a store (from lib/storesApi.ts), and for each item it lists compare its avgUnitPrice against the market median (lib/marketApi.ts), flagging items priced notably above or below market. This is the one page that joins two sources - degrade to a clear note if either is unavailable.

Conventions

  • One heading tier + at most one short intro line per page, minimal prose (the site is mid-cleanup toward this in #97 - match that direction, do not add stacked intros).
  • Use Layout (+ Hero where it fits), react-router, and the ?param= deep-link pattern the other pages use so QA can share links.
  • Add vitest component tests per page (mirror pages/Trade.test.tsx / pages/Items.test.tsx), including the degraded-when-null branch.

Done when

/uses lists the use cases with one homepage card, the four demand-side pages render real data and each degrades independently, every page is deep-linkable and carries one heading tier, and the test + lint gates (ward exec / frontend-test / frontend-lint) are green. Update docs/FEATURES.md with the /uses hub and the demand-side pages, and add a short docs/uses.md walkthrough linked from the FEATURES entry. Land on main so the deploy picks it up - Kai is sending this to QA after it deploys, so leave each page usable and shareable standalone.

Ship the first slice of the practical-usefulness layer: the `/uses` hub plus the demand-side, task-focused use-case pages. This is follow-up **F** (and the shared hub it needs) from the design on #98. Kai asked to start here because it depends on zero new data - every panel reads data eco-app already hydrates and the `/trade` page already renders. Do NOT build anything recipe-shaped or cost/margin-based here. Those (the recipes page, cost engine, value-per-profession, and the "how to price X" page) are follow-ups A-E on #98 and are gated on the recipe exporter. This ticket is the no-dependency slice only. ## 1. The shared `/uses` hub - Add a `/uses` route (`App.tsx`) and one homepage card in `Home.tsx` (`data-testid` in the `dir-*` family). This is the ONLY homepage card the whole use-case family gets - the individual use-case pages are URL-only, reached from the hub, mirroring how `/item` is only reached from `/items`. - `/uses` is a single page that lists the use cases as cards, each linking to its page. It is NOT the recipes page (that is a separate data hub on #98). - List the four demand-side pages below as live cards. Optionally show the recipe-dependent use cases (from #98's Tier B/C list) as muted "coming soon" cards so the hub reads as the full roadmap, but do not build them. ## 2. The demand-side use-case pages (all buildable now) Each is a task-framed page with a hero stating the job, one primary input (an item picker where relevant, deep-linkable via `?item=<id>`), then panels composed from existing typed clients. Each panel degrades on its own via `fetchJsonOrNull` so one dead source never blanks the page (the `/preview/logistics.json` sibling can 404 on a reset-gated shelf - `fetchLogistics` already resolves to null). Reuse `formatCount` / `prettifyEcoName` from `lib/format.ts`. - **`/uses/demand` - "What's in demand right now."** Rank `LogisticsBoard.supplyGaps` (`lib/logisticsApi.ts`) by `demandQty`, showing the item, the `reason` tag (`no_supply` / `thin_supply` / `overpriced`) with a glyph+label+color severity treatment (never color alone), `buyerCount`, and who needs it (`buyers[]`: owner, store, quantity, price). This is the Supply-gaps signal Kai likes, given its own focused page. - **`/uses/buy-sell` - "Where to buy X cheapest / sell X highest."** For a picked item, show the cheapest sell offers (`LogisticsBoard.cheapest` -> `PricedBoardRow.offers`, `cheapest` price) and the best buy offers (`resale`, `best` price), each row naming the store, owner, price, quantity, and `source` (live / history). - **`/uses/arbitrage` - "Buy low here, sell high there."** Render `LogisticsBoard.arbitrage` (`ArbitrageSpread`): buyFrom store, sellTo store, `spread` / `spreadPct`, `volume`, and `opportunity`, ranked by `opportunity`. - **`/uses/shop-check` - "Is my shop priced right?"** Pick a store (from `lib/storesApi.ts`), and for each item it lists compare its `avgUnitPrice` against the market median (`lib/marketApi.ts`), flagging items priced notably above or below market. This is the one page that joins two sources - degrade to a clear note if either is unavailable. ## Conventions - One heading tier + at most one short intro line per page, minimal prose (the site is mid-cleanup toward this in #97 - match that direction, do not add stacked intros). - Use `Layout` (+ `Hero` where it fits), `react-router`, and the `?param=` deep-link pattern the other pages use so QA can share links. - Add vitest component tests per page (mirror `pages/Trade.test.tsx` / `pages/Items.test.tsx`), including the degraded-when-null branch. ## Done when `/uses` lists the use cases with one homepage card, the four demand-side pages render real data and each degrades independently, every page is deep-linkable and carries one heading tier, and the test + lint gates (`ward exec` / `frontend-test` / `frontend-lint`) are green. Update `docs/FEATURES.md` with the `/uses` hub and the demand-side pages, and add a short `docs/uses.md` walkthrough linked from the FEATURES entry. Land on `main` so the deploy picks it up - Kai is sending this to QA after it deploys, so leave each page usable and shareable standalone.
Member

🔒 Reserved by ward agent --driver claude — container engineer-claude-eco-app-99 on host KAI-DESKTOP-TOWER is carrying this issue (reserved 2026-07-07T06:37:48Z). Concurrent ward agent runs are blocked until it finishes or the reservation goes stale (2h0m0s TTL); --force overrides.

Do not comment on or edit this issue to steer the run while it is reserved. The engineer seeded the body once at launch and never re-reads it, so a comment or edit reaches only human readers, never the running engineer. A correction goes to a new issue, dispatched fresh — that is the only channel that reaches a run in flight. Where the forge supports it, ward locks this conversation to make that a road-block rather than a convention (ward#494).

run seed context — what this run is carrying (ward#609)
  • Resolved: coilyco-gaming/eco-app#99 · branch issue-99 · driver claude · workflow direct-main
  • Run: engineer-claude-eco-app-99 · ward v0.419.0 · dispatched 2026-07-07T06:37:48Z
  • Comment thread: 0 included in the pre-flight read, 0 stripped (ward's own automated comments).

Issue body as seeded:

Ship the first slice of the practical-usefulness layer: the `/uses` hub plus the demand-side, task-focused use-case pages. This is follow-up **F** (and the shared hub it needs) from the design on #98. Kai asked to start here because it depends on zero new data - every panel reads data eco-app already hydrates and the `/trade` page already renders.

Do NOT build anything recipe-shaped or cost/margin-based here. Those (the recipes page, cost engine, value-per-profession, and the "how to price X" page) are follow-ups A-E on #98 and are gated on the recipe exporter. This ticket is the no-dependency slice only.

## 1. The shared `/uses` hub

- Add a `/uses` route (`App.tsx`) and one homepage card in `Home.tsx` (`data-testid` in the `dir-*` family). This is the ONLY homepage card the whole use-case family gets - the individual use-case pages are URL-only, reached from the hub, mirroring how `/item` is only reached from `/items`.
- `/uses` is a single page that lists the use cases as cards, each linking to its page. It is NOT the recipes page (that is a separate data hub on #98).
- List the four demand-side pages below as live cards. Optionally show the recipe-dependent use cases (from #98's Tier B/C list) as muted "coming soon" cards so the hub reads as the full roadmap, but do not build them.

## 2. The demand-side use-case pages (all buildable now)

Each is a task-framed page with a hero stating the job, one primary input (an item picker where relevant, deep-linkable via `?item=<id>`), then panels composed from existing typed clients. Each panel degrades on its own via `fetchJsonOrNull` so one dead source never blanks the page (the `/preview/logistics.json` sibling can 404 on a reset-gated shelf - `fetchLogistics` already resolves to null). Reuse `formatCount` / `prettifyEcoName` from `lib/format.ts`.

- **`/uses/demand` - "What's in demand right now."** Rank `LogisticsBoard.supplyGaps` (`lib/logisticsApi.ts`) by `demandQty`, showing the item, the `reason` tag (`no_supp

… (truncated to 2000 chars; full body is on this issue)

Static container doctrine and seed boilerplate are identical every run and omitted here (they ride ward v0.419.0).

— Claude (she/her), via ward agent

<!-- ward-agent-reservation --> 🔒 Reserved by `ward agent --driver claude` — container `engineer-claude-eco-app-99` on host `KAI-DESKTOP-TOWER` is carrying this issue (reserved 2026-07-07T06:37:48Z). Concurrent `ward agent` runs are blocked until it finishes or the reservation goes stale (2h0m0s TTL); `--force` overrides. **Do not comment on or edit this issue to steer the run while it is reserved.** The engineer seeded the body once at launch and never re-reads it, so a comment or edit reaches only human readers, never the running engineer. A correction goes to a **new issue, dispatched fresh** — that is the only channel that reaches a run in flight. Where the forge supports it, ward locks this conversation to make that a road-block rather than a convention (ward#494). <details><summary>run seed context — what this run is carrying (ward#609)</summary> - **Resolved:** `coilyco-gaming/eco-app#99` · branch `issue-99` · driver `claude` · workflow `direct-main` - **Run:** `engineer-claude-eco-app-99` · ward `v0.419.0` · dispatched `2026-07-07T06:37:48Z` - **Comment thread:** 0 included in the pre-flight read, 0 stripped (ward's own automated comments). **Issue body as seeded:** ``` Ship the first slice of the practical-usefulness layer: the `/uses` hub plus the demand-side, task-focused use-case pages. This is follow-up **F** (and the shared hub it needs) from the design on #98. Kai asked to start here because it depends on zero new data - every panel reads data eco-app already hydrates and the `/trade` page already renders. Do NOT build anything recipe-shaped or cost/margin-based here. Those (the recipes page, cost engine, value-per-profession, and the "how to price X" page) are follow-ups A-E on #98 and are gated on the recipe exporter. This ticket is the no-dependency slice only. ## 1. The shared `/uses` hub - Add a `/uses` route (`App.tsx`) and one homepage card in `Home.tsx` (`data-testid` in the `dir-*` family). This is the ONLY homepage card the whole use-case family gets - the individual use-case pages are URL-only, reached from the hub, mirroring how `/item` is only reached from `/items`. - `/uses` is a single page that lists the use cases as cards, each linking to its page. It is NOT the recipes page (that is a separate data hub on #98). - List the four demand-side pages below as live cards. Optionally show the recipe-dependent use cases (from #98's Tier B/C list) as muted "coming soon" cards so the hub reads as the full roadmap, but do not build them. ## 2. The demand-side use-case pages (all buildable now) Each is a task-framed page with a hero stating the job, one primary input (an item picker where relevant, deep-linkable via `?item=<id>`), then panels composed from existing typed clients. Each panel degrades on its own via `fetchJsonOrNull` so one dead source never blanks the page (the `/preview/logistics.json` sibling can 404 on a reset-gated shelf - `fetchLogistics` already resolves to null). Reuse `formatCount` / `prettifyEcoName` from `lib/format.ts`. - **`/uses/demand` - "What's in demand right now."** Rank `LogisticsBoard.supplyGaps` (`lib/logisticsApi.ts`) by `demandQty`, showing the item, the `reason` tag (`no_supp ``` … (truncated to 2000 chars; full body is on this issue) Static container doctrine and seed boilerplate are identical every run and omitted here (they ride ward v0.419.0). </details> <!-- ward-agent-signature --> — Claude (she/her), via `ward agent`
Author
Owner

WARD-OUTCOME: done - /uses hub + four demand-side use-case pages landed on main, all gates green.

This one went smoothly, mostly because the ground was already prepared. The issue was right that it needs zero new data: every panel I built is just a focused re-slice of the same logistics/stores/market planes /trade already renders, so the real work was reading Trade.tsx closely and carving four task-framed views out of it. The typed lib/*Api.ts clients and the fetchJsonOrNull degrade pattern did all the heavy lifting - each page degrades panel-by-panel almost for free.

What fought back a little: the container had no pnpm, so I had to enable it through corepack before ward exec frontend-install would run. And the playwright browser lives outside this container's network namespace, so I couldn't drive the preview server in a real browser - I leaned on the jsdom component tests (which do exercise routing, ranking/joining, and the degraded-when-null branch for every page) plus the production build. The one genuinely interesting page was shop-check, since it's the only one joining two planes (store avgUnitPrice vs market median) - I keyed the join on the raw item id and made it degrade to a clear note when either side is missing.

Mid-run origin/main advanced by three commits (an item-feed rewrite touching format.ts, Items/Item, index.css, FEATURES.md). The merge came out clean with no conflicts, and I re-ran the full test/lint/build on the merged tree before pushing (111 tests green) rather than trusting the pre-merge run.

Confidence is high that the pages render and degrade correctly. The one thing I could not verify is how they look against live server data - QA will be the first eyes on real supply gaps and arbitrage spreads. Possible follow-ups worth filing if QA wants them: the buy-sell and shop-check pickers are flat filter-lists rather than a proper combobox, and I re-declared the supply-gap severity map locally instead of extracting the shared one from Trade.tsx (fine for now, a candidate for a small dedup later).

WARD-OUTCOME: done - /uses hub + four demand-side use-case pages landed on main, all gates green. This one went smoothly, mostly because the ground was already prepared. The issue was right that it needs zero new data: every panel I built is just a focused re-slice of the same logistics/stores/market planes /trade already renders, so the real work was reading Trade.tsx closely and carving four task-framed views out of it. The typed lib/*Api.ts clients and the fetchJsonOrNull degrade pattern did all the heavy lifting - each page degrades panel-by-panel almost for free. What fought back a little: the container had no pnpm, so I had to enable it through corepack before ward exec frontend-install would run. And the playwright browser lives outside this container's network namespace, so I couldn't drive the preview server in a real browser - I leaned on the jsdom component tests (which do exercise routing, ranking/joining, and the degraded-when-null branch for every page) plus the production build. The one genuinely interesting page was shop-check, since it's the only one joining two planes (store avgUnitPrice vs market median) - I keyed the join on the raw item id and made it degrade to a clear note when either side is missing. Mid-run origin/main advanced by three commits (an item-feed rewrite touching format.ts, Items/Item, index.css, FEATURES.md). The merge came out clean with no conflicts, and I re-ran the full test/lint/build on the merged tree before pushing (111 tests green) rather than trusting the pre-merge run. Confidence is high that the pages render and degrade correctly. The one thing I could not verify is how they look against live server data - QA will be the first eyes on real supply gaps and arbitrage spreads. Possible follow-ups worth filing if QA wants them: the buy-sell and shop-check pickers are flat filter-lists rather than a proper combobox, and I re-declared the supply-gap severity map locally instead of extracting the shared one from Trade.tsx (fine for now, a candidate for a small dedup later).
Sign in to join this conversation.
No description provided.