# BlueCap Strategies Website

Static marketing site for BlueCap Strategies, built with [Astro](https://astro.build/) and
deployed to a k3s homelab cluster via GitOps (ArgoCD).

## Stack

- **Astro 5** — static output (`output: "static"`), no runtime JS framework.
- **Content Collections (Markdown)** — page copy lives in `src/content/` (services, focus-areas,
  pages, insights), validated by a Zod SEO schema at build time.
- **nginx** (Alpine) serves the built `dist/` from a multi-stage Docker image.
- **ArgoCD + Kustomize** (`k8s/`) reconcile the deployment; images are published to GHCR by CI.

## Local development

```bash
npm install
npm run dev          # dev server at http://localhost:4321
npm run build        # astro check (typecheck) + astro build → dist/
npm run preview      # serve the production build
npm run seo:lint     # structural SEO checks over dist/ (run after build)
npm run test:e2e     # Playwright end-to-end tests
```

Copy `.env.example` to `.env` and fill in values as needed (site URL, contact form endpoint,
analytics keys). Never commit `.env`.

## Editing content

Page copy is Markdown with typed frontmatter — no code changes needed to edit words:

- `src/content/services/*.md` — service detail pages
- `src/content/focus-areas/*.md` — focus-area detail pages
- `src/content/pages/*.md` — standalone long-form pages (e.g. About)
- `src/content/insights/*.md` — blog/insights posts

Frontmatter is enforced by the Zod schema in `src/content.config.ts` (e.g. `description` must be
120–158 chars), so the build fails fast on SEO violations. The `.md` files are **build-time
source**: Astro compiles them to static HTML in `dist/`. The Markdown itself is never served.

## Project layout

```
src/            Astro pages, layouts, components, content collections, styles
public/         Static assets served as-is (images, robots.txt, healthz)
scripts/        Build tooling (seo-lint.mjs)
tests/          Playwright e2e specs
deploy/         nginx.conf for the runtime image
k8s/            Kustomize manifests (namespace, deployment, service, ingress, configmap)
docs/           Committed engineering records — ADRs, deployment, SEO/AEO, deviations
Dockerfile      Multi-stage build → nginx image containing only dist/
```

`planning/` (git-ignored) holds working docs — content inventories, parity checklists, and the
original rebuild brief. See `docs/adr/` for the decision record.

## Deployment

Push to `main` → GitHub Actions runs the quality gates, builds and pushes a `<git-sha>`-tagged
image to GHCR, and updates the image tag in `k8s/`. ArgoCD reconciles the change to k3s. GitHub
never receives cluster credentials. See `docs/gitops-deployment-strategy.md`.
