|
| 1 | +# CLAUDE.md |
| 2 | + |
| 3 | +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. |
| 4 | + |
| 5 | +## Project Overview |
| 6 | + |
| 7 | +Interactive map + REST API for visualizing Veeam Data Cloud (VDC) service availability across AWS and Azure regions. Deployed on Cloudflare Pages (static Hugo frontend + Hono API on Workers). |
| 8 | + |
| 9 | +## Common Commands |
| 10 | + |
| 11 | +```bash |
| 12 | +# Development |
| 13 | +npm run dev # API + already-built public/ at http://localhost:8788 via wrangler. |
| 14 | + # Does NOT rebuild Hugo — run `npm run build` first if public/ is stale. |
| 15 | +hugo server # Frontend hot reload at http://localhost:1313 (no API) |
| 16 | + |
| 17 | +# Build |
| 18 | +npm run build # Full production build: build:data → build:worker → typecheck → hugo |
| 19 | +npm run build:data # Convert YAML → functions/regions.json |
| 20 | +npm run build:worker # Compile TypeScript → functions/_worker.js (esbuild) |
| 21 | +npm run typecheck # tsc --noEmit (strict validation) |
| 22 | + |
| 23 | +# Testing |
| 24 | +npm run test # All tests: validate + scraper + API |
| 25 | + # `pretest` hook auto-runs build:data + build:worker first |
| 26 | +npm run test:api # API integration tests (require server already running) |
| 27 | +npm run test:validate # YAML validation tests |
| 28 | +npm run test:ui # Playwright UI tests (headless) |
| 29 | +npm run test:ui:headed # Playwright with browser UI |
| 30 | +npm run test:ui:debug # Playwright debug mode |
| 31 | +npm run test:ui:report # View Playwright HTML report |
| 32 | + |
| 33 | +# Data |
| 34 | +npm run validate # Validate region YAML files |
| 35 | +npm run scrape:regions # Scrape Veeam docs for service availability data |
| 36 | +npm run clean # Remove build artifacts |
| 37 | +``` |
| 38 | + |
| 39 | +## Architecture |
| 40 | + |
| 41 | +### Data Flow |
| 42 | + |
| 43 | +``` |
| 44 | +data/regions/{aws,azure}/*.yaml ← Source of truth for region data |
| 45 | + ↓ |
| 46 | + build:data script |
| 47 | + ↓ |
| 48 | + functions/regions.json ← Loaded by Hono API at runtime |
| 49 | + ↓ |
| 50 | + Hugo template injection ← Also embedded as JS in frontend HTML |
| 51 | + ↓ |
| 52 | + Cloudflare Pages deployment |
| 53 | +``` |
| 54 | + |
| 55 | +### Frontend |
| 56 | +- **Single-file SPA:** `layouts/index.html` (~1665 lines) — Leaflet map, search, filters |
| 57 | +- **Hugo** injects YAML data as a `regions[]` JavaScript array at build time — no runtime data fetching |
| 58 | +- Leaflet.js with CartoDB Dark Matter tiles; uses marker clustering for dense regions |
| 59 | +- **UI edit hotspots:** `getServiceIcon()` (inline SVGs per service), `getProviderBadgeColor()` (Tailwind classes per provider), and the `serviceDisplayNames` object — search for these when changing service rendering |
| 60 | + |
| 61 | +### API (Cloudflare Workers) |
| 62 | +- Entry point: `src/functions/_worker.ts` — Hono app with middleware + route registration |
| 63 | +- Routes: `src/functions/routes/v1/` — 8 endpoints: |
| 64 | + - `ping.ts`, `health.ts` |
| 65 | + - `services.ts`, `services-by-id.ts` |
| 66 | + - `regions.ts`, `regions-by-id.ts`, `regions-nearest.ts`, `regions-compare.ts` |
| 67 | +- Schemas: `src/functions/schemas/common.ts` — Zod + `@hono/zod-openapi` for automatic OpenAPI 3.1 spec |
| 68 | +- Utils: `src/functions/utils/` — `data.ts` (loads `regions.json` and provides stats helpers), `geo.ts` (haversine distance for `regions-nearest`), `response.ts`, `validation.ts` |
| 69 | +- Types: `src/functions/types/` — `env.ts` (`Env` interface) and `data.ts` (`Region`, `Service`, `VdcVaultConfig`, etc.) |
| 70 | +- OpenAPI UI available at `/api/docs` (Scalar); spec at `/api/openapi.json` |
| 71 | + |
| 72 | +### Middleware Stack |
| 73 | +Applied globally: `secureHeaders()` → `cors()` → custom `X-API-Version` header → `Cache-Control: public, max-age=3600` |
| 74 | + |
| 75 | +### Error Response Format |
| 76 | +```json |
| 77 | +{ |
| 78 | + "error": "Short message", |
| 79 | + "code": "ERROR_CODE_ENUM", |
| 80 | + "message": "Detailed explanation", |
| 81 | + "parameter": "fieldName", |
| 82 | + "value": "invalidValue", |
| 83 | + "allowedValues": ["valid", "values"] |
| 84 | +} |
| 85 | +``` |
| 86 | +Errors are standardized via Hono's `defaultHook` intercepting Zod validation failures. |
| 87 | + |
| 88 | +## Data Conventions |
| 89 | + |
| 90 | +These are strict — validation will fail otherwise: |
| 91 | + |
| 92 | +- **Provider**: `"AWS"` or `"Azure"` exactly (case-sensitive) |
| 93 | +- **Coordinates**: Array `[lat, lng]` — not a string |
| 94 | +- **Boolean services**: `true` — not `"true"` |
| 95 | +- **Service IDs**: `vdc_vault`, `vdc_m365`, `vdc_entra_id`, `vdc_salesforce`, `vdc_azure_backup` |
| 96 | +- **Region IDs**: lowercase hyphenated (e.g., `aws-us-east-1`) |
| 97 | +- **Vault editions**: `"Foundation"`, `"Advanced"` |
| 98 | +- **Vault tiers**: `"Core"`, `"Non-Core"` |
| 99 | +- **`vdc_vault`** is tiered (array of `{edition, tier}` objects); all other services are boolean |
| 100 | + |
| 101 | +## Testing Notes |
| 102 | + |
| 103 | +- Playwright tests cover 5 targets: Chromium, Firefox, WebKit, Mobile Chrome (Pixel 7), Mobile Safari (iPhone 15 Pro) |
| 104 | +- Some tests are skipped for WebKit due to Leaflet instability on Linux CI |
| 105 | +- API tests are Node.js integration tests in `scripts/test-api.js` — require a running server |
| 106 | +- Data validation runs automatically on push/PR to `data/regions/` |
| 107 | + |
| 108 | +## Adding Things |
| 109 | + |
| 110 | +**New region:** Copy `.github/region-template.yaml` → `data/regions/{aws|azure}/{provider}_{region_code}.yaml` → run `npm run validate` → `npm run build` |
| 111 | + |
| 112 | +**New API endpoint:** |
| 113 | +1. Create `src/functions/routes/v1/{name}.ts` with Zod schema, `createRoute()`, and handler |
| 114 | +2. Export `register{Name}Route()` |
| 115 | +3. Register in `src/functions/_worker.ts` |
| 116 | +4. Run `npm run typecheck` |
| 117 | + |
| 118 | +**New service type:** Update YAML files, `layouts/index.html` (icon, display name, filter dropdown), Zod schemas in `src/functions/schemas/common.ts`, route enums in `regions.ts`, and `static/llms*.txt` |
| 119 | + |
| 120 | +## Branching & Commits |
| 121 | + |
| 122 | +This project uses **Gitflow**. See `GITFLOW_RELEASE_GUIDE.md` for the full release process. |
| 123 | + |
| 124 | +| Branch | Purpose | |
| 125 | +|--------|---------| |
| 126 | +| `main` | Production only — never commit directly | |
| 127 | +| `develop` | Integration branch — PRs target here by default | |
| 128 | +| `feature/*` | New features, branched from `develop` | |
| 129 | +| `release/X.Y.Z` | Release prep, branched from `develop`, merged to `main` then back to `develop` | |
| 130 | +| `chore/*`, `fix/*`, etc. | Other work types, branched from `develop` | |
| 131 | + |
| 132 | +All commits must follow **Conventional Commits**: |
| 133 | + |
| 134 | +``` |
| 135 | +<type>(<scope>): <description> |
| 136 | +
|
| 137 | +Types: feat, fix, docs, test, chore, refactor, perf, ci, style |
| 138 | +Examples: |
| 139 | + feat(api): add region clustering endpoint |
| 140 | + fix(ui): correct marker position on mobile Safari |
| 141 | + chore(release): bump version to 1.3.0 |
| 142 | +``` |
| 143 | + |
| 144 | +## Development Principles |
| 145 | + |
| 146 | +New code in this project should follow these principles, even where existing code does not: |
| 147 | + |
| 148 | +- **TDD**: Write tests before implementation. For API endpoints, write integration tests in `scripts/test-api.js` first. For UI behaviour, write Playwright tests in `tests/ui.spec.ts` first. |
| 149 | +- **DRY**: Extract shared logic to `src/functions/utils/`. Shared Zod schemas belong in `src/functions/schemas/common.ts`. |
| 150 | +- **SOLID**: Each route file owns one endpoint. Keep handlers thin — push business logic to utils. Don't modify existing route files to add new behaviour; add new files. |
| 151 | +- **KISS**: Prefer explicit, readable code over clever abstractions. The API is stateless and data is static — don't over-engineer. |
| 152 | + |
| 153 | +## LLM Documentation |
| 154 | + |
| 155 | +`static/llms.txt` and `static/llms-full.txt` are API docs optimized for AI consumption. Keep these synchronized with endpoint changes. |
| 156 | + |
| 157 | +## CI/CD |
| 158 | + |
| 159 | +Four GitHub Actions workflows: |
| 160 | +- `validate-data.yml` — Validates YAML on push/PR to `data/regions/` |
| 161 | +- `pr-validation.yml` — Full validation suite on PRs |
| 162 | +- `hugo.yml` — Legacy GitHub Pages backup |
| 163 | +- `region-maintenance.yml` — Weekly scraper (Mondays 9 AM UTC) that creates GitHub issues for data discrepancies |
| 164 | + |
| 165 | +Cloudflare Pages build expects `HUGO_VERSION=0.139.3` and `NODE_VERSION=18` (see `DEPLOYMENT.md`). |
| 166 | + |
| 167 | +## Further Reading |
| 168 | + |
| 169 | +Repo-internal docs to check before re-deriving things: |
| 170 | + |
| 171 | +- `ARCHITECTURE.md` — request flow, middleware stack, OpenAPI generation details, error code enum |
| 172 | +- `DEPLOYMENT.md` — Cloudflare Pages build config, troubleshooting (API returning HTML, build failures) |
| 173 | +- `TESTING.md` — manual test cases for `/api/v1/services*` endpoints |
| 174 | +- `GITFLOW_RELEASE_GUIDE.md` — release branch process and version bumping |
| 175 | +- `.github/copilot-instructions.md` — overlapping guidance with concrete UI/route code examples |
| 176 | +- `.github/instructions/self-explanatory-code-commenting.instructions.md` — project comment-style rules (comment WHY, not WHAT) |
0 commit comments