- app/[lang]/* — one folder per tool, /[lang] path-prefix locale
- components/ — shared widgets
- lib/ — helpers (apiUrl / flag / format_result)
- 11 Zustand stores (auth / settings / sessions / etc.)
A cube-tools site with 24+ tool pages — one Next.js 16 codebase deployed two ways (self-hosted VM + Vercel edge, split-horizon DNS). Backend is Hono + PostgreSQL, and the WCA statistics pipeline runs separately on a weekly cadence. This page walks every layer — from a mouse click to a DOM update, and everything in between.
One line: everything sits on one self-hosted VM — nginx reverse-proxies systemd Next standalone (:3002) + Hono API (:3001); Hono talks to PG over a local socket. The other line hits Vercel edge running the same Next code; the API call still resolves to api.cuberoot.me. static.cuberoot.me is a dedicated subdomain serving /tools and /stats for the Vercel function fallback.
core/ is a pnpm + Turbo monorepo with five packages, each owning one slice. CI only re-runs packages that actually changed — cache hits make most builds sub-second.
Not every route was built from scratch. own = designed and built here; port = someone else's React/HTML rewritten in-repo; fork = upstream assets hosted as-is. Click a card to visit the module.
| Host | Backed by | Role |
|---|---|---|
cuberoot.mewww.cuberoot.me | Split-horizon DNS — one line → self-hosted VM nginx → systemd Next standalone :3002; the other → Vercel Hobby edge (same code, push-to-deploy) | Primary site, Next.js 16 App Router |
api.cuberoot.me | Cloud VM nginx → :3001 | Hono API + 24h proxy_cache |
next.cuberoot.me | Same systemd cuberoot-next :3002 (alias) | Staging alias / direct to self-hosted Next, bypassing DNS routing |
static.cuberoot.me | Same nginx, dedicated vhost serving only /tools/ + /stats/ (CORS:*) | Static-asset origin for Vercel function fallback |
cuberoot.me/blog/blog.cuberoot.me | Dual via split-horizon DNS: same-VM nginx alias / GH Pages | WordPress static archive (frozen 2026-05) |