Document /r and /sticker short-link redirects in README
Neither route was mentioned anywhere despite predating this session (/r) or being added this session (/sticker) — every other route/collection this size gets its own section. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G5mssdCBir9kyXTmqBjV3h
This commit is contained in:
@@ -1903,6 +1903,36 @@ one; a second `google-maps` row would collide on that name. To actually
|
||||
use it: `<GoogleMapsEmbed src="<Google Maps embed URL>" title="..." />`
|
||||
anywhere.
|
||||
|
||||
## Short links & QR redirects
|
||||
|
||||
`app/r/[code]/route.ts` and `app/sticker/[code]/route.ts` are static
|
||||
short-link routes (e.g. printed on a flyer or a physical sticker's QR
|
||||
code) that resolve a `code` against Payload's `redirects` collection and
|
||||
307-redirect (`redirect()`, deliberately not `permanentRedirect()` — the
|
||||
target can change at any time and this must never be client-cached) to
|
||||
that doc's `targetPath`. Both routes call the same
|
||||
`resolveAndTrackRedirect(code, urlPrefix)` in `app/lib/payload.ts`, which
|
||||
also fire-and-forget PATCHes `clickCount`/`lastClickedAt` on every hit
|
||||
(tracking failure only logs — never worth stranding a visitor over).
|
||||
|
||||
- **`/r/[code]`** is the default scheme for all new short links —
|
||||
`einfach-produktiv.com/r/aktion-sommer`.
|
||||
- **`/sticker/[code]`** exists only because a batch of physical stickers
|
||||
was already printed as `einfach-produktiv.com/sticker/<code>` (`echt`,
|
||||
`geheimnis`, `fokus`) before `/r/[code]` existed and can't be
|
||||
reprinted — same collection, same lookup, just a second fixed prefix.
|
||||
- The Redirects doc's `urlPrefix` field (`/r` or `/sticker`) isn't just an
|
||||
admin label — `resolveAndTrackRedirect` filters on it too, so a code is
|
||||
only reachable under whichever prefix its doc is actually set to.
|
||||
Changing `urlPrefix` in Payload immediately changes which route serves
|
||||
that code.
|
||||
- Defense in depth: `targetPath` must start with `/` and not `//` (open-
|
||||
redirect guard, same check `app/api/preview/route.ts` does), enforced
|
||||
both in Payload's own field validation and again in each route.ts before
|
||||
calling `redirect()`.
|
||||
- A deactivated (`active: false`) doc — or no matching doc at all —
|
||||
renders a plain 404 (`notFound()`), not a redirect to some fallback.
|
||||
|
||||
## Product image gallery
|
||||
|
||||
`ProductGallery.tsx` — main image + thumbnail strip, swappable on click OR
|
||||
|
||||
Reference in New Issue
Block a user