Split api/links/routes.rs into landing.rs, qr.rs, and slimmer routes.rs#116
Open
Split api/links/routes.rs into landing.rs, qr.rs, and slimmer routes.rs#116
Conversation
`api/links/routes.rs` was 2249 lines — about 5x the median routes file. A new contributor (or AI agent) opening it had to load ~370 lines of HTML rendering and ~265 lines of QR styling before reaching the actual route handlers, even when their task only touched link CRUD. Three sibling modules now share the file's responsibilities: - `api/links/landing.rs` (~520 lines) — `LandingPageContext`, `render_smart_landing_page`, and the rendering-only helpers (`social_preview_from_metadata`, `js_escape`, `build_agent_panel`, `action_to_schema_type`). - `api/links/qr.rs` (~365 lines) — `QrOutputFormat`, `render_link_qr` (the orchestrator), `QrRenderOptions`, `LogoImage`, all the `parse_*` validators, `fetch_logo`, and `render_qr`. - `api/links/routes.rs` (~1400 lines) — handlers for link CRUD, resolve, attribution, timeseries, plus the helpers genuinely shared across multiple flows (`html_escape`, `urlencoding`, `canonical_link_url`, `compute_link_status`, `lookup_tenant_domain`, `build_rift_meta`, `check_link_resolvable`, `do_resolve`, `Platform`, `detect_platform`). Helpers used by both routes.rs and the new modules are marked `pub(crate)`: `html_escape`, `urlencoding`, `canonical_link_url`, `Platform`. Same approach as the attribution slice's reuse of `check_link_resolvable` etc. Pure code motion. No behavior change. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Contributor
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
I left `action_to_schema_type` and `social_preview_from_metadata` at the top of `landing.rs` when I created the file — both private helpers above the public `render_smart_landing_page`. That violates the stepdown rule we already codified. Reordered: `LandingPageContext` + `render_smart_landing_page` now sit at the top, all four private helpers (`action_to_schema_type`, `social_preview_from_metadata`, `js_escape`, `build_agent_panel`) collected in a `// ── Helpers ──` section at the bottom. A reader opening the file now sees the file's reason to exist first (the pub(crate) entry point) and descends into helpers as they read. Caught by review, not by the architecture test — the test's enforced file list doesn't yet include `landing.rs`. Worth a follow-up to flip that to a denylist so new helper files are caught automatically. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
api/links/routes.rswas 2249 lines — roughly 5× the median routes file in the codebase. A new contributor (or AI agent) opening it had to scroll past ~370 lines of HTML rendering and ~265 lines of QR styling code before reaching the actual route handlers, even when their task only touched link CRUD. This PR splits the file into three focused siblings.What moved
api/links/landing.rsLandingPageContext,render_smart_landing_page, plus rendering-only helpers (social_preview_from_metadata,js_escape,build_agent_panel,action_to_schema_type)api/links/qr.rsQrOutputFormat,render_link_qr(the orchestrator),QrRenderOptions,LogoImage, allparse_*validators,fetch_logo,render_qrapi/links/routes.rsWhat stayed in routes.rs
do_resolve(used by both resolve handlers)check_link_resolvable(used by resolve and attribution paths)Platform/detect_platform(used across resolve, attribution, landing)compute_link_status,lookup_tenant_domain,canonical_link_url,build_rift_meta(used by JSON resolve and landing)link_error_to_response,is_valid_link_idhtml_escape,urlencoding— used by both routes.rs and the new modulesVisibility model
Same
pub(crate)pattern we used for the attribution slice's helper reuse: types and helpers crossing module boundaries within the crate arepub(crate). This includes:Platform,Platform::as_str(fordetect_platformcallers)html_escape,urlencoding,canonical_link_url(used by landing)LandingPageContext(constructed in routes, consumed by landing)QrOutputFormat,render_link_qr(called from the route handler)Test plan
cargo fmt -- --checkcargo clippy --all-targets -- -D warningscargo test— 107 lib + 145 integration tests passNote on stacking
This branches off
main(which doesn't yet have #115). When #115 (the attribution slice extraction) lands,routes.rswill lose the three attribution handlers, taking it to ~1100 lines. Both PRs are independent code motion in the same file but in non-overlapping regions; rebase is mechanical either way.🤖 Generated with Claude Code