nikom.work: Go portfolio renderer
This small Go SSR application replaced an uncacheable Laravel portfolio, removed millions of possible filter URLs, and kept durable contact intake without putting sessions or database work on public page requests.
What needed to change
The previous portfolio started a Laravel session on public GET requests, returned Cache-Control: no-cache, private, and exposed every tag toggle as another crawlable query URL. The July 2026 Search Console export contained 2,900,597 URLs excluded by noindex while only the homepage was indexed.
The constraint shaping the build
Keep the useful project history and contact workflow, remove the database-backed presentation layer, remain deployable as one tiny container, and avoid competing with the two specialist practice sites.
How I built it
- Render the public site from immutable in-memory content with no session or database reads on GET requests.
- Use buttons and local DOM filtering for portfolio categories; filters never create URLs.
- Permanently redirect every legacy query-string view to its clean path and every retired topic page to one capability hub.
- Pre-compress text responses, emit validators, and give the CDN explicit shared-cache and stale-on-error policy.
- Keep SQLite only for durable contact intake and use an outbox so Brevo contact, deal, note, and notification steps can retry independently.
What I verified
- GSC baseline: 2,900,631 not indexed versus 1 indexed URL on 10 July 2026.
- Coverage causes: 2,900,597 noindex URLs, 22 discovered-not-indexed, 9 crawled-not-indexed, and 1 server error.
- Public Laravel HTML returned two session cookies and Cloudflare DYNAMIC on every sampled page.
- The new site exposes only identity, work, capabilities, contact, and original engineering cases as indexable pages.
Current state: The replacement removes the application-level crawl trap. Final closure still depends on the CDN rollout, purge, and post-release crawl evidence.