My landing page at nicolaskion.dev. It shows the tools I build for the EVE Online community: featured projects like MutaMarket, wormhole.systems and Telescope, a pilot dossier from EVE's ESI, and a live, searchable list of my public repositories from the GitHub API.
- Featured projects, curated in
src/featured.rs, linked to their source and stats while the repository is public - Public repositories with search and an owner filter, and the three most used languages across everything the token sees (only the language names reach the page)
- A pilot dossier from ESI: corporation, alliance, security status
- GitHub and ESI answers cached in memory (GitHub 10 minutes fresh and an hour stale, ESI an hour and a day), refreshed in the background. When an API fails the page renders without that part, or with the last good data
- Server-rendered page with the SEO and social tags, light and dark following the system
- The update feed of the tournament-tool desktop app (see below)
- API: Rust and Axum, no database
- Frontend: SvelteKit (SSR, adapter-node), Svelte 5 and Tailwind CSS 4
- Caddy in front:
/api/*,/storage/*and/upgo to the API, everything else to SvelteKit.frontend/proxy-paths.tsanddeploy/Caddyfilehold that list.
src/ the API: GitHub and ESI clients, the cache, the page props, the router
src/bin/ sync_logos, downloads the featured project logos
frontend/ the SvelteKit app and its Playwright suite (frontend/e2e)
tests/ the Rust integration suites and the mock GitHub and ESI data
deploy/ the Caddyfile and the proxy image, shared by the local stack and production
The whole stack (API, SvelteKit, Caddy) on http://localhost:5314:
docker compose up --buildWith the mock GitHub and ESI the end-to-end tests use:
docker compose -f docker-compose.yml -f compose.e2e.yml up --build -dOr natively:
cargo run # API on 127.0.0.1:3000
cd frontend && npm install && npm run devConfiguration lives in .env (see .env.example). Without
GITHUB_TOKEN the page renders without GitHub data, without
EVE_CHARACTER_ID without the dossier. The token stays on the server;
private repositories only count toward the language stack.
The featured project logos live in frontend/static/logos. Each one has
a source in its project's repository, and
cargo run --bin sync_logosdownloads them again (a failed or unexpected download keeps the current
file). The logos workflow runs it monthly and opens a pull request when
a logo changed.
The tournament-tool desktop app checks
https://nicolaskion.dev/storage/tt-8d20886697466b8297bb6d6e1735fa53/latest.json
for updates; installed clients have that URL compiled in, so it must keep
working. The proxy serves the directory straight from the host,
independent of the api and the frontend (deploy/Caddyfile):
- On the server the files live in
/srv/nicolaskion/update-feed(latest.json,latest.json.sigand theupdate-v*archives), mounted read-only into the proxy container at the same path. - tournament-tool's release workflow uploads new releases into that directory over rsync, with a key restricted to it.
- Archives and the signature are served as
application/octet-stream,latest.jsonasapplication/json, with byte ranges and conditional requests, never compressed.
Locally the composed stack serves $UPDATE_FEED_DIR (an empty
storage/update-feed by default) the same way.
cargo test
cd frontend && npm run check && npm run lint && npm test
docker compose -f docker-compose.yml -f compose.e2e.yml up --build -d
cd frontend && npm run test:e2eThe Rust suites drive the real router against a mock GitHub and ESI on an ephemeral port. Playwright runs against the composed stack on port 5314.
Coolify deploys compose.prod.yml on the server. A merge to main runs
.github/workflows/release.yml, which builds the api, frontend and proxy
images, pushes them to ghcr.io/nicolaskion/nicolaskion-* (latest and
the commit) and calls Coolify's deploy webhook, so Coolify pulls and
restarts them. Only the proxy has a domain (https://nicolaskion.dev and
www, which it redirects to the apex); Traefik terminates TLS in front of
it. GITHUB_TOKEN and EVE_CHARACTER_ID are Coolify environment
variables.



