Lean static portfolio with interactive diagrams and self-hosted analytics
Lean static portfolio with interactive diagrams and self-hosted analytics
This site: a statically exported Next.js portfolio with interactive architecture diagrams, served by nginx behind Caddy on a single small VPS, with privacy-friendly self-hosted GoatCounter analytics.
// Background
Past projects exist — but there's nowhere to show them.
A GitHub link isn't a portfolio; a PDF isn't a demo.
No centralized showcase
Work lived across GitHub repos, local drives, old Notion
docs, and expired demo links — never in one place.
Interviewers get a repo list, not a story
Code repos don't communicate value
A README explains what the code does. It doesn't explain
the problem it solved, the tradeoffs made, or the impact.
Context lives in your head, not on the screen
No live proof of technical depth
Architecture diagrams in slides go stale. Without a running
app + interactive diagrams, depth stays invisible.
Claims without evidence aren't convincing
No indexed, findable web presence
GitHub profiles rank poorly for recruiters searching specific
skills. A personal domain with structured content does.
Good work that can't be found doesn't get you hired
Static platforms age out of date
A PDF or static site can't be updated without a rebuild.
New projects, new context, new skills — always out of sync.
Portfolio reflects who you were, not who you are
Net effect
Strong past work with nowhere to point — the depth of each
project invisible until you explain it live in an interview.
// Solution
Data sources
PostgreSQL
porto_projects table
auto-migrated on boot
MinIO Object Store
S3-compatible bucket
images · diagrams · demos
Pipeline
Request
nginx → /porto/
/porto/api/
Request
Auth
jose JWT verify
career-ops token
Auth
Data
pg query
MinIO presign
Data
Render
Next.js SSR
App Router
Render
Serve
HTML + JSON
ISR-cached
Serve
Next.js static export · nginx · Caddy auto-TLS · GoatCounter (SQLite) · GitHub Actions deploy · Docker Compose
// Impact
Content lifecycle — before/after
Before
edit → commit → build → deploy (minutes)After
edit in /manage → save → live0
rebuilds to update
a project description
Feature matrix
Live project data
PostgreSQL CRUD via API routes
Admin CMS
/manage: JWT auth, CRUD + upload
Media CDN path
MinIO presigned · no binaries in git
Shared auth
jose JWT, shared career-ops token
Server-rendered
RSC data fetch, cached + tag-revalidated
SSR + ISR
App Router SSR + stale-revalidate
Stack metrics
API routes
8
Languages
2
DB tables
1
Runtime
Bun
Full-stack: API + SSR + auth,
one Next.js app, deployed via Docker.
| Layer | Technologies |
|---|---|
| Frontend | Next.js 16 static export, React 19, TypeScript, Tailwind |
| Serving | nginx, Caddy (auto-TLS) |
| Analytics | GoatCounter (SQLite, self-hosted) |
| Delivery | GitHub Actions, rsync, Docker Compose |
Disclaimer: sample visuals may contain anonymized, simulated, or non-production values for presentation purposes.