Case Study

Redirect Manager

Sitecore Marketplace app for Redirect Maps — full-page workbench with regex authoring and a built-in proxy simulator, a context-panel quick-add, and a dashboard tile for recent activity.

Case Study10 min read

What it does

Redirect Maps are how a Sitecore content team tracks every URL change a site has lived through: pages renamed for a relaunch, campaign URLs retired, vanity slugs added for a product reveal. The data lives in Sitecore as a tree of Redirect Map items, each carrying a pile of source-URL → target mappings with a per-row redirect type. Editing them in classic Content Editor is fast for a developer and miserable for anyone else.

Redirect Manager is a Sitecore Marketplace app that puts Redirect Maps where editors actually work. Three surfaces ship from one app installation:

  • Full Page — the daily-driver workbench, split across two tabs. Manage lists every redirect map in the tenant, opens a map into a virtualized table that scales to thousands of rows, supports both Pattern and Regex source modes with save-time validation, and exposes a hero CTA that triggers a real publish to the live site. Test simulates how the upstream Content SDK RedirectsProxy would evaluate any URL against the loaded redirect inventory — structured-card trace per pipeline stage so a content-ops person can debug "why didn't my redirect fire?" without leaving the app.
  • Page Builder Context Panel — a focused inline form for the most common ask: "I'm editing this page, I just renamed it, add a redirect for the old URL." One click, one form, one row added to whichever map the user selects.
  • Dashboard Widget — at-a-glance health and recent activity. A content-ops manager glances at the dashboard and sees whether any map needs attention before they even open the editor.

All three talk to the same SitecoreAI Authoring GraphQL surface. The product is a client-side iframe app — no backend, no token cache, no persisted state outside the editor.

3
extension points
from one installation
5
shipped releases
(foundation · redesign · publish · regex+Test · drift)
49
architecture decisions
captured as ADRs
100%
upstream-fixture parity
in the local simulator

How it actually works

Three SDK conventions did the heavy lifting once they were nailed down, and each one is reused across all three surfaces.

  • Aliased field(name:) accessors read named fields explicitly instead of paging the generic fields(...) connection. The workbench list-view payload that used to come back at ~4 KB per map now comes back in ~1 KB — ~75% smaller, and faster to render at the table scale Sitecore tenants reach.
  • The UrlMapping URL-encoded contract. Sitecore stores the source/target pair list as a single string with = between source and target and & between rows, both URL-encoded. ADR-0008 pinned the parse-and-write contract before any UI touched it, so every surface reads and writes through one canonical path.
  • The Authoring write envelopes. createItem does not accept an id — Sitecore mints the GUID. renameItem is a dedicated separate mutation; renaming is not a property update. Every response wraps under { item { … } }. addItemVersion is the canonical version verb. Each of these is a small surprise that's faster to know than to re-discover.

The publish path is its own integration. It talks to the SitecoreAI Publishing v1 API at the shared edge-platform.sitecorecloud.io host. The Jobs API has an asymmetry worth knowing about: GET /jobs returns a flat shape (options.xmc.{type, mode, locales}) while POST /jobs needs the nested form (options.xmc.site.{mode}). Passing the flat shape to POST crashes the model binder with a 500, not a 400. Trust the spec; treat the listing response as informational.

The three surfaces

Surface · 01

Full Page — the daily-driver workbench

xmc:fullscreen — the SitecoreAI Full Screen extension point, two tabs

The default view a content ops person lands on when they want to manage redirects in bulk.

  • Manage tab — list of every Redirect Map — a virtualized table backed by react-virtuoso so the list stays smooth at thousands of maps. Each row shows the map name, the row count, and the last-modified stamp.
  • Manage tab — map editor — open a map, see every row in a virtualized grid: source URL, target, redirect type. Inline edit. Inline create. Inline delete. The UrlMapping contract serializes the pile back to Sitecore in one write.
  • EditRowModal with Pattern / Regex toggle — every row edit happens in a small focused modal with a segmented Pattern / Regex source-mode toggle. Save-time new RegExp(source, flags) validation blocks malformed patterns before they reach Sitecore; capture-group references in the destination are cross-checked against the source group count.
  • Test tab — local simulator with structured trace — paste a URL, see exactly how the upstream Content SDK RedirectsProxy would evaluate it against the loaded redirect inventory: normalize → candidate paths → per-row evaluation → capture-group substitution → flag effects → dispatch. Each stage is a card; the matched row links back into Manage. The simulator is a verbatim local port with 100% parity against imported upstream test fixtures.
  • Test tab — upstream parity check — an on-demand "Check upstream" button compares the local simulator’s baseline SHAs against Sitecore/content-sdk via the GitHub commits API. When the simulator is current, a quiet inline success status confirms it. When upstream has moved, a destructive-tinted banner above the trace area tells you the trace may be subtly inaccurate and points at the dev-time slash command that re-ports the changes.
  • Hero publish CTA — a single button at the top of the workbench fires a real site publish through the SitecoreAI Publishing v1 API and tracks the job to terminal state with a 3-second poll. Cross-session resume via localStorage means a refresh doesn’t lose the job.
  • Three RedirectType values — 301 / 302 / Server Transfer. The picker is constrained to Sitecore’s actual enum (PRD-002 reconciled this against shipped code; the spec had four, reality had three).
