Redundant routes: /admin/ and /ui/ render the same content in hero_books #135

Open
opened 2026-05-25 15:04:16 +00:00 by mahmoud · 1 comment
Owner

Description

In hero_books, the following two routes appear to render identical content:

  • http://[50c:2786:2581:b5fe:3::1]:9988/hero_books/admin/
  • http://[50c:2786:2581:b5fe:3::1]:9988/hero_books/ui/

These routes seem redundant. Additionally, the admin route should likely be prefixed appropriately (e.g., admin_ui).

Expected behavior: Clarify whether both routes are necessary. If they are redundant, consolidate them into a single route or differentiate their purposes clearly. The admin interface should use a consistent, properly prefixed route.

### Description In hero_books, the following two routes appear to render identical content: - `http://[50c:2786:2581:b5fe:3::1]:9988/hero_books/admin/` - `http://[50c:2786:2581:b5fe:3::1]:9988/hero_books/ui/` These routes seem redundant. Additionally, the admin route should likely be prefixed appropriately (e.g., `admin_ui`). Expected behavior: Clarify whether both routes are necessary. If they are redundant, consolidate them into a single route or differentiate their purposes clearly. The admin interface should use a consistent, properly prefixed route.
Author
Owner

Root cause: this is a hero_router routing behavior, not duplicate UIs in hero_books. The two binaries actually serve different pages — the router is collapsing both routes onto the admin socket.

Verified by hitting the sockets directly (bypassing the router):

Source <title> Size
hero_books/web.sock (hero_books_web, kind=web) The Knowledge World — Hero Books (public reader) ~33 KB
hero_books/admin.sock (hero_books_admin, kind=admin) Hero Books — Libraries (admin) ~15 KB

But through the router, both /hero_books/ui/ and /hero_books/admin/ return the admin page (~15 KB, "Hero Books — Libraries"). The only difference between the two responses is the injected base path (BASE_PATH = "/hero_books/ui" vs "/hero_books/admin"); the markup is otherwise identical.

Where it comes from

hero_routercrates/hero_router/src/server/routes.rs. Both path segments dispatch to the same resolver:

"ui" | "admin" => resolve_ui_socket(state, service_name, sock_dir).await

resolve_ui_socket() resolves in priority order: a cache entry that is admin.sock/ui.sock<svc>/admin.sock<svc>/ui.sock<svc>/web.sock. Since admin.sock exists it wins for both routes, and web.sock (explicitly commented "legacy web-only") is never reached. So /ui/ is effectively an alias of /admin/, and the public hero_books_web reader is unreachable through the router.

Options

  1. Admin-only: stop/drop the hero_books_web binary — its web.sock is unroutable through the router anyway — so only /admin/ (plus its /ui/ alias) exist.
  2. Expose the public reader: fix hero_router so /ui/web.sock and /admin/admin.sock resolve distinctly (and rename the admin route, e.g. admin_ui, per the description).

Since the redundancy originates in hero_router, the fix most likely belongs there — consider moving or cross-linking this issue to hero_router.

(Investigated on devbox; hero_books debug build; router instance at [50c:2786:2581:b5fe:3::1]:9988.)

**Root cause: this is a `hero_router` routing behavior, not duplicate UIs in hero_books.** The two binaries actually serve *different* pages — the router is collapsing both routes onto the admin socket. Verified by hitting the sockets directly (bypassing the router): | Source | `<title>` | Size | |---|---|---| | `hero_books/web.sock` (`hero_books_web`, kind=web) | The Knowledge World — Hero Books (public reader) | ~33 KB | | `hero_books/admin.sock` (`hero_books_admin`, kind=admin) | Hero Books — Libraries (admin) | ~15 KB | But **through the router**, both `/hero_books/ui/` and `/hero_books/admin/` return the *admin* page (~15 KB, "Hero Books — Libraries"). The only difference between the two responses is the injected base path (`BASE_PATH = "/hero_books/ui"` vs `"/hero_books/admin"`); the markup is otherwise identical. ### Where it comes from `hero_router` → `crates/hero_router/src/server/routes.rs`. Both path segments dispatch to the **same** resolver: ```rust "ui" | "admin" => resolve_ui_socket(state, service_name, sock_dir).await ``` `resolve_ui_socket()` resolves in priority order: a cache entry that is `admin.sock`/`ui.sock` → `<svc>/admin.sock` → `<svc>/ui.sock` → `<svc>/web.sock`. Since `admin.sock` exists it wins for **both** routes, and `web.sock` (explicitly commented "legacy web-only") is never reached. So `/ui/` is effectively an alias of `/admin/`, and the public `hero_books_web` reader is unreachable through the router. ### Options 1. **Admin-only:** stop/drop the `hero_books_web` binary — its `web.sock` is unroutable through the router anyway — so only `/admin/` (plus its `/ui/` alias) exist. 2. **Expose the public reader:** fix `hero_router` so `/ui/` → `web.sock` and `/admin/` → `admin.sock` resolve distinctly (and rename the admin route, e.g. `admin_ui`, per the description). Since the redundancy originates in `hero_router`, the fix most likely belongs there — consider moving or cross-linking this issue to `hero_router`. *(Investigated on devbox; hero_books debug build; router instance at `[50c:2786:2581:b5fe:3::1]:9988`.)*
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
lhumina_code/hero_books#135
No description provided.