diff --git a/.gitea/workflows/ci.yaml b/.gitea/workflows/ci.yaml
new file mode 100644
index 0000000..584d298
--- /dev/null
+++ b/.gitea/workflows/ci.yaml
@@ -0,0 +1,64 @@
+# Required secrets:
+# REGISTRY_USER — Gitea container registry username
+# REGISTRY_PASSWORD — Gitea container registry password
+
+name: CI
+
+on:
+ push:
+ branches:
+ - main
+ pull_request:
+ branches:
+ - main
+
+jobs:
+ build-check:
+ if: github.event_name == 'pull_request'
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ with:
+ submodules: recursive
+
+ - name: Verify Hugo build
+ uses: docker://hugomods/hugo:exts
+ with:
+ args: hugo --minify
+
+ build-and-push:
+ if: github.event_name == 'push'
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ with:
+ submodules: recursive
+
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v3
+ with:
+ driver: docker-container
+ driver-opts: network=host
+
+ - name: Log in to Gitea registry
+ uses: docker/login-action@v3
+ with:
+ registry: gitea.nik4nao.com
+ username: ${{ secrets.REGISTRY_USER }}
+ password: ${{ secrets.REGISTRY_PASSWORD }}
+
+ - name: Resolve short SHA
+ id: sha
+ run: echo "short=$(echo ${{ github.sha }} | cut -c1-7)" >> $GITHUB_OUTPUT
+
+ - name: Build and push multiarch image
+ uses: docker/build-push-action@v5
+ with:
+ context: .
+ platforms: linux/amd64,linux/arm64
+ push: true
+ tags: |
+ gitea.nik4nao.com/nik/portfolio:latest
+ gitea.nik4nao.com/nik/portfolio:${{ steps.sha.outputs.short }}
diff --git a/.gitignore b/.gitignore
index 2eea525..a460014 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,4 @@
-.env
\ No newline at end of file
+.env
+.hugo_build.lock
+public/
+resources/_gen/
\ No newline at end of file
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..a6851ba
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "themes/terminal"]
+ path = themes/terminal
+ url = https://github.com/panr/hugo-theme-terminal.git
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..8bb4f65
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,10 @@
+FROM hugomods/hugo:exts AS builder
+
+WORKDIR /site
+COPY . .
+RUN hugo --minify
+
+FROM nginx:alpine
+
+COPY --from=builder /site/public /usr/share/nginx/html
+EXPOSE 80
diff --git a/content/cv.md b/content/cv.md
new file mode 100644
index 0000000..5379963
--- /dev/null
+++ b/content/cv.md
@@ -0,0 +1,149 @@
+---
+title: "CV"
+type: "cv"
+date: 2026-03-17
+draft: false
+---
+
+# NIK AFIQ
+
+Tokyo, Japan
+nik@nik4nao.com | github.com/nikafiq | nik4nao.com
+
+
+---
+
+## PROFESSIONAL SUMMARY
+
+Backend engineer with 3 years of professional experience designing and
+operating distributed, high-throughput systems on GCP and AWS. Core
+expertise in Go and Python, with hands-on production experience in
+event-driven microservices, Kafka-based pipelines, Kubernetes, and
+cloud-native data infrastructure. Comfortable operating systems at
+hundreds of TPS with reliability and zero-downtime migration
+constraints. Trilingual (English, Japanese N1, Malay) — routinely
+bridges Japanese and overseas engineering teams. Actively integrates
+AI tooling (GitHub Copilot, Gemini, Claude) into daily coding,
+review, and documentation workflows.
+
+
+---
+
+## WORK EXPERIENCE
+
+### 株式会社ホープス (Hopes Co., Ltd.) — Tokyo
+**Backend Engineer** | Aug 2025 – Present
+
+Designing and operating a distributed RCS consent management pipeline
+(SO→FoRCE) on GCP/GKE connecting a high-traffic notice delivery
+system to a downstream fulfillment API.
+
+- Architected an event-driven pipeline using GKE + Managed Kafka
+ (8 partitions, keyed by account_id) + Cloud Spanner, handling a
+ global cap of 200 TPS with a 10-second downstream timeout budget
+- Built the Go consumer service (so-notice-receiver) with
+ singleflight coalescing to prevent duplicate in-flight requests,
+ and circuit breaker logic to shed load under downstream failure
+- Designed reliable offset commit ordering: offsets committed only
+ after durable Spanner write, ensuring at-least-once delivery with
+ no data loss on crash
+- Implemented a retry cronjob requeuing up to 5 failed Spanner rows
+ back to Kafka every 5 minutes, with configurable backoff
+- Designed a zero-downtime interleaved index migration on a Cloud
+ Spanner accounts table under 400 TPS sustained read traffic
+- Right-sized GKE resource configs (CPU/memory requests and limits)
+ from Locust load test data at 40 TPS steady / 120 TPS burst
+- Propagated distributed traces across service boundaries for
+ end-to-end production observability
+
+
+### 株式会社ニッポンダイナミックシステムズ — Tokyo
+**Full Stack Engineer, IT Solutions — Pharma Market Team**
+| Apr 2023 – Jul 2025
+
+- Built a scalable analytical DWH on Amazon Aurora (RDS) for a
+ pharmaceutical client, integrating Salesforce and multiple
+ external data sources via daily/weekly ETL batch pipelines using
+ ECS/Fargate and Lambda; designed for HA with Multi-AZ failover
+- Constructed a SaaS data lake using AWS CDK + Glue +
+ TypeScript/Python, fully automating ETL ingestion across
+ heterogeneous data sources
+- Developed an internal AI application using AWS Bedrock (Claude
+ Sonnet) + React, implementing RAG-based document retrieval and
+ SES-based user matching in a small cross-functional team
+- Built a license authentication service (Node.js + Docker + Azure
+ Web Apps + ADB2C), owning requirements definition, auth logic
+ design, and client-facing communication
+- Designed and automated monthly maintenance operations: AMI image
+ updates, security patching, automated regression testing, and
+ blue/green deployments via AWS CodePipeline and Azure Pipelines
+- Conducted Docker image vulnerability scanning as part of CI/CD
+ pipeline; managed VPC, WAF, and Security Group configurations
+- Mentored junior engineers on cloud architecture patterns;
+ functioned as bilingual (EN/JA) liaison between domestic and
+ overseas engineering teams
+
+
+---
+
+## SKILLS
+
+**Languages:** Go, Python, TypeScript/JavaScript
+**Frameworks:** Gin, Flask, Next.js, Node.js
+**Cloud — AWS:** ECS/Fargate, Lambda, Aurora/RDS, DynamoDB, Glue,
+ CDK, CodePipeline, Bedrock, Secrets Manager
+**Cloud — GCP:** GKE, Cloud Spanner, Managed Kafka (Pub/Sub),
+ BigQuery, Cloud Trace
+**Cloud — Azure:** Web Apps, ADB2C, Azure Pipelines
+**Data:** MySQL, Aurora, PostgreSQL, DynamoDB, Cloud Spanner,
+ Kafka, Redis
+**DevOps:** Docker, Kubernetes, ArgoCD, CI/CD, IaC (AWS CDK)
+**Observability:** Distributed tracing, ELK stack, Kibana
+**AI Tooling:** GitHub Copilot (daily coding + code review),
+ Gemini (documentation + research), Claude (architecture
+ reasoning + coding), AWS Bedrock RAG (production)
+**Security:** VPC, WAF, Security Groups, Secrets Manager,
+ Docker vulnerability scanning
+**Other:** Homelab (k3s, self-hosted services, Ansible/IaC),
+ personal dev blog at nik4nao.com
+
+
+---
+
+## CERTIFICATIONS
+
+| Certification | Issued |
+|---|---|
+| AWS Certified Solutions Architect – Associate (SAA) | Oct 2024 |
+| AWS Certified Developer – Associate (DVA) | Dec 2024 |
+| AWS Certified Cloud Practitioner (CLF) | Apr 2024 |
+| 基本情報技術者試験 (FE) — IPA Fundamental IT Engineer | Aug 2024 |
+| JLPT N1 — Japanese Language Proficiency | Dec 2022 |
+
+*In progress: AWS Solutions Architect – Professional (SAP),
+Applied Information Technology Engineer (AP)*
+
+
+---
+
+## EDUCATION
+
+**Tokai University** — Bachelor of Engineering
+Major: Electrical and Electronic Engineering
+Minor: Information Technology
+Graduated: March 2023
+
+*During a COVID-related leave of absence (2020–2021), independently
+studied programming and cloud architecture; resumed with an
+added IT minor upon return.*
+
+
+---
+
+## ADDITIONAL
+
+- **Languages:** English (business), Japanese (JLPT N1), Malay (native)
+- **Homelab:** Self-hosted k3s cluster, Gitea, Jellyfin, Cloudflare
+ Tunnel, Ansible-based IaC on Minisforum UM790 Pro
+- **Dev blog / personal site:** nik4nao.com
+- **Self-hosted Git:** git.nik4nao.com (mirrored to github.com/nikafiq)
\ No newline at end of file
diff --git a/content/posts/hello-world.md b/content/posts/hello-world.md
new file mode 100644
index 0000000..b578b96
--- /dev/null
+++ b/content/posts/hello-world.md
@@ -0,0 +1,14 @@
+---
+title: "Hello World"
+date: 2026-03-17
+draft: false
+tags: ["meta"]
+---
+
+Welcome to my corner of the internet.
+
+This site is where I write about things I'm building, breaking, and learning — mostly homelabs,
+Kubernetes, and the occasional software project. Expect posts about infrastructure, self-hosting,
+and whatever rabbit hole I've fallen down most recently.
+
+If you want to see what I'm currently working on, check out the [projects](/projects) page.
diff --git a/content/projects/_index.md b/content/projects/_index.md
new file mode 100644
index 0000000..e99a978
--- /dev/null
+++ b/content/projects/_index.md
@@ -0,0 +1,8 @@
+---
+title: "Projects"
+date: 2026-03-17
+draft: false
+---
+
+A collection of things I've built or am currently working on — mostly self-hosted infrastructure,
+homelab experiments, and open-source tooling.
diff --git a/content/projects/homelab.md b/content/projects/homelab.md
new file mode 100644
index 0000000..86b4ccc
--- /dev/null
+++ b/content/projects/homelab.md
@@ -0,0 +1,54 @@
+---
+title: "Homelab Kubernetes Cluster"
+date: 2026-03-17
+draft: false
+description: "Self-hosted k3s cluster on bare-metal with Gitea CI/CD, multi-arch builds, Authentik SSO, and ~15 running workloads."
+tags: ["kubernetes", "k3s", "homelab", "infrastructure", "traefik", "authentik"]
+github: ""
+url: ""
+---
+
+## Overview
+
+A self-hosted Kubernetes cluster running on bare-metal hardware at home. The cluster serves as a
+platform for running personal services, experimenting with cloud-native tooling, and learning
+operational patterns without a cloud bill.
+
+## Hardware
+
+| Host | Role | Specs |
+|---|---|---|
+| Minisforum UM780 XTX | K3s control-plane | AMD Ryzen 7 8745H |
+| HP ProDesk (nik-debian) | K3s storage agent | NFS server, mergerfs media pool |
+| Mac Mini M2 | Standalone Docker host | ARM, outside the cluster |
+
+## Stack
+
+- **Distribution:** k3s
+- **Ingress:** Traefik v3
+- **TLS:** cert-manager — Let's Encrypt (public) + internal CA (LAN)
+- **Auth:** Authentik SSO — OIDC + forwardAuth proxy, TOTP MFA enforced
+- **DNS:** Pihole (primary + secondary, externalIPs)
+- **Storage:** NFS (Debian) + local-path dynamic provisioner
+- **CI/CD:** Gitea Actions + act_runner, Docker buildx multiarch (amd64 + arm64)
+- **Registry:** Gitea built-in container registry
+- **Observability:** Prometheus + Grafana + Loki + Promtail
+- **IaC:** Ansible (host-level), Helm + raw manifests (cluster-level), all tracked in Gitea
+
+## Highlights
+
+- All cluster state is managed as code in a Gitea monorepo — single-file manifests per service, organised by concern
+- Authentik SSO protects all web-facing services via Traefik forwardAuth; OIDC integrated with Gitea and Grafana
+- Multi-arch image builds (amd64 + arm64) via buildx on every push to `main`, pushed to the self-hosted registry
+- Dual-cert TLS strategy: internal CA for `*.home.arpa` services, Let's Encrypt for `*.nik4nao.com` public services
+- Pihole running as primary + secondary with externalIPs for LAN-wide DNS and ad-blocking
+- DDNS CronJob keeps the public A record in sync via the Porkbun API
+
+## Running Workloads
+
+Traefik, cert-manager, Pihole, Authentik, Gitea, Prometheus, Grafana, Loki, Promtail,
+Jellyfin, qBittorrent, JDownloader, Photoview, Dashy, Glances, DDNS CronJob, this portfolio site.
+
+## Status
+
+Active and in daily use.
\ No newline at end of file
diff --git a/hugo.toml b/hugo.toml
new file mode 100644
index 0000000..735c3b4
--- /dev/null
+++ b/hugo.toml
@@ -0,0 +1,54 @@
+baseURL = "https://nik4nao.com/"
+languageCode = "en-us"
+title = "nik4nao"
+theme = "terminal"
+
+[params]
+ # dir name of your main content (default is `content/posts`).
+ # the list of set content will show up on your index page (baseurl).
+ contentTypeName = "posts"
+
+ # ["orange", "blue", "red", "green", "pink"]
+ themeColor = "orange"
+
+ # if you set this to 0, only metadata of posts will appear
+ fullWidthTheme = false
+
+ # centered theme with any value (e.g. "true")
+ centerTheme = false
+
+ # if your resource directory contains an image called `cover.png`,
+ # it will be used as the cover of your blog
+ showCoverImage = true
+
+ # set terminal prompt
+ terminalPrompt = "nik@nik4nao ~ $"
+
+ # show/hide posts list on start page
+ showMenuItems = 3
+
+ # show a footer instead of the HUGO signature
+ # customFooter = ""
+
+ # set theme to full screen width
+ # fullWidthTheme = false
+
+[[params.menu]]
+ identifier = "posts"
+ name = "posts"
+ url = "/posts"
+
+[[params.menu]]
+ identifier = "projects"
+ name = "projects"
+ url = "/projects"
+
+[[params.menu]]
+ identifier = "cv"
+ name = "cv"
+ url = "/cv"
+
+[taxonomies]
+ tag = "tags"
+
+paginate = 5
diff --git a/layouts/cv/single.html b/layouts/cv/single.html
new file mode 100644
index 0000000..6336b61
--- /dev/null
+++ b/layouts/cv/single.html
@@ -0,0 +1,10 @@
+{{ define "main" }}
+
+ Backend engineer based in Tokyo. I build distributed systems, + operate Kubernetes infrastructure, and occasionally write about it. +
+{{ . }}
+ {{ end }} + + {{ with .Params.tags }} + + {{ end }} + + +{{ . }}
+ {{ end }} + + {{ with .Params.tags }} + + {{ end }} + + {{ if or .Params.github .Params.url }} +