iili: the shortener frontend at iili.uk, on the 1d4 stack (#1359) - #1430
Conversation
Cloudflare Worker SPA replacing the Go VM's static page: shorten form
with expiry chips, copy + recent links, /r/{slug} 302 to the v2 API
keeping v1's link shape. Multi-origin CORS at api.muchq.com (pinned by
deploy test), test-r3dr-web CI job.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017HmkKHfFNgq4buWdcAFqB8
Light meadow palette — warm whites, leaf green, blossom pink (the 3). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017HmkKHfFNgq4buWdcAFqB8
- Floor url_ids at 1M in migrations: v1 minted the same slugs from its own sequence, so post-cutover v1 links must 404, not alias - 30-day chip sits 5min under the ceiling (client clock skew) - Worker: HEAD gets the 302, trailing slash tolerated - 10s fetch timeout; friendly network-failure message - Palette to AA: darker CTA/muted/expiry text, accent-deep rename - a11y: busy-not-disabled submit (focus survives), persistent live regions, announced copy states, aria-pressed chips, labelled Clear - normalizeUrl lowercases http(s); lengths count code points; in-flight typing survives the input clear; recent list re-prunes each minute - VITE_SHORT_LINK_BASE for workers.dev previews - Tests: bare-domain form path, copy paths, expiry note text, option table, double-submit guard, network failures; CORS test scopes preflight vs response echoes and closes the origin set Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017HmkKHfFNgq4buWdcAFqB8
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
1d4-web | 632ea6d | Commit Preview URL Branch Preview URL |
Aug 21 2026, 10:29 PM |
localStorage slugs render into hrefs; filter to the 3/6/11 base64url shape on load and encode in shortLink. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017HmkKHfFNgq4buWdcAFqB8
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017HmkKHfFNgq4buWdcAFqB8
r3dr_v2 is the second aura::Cache emitter #1209 was waiting for. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017HmkKHfFNgq4buWdcAFqB8
Scoping alone can't tell hit rate from miss rate. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017HmkKHfFNgq4buWdcAFqB8
Review (panel-style, fold-ins only — no separate issues)Four lenses (correctness, tests/docs/CI, altitude; findings self-refuted then verified). Survivors are the line comments on this PR. Highest leverage
Nits / simplify: slug-shape Refuted / not filed: double-submit race; worker HEAD vs Caddy GET-only; site-wide ACAO for credential-less APIs; collapsing the worker→API 302 (rate-limit client identity earns keep); “one item one PR” against this #1359 chunk (aggregation intentional).
|
- Migrations clear pre-floor rows (v1's slug space); creates before data fixes so a fresh DB migrates; floor test uses nextval + monotone case - Slug shape tightened to exactly 3|6|11 - Link labels derive from the same base as hrefs - Pin busy-not-disabled, the fetch timeout signal, CORS Allow-Methods POST, and the single-line unconditional-ACAO form - README: "just under the ceiling"; honest workers.dev preview flow Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017HmkKHfFNgq4buWdcAFqB8
|
Round 2 folded (latest push):
Tailwind stays (see thread): preflight-only is 1d4_web's own usage; parity was the brief. Generated by Claude Code |
r3dr_web_v2 -> iili_web, served at iili.uk (fresh short domain — no
cutover; r3dr.net retires with v1 in chunk 3). Short links are
iili.uk/r/{slug}; CORS origin swaps r3dr.net -> iili.uk. The muchq.com
/r3dr page (muchq.github.io) mints the same links.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017HmkKHfFNgq4buWdcAFqB8
Review (round 3 @ b196521 — aggregated; fold-ins only, no separate issues)Four lenses on the post-rebrand HEAD (correctness, data/CORS/SQL, tests/docs/CI, altitude). Findings self-refuted then verified against the tree. Round-2 folds (floor clear + nextval/monotone, labels from Highest leverage
Medium
Nits
Refuted / not filedWorker HEAD vs Caddy GET-only; double-submit race; Tailwind preflight-only (author already defended 1d4 parity); collapsing worker→API 302 (rate-limit client identity); proxying shorten through the worker; CI note
|
- run_worker_first=/r/* and bump compat date so SPA asset routing cannot swallow short-link navigations; unit tests cannot see this - Pin the minute Recent prune with fake setInterval; pin shorten timeout at 10_000 via AbortSignal.timeout spy - Drop stale "UI not here" from r3dr_v2 README; smithy blurb names /r3dr/v2/*; rewrite floor comments past the dissolved cutover - setupTests: in-memory localStorage when Node's experimental one is undefined (local Node 26)
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
moonbase | 632ea6d | Aug 21 2026, 10:30 PM |
2025-04-01 was only the assets-routing threshold; with run_worker_first in place, use CF's recommended current date.
Chunk 2 of #1359:
domains/r3dr/apps/iili_web— a Cloudflare Worker SPA on the 1d4_web stack (Vite, React 19, Tailwind preflight, Vitest) for iili.uk, the shortener's new short domain. A second frontend for the same API ships separately as muchq.com/r3dr (muchq/muchq.github.io#277); both mintiili.uk/r/{slug}links. Springtime look: meadow whites, leaf green, blossom pink, AA-checked.https://, schemes lowercased, traits mirrored client-side in code points), expiry chips (1h/1d/7d/30d — the 30-day option sits 5 minutes under the API ceiling so a fast client clock can't turn it into a 400), copy with announced states, last-five recent links in localStorage (slug-shape validated, expiry-pruned each minute), 10s fetch timeout, friendly 429/network messages. Desktop + mobile; keyboard focus survives submit (busy, not disabled); persistent live regions.GET|HEAD /r/{slug}(trailing slash tolerated;/r/, not bare/{slug}— asset paths are themselves slug-shaped) 302s toapi.muchq.com/r3dr/v2/r/{slug}— the browser follows directly, so the API's per-client rate limit keys on the real client, not worker egress IPs. Everything else is the SPA./r3dr/v2/*(model, Caddy matchers, deploy pins, UI, worker — one rename).url_ids; v2's migrations floor its sequence at 1M and clear any pre-floor rows, so v2 ids can never alias v1's slug space (belt-and-suspenders now that iili.uk is a fresh domain — r3dr.net links die with v1 in chunk 3). Pinned by nextval/monotone/clear tests.muchq.com,iili.uk,localhost:5173for vite dev) +Vary: Origin, response and preflight both.caddy validateclean; the deploy test scopes preflight vs response halves, closes the origin set, and pins Content-Type + POST in the allow-lists.test-iili-webjob (typecheck, vitest, build) mirroringtest-1d4-web. The CodeQL high on stored-slug hrefs is closed by a slug-shape barrier inloadRecent+ encoding inshortLink.Verified: 43 web tests + 15 PG-gated store tests (local Postgres 16, plus a fresh-database run for the migration ordering), two review panels (4 lenses each; all surviving findings folded), 18/18 mutation checks killed, Playwright smoke in real Chromium at 1440×900 and 390×844.
Deploy is dashboard-side (like 1d4-web): Workers project
iili-web, root/domains/r3dr/apps/iili_web, buildnpm ci && npm run build, deploynpx wrangler deploy --config dist/iili_web/wrangler.json, then attach theiili.ukcustom domain — a fresh domain, so that's the whole launch. Chunk 3 (retiring r3dr.net, the VM, the Go service, and the Neon credential) stays in #1359.🤖 Generated with Claude Code
https://claude.ai/code/session_017HmkKHfFNgq4buWdcAFqB8
Generated by Claude Code