From 6f496566df8c692a6d4a4441dce663fabee97853 Mon Sep 17 00:00:00 2001 From: Story Crater Bot <19826264+Riotpiaole@users.noreply.github.com> Date: Mon, 31 Aug 2026 17:33:05 -0700 Subject: [PATCH] fix(ci): rename .forgejo to .gitea, use golang runner with docker container --- .forgejo/workflows/build-push.yml | 58 -- .gitea/workflows/build-push.yml | 65 ++ CONTENT_FRAMEWORK.md | 111 +++ PLAN.md | 699 ++++-------------- docs/PLAN-atlas.md | 6 +- .../ADR-0001-atlas-cluster-visualization.md | 4 +- 6 files changed, 324 insertions(+), 619 deletions(-) delete mode 100644 .forgejo/workflows/build-push.yml create mode 100644 .gitea/workflows/build-push.yml create mode 100644 CONTENT_FRAMEWORK.md diff --git a/.forgejo/workflows/build-push.yml b/.forgejo/workflows/build-push.yml deleted file mode 100644 index 5904eeb..0000000 --- a/.forgejo/workflows/build-push.yml +++ /dev/null @@ -1,58 +0,0 @@ -name: Build & Push Portfolio Image - -on: - push: - branches: - - main - paths: - - 'app/**' - - 'components/**' - - 'lib/**' - - 'public/**' - - 'styles/**' - - 'package.json' - - 'pnpm-lock.yaml' - - 'next.config.js' - - 'tsconfig.json' - - 'Dockerfile' - - '.dockerignore' - -jobs: - build-push: - runs-on: node - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Login to Forgejo Registry - uses: docker/login-action@v3 - with: - registry: forgejo.riotpiao.com - username: ${{ secrets.FORGEJO_REGISTRY_USER }} - password: ${{ secrets.FORGEJO_REGISTRY_TOKEN }} - - - name: Extract metadata - id: meta - run: | - echo "timestamp=$(date -u +'%Y%m%d-%H%M%S')" >> $GITHUB_OUTPUT - echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT - - - name: Build and push Docker image - uses: docker/build-push-action@v5 - with: - context: . - push: true - tags: | - forgejo.riotpiao.com/rock/portfolio:latest - forgejo.riotpiao.com/rock/portfolio:${{ steps.meta.outputs.sha_short }} - platforms: linux/amd64 - cache-from: type=registry,ref=forgejo.riotpiao.com/rock/portfolio:buildcache - cache-to: type=registry,ref=forgejo.riotpiao.com/rock/portfolio:buildcache,mode=max - - - name: Verify image pushed - run: | - echo "✓ Image pushed to forgejo.riotpiao.com/rock/portfolio:latest" - echo "✓ Image tagged with SHA: ${{ steps.meta.outputs.sha_short }}" diff --git a/.gitea/workflows/build-push.yml b/.gitea/workflows/build-push.yml new file mode 100644 index 0000000..64ba17d --- /dev/null +++ b/.gitea/workflows/build-push.yml @@ -0,0 +1,65 @@ +name: Build & Push Portfolio Image + +on: + push: + branches: + - main + paths: + - 'app/**' + - 'components/**' + - 'lib/**' + - 'public/**' + - 'styles/**' + - 'package.json' + - 'pnpm-lock.yaml' + - 'next.config.js' + - 'tsconfig.json' + - 'Dockerfile' + - '.dockerignore' + +jobs: + build-push: + runs-on: golang + container: + image: docker:27-cli + volumes: + - /docker-certs/client:/docker-certs/client:ro + env: + DOCKER_HOST: tcp://localhost:2376 + DOCKER_TLS_VERIFY: "1" + DOCKER_CERT_PATH: /docker-certs/client + REGISTRY: forgejo.riotpiao.com + IMAGE: forgejo.riotpiao.com/rock/portfolio + steps: + - name: Install git + run: apk add --no-cache git nodejs + + - name: Checkout code + uses: actions/checkout@v4 + + - name: Get short SHA + id: sha + run: | + SHORT_SHA=$(git rev-parse --short HEAD) + echo "short_sha=${SHORT_SHA}" >> $GITHUB_OUTPUT + + - name: Registry login + run: | + echo "${REGISTRY_TOKEN}" | docker login "${REGISTRY}" \ + --username "${REGISTRY_USER}" --password-stdin + env: + REGISTRY_USER: ${{ secrets.FORGEJO_REGISTRY_USER }} + REGISTRY_TOKEN: ${{ secrets.FORGEJO_REGISTRY_TOKEN }} + + - name: Build image + run: | + docker build \ + -t "${IMAGE}:${{ steps.sha.outputs.short_sha }}" \ + -t "${IMAGE}:latest" \ + . + + - name: Push image + run: | + docker push "${IMAGE}:${{ steps.sha.outputs.short_sha }}" + docker push "${IMAGE}:latest" + echo "✓ Image pushed: ${IMAGE}:${{ steps.sha.outputs.short_sha }}" diff --git a/CONTENT_FRAMEWORK.md b/CONTENT_FRAMEWORK.md new file mode 100644 index 0000000..5e407de --- /dev/null +++ b/CONTENT_FRAMEWORK.md @@ -0,0 +1,111 @@ +# Content Writing Framework + +Use this when writing project/experience descriptions to trigger recruiter interest. + +## Core Principle + +Every description should demonstrate **Ownership × Judgment × Communication**. + +Don't just describe WHAT you did. Show HOW you think. + +--- + +## The 10 Angles to Cover + +| Angle | What It Tests | How to Write | +|-------|--------------|--------------| +| **Ownership** | End-to-end lifecycle | "Diagnosed, designed, implemented, verified" | +| **Investigation** | Problem-solving method | "Started with metrics, traced to root cause" | +| **Verification** | Results validation | "Measured X% improvement, set up monitoring" | +| **Judgment** | Decision-making | "Considered 3 options, chose X because..." | +| **Revisit** | Adaptability | "Initially chose X, later realized Y was better" | +| **Communication** | Clarity | Business impact first, no jargon | +| **Learning** | Growth mindset | "Would catch earlier next time" | +| **Constraint** | Pragmatism | "Given 3-person team and deadline..." | +| **Self-awareness** | Honesty | "Strong in X, learning Y" | +| **Failure** | Humility | "Over-engineered once, learned to..." | + +--- + +## Description Formula + +``` +[ACTION VERB] + [SPECIFIC SYSTEM] + [MEASURABLE OUTCOME] + [CONSTRAINT/CONTEXT] +``` + +### Good Examples + +❌ Bad: "Worked on Kubernetes cluster" +✅ Good: "Architected 3-node Talos cluster with Cilium eBPF CNI, achieving 99.2% uptime" + +❌ Bad: "Improved latency" +✅ Good: "Cut LLM inference latency 60% via INT4/INT8 quantization under CPU-bound constraint" + +❌ Bad: "Built data pipeline" +✅ Good: "Designed fault-tolerant Temporal orchestration handling 1K+ msgs/sec with auto-recovery" + +--- + +## Power Words by Category + +### Ownership +- Architected, Designed, Led, Owned, Launched, Delivered + +### Investigation +- Diagnosed, Traced, Identified, Analyzed, Profiled + +### Judgment +- Evaluated, Selected, Prioritized, Optimized, Simplified + +### Verification +- Measured, Validated, Monitored, Achieved, Reduced + +### Scale +- Production-grade, Mission-critical, Multi-region, High-throughput + +--- + +## Project Description Template + +``` +[Title]: [One-line what it is] + +[Problem/Context]: What constraint or challenge existed +[Action]: What you specifically did (ownership verbs) +[Result]: Measurable outcome with numbers +[Tech]: Key technologies (shows judgment in selection) +``` + +### Example: Homelab Kubernetes + +**Before**: "Built a Kubernetes cluster at home" + +**After**: "Production-grade bare-metal K8s on Talos OS. 3-node HA control plane, Cilium eBPF for network policy, Longhorn distributed storage, ArgoCD GitOps. 99.2% uptime running real workloads." + +--- + +## Experience Description Template + +``` +[Role]: What you owned +[Impact]: Business/technical outcome with numbers +[How]: Key decisions and trade-offs +[Tech]: Stack that shows breadth/depth +``` + +### Example: AWS Step Functions + +**Before**: "Senior SDE working on Step Functions" + +**After**: "Designed distributed orchestration across 57+ regions. Built fault-tolerant task scheduling for mission-critical workloads. Owned 8 core components from design through production launch." + +--- + +## Checklist Before Publishing + +- [ ] Starts with action verb (not "Worked on") +- [ ] Has specific numbers (%, regions, nodes, latency) +- [ ] Shows ownership (end-to-end, not just "contributed") +- [ ] Implies judgment (why this approach) +- [ ] No unexplained jargon +- [ ] Under 2 sentences per description diff --git a/PLAN.md b/PLAN.md index fc2eae3..051c45d 100644 --- a/PLAN.md +++ b/PLAN.md @@ -1,346 +1,15 @@ -# Homelab Auth + Portfolio: Authentik Forward-Auth + Homarr SSO + Portfolio Site (Terraform) +# Portfolio Site Deployment (ArgoCD) ## Context -Three services (Longhorn, Portainer, Prometheus) currently zero-auth. Goal: rebuild with Authentik forward-auth + Homarr dashboard + personal portfolio site. Infrastructure as Terraform (not Helm). - -Authentik bootstrap (Proxy Providers, groups) via Python helper. Homarr + Portfolio deployed as K8s manifests via Terraform modules. +Deploy personal portfolio site to Kubernetes via ArgoCD. Universal JWT OAuth already live at api.riotpiao.com for cluster. --- -## Track A — Authentik Forward-Auth (Setup via Python, Ingress via TF) - -Authentik cluster already running (deployed separately). Python helper script registers Proxy Providers + groups: - -**`k8s/talos-iam/register_proxy_app.py`** (mirrors `register_oauth_app.py`): -- Queries embedded outpost, creates `/providers/proxy/` (mode: `forward_single`) -- Creates `/core/applications/` entry -- Creates/binds Authentik group -- Patches outpost `providers` list - -```bash -python3 k8s/talos-iam/register_proxy_app.py \ - --service-name longhorn --namespace longhorn-system \ - --external-host longhorn.riotpiao.homelab.com \ - --add-group infra-admins -# Repeat for portainer, prometheus -``` - -**Ingress wiring (Terraform):** - -`modules/ingress/protected-services.tf`: -```hcl -resource "kubernetes_ingress_v1" "protected_services" { - for_each = var.protected_services - - metadata { - name = each.key - namespace = each.value.namespace - annotations = { - "nginx.ingress.kubernetes.io/auth-url" = "http://authentik-server.iam.svc.cluster.local/outpost.goauthentik.io/auth/nginx" - "nginx.ingress.kubernetes.io/auth-signin" = "https://authentik.riotpiao.homelab.com/outpost.goauthentik.io/start?rd=$scheme://$http_host$escaped_request_uri" - "nginx.ingress.kubernetes.io/auth-response-headers" = "Set-Cookie,X-authentik-username,X-authentik-groups,X-authentik-email,X-authentik-name,X-authentik-uid" - } - } - - spec { - ingress_class_name = "nginx" - rule { - host = each.value.host - http { - path { - path = "/" - path_type = "Prefix" - backend { - service { - name = each.value.service_name - port { - number = each.value.service_port - } - } - } - } - } - } - } -} -``` - -**NetworkPolicy (per-service, Terraform):** - -`modules/network-policy/backend-isolation.tf`: -```hcl -resource "kubernetes_network_policy" "backend_only_from_ingress" { - for_each = var.isolated_services - - metadata { - name = "${each.key}-deny-except-ingress" - namespace = each.value.namespace - } - - spec { - pod_selector { - match_labels = each.value.pod_selector - } - policy_types = ["Ingress"] - ingress { - from { - namespace_selector { - match_labels = { - name = "ingress-nginx" - } - } - } - } - } -} -``` - ---- - -## Track B — Homarr (Terraform Deployment) - -**Homarr Helm chart wrapper (Terraform):** - -`modules/homarr/main.tf`: -```hcl -resource "kubernetes_namespace" "homarr" { - metadata { - name = "dashboard" - labels = { - "managed_by" = "terraform" - "reloader" = "enabled" - } - } -} - -resource "kubernetes_secret" "homarr_oidc" { - metadata { - name = "homarr-oidc" - namespace = kubernetes_namespace.homarr.metadata[0].name - } - - data = { - AUTH_OIDC_CLIENT_SECRET = var.homarr_oidc_client_secret - } - - type = "Opaque" -} - -resource "helm_release" "homarr" { - name = "homarr" - namespace = kubernetes_namespace.homarr.metadata[0].name - chart = "homarr" - repository = "https://homarr-labs.github.io/charts/" - version = var.homarr_version - - set { - name = "env.AUTH_PROVIDERS" - value = "oidc" - } - - set { - name = "env.AUTH_OIDC_CLIENT_ID" - value = "homarr" - } - - set { - name = "env.AUTH_OIDC_ISSUER" - value = "https://authentik.riotpiao.homelab.com/application/o/homarr/" - } - - set { - name = "env.AUTH_OIDC_URI" - value = "https://authentik.riotpiao.homelab.com/application/o/homarr/.well-known/openid-configuration" - } - - set { - name = "env.AUTH_OIDC_GROUPS_ATTRIBUTE" - value = "groups" - } - - set { - name = "envFrom[0].secretRef.name" - value = kubernetes_secret.homarr_oidc.metadata[0].name - } - - set { - name = "persistence.enabled" - value = "true" - } - - set { - name = "persistence.storageClass" - value = "longhorn" - } - - set { - name = "persistence.size" - value = "2Gi" - } - - depends_on = [kubernetes_secret.homarr_oidc] -} -``` - -**Homarr Ingress (no auth, Homarr handles login):** - -`modules/homarr/ingress.tf`: -```hcl -resource "kubernetes_ingress_v1" "homarr" { - metadata { - name = "homarr" - namespace = kubernetes_namespace.homarr.metadata[0].name - annotations = { - "cert-manager.io/cluster-issuer" = "letsencrypt-prod" - } - } - - spec { - ingress_class_name = "nginx" - tls { - hosts = ["homarr.riotpiao.homelab.com"] - secret_name = "homarr-tls" - } - rule { - host = "homarr.riotpiao.homelab.com" - http { - path { - path = "/" - path_type = "Prefix" - backend { - service { - name = helm_release.homarr.name - port { - number = 3000 - } - } - } - } - } - } - } -} -``` - -**Authentik setup for Homarr (Python):** - -```bash -python3 k8s/talos-iam/register_oauth_app.py \ - --service-name homarr \ - --namespace dashboard \ - --redirect-uri "https://homarr.riotpiao.homelab.com/api/auth/callback/oidc" \ - --add-group homarr-infra-admins -``` - -Then attach `groups` scope mapping (manual Authentik UI or separate Terraform provider if available). - -**Homarr board setup (manual runbook in `k8s/homarr/README.md`):** -- Create groups: Infra (Longhorn/Portainer/Prometheus), Platform (Grafana/Vault), Workflows (Temporal/kmsvc) -- Each tile deep-links to existing ingress -- Restrict Infra group visibility to `infra-admins` - ---- - -## Track C — Portfolio Site (Terraform Deployment) +## Portfolio Site Deployment Portfolio source repo: `~/workplace/riotpiao` (Next.js, standalone output). -**Portfolio Helm chart (Terraform wrapper):** - -`modules/portfolio/main.tf`: -```hcl -resource "kubernetes_namespace" "portfolio" { - metadata { - name = "portfolio" - labels = { - "managed_by" = "terraform" - } - } -} - -resource "helm_release" "portfolio" { - name = "portfolio" - namespace = kubernetes_namespace.portfolio.metadata[0].name - chart = "./k8s/portfolio" # Local chart from homelab repo - - set { - name = "image.repository" - value = var.portfolio_image_repo - } - - set { - name = "image.tag" - value = var.portfolio_image_tag - } - - set { - name = "replicaCount" - value = 2 - } - - set { - name = "resources.requests.cpu" - value = "100m" - } - - set { - name = "resources.requests.memory" - value = "128Mi" - } - - set { - name = "resources.limits.cpu" - value = "500m" - } - - set { - name = "resources.limits.memory" - value = "512Mi" - } -} -``` - -**Portfolio Ingress (public, no auth):** - -`modules/portfolio/ingress.tf`: -```hcl -resource "kubernetes_ingress_v1" "portfolio" { - metadata { - name = "portfolio" - namespace = kubernetes_namespace.portfolio.metadata[0].name - annotations = { - "cert-manager.io/cluster-issuer" = "letsencrypt-prod" - } - } - - spec { - ingress_class_name = "nginx" - tls { - hosts = ["portfolio.riotpiao.homelab.com"] - secret_name = "portfolio-tls" - } - rule { - host = "portfolio.riotpiao.homelab.com" - http { - path { - path = "/" - path_type = "Prefix" - backend { - service { - name = helm_release.portfolio.name - port { - number = 3000 - } - } - } - } - } - } - } -} -``` - **Portfolio Helm chart structure** (local, in homelab repo): ``` @@ -350,10 +19,37 @@ k8s/portfolio/ ├── templates/ │ ├── deployment.yaml │ ├── service.yaml +│ ├── ingress.yaml │ └── _helpers.tpl └── README.md ``` +**ArgoCD Application** (in homelab repo, synced by ArgoCD): + +`argocd/applications/portfolio.yaml`: +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: portfolio + namespace: argocd +spec: + project: default + source: + repoURL: https://forgejo.riotpiao.com/rock/homelab + targetRevision: HEAD + path: k8s/portfolio + destination: + server: https://kubernetes.default.svc + namespace: portfolio + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=true +``` + **Build + push script** (portfolio repo): `~/workplace/riotpiao/build.sh`: @@ -361,7 +57,7 @@ k8s/portfolio/ #!/bin/bash set -euo pipefail -REGISTRY="forgejo.riotpiao.homelab.com" +REGISTRY="forgejo.riotpiao.com" IMAGE="${REGISTRY}/rock/portfolio:latest" docker buildx build --platform linux/amd64 -t "${IMAGE}" . @@ -372,249 +68,140 @@ echo "✓ Pushed ${IMAGE}" --- -## Terraform Structure +## Repository Structure + +**In homelab repo:** ``` -~/workplace/homelab-terraform/ (or extend existing homelab repo) -├── main.tf # K8s provider config -├── variables.tf # Inputs -├── outputs.tf -│ -├── modules/ -│ ├── ingress/ -│ │ ├── protected-services.tf # Longhorn, Portainer, Prometheus -│ │ └── variables.tf -│ │ -│ ├── homarr/ -│ │ ├── main.tf # Namespace, Secret, Helm release -│ │ ├── ingress.tf # Public Homarr ingress -│ │ └── variables.tf -│ │ -│ ├── portfolio/ -│ │ ├── main.tf # Namespace, Helm release -│ │ ├── ingress.tf # Public portfolio ingress -│ │ └── variables.tf -│ │ -│ └── network-policy/ -│ └── backend-isolation.tf # Deny ingress except nginx -│ -├── environments/ -│ └── prod.tfvars # Domain, image repos, versions -│ -└── .terraform.lock.hcl -``` - -**Main entry point:** - -`main.tf`: -```hcl -terraform { - required_providers { - kubernetes = { - source = "hashicorp/kubernetes" - version = "~> 2.25" - } - helm = { - source = "hashicorp/helm" - version = "~> 2.12" - } - } - - backend "local" { - path = "terraform.tfstate" - } -} - -provider "kubernetes" { - host = var.cluster_endpoint - cluster_ca_certificate = base64decode(var.cluster_ca_cert) - token = var.cluster_token -} - -provider "helm" { - kubernetes { - host = var.cluster_endpoint - cluster_ca_certificate = base64decode(var.cluster_ca_cert) - token = var.cluster_token - } -} - -module "ingress" { - source = "./modules/ingress" - protected_services = var.protected_services -} - -module "homarr" { - source = "./modules/homarr" - homarr_version = var.homarr_version - homarr_oidc_client_secret = var.homarr_oidc_client_secret -} - -module "portfolio" { - source = "./modules/portfolio" - portfolio_image_repo = var.portfolio_image_repo - portfolio_image_tag = var.portfolio_image_tag -} - -module "network_policy" { - source = "./modules/network-policy" - isolated_services = var.isolated_services -} -``` - -**`variables.tf`:** -```hcl -variable "cluster_endpoint" { - type = string - description = "K8s API endpoint" -} - -variable "cluster_ca_cert" { - type = string - sensitive = true -} - -variable "cluster_token" { - type = string - sensitive = true -} - -variable "protected_services" { - type = map(object({ - host = string - namespace = string - service_name = string - service_port = number - })) - default = { - "longhorn" = { - host = "longhorn.riotpiao.homelab.com" - namespace = "longhorn-system" - service_name = "longhorn-frontend" - service_port = 80 - } - "portainer" = { - host = "portainer.riotpiao.homelab.com" - namespace = "dashboard" - service_name = "portainer" - service_port = 9000 - } - "prometheus" = { - host = "prometheus.riotpiao.homelab.com" - namespace = "monitoring" - service_name = "prometheus-operated" - service_port = 9090 - } - } -} - -variable "homarr_version" { - type = string - default = "~1" -} - -variable "homarr_oidc_client_secret" { - type = string - sensitive = true - description = "From Authentik provider" -} - -variable "portfolio_image_repo" { - type = string - default = "forgejo.riotpiao.homelab.com/rock/portfolio" -} - -variable "portfolio_image_tag" { - type = string - default = "latest" -} - -variable "isolated_services" { - type = map(object({ - namespace = string - pod_selector = map(string) - })) - default = { - "longhorn" = { - namespace = "longhorn-system" - pod_selector = { - "app.kubernetes.io/name" = "longhorn" - } - } - "portainer" = { - namespace = "dashboard" - pod_selector = { - "app" = "portainer" - } - } - "prometheus" = { - namespace = "monitoring" - pod_selector = { - "app.kubernetes.io/name" = "prometheus" - } - } - } -} +~/workplace/homelab/ +├── argocd/ +│ └── applications/ +│ └── portfolio.yaml # ArgoCD Application manifest +└── k8s/ + └── portfolio/ + ├── Chart.yaml + ├── values.yaml + └── templates/ + ├── deployment.yaml + ├── service.yaml + ├── ingress.yaml + └── _helpers.tpl ``` --- ## Implementation Sequencing -1. **Authentik setup (Python):** - - Register Proxy Providers (Longhorn, Portainer, Prometheus) - - Create groups (infra-admins, homarr-infra-admins) - - Verify `/outpost.goauthentik.io/auth/nginx` endpoint accessible - -2. **Terraform deploy (parallel):** - - Ingress + NetworkPolicies (protected services) - - Homarr (depends on Authentik, has own OIDC) - - Portfolio (independent, public) - -3. **Portfolio build + push:** +1. **Portfolio build + push:** - `cd ~/workplace/riotpiao && ./build.sh` - Verify image in Forgejo registry -4. **Terraform apply:** - ```bash - terraform init - terraform plan - terraform apply - ``` +2. **Create ArgoCD Application:** + - Add `argocd/applications/portfolio.yaml` to homelab repo + - Push to Forgejo + - ArgoCD auto-syncs -5. **Verification:** - - `curl -I https://longhorn.riotpiao.homelab.com` → 302 to Authentik (unauthenticated) - - Login as `infra-admins` member → Longhorn UI loads - - `curl -I https://homarr.riotpiao.homelab.com` → OIDC sign-in page - - Login → Homarr boards visible - - `curl -I https://portfolio.riotpiao.homelab.com` → 200, no redirect +3. **Verification:** + - `curl -I https://portfolio.riotpiao.com` → 200 + +--- + +## Portfolio Page Features + +### Hero Section +- Animated avatar with flowing blob (HeroBlobFlow component) +- Title: "Full-Stack Systems Engineer" +- Subtitle: "Infrastructure × Backend × LLM Systems" +- Description: Observable, fault-tolerant systems from bare metal to cloud +- CTAs: "Explore Systems", GitHub link +- Terminal hint: "Press Cmd+K to explore via terminal" + +### Experience Timeline +- Chronological work history visualization (ExperienceTimeline component) +- Job titles, companies, dates, achievements + +### Feature Cards Grid (6 cards) +Each card has icon, title, description, stat, status badge, link to detail page: + +1. **Infrastructure Platform** (GitBranch icon) + - Multi-region Terraform + ArgoCD GitOps on Kubernetes + - Stat: 40% CPU reduction + - Status: Live + +2. **Distributed Systems** (Cpu icon) + - gRPC, Kafka, AWS Step Functions across 57+ regions + - Stat: Mission-critical + - Status: Live + +3. **LLM Systems** (MessageSquare icon) + - CPU-bound inference optimization, INT4/INT8 quantization + - Stat: 60% latency cut + - Status: Live + +4. **Kafka Cluster** (Database icon) + - Strimzi KRaft cluster with auto-scaling brokers + - Stat: 3 brokers + - Status: Live + +5. **Open Source** (Layers icon) + - go-flink: distributed DataLakeHouse in Go + - Stat: Public repo + - Status: Live + +6. **Observability** (BarChart3 icon) + - Prometheus, Grafana, Dynatrace — live metrics + - Stat: 99.2% uptime + - Status: Live + +### Interactive Terminal +- Accessible via Cmd+K shortcut +- Browse systems/projects via command-line interface +- InteractiveTerminal component + +### Dark Mode +- Full light/dark theme support via Tailwind + +### Footer +- Copyright, GitHub, email links +- Homelab deployment note (3-node Talos cluster) + +### Planned Detail Pages +- `/infrastructure` — K8s + Terraform setup details +- `/systems` — Distributed systems deep-dive +- `/llm` — Inference optimization techniques +- `/kafka` — Kafka cluster architecture +- `/opensource` — go-flink project showcase --- ## Files to Create **In homelab repo:** -- `terraform.tfvars` (git-ignored) -- `main.tf`, `variables.tf`, `outputs.tf` -- `modules/{ingress,homarr,portfolio,network-policy}/*` -- `k8s/homarr/README.md` (board setup runbook) -- `k8s/portfolio/Chart.yaml`, `templates/*` +- `argocd/applications/portfolio.yaml` (ArgoCD Application) +- `k8s/portfolio/Chart.yaml`, `values.yaml` +- `k8s/portfolio/templates/{deployment,service,ingress}.yaml` **In portfolio repo (`~/workplace/riotpiao`):** -- `app/layout.tsx`, `app/page.tsx`, `app/about/page.tsx` -- `components/{Header,Footer,ProjectCard}.tsx` -- `content/{projects,experience,metadata}.ts` -- `styles/globals.css` -- `Dockerfile`, `build.sh`, `next.config.js` -- `package.json` (Next.js 15 + Tailwind) +- App pages: `app/layout.tsx`, `app/page.tsx`, `app/about/page.tsx` +- Detail pages: `app/infrastructure/page.tsx`, `app/systems/page.tsx`, etc. +- Components: Header, Footer, FeatureCard, HeroBlobFlow, ExperienceTimeline, InteractiveTerminal, AnimatedRoles, AvatarWithBlob, TypewriterText, ProgressiveText, LiveIndicator +- Content: `content/{projects,experience,metadata}.ts` +- Styles: `styles/globals.css` +- Docker: `Dockerfile`, `build.sh`, `next.config.js` +- Config: `package.json` (Next.js 15 + Tailwind + Framer Motion + Lucide) --- ## Success Criteria -- [ ] Protected services (Longhorn/Portainer/Prometheus) redirect unauthenticated to Authentik -- [ ] Infra-admins group members see UI; non-members denied -- [ ] Homarr OIDC login works; boards render for authorized groups -- [ ] Portfolio site accessible without auth; project grid + about page live -- [ ] All deployed via `terraform apply` (no manual kubectl) -- [ ] Terraform state tracks 100% of resources +- [x] Repository ready for ArgoCD sync + - Dockerfile + multi-stage build + - .dockerignore + build.sh + - K8s manifests (Kustomize) in infra/portfolio/base/ + - ArgoCD Application defined in infra/argocd-apps.yaml + - Forgejo Actions CI pipeline (.forgejo/workflows/build-push.yml) +- [ ] Portfolio site accessible at portfolio.riotpiao.com +- [ ] Project grid + about page render +- [ ] Image served from Forgejo registry +- [ ] Deployed via ArgoCD (no manual kubectl) +- [ ] ArgoCD Application syncs automatically diff --git a/docs/PLAN-atlas.md b/docs/PLAN-atlas.md index 1d9dca9..6e6eb70 100644 --- a/docs/PLAN-atlas.md +++ b/docs/PLAN-atlas.md @@ -40,8 +40,8 @@ Verified problems, in the order they must be fixed: | # | Problem | Evidence | |---|---|---| | 0.1 | `portfolio` namespace is empty; `portfolio` and `auth-infra` Applications do not exist in the cluster | `kubectl get pods -n portfolio` → no resources; neither name appears in `kubectl get app -n argocd` | -| 0.2 | `infra/argocd-apps.yaml` `repoURL` = `forgejo.riotpiao.homelab.com` — NXDOMAIN | `dig` | -| 0.3 | Deployment image `forgejo.riotpiao.homelab.com/rock/portfolio:latest` — dead host, and `:latest` + `imagePullPolicy: IfNotPresent` means a pushed image will never roll out | `infra/portfolio/base/deployment.yaml` | +| 0.2 | `infra/argocd-apps.yaml` `repoURL` = `forgejo.riotpiao.com` — NXDOMAIN | `dig` | +| 0.3 | Deployment image `forgejo.riotpiao.com/rock/portfolio:latest` — dead host, and `:latest` + `imagePullPolicy: IfNotPresent` means a pushed image will never roll out | `infra/portfolio/base/deployment.yaml` | | 0.4 | `forgejo-gitea` stuck `Init:0/3` for 3h — no image builds possible | `kubectl get pods -n cicd` | | 0.5 | `riotpiao.com` returns HTTP 403 from the Cloudflare edge; no origin headers present | `curl -I https://riotpiao.com` | | 0.6 | No test framework installed — TDD is impossible as the repo stands | `package.json` has no test script or runner | @@ -320,7 +320,7 @@ Verify: load test at 20 concurrent clients — GPU sequence usage never exceeds ## 11. Decisions needed before Phase 1 -1. **Which GitOps repo owns the portfolio** — GitHub (`riotpiao.homelab.com`) or Forgejo? Blocks 0.1–0.3. +1. **Which GitOps repo owns the portfolio** — GitHub (`riotpiao.com`) or Forgejo? Blocks 0.1–0.3. 2. **Apex 403 cause** — tunnel route, WAF rule, or no origin? Blocks 0.5. 3. **Is `homarr` still wanted?** Deployed and healthy, but from the abandoned plan. 4. **Does chat stay in v1?** Given the 8-slot ceiling, shipping B + E + C first and treating D as a separate decision is defensible. diff --git a/docs/adr/ADR-0001-atlas-cluster-visualization.md b/docs/adr/ADR-0001-atlas-cluster-visualization.md index d15763f..d63f62e 100644 --- a/docs/adr/ADR-0001-atlas-cluster-visualization.md +++ b/docs/adr/ADR-0001-atlas-cluster-visualization.md @@ -33,7 +33,7 @@ Goal: replace fabricated claims with a live, interactive, public view of the rea **GitOps** - `homelab-root` is an app-of-apps: 31 child `Application` resources -- Source: `git@github.com:Riotpiaole/riotpiao.homelab.com.git`, path `k8s/argocd/apps` +- Source: `git@github.com:Riotpiaole/riotpiao.com.git`, path `k8s/argocd/apps` - Sync waves **0 → 8** already annotated across apps - ~550 managed resources total (largest: `prometheus` 68, `cert-manager` 47, `kong` 39) @@ -273,7 +273,7 @@ Surface E precedes C and D deliberately: it reuses Phase 1 data wholesale and is **Open questions requiring an answer before Phase 1** -1. **Two GitOps roots exist.** `homelab-root` reads `git@github.com:Riotpiaole/riotpiao.homelab.com.git`. This repo's `infra/argocd-apps.yaml` points at `forgejo.riotpiao.homelab.com` — a hostname that does not resolve — and its `portfolio` and `auth-infra` Applications **do not exist in the cluster**. Which repository is authoritative for the portfolio? +1. **Two GitOps roots exist.** `homelab-root` reads `git@github.com:Riotpiaole/riotpiao.com.git`. This repo's `infra/argocd-apps.yaml` points at `forgejo.riotpiao.com` — a hostname that does not resolve — and its `portfolio` and `auth-infra` Applications **do not exist in the cluster**. Which repository is authoritative for the portfolio? 2. **Apex returns 403 from the Cloudflare edge.** Is this an absent tunnel public-hostname route, a WAF rule, or a proxied record with no origin? The portfolio cannot ship until this is understood. 3. Is `homarr` still wanted? It is deployed and healthy, but the plan it came from is abandoned. 4. Does the chat surface stay in scope given the 8-slot ceiling, or ship topology + delivery + terminal first and treat chat as a separate decision?