No description
  • Vue 69.2%
  • TypeScript 15.2%
  • JavaScript 6.9%
  • CSS 4.7%
  • Dockerfile 4%
Find a file
redines 97b4397f1e
All checks were successful
Build and Publish / Build (push) Successful in 52s
Build and Publish / SonarQube Analysis (push) Successful in 24s
Build and Publish / Sync SonarQube Issues (push) Successful in 8s
Build and Publish / Publish Docker image (push) Has been skipped
adding filter for github user specific repo, fork and archive
2026-04-17 23:02:34 +02:00
.forgejo/workflows feat: add docker-compose configuration for portfolio service 2026-04-11 15:35:45 +02:00
.github feat: update content configuration and remove deprecated blog posts 2026-04-11 12:28:05 +02:00
app feat: update content configuration and remove deprecated blog posts 2026-04-11 12:28:05 +02:00
i18n/locales feat: update content configuration and remove deprecated blog posts 2026-04-11 12:28:05 +02:00
public p 2026-04-03 14:58:55 +02:00
server adding filter for github user specific repo, fork and archive 2026-04-17 23:02:34 +02:00
shared/domain fixing 2026-03-31 23:26:41 +02:00
.env.example p 2026-04-03 14:58:55 +02:00
.gitignore init 2026-03-27 22:52:26 +01:00
bun.lock feat: update content configuration and remove deprecated blog posts 2026-04-11 12:28:05 +02:00
content.config.ts feat: update content configuration and remove deprecated blog posts 2026-04-11 12:28:05 +02:00
docker-compose.yml feat: add docker-compose configuration for portfolio service 2026-04-11 15:35:45 +02:00
Dockerfile fix: add --ignore-scripts to Dockerfile installs to avoid optional native module compilation 2026-04-11 14:44:08 +02:00
eslint.config.mjs feat: update content configuration and remove deprecated blog posts 2026-04-11 12:28:05 +02:00
nuxt.config.ts feat: update content configuration and remove deprecated blog posts 2026-04-11 12:28:05 +02:00
package.json feat: update content configuration and remove deprecated blog posts 2026-04-11 12:28:05 +02:00
README.md fix: add --ignore-scripts to Dockerfile installs to avoid optional native module compilation 2026-04-11 14:44:08 +02:00
sonar-project.properties p 2026-04-03 14:58:55 +02:00
tailwind.config.js feat: update content configuration and remove deprecated blog posts 2026-04-11 12:28:05 +02:00
tsconfig.json init 2026-03-27 22:52:26 +01:00

Pontus Göth — Portfolio

Personal portfolio site built with Nuxt 4, featuring a blog, GitHub projects feed, and a resume page with server-side PDF generation.

Tech stack

Prerequisites

  • Bun v1.0+
  • A GitHub personal access token (optional — without one the GitHub API falls back to 60 req/h)

Setup

1. Install dependencies

bun install

2. Download the Playwright browser

The resume page generates a downloadable PDF server-side using a headless Chromium browser managed by Playwright. Download it once with:

bun run setup:browsers

This saves Chromium to ~/.cache/ms-playwright/ and only needs to be done once per machine (or after a major Playwright version bump).

3. Configure environment variables

Copy the example env file and fill in your values:

cp .env.example .env
Variable Required Description
NUXT_GITHUB_TOKEN No GitHub fine-grained token with "Public Repositories (read-only)" permission. Without it the API is limited to 60 requests/hour.
NUXT_GITHUB_USERNAME No GitHub username to fetch public repos for (defaults to redines).
CHROMIUM_PATH No Path to a system Chromium binary. Leave unset locally — Playwright uses its own downloaded browser. Only set this in Docker/CI.

Development

Start the development server on http://localhost:3000:

bun run dev

Production

Build for production:

bun run build

Preview the production build locally:

bun run preview

Docker

Build and run with Docker:

docker build -t portfolio .
docker run -p 3000:3000 portfolio

The Docker image uses Bun for both build and runtime. For this Nuxt app, the final image also installs the full production dependency tree into server/node_modules, because Bun resolves packages against the standalone server's local module tree and Nitro's traced copy can omit Bun-specific runtime files from transitive packages such as ofetch.

Docker installs also use --ignore-scripts to avoid compiling optional native modules such as better-sqlite3 in CI. This project's Bun-targeted server output uses bun:sqlite, so those native install scripts are not required for the container build.

The Docker image installs system Chromium via apt-get and sets CHROMIUM_PATH=/usr/bin/chromium automatically — no extra configuration needed.

To pass a GitHub token at runtime:

docker run -p 3000:3000 -e NUXT_GITHUB_TOKEN=your_token portfolio

CI/CD

On every push to main, the pipeline runs three jobs:

build ─┐
       ├─→ publish
analyze┘
  • build — installs dependencies and runs nuxt build to validate the project compiles
  • analyze — runs a SonarQube scan against the source code (runs in parallel with build)
  • publish — builds and pushes the Docker image; only runs if both build and analyze pass

The following secrets must be set in your Forgejo user account (globally available to all repositories):

Secret Description
REGISTRY_URL Hostname of the private Docker registry
REGISTRY_USERNAME Username for the registry
REGISTRY_PASSWORD Password for the registry
SONAR_HOST_URL URL of your SonarQube instance
SONAR_TOKEN SonarQube authentication token
NUXT_GITHUB_TOKEN GitHub token — passed at container runtime, not needed at build time

The published image is tagged with both latest and the commit SHA:

$REGISTRY_URL/portfolio:latest
$REGISTRY_URL/portfolio:<commit-sha>

To deploy, pull and run the latest image:

docker pull $REGISTRY_URL/portfolio:latest
docker run -p 3000:3000 \
  -e NUXT_GITHUB_TOKEN=your_token \
  $REGISTRY_URL/portfolio:latest

Resume page

The resume is available at /resume. It renders as a normal HTML page using the site layout.

Clicking Download PDF on that page triggers a server-side request to GET /resume.pdf. The Nitro server route launches a headless Chromium, renders /resume?pdf=1 (a stripped layout with no header or footer), and streams back the generated PDF.