windows-iso-downloader/PROGRESS.md
Shekhar Vaidya e3f34016c6 chore: plan frontend UX improvements — expiry countdown, refresh, CLI tabs, recently viewed, file size
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 20:54:55 +05:30

3.9 KiB
Raw Blame History

MSDL — Progress Log

Shipped

eval ISOs — PR #13 feat/evalcenter-isos

Windows Server 20162025 + Windows 11 Enterprise evaluation editions

  • GET /evallinks?product=<slug> endpoint — resolves Microsoft Eval Center fwlink redirects, caches for 24h, warms on startup
  • Frontend eval section: /eval listing page + /eval/:slug detail page with download links
  • Eval products: server-2025, server-2022, server-2019, server-2016, win11-ent
  • ComparisonTable + FAQAccordion updated to mention eval ISOs
  • HowItWorks step 1 updated
  • SEO audit across all pages (meta descriptions, robots noindex on legal pages, JSON-LD on product detail)
  • README: /evallinks API docs, eval product table, contributing guide for eval editions

Two-layer caching — PR #14 + #15 feat/caching-layer (closes #12)

Reduced Microsoft API calls from thousands/day to ~50100/day

  • Singleflight (golang.org/x/sync/singleflight) — collapses concurrent cache misses into 1 Microsoft fetch
  • SKU cache — 7-day TTL, keyed by product_id
  • Link cache — dynamic TTL parsed from se param in signed Microsoft CDN URL, minus 30min buffer
  • Eval cache — 24h TTL, keyed by slug, warmed at startup
  • Negative cache — 60s TTL, prevents thundering-herd retries during rate-limit blocks
  • Stale-on-failure — serves expired entry if refresh fails; background refresh via singleflight
  • Jitter — ±5min random offset on TTLs to prevent synchronized mass-expiry
  • Cache eviction — background goroutine every 30min, logs only when entries deleted
  • Cache hit/miss logging — every request logs fetched vs cached + expiry timestamp
  • Dockerfile bumped to golang:1.25-alpine to match go.mod

Metrics endpoint — feat/metrics

Real-time cache observability

  • GET /metrics?secret=<secret> — returns cache hit rates, miss counts, MS fetch totals, cache sizes
  • Auth via METRICS_SECRET env var (?secret= param or Authorization: Bearer header)
  • Atomic counters (sync/atomic) — lock-free, resets on restart
  • Covers SKU, link, eval, and negative caches
  • Background stale refresh routed through singleflight (prevents race condition under concurrent stale hits)

README architecture docs — direct to main

  • How It Works flow diagram updated with cache check step
  • Caching layer section — table of all 4 caches, singleflight, stale-on-failure, jitter, eviction
  • Backend Tech Stack table updated (Go 1.25+, real cache description)
  • /metrics added to API Reference with example response
  • METRICS_SECRET added to env vars block

Production metrics snapshot (after ~1 day of traffic)

{
  "sku":  { "requests": 37, "cache_hits": 29, "ms_fetches": 8,  "hit_rate": "78.4%" },
  "link": { "requests": 28, "cache_hits": 14, "ms_fetches": 14, "hit_rate": "50.0%" },
  "eval": { "requests": 2,  "cache_hits": 1,  "stale": 0,       "hit_rate": "50.0%" },
  "total_ms_fetches": 22
}

67 user requests → 22 Microsoft calls. 67% of calls eliminated on a still-warming cache. CF Worker ensures Hetzner IP is never exposed to Microsoft — rate-limit block (715-123130) is effectively impossible.


Planned — Frontend UX improvements

Feature Notes
Expiry countdown Parse se param from signed URL, live countdown. Under 6h → show Refresh button
Refresh links ?force=true on /proxy bypasses cache, returns fresh URL, resets countdown
CLI command tabs aria2 / wget / curl tabs, persist selection in localStorage, default wget
Recently viewed localStorage only — active links show countdown, expired show re-fetch CTA
File size Research first — verify if Microsoft CDN response includes it

Deferred

Item Notes
Per-IP / per-product rate limiter Revisit after 1 month of production traffic data
_redirects Cloudflare Pages bug SPA fallback rule flagged as infinite loop, may cause 404s on direct nav