Skip to content

Ad Network as a first class section: what to review โ€‹

FieldValue
Branchfeat/admin-and-merchant-portals, draft PR #976: feat(admin): portal navigation, financials and monitoring, plus the agent-process work behind them, not merged
ProjectREADME.md
Issue#986: feat(admin): promote Ad Network to a first class section with Delivery, Placements and Review tabs
Servers you needAdmin portal on http://localhost:3001 (npm run admin:dev). Admin Storybook on http://localhost:6008 (npm run storybook:admin)
Local originsRequired for the Delivery tab. The Review tab needs merchants-api, which already proxies locally
Test plandocs/engineering/testing/runs/ad-network-first-class/README.md, 8 of 10 scenarios passed, 2 blocked on data

Why does the Delivery row say "needs the local origins"? โ€‹

The Delivery tab reads analytics-api, which the admin portal proxies to the DEPLOYED service by default. โ€‹

What changed here? โ€‹

Ad Network became a top-level Platform item beside Venues and Merchants. โ€‹

  • Your words on 2026-08-24: it needs its own dedicated considerations. It used to be /admin/analytics/dashboards/ads, one tab among five, two clicks deep.
  • Option B was chosen: a section with tabs, not a bare promotion.

Three tabs, which are the ad lifecycle. โ€‹

TabWhat it isWhere it came from
DeliveryThe existing Ad Delivery dashboardMoved from analytics/dashboards/ads
PlacementsThe inventory viewNew. The concept existed in the data with no surface owning it
ReviewThe gate an offer passes to enter the networkMoved from merchants/offer-review

Merchants changes meaning as a result. โ€‹

  • With Offer review gone, Merchants is accounts and applications only. That is a real change to a section nobody asked to change, so it is named here rather than left to be discovered.

A defect was waiting at the destination, and its second half is the important one. โ€‹

  • The Offer review queue read empty on localhost regardless of what was in the database, with no error and no failed request. Two causes: vite.config.mjs proxied no /api/admin route, and parseResponse turned a non-JSON 200 (the app shell answering) into an empty list.
  • Both fixed. Verified rather than inferred: an unauthenticated request went from 200 text/html to 401 application/json.
  • This is why the 2026-08-24 design survey recorded the queue as empty and reasoned about it as a product state. It was not a product state.

Where do I look, and what am I looking for? โ€‹

The section and its tab strip http://localhost:3001/admin/ad-network โ€‹

  • It should redirect to /admin/ad-network/delivery.
  • Three tabs: Delivery, Placements, Review. The sidebar entry should be top level under Platform, one click, beside Venues and Merchants.

Delivery http://localhost:3001/admin/ad-network/delivery โ€‹

  • Needs the local origins.
  • It should render inside the section chrome rather than as a standalone analytics dashboard.
  • The old path /admin/analytics/dashboards/ads should redirect here.
  • The chart still segments Hero, Inline, Feed and Unknown. Unknown is a data-quality bucket for rollup rows whose placement did not match the vocabulary, and it stays on the chart deliberately.

Placements http://localhost:3001/admin/ad-network/placements โ€‹

  • The inventory half is real: three surfaces, where each appears, how contended each is, with copy taken from the placement table in docs/economics/AD_PLACEMENT_ECONOMICS.md so the portal and the economics model use the same words.
  • The three per-surface figures (fill rate, eligible offers, CTR) render through Scaffold, dated, pointing at an issue. They are not faked and they are not zeroes. A zero would have lied: it reads as "nothing is delivering" when the truth is "nothing has been asked".
  • Unknown is deliberately absent from this tab. It is not inventory anyone can buy.

Review http://localhost:3001/admin/ad-network/review โ€‹

  • The queue should read {"offers":[],"count":0}: genuinely empty in dev, which is a different claim from the one the survey made.
  • The old path /admin/merchants/offer-review should redirect here.
  • If it reads empty with no error at all, that is now the true state rather than the swallowed-error state. A failed request should now throw and show.

Storybook http://localhost:6008 โ€‹

What is deliberately NOT done? โ€‹

The Offer review redesign. This project does the MOVE, not the redesign. โ€‹

  • You named that redesign separately. Keeping the two apart is what stops one build turning into three.

The per-placement aggregate behind the three figures. โ€‹

Pacing and fill rules. โ€‹

  • The Ad Delivery copy already gestures at them with nothing behind it. Out of scope for the move, named so it is not lost.

What open findings touch this project? โ€‹

Cross-referenced from ../merchant-and-venue-dashboards/branch-review-0828.md.

  • AdDeliveryDashboard.jsx got a diff read, not a line-by-line pass. It is one of four large rewrites the reviewer named as reviewed at a shallower depth than the rest.
  • The non-JSON 200 hardening was applied to merchantsApi.js and NOT to analyticsApi.js. That is finding 7 in the review, and it belongs to the analytics surfaces rather than this one, but the Delivery tab reads through the unhardened path.
  • No finding in the review targets the Placements or Review tab directly.

What issue does each piece close? โ€‹

PieceIssueState
The section, its three tabs, and the moves#986: feat(admin): promote Ad Network to a first class section with Delivery, Placements and Review tabsBuilt on branch
The empty Offer review queue on localhost#981: bug(admin): the Offer review queue reads empty on localhost, because vite proxies no /api/admin routeClosed, both halves fixed
The three per-surface figures on Placements#998: feat(analytics): expose a per-placement aggregate so the Ad Network Placements tab can show fill rate, eligible offers and CTROpen, scaffolded and dated
The Scaffold component the figures render through#991: feat(admin): a shared Scaffold component whose required props make a placeholder declare its age and its wiring issueBuilt on branch

Built with VitePress