add URL redirects with ETS-cached plug, broken URL tracking, and admin UI
All checks were successful
deploy / deploy (push) Successful in 3m30s

Redirects context with redirect/broken_url schemas, chain flattening,
ETS cache for fast lookups in the request pipeline. BrokenUrlTracker
plug logs 404s. Auto-redirect on product slug change via upsert_product
hook. Admin redirects page with active/broken tabs, manual create form.
RedirectPrunerWorker cleans up old broken URLs. 1227 tests passing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
jamey
2026-02-26 14:14:14 +00:00
parent 23e95a3de6
commit 6e57af82fc
21 changed files with 1493 additions and 24 deletions

View File

@@ -0,0 +1,34 @@
defmodule BerrypodWeb.Plugs.BrokenUrlTracker do
@moduledoc """
Wraps the router to record 404s in the broken URLs table.
Works in dev mode too — Plug.Debugger intercepts exceptions before
error templates render, so we catch NoRouteError here, record it,
then re-raise so the normal error handling continues.
"""
@behaviour Plug
def init(opts) do
router = Keyword.fetch!(opts, :router)
router_opts = router.init([])
{router, router_opts}
end
def call(conn, {router, router_opts}) do
router.call(conn, router_opts)
rescue
e in Phoenix.Router.NoRouteError ->
unless static_path?(conn.request_path) do
Berrypod.Redirects.record_broken_url(conn.request_path, 0)
end
reraise e, __STACKTRACE__
end
defp static_path?(path) do
String.starts_with?(path, "/assets/") or
String.starts_with?(path, "/images/") or
String.starts_with?(path, "/favicon")
end
end