Surface · 02

Page Builder Context Panel — inline quick-add

xmc:pages:contextpanel — the SitecoreAI Page Builder side panel

The right place at the right time: you're editing the page, you just renamed it, add a redirect without leaving the editor.

  • Inline quick-add form — picks which Redirect Map to write into, captures the source URL the editor wants to redirect from, defaults the target to the current page. Submit. The row lands in the chosen map and the page editor never lost focus.
  • Map picker with localStorage memory — remembers the last-used map per tenant, so the common case is one fewer click. Versioned (ADR-0022) so a schema bump doesn’t leave stale state in the editor.
  • Exact-match guardrail — when the source URL already exists in the selected map, the form surfaces the conflict before submission instead of silently overwriting (ADR-0005).
  • Inline replacement of the older modal flow — PRD-002 evolved the panel from a separate modal into an inline form because the editor context is already focused work; the modal added an unnecessary mode switch.
Surface · 03

Dashboard Widget — at-a-glance health

xmc:dashboardwidget — the SitecoreAI Dashboard tile

The thing a content ops manager glances at to know whether anything needs attention.

  • Hero count + sparkline — total redirect maps across the tenant, with a sparkline that shows the trend over recent days.
  • Top destinations list — the most-redirected-to URLs across the tenant, surfaced so the team knows where traffic is being funneled.
  • Recently shipped tile — the last published change, so an opener of the dashboard can see “Redirects updated 4h ago by Anna” without opening anything.
  • Preview-data banner — where the V4 visual chassis shows content that doesn’t yet have a real data source, a small banner makes that explicit so operators don’t mistake mocks for live values. A follow-on PRD will wire each banner-marked element to a live source.

What shipped, in five acts

The product reached its current shape through five sequential PRDs against a live tenant. Each one earned a /ship against real traffic before the next one started.

Foundation
2026-05-12

List, create, edit, delete Redirect Maps and their rows across all three surfaces. Shared SDK plumbing, the UrlMapping URL-encoded contract pinned by ADR-0008, en-only operation called out explicitly as a foundation decision so multilingual could be addressed cleanly later.

V4 Blok Elevated redesign
2026-05-15

Adopted a marketing-grade visual language across all three surfaces. Evolved the UX where the V4 marketing POC showed a better interaction pattern — the Page Builder Context Panel got an inline quick-add form replacing the older modal, and hero-scale h1 count headers replaced the quieter section headers. Preserved the SDK contract one-to-one; no new GraphQL surfaces.

Sitecore publish
2026-05-17

Wired the placeholder hero CTA to the real SitecoreAI Publishing v1 API. 3-second polling on the in-flight job, cross-session resume via localStorage plus a name-prefix list scan, button locks while polling, toast updates on terminal state. A Tranche 3 amendment post-smoke scoped the action correctly: site-scoped publish only, en-only locales, no per-map publish (Sitecore silently no-ops Redirect Map items at Edge).

Regex source mode + Test tab
2026-05-22

Added a Pattern / Regex toggle inside a focused EditRowModal — save-time new RegExp() validation blocks malformed patterns; capture-group references in the destination cross-checked against source group count. Then added a Test tab with a verbatim local port of upstream RedirectsProxy: pipeline-stage trace cards, 100% parity against imported upstream test fixtures, AST-walking extractor that regenerates the fixture file from upstream source so the parity contract stays mechanical, not vibes-based.

Upstream drift detection
2026-05-28

