$ cat how-this-site-is-built.md
Live pipeline status
last commit: eb98e1e — feat: mount command palette globally, theme init, work list wiring, Cmd+K nav button
committed: Fri, 12 Jun 2026 06:17:36 GMT
last CI run: in_progress view ↗
Fetched from the GitHub API at build time.
$ architecture
Two real delivery paths. Click any node to read the actual config from this repo.
Live path · deploys production
GitOps path · reproducible on any cluster (make local-k8s)
name: ci
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
defaults:
run:
working-directory: site
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
cache-dependency-path: site/package-lock.json
- run: npm ci
- run: npm run check
- run: npm test
- run: npm run build
- name: Lighthouse CI
run: npx --yes @lhci/[email protected] autorun || echo "Lighthouse budget warning"
- uses: actions/upload-artifact@v4
with:
name: site-dist
path: site/dist
deploy:
needs: build
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
cache-dependency-path: site/package-lock.json
- run: npm ci
working-directory: site
- run: npm run build
working-directory: site
- name: Ensure Cloudflare Pages project exists
run: npx --yes wrangler@3 pages project create hayden-remington --production-branch=main || echo "project already exists, continuing"
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
- name: Deploy to Cloudflare Pages
uses: cloudflare/wrangler-action@v3
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
command: pages deploy site/dist --project-name=hayden-remington --branch=main // @ts-check
import { defineConfig } from 'astro/config';
import react from '@astrojs/react';
import sitemap from '@astrojs/sitemap';
import tailwindcss from '@tailwindcss/vite';
import mdx from '@astrojs/mdx';
export default defineConfig({
site: 'https://haydenremington.com',
integrations: [react(), sitemap(), mdx()],
vite: { plugins: [tailwindcss()] },
}); # Multi-stage build: compile the static Astro site, then serve it with nginx.
FROM node:22-alpine AS build
WORKDIR /app
COPY site/package*.json ./
RUN npm ci
COPY site/ ./
RUN npm run build
FROM nginx:1.27-alpine AS runtime
COPY infra/nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=build /app/dist /usr/share/nginx/html
EXPOSE 80
HEALTHCHECK CMD wget -q --spider http://localhost/ || exit 1 replicaCount: 2
image:
repository: ghcr.io/haydumb/hayden-portfolio
tag: latest
pullPolicy: IfNotPresent
service:
type: ClusterIP
port: 80
ingress:
enabled: true
className: nginx
host: haydenremington.com
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
cpu: 200m
memory: 128Mi apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "hayden-portfolio.fullname" . }}
labels:
{{- include "hayden-portfolio.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
{{- include "hayden-portfolio.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
{{- include "hayden-portfolio.selectorLabels" . | nindent 8 }}
spec:
containers:
- name: web
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: 80
readinessProbe:
httpGet:
path: /
port: http
livenessProbe:
httpGet:
path: /
port: http
resources:
{{- toYaml .Values.resources | nindent 12 }} apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: hayden-portfolio
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/haydumb/hayden-portfolio
targetRevision: main
path: infra/helm
destination:
server: https://kubernetes.default.svc
namespace: hayden-portfolio
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true terraform {
required_version = ">= 1.5"
required_providers {
cloudflare = {
source = "cloudflare/cloudflare"
version = "~> 4.0"
}
}
}
# Authenticates via the CLOUDFLARE_API_TOKEN environment variable.
provider "cloudflare" {}
# The Cloudflare Pages project that hosts the static site.
resource "cloudflare_pages_project" "site" {
account_id = var.cloudflare_account_id
name = "hayden-remington"
production_branch = "main"
}
# Point the apex domain at the Pages project.
resource "cloudflare_record" "apex" {
zone_id = var.cloudflare_zone_id
name = "@"
type = "CNAME"
content = "hayden-remington.pages.dev"
proxied = true
}
The live path deploys this site: a push to main triggers GitHub Actions
(lint, type-check, tests, build, Lighthouse budget) which deploys the static output to Cloudflare Pages.
The GitOps path is a real, reproducible Kubernetes deployment — the same site
containerized and shipped via a Helm chart managed by ArgoCD. Run it locally with
make local-k8s (kind). The nodes above open the actual files from this repo.