Personal portfolio — blog, résumé, and playground. Built with Nuxt 4 and Vue 3, deployed on DigitalOcean via Docker.
- Animated particle-network hero with interactive 3D depth effect
- Sections: About, Experience, Skills, Projects, Contact
- Spotify "Last Liked" widget — live card showing the most recently liked track, linked directly to Spotify (see setup below)
- Dark / light theme toggle
- Fully static-export capable (
bun run generate)
| Layer | Choice |
|---|---|
| Framework | Nuxt 4 (Vue 3, Vite, Nitro) |
| Language | TypeScript (strict) |
| Styling | Tailwind CSS |
| Package manager | Bun |
| Hosting | DigitalOcean (Docker) |
| Registry | DigitalOcean Container Registry |
bun install
bun run dev # http://localhost:3000Other commands:
bun run build # production build → .output/
bun run generate # static site → .output/public/
bun run preview # preview production build
bun run lint # ESLint + Prettier check
bun run lint:fix # auto-fixThe "Last liked on Spotify" card calls /api/spotify/last-liked (a Nitro server route), which fetches your most recently saved track via the Spotify Web API. The response is cached server-side for one hour.
- Create an app at developer.spotify.com and note the Client ID and Client Secret.
- Add
http://localhost:3000/api/spotify/callbackas a Redirect URI in the app settings. - Create a
.envfile (git-ignored) with:
NUXT_SPOTIFY_CLIENT_ID=
NUXT_SPOTIFY_CLIENT_SECRET=
NUXT_SPOTIFY_REDIRECT_URI=http://localhost:3000/api/spotify/callback
NUXT_SPOTIFY_AUTH_SECRET=any-random-string
NUXT_SPOTIFY_REFRESH_TOKEN= # filled in step 5- Start the dev server and open
http://localhost:3000/api/spotify/auth— this redirects to Spotify's OAuth consent screen. - After granting access, the callback prints a refresh token to the terminal. Paste it into
NUXT_SPOTIFY_REFRESH_TOKEN.
In production set the same env vars on your server (or as DigitalOcean App Platform env vars), using your live domain as the redirect URI.
Releases are managed with release-it.
GITHUB_TOKEN=ghp_xxx bun run releaseThis will interactively bump the version, commit, create an annotated git tag, push everything to main, and open a GitHub Release. Pushing the tag then triggers the release pipeline which retags the existing :latest Docker image with the semver version — no rebuild needed.
| Workflow | Trigger | What it does |
|---|---|---|
| ci.yml | push / PR → main |
lint, build, Docker build & push :latest |
| release.yml | push of v*.*.* tag |
pulls :latest, retags as vX.Y.Z, pushes |
Required repository secrets: DO_ACCESS_TOKEN, DO_REGISTRY.