Closed the parity contract over time. The Test tab now carries an on-demand "Check upstream" button that compares baseline SHAs against Sitecore/content-sdk via the GitHub commits API; when upstream moves, a destructive-tinted banner appears with the last-sync timestamp. A dev-time /sync-redirect-proxy Claude Code slash command in the product repo fetches latest upstream, proposes a verbatim re-port via Claude Code's edit flow, regenerates the AST-extracted fixtures, runs the test suite, and on green auto-bumps the snapshot SHAs. Zero LLM dependency reaches the deployed app — AI lives only at dev time.

The chapter worth naming

Between the foundation and the redesign, a fourth PRD was attempted — PRD-001, multilingual maps with per-language overrides. The thesis was reasonable: Redirect Map items carry per-language versions, so de mappings can differ from en. The plan was credible. The architecture was credible. The mocks were credible.

Two days into implementation, a real-tenant capture probe introspected the stock Redirect Map template's field definitions on the live tenant.

SHARED
UrlMapping
field sharing
SHARED
RedirectType
field sharing
SHARED
3 boolean flags
(Sitecore-prefixed)
UNVERSIONED
__Display name
only

UrlMapping — the field PRD-001's whole multilingual story depended on — is SHARED. One value across all languages on the stock template. No per-language override path that didn't involve replacing the template, which would have orphaned every existing redirect map in every customer tenant the app had ever been installed into.

PRD-001 was cancelled the same day. Two days spent. Two-to-four weeks of architecture, task breakdown, implementation, smoke, and retro not spent. The captured field-versioning matrix lives as a reference artefact for any future multilingual proposal.

That cancellation was the first time the agentic pipeline produced a red verdict at the spike phase — a moment worth its own essay, The Real-Tenant Probe.

The product itself proceeded straight from the foundation to PRD-002's visual redesign. With multilingual definitively off the table for the stock template, the next two PRDs landed on a foundation that was already proven against live traffic.

What you get if you install it

Value 01

Redirects live where editing happens.

An editor never has to alt-tab from the page builder to a separate tool to add a redirect. The Context Panel form is right there; the workbench is two clicks away on the main nav.

Value 02

Regex authoring with a built-in safety net.

The EditRowModal’s Regex mode catches malformed patterns at save time via new RegExp(source, flags) — no more publish-and-pray. Capture-group references in the destination are cross-checked against the source group count. The Test tab then dry-runs the regex against any URL, showing exactly which row would win.

Value 03

Lists scale to thousands of rows.

The workbench uses virtualized lists for both the map index and the map editor, so a tenant with 10,000 redirect rows still scrolls at 60 fps.

Value 04

Publish is one click — with honest job tracking.

Hero CTA triggers a real Sitecore site publish. The job is polled every 3 seconds until terminal state; localStorage persists the in-flight job so a tab refresh doesn’t lose it. The button locks while a job is running.

Value 05

The simulator never quietly drifts.

The local RedirectsProxy port maintains 100% upstream-fixture parity at port time — and the on-demand "Check upstream" tells you the moment that contract breaks. A dev-time slash command in the repo re-ports the changes verbatim with a click-through review.

Value 06

One install, three surfaces.

Full Page, Context Panel, and Dashboard Widget are all activated by a single Marketplace app registration. No second install, no second auth, no second sync.

Value 07

No backend to maintain.

The whole product runs inside the Cloud Portal iframe, talking to Sitecore through the Authoring GraphQL surface. There is no server to operate, no token cache to rotate, no infra to bill.

Value 08

Built end-to-end against a real tenant.

Every shipped release ended on a real-tenant smoke against production data, not a mock. Tranche 3 of the publish PRD alone reshaped scope before /ship on the back of two smoke findings.

Where it goes next

Two PRDs are in the queue.

Drift detection automation. The current "Check upstream" is on-demand: an operator clicks, the app fetches, the banner appears when SHAs differ. The next release adds a scheduled background check (cron job against the GitHub commits API) and a PAT-based auth path so a team sharing an egress IP can run more checks without hitting the 60-req/hr/IP limit on unauthenticated calls. A small follow-on also lands a gh pr create step inside the /sync-redirect-proxy slash command so the verbatim re-port can ship without leaving Claude Code.

Analytics. The dashboard widget currently shows recent activity; the analytics PRD wires real per-redirect hit counts and last-served timestamps so the team can see which redirects are still load-bearing and which can be retired.

Both will ship through the same agentic pipeline that delivered the foundation, the redesign, the publish, regex + Test tab, and drift detection — and both will start with a two-day real-tenant probe against their single load-bearing assumption before deep planning. That move is now standard.

Related case studies