URL Manager — Improvement & Growth Plan
Package: capell-app/url-manager · Kind: package · Tier: premium · Product group: Capell Search & SEO · Bundle: search-seo · Status: Draft
1. Snapshot
Section titled “1. Snapshot”URL Manager is an action-driven redirect engine for Capell. It surfaces two admin Filament pages (RedirectRulesPage, NotFoundOpportunitiesPage) and decorates Core’s RedirectResolver binding on the public request path via UrlManagerRedirectResolver. Core domain logic lives in src/Actions — ResolveRedirectRuleAction (exact/prefix/regex matching + hit recording), UpsertRedirectRuleAction, RecordNotFoundOpportunityAction, ConvertNotFoundOpportunityToRedirectAction, the CSV import/export family, BuildNotFoundRedirectSuggestionsAction, and ImportSeoSuiteBrokenLinksAction. Three models/tables back it: url_manager_redirect_rules, url_manager_redirect_hits, url_manager_not_found_opportunities. Deps: capell-app/core, capell-app/admin, lorisleiva/laravel-actions, spatie/laravel-data; soft-supports capell-app/seo-suite.
Current marketplace summary (verbatim): “Manage redirects, preserve moved URLs, track redirect hits, and turn repeated 404s or SEO Suite broken URL findings into redirect opportunities.” Current screenshot-quality follow-up demotes the 8 existing docs/screenshots/* PNGs from capell.json because visual audit showed the captures are dominated by a broken default shell/oversized black arc rather than usable Capell UI. docs/screenshots.json still defines the runner contract so the redirect workflows can be recaptured and re-promoted after the runner loads the correct assets.
2. Improvements (existing functionality)
Section titled “2. Improvements (existing functionality)”- Done/Shipped: Lowercase / canonicalise the matched path in normalisation —
NormalizeManagedUrlAction::handle()lowercases managed paths before hashing and resolution. Evidence:tests/Unit/Actions/RedirectRuleActionsTest.phpcovers/Old-Page/resolving from/old-page?utm_source=test. —src/Actions/NormalizeManagedUrlAction.php— S - Done/Shipped: Strip the query string before hashing for match (keep it only for
preserve_queryreattachment) —NormalizeManagedUrlAction::pathFromUrl()returns onlyPHP_URL_PATH; query reattachment remains inUrlManagerRedirectResolver::targetUrl(). Evidence:tests/Unit/Actions/RedirectRuleActionsTest.phpandtests/Unit/Filament/RedirectRulesPageTest.phpcover query-free matching and preserve-query response behavior. —src/Actions/NormalizeManagedUrlAction.php, consumed byResolveRedirectRuleAction::findExactRule()— M - Done/Shipped: Make hot-path hit recording asynchronous / deferrable —
ResolveRedirectRuleAction::recordHit()defers redirect hit writes to an applicationterminating()callback by default viacapell-url-manager.hit_recording.defer, while keeping synchronous recording available for tests/explicit callers.RecordRedirectHitActionupdates rule counters atomically when the deferred callback runs. Evidence:tests/Unit/Actions/RedirectRuleActionsTest.phpcovers resolving a redirect without any immediateredirect_hitsrow orhit_countupdate, then recording afterapp()->terminate(). —src/Actions/ResolveRedirectRuleAction.php,src/Actions/RecordRedirectHitAction.php,config/capell-url-manager.php— M - Done/Shipped: avoid unbounded prefix/regex scans. —
findPrefixRule()builds concrete path candidates and resolves them withwhereIn(...), priority, and longest-source ordering;findRegexRule()is priority ordered and capped bycapell-url-manager.redirects.regex.max_rules_checked. —src/Actions/ResolveRedirectRuleAction.php,config/capell-url-manager.php— M - Done/Shipped: add a
priority/ordering column toredirect_rules. — Redirect rules persistpriority, the form exposes bounded priority editing, the table displays/sorts it, and resolver order honors priority for exact/prefix/regex paths. —database/migrations/2026_05_31_000001_create_url_manager_redirect_rules_table.php,database/migrations/2026_06_04_000001_add_priority_to_url_manager_redirect_rules_table.php,src/Actions/ResolveRedirectRuleAction.php,src/Filament/Pages/Schemas/RedirectRuleForm.php— M - Done/Shipped: form-level validation parity with the Action. —
RedirectRuleFormcallsPrepareRedirectRuleDataActionfrom Filament validation closures so invalid regex, disallowed status codes, absolute target host rejection, self redirects, and loop checks surface before save. —src/Filament/Pages/Schemas/RedirectRuleForm.php,src/Actions/PrepareRedirectRuleDataAction.php— S - Done/Shipped: index
redirect_hits.hit_at/ rule FK for analytics queries. — Redirect hits now have a compoundredirect_rule_id, hit_atindex, andPruneRedirectHitsAction/capell:url-manager-prune-hitsprune old hit rows using the configured retention window. —database/migrations/2026_05_31_000002_create_url_manager_redirect_hits_table.php,src/Actions/PruneRedirectHitsAction.php,src/Console/Commands/PruneRedirectHitsCommand.php— S
3. Missing Features (gaps)
Section titled “3. Missing Features (gaps)”Mapped to capabilities[] in capell.json:
- Done/Shipped: redirect loop & chain detection. —
PrepareRedirectRuleDataAction::resolveFinalTargetUrl()follows active exact-rule chains up to the configuredmax_chain_depth, rejects cycles, and collapses intermediate exact targets to their final target. —src/Actions/PrepareRedirectRuleDataAction.php,config/capell-url-manager.php - Done/Shipped: 404 capture is wired in-repo. —
UrlManagerServiceProviderappendsRecordNotFoundOpportunityMiddlewareto the frontend route middleware registry, and the middleware records non-ignored 404 responses as opportunities with site/language context. —src/Providers/UrlManagerServiceProvider.php,src/Http/Middleware/RecordNotFoundOpportunityMiddleware.php - Done/Shipped: Resolver auto-wiring verification. — Capell Core binds
RedirectResolver::classtoPageUrlRedirectResolver, Capell Frontend invokesresolve(RedirectResolver::class)->resolve(...)inResolvePublicPageRequestActionbefore returning public pages, and URL Manager decorates the bound resolver when installed. Package coverage verifies the decorator preserves Core decisions and falls back to managed redirects. —../capell-4/packages/core/src/Providers/CapellServiceProvider.php,../capell-4/packages/frontend/src/Actions/ResolvePublicPageRequestAction.php,src/Providers/UrlManagerServiceProvider.php,tests/Unit/Actions/RedirectIntegrationActionsTest.php - Done/Shipped: auto slug-change redirects beyond exact.
RecordChangedUrlRedirectActioncreates the exact redirect for a changed page URL and, whencreate_prefix_redirect_on_parent_moveis enabled, also records a prefix redirect for parent moves so child URLs continue to resolve. —src/Actions/RecordChangedUrlRedirectAction.php,config/capell-url-manager.php,tests/Unit/Actions/RedirectRuleActionsTest.php - Done/Shipped: canonical URL management policy.
BuildCanonicalUrlActionprovides the URL Manager canonical policy: force scheme/host when configured, lowercase paths, add/remove trailing slashes, and strip configured tracking query keys. The config exposes the policy and docs identify it as a callable integration surface rather than automatic tag rendering. —src/Actions/BuildCanonicalUrlAction.php,config/capell-url-manager.php,docs/overview.md,tests/Unit/Actions/RedirectRuleActionsTest.php - Done/Shipped: bulk operations in admin. —
RedirectRulesTablewires bulk activate, bulk disable, and bulk delete actions, plus import, preview-import, export, and template-download header actions. —src/Filament/Pages/Tables/RedirectRulesTable.php - 301 vs 302 guidance / defaults per source — status code is a free Select (301/302/307/308) with no guidance; auto-suggest 301 for permanent moves, 302 for temporary, and warn on 302 for slug-change redirects. — table-stakes polish
- Done/Shipped: Open-redirect allowlist for absolute targets —
PrepareRedirectRuleDataActionvalidates absolute target hosts againstcapell-url-manager.redirects.absolute_target_allowed_hostsplus the configuredapp.urlhost when enabled. Evidence:tests/Unit/Actions/RedirectRuleActionsTest.phpcovers rejected, allowed, update, and import-preview paths. - Done/Shipped: Health check implementation —
UrlManagerHealthChecknow checks required tables, manifest-declared action classes, runtime/admin provider metadata, and required table metadata. Evidence:tests/Unit/Health/UrlManagerHealthCheckTest.php.
4. Issues / Risks
Section titled “4. Issues / Risks”- Done/Shipped: Health check is a stub — resolved by
UrlManagerHealthCheck::runDiagnostics(), which returns table, action class, and provider metadata diagnostics and fails missing table/action/provider metadata cases. Evidence:tests/Unit/Health/UrlManagerHealthCheckTest.php. —src/Health/UrlManagerHealthCheck.php,capell.jsonhealthChecks - Done/Shipped: Open-redirect surface — resolved by
PrepareRedirectRuleDataAction::assertAllowedTargetUrl(), backed by configurable absolute target host allowlists and import/update coverage. Evidence:tests/Unit/Actions/RedirectRuleActionsTest.php. —src/Actions/PrepareRedirectRuleDataAction.php,config/capell-url-manager.php - Done/Shipped: untrusted regex patterns are validated and bounded before save. —
PrepareRedirectRuleDataAction::normalizeRegexSource()trims regex sources, rejects empty, invalid, or overlong patterns usingcapell-url-manager.redirects.regex.max_pattern_length, and resolver checks are capped bymax_rules_checked. —src/Actions/PrepareRedirectRuleDataAction.php,src/Actions/ResolveRedirectRuleAction.php,config/capell-url-manager.php - Done/Shipped: loop detection — see §3; save-time exact-rule chain traversal rejects cyclic redirect sets before they can be served to the public.
- Done/Shipped: Synchronous double-write per redirect — resolved by deferring hit-row creation and rule counter updates to an application termination callback by default, so public redirect resolution can return the redirect decision before hit writes execute. Evidence:
tests/Unit/Actions/RedirectRuleActionsTest.phpcovers no immediate hit row or counter update beforeapp()->terminate(). - No result caching of resolved rules — exact-match lookups by
source_hashare cheap but prefix/regex resolution is O(rows) in PHP per request with no memoisation. ManifestadminQueryBudget: 40covers admin, but there is no frontend query budget enforced. - Done/Shipped: Test coverage gaps reconciled. — Existing package coverage now proves fallback chaining/Core-decision precedence, managed resolver preserve-query reattachment, open-redirect rejection for create/update/import preview, loop/cycle rejection, SEO Suite broken-link import, health diagnostics, and manifest requirements. URL Manager has no public Blade output surface, so anonymous/non-admin output-safety coverage is not applicable for this package. —
tests/Unit/Actions/RedirectIntegrationActionsTest.php,tests/Unit/Actions/RedirectRuleActionsTest.php,tests/Unit/Actions/NotFoundOpportunityActionsTest.php,tests/Unit/Filament/RedirectRulesPageTest.php,tests/Unit/Health/UrlManagerHealthCheckTest.php,tests/Unit/ManifestRequirementsTest.php - Done/Shipped: Action exception messages are translated. — URL normalization, redirect validation, import preview/import failures, CSV parsing, and 404 opportunity conversion now raise package translation strings via
capell-url-manager::validation.*. —src/Actions/PrepareRedirectRuleDataAction.php,src/Actions/ImportRedirectRulesAction.php,src/Actions/PreviewRedirectRulesImportAction.php,src/Actions/ConvertNotFoundOpportunityToRedirectAction.php,src/Actions/ParseRedirectRulesCsvAction.php,resources/lang/en/validation.php - Done/Shipped: config file added. —
config/capell-url-manager.phpnow exposes status-code allowlist, absolute target hosts, redirect chain depth, regex bounds, prefix redirect behavior, deferred hit recording, hit retention, 404 capture settings, ignored 404 prefixes, and canonical URL behavior; the service provider publishes it viahasConfigFile('capell-url-manager').
5. Marketplace & Selling
Section titled “5. Marketplace & Selling”Critique. The manifest summary is accurate but reads as a feature list, not a value statement, and buries the strongest hook (recovering lost SEO traffic). The package manifest now uses recovery-led marketplace copy, but the previously promoted 8 screenshots are demoted until they are recaptured as styled Capell UI instead of broken default-shell output.
Improved 1-sentence summary: Stop losing traffic to broken links — manage redirects, auto-preserve moved page URLs, and turn repeated 404s into recovered SEO.
Improved 3–4 sentence description: URL Manager keeps your site’s link equity intact when pages move or get renamed. It auto-creates redirects when a page URL changes, resolves exact, prefix, and regex rules on the live request, and tracks hit counts so you can see which redirects matter. Repeated 404s and SEO Suite broken-link findings surface as one-click redirect opportunities, with CSV import/export for bulk migrations. Built for editors and SEO teams who need redirect hygiene without touching server config.
Screenshot/media gaps: Reopened. The existing docs/screenshots/* set (create/edit form, import workflow, export workflow, health snapshot) and matching Capell runner contract remain useful as target definitions, but the committed captures are not buyer-facing quality and are no longer promoted in capell.json. Recapture styled light/dark redirect workflows before marking marketplace media complete. Still missing: the 404 Opportunities table with a convert action, and a redirect-hit analytics view (once §2 analytics lands).
Pricing / tier / bundle positioning: premium tier inside the search-seo bundle is right. Cross-sell is the lever: it supports seo-suite and consumes its BrokenLink rows, so position as the remediation half of an SEO loop (SEO Suite finds, URL Manager fixes). Strong fit with the migration-assistant and wordpress-importer Extension Suites — bulk redirect import is exactly what platform migrations need; surface ImportRedirectRulesAction as their redirect-mapping target. Bundle it as the default redirect layer whenever migration-assistant is purchased.
Differentiators / value props / target buyer: differentiator is the closed loop — automatic slug-change capture + 404 mining + SEO Suite import feeding suggested redirects, all inside the CMS. Target buyer: SEO managers and content teams on multi-site Capell installs who run frequent content reorganisations and migrations.
Keywords/tags: redirects, 301 redirect, 404 management, url management, seo, link equity, slug change, redirect import, broken links, site migration, regex redirect, multi-site.
6. Prioritized Roadmap
Section titled “6. Prioritized Roadmap”| Item | Bucket | Effort | Impact | Section ref |
|---|---|---|---|---|
Done/Shipped: Implement real UrlManagerHealthCheck (tables/actions/provider discoverable) | Done | S | High | §4 |
Done/Shipped 2026-06-08: Add managed 410 Gone rules for bulk/imported URL removals | Done | M | High | §3 — empty-target imports, form validation, resolver filtering, and frontend middleware |
Recapture styled marketplace screenshots from the existing docs/screenshots/* runner contract | Later | S | High | §5 — deferred until styled runner recapture; no implementation blocker |
| Done/Shipped: Strip query from match key; lowercase normalisation | Done | M | High | §2 |
| Done/Shipped: Open-redirect host allowlist for absolute targets | Done | M | High | §3, §4 |
| Done/Shipped: Defer hot-path hit recording (queue / terminating) | Done | M | High | §2, §4 |
| Done/Shipped: Validate & bound regex patterns at write time (ReDoS) | Done | M | High | §4 |
| Done/Shipped: Redirect loop & chain detection on save | Done | M | High | §3 |
| Done/Shipped: Wire 404 capture into frontend route middleware | Done | M | High | §3 |
Done/Shipped: Verify/confirm Core invokes the bound RedirectResolver | Done | S | High | §3, §4 |
Done/Shipped: Add priority ordering column + resolver/form support | Done | M | Med | §2, §3 |
| Done/Shipped: Replace unbounded prefix/regex scans with bounded candidate resolution | Done | M | Med | §2, §4 |
| Done/Shipped: Tests: resolver fallback, preserve_query, open-redirect, loops, SEO import | Done | M | High | §4 |
Done/Shipped: Add config/ for status codes, host allowlist, regex/retention | Done | S | Med | §4 |
| Done/Shipped: Prefix-cascade auto-redirects on page-subtree moves | Done | M | Med | §3 |
| Done/Shipped: Canonical URL management surface | Done | L | Med | §3 |
| Done/Shipped: Translate Action exception messages | Done | S | Low | §4 |