diff --git a/README.md b/README.md index 671d873..29facdb 100644 --- a/README.md +++ b/README.md @@ -1903,6 +1903,36 @@ one; a second `google-maps` row would collide on that name. To actually use it: `` 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/` (`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