# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Overview

RustyAstro is an Astro + Svelte frontend for **RustyCMS** (a Rust-based CMS). It fetches all content via REST API, generates TypeScript types from the OpenAPI spec, and deploys as a static site to Firebase Hosting.

**Requires:** RustyCMS running at `PUBLIC_CMS_URL` (default `http://localhost:3000`) for development and build.

## Commands

```bash
# Development (requires RustyCMS running separately)
yarn dev                    # Generates API types, starts Astro dev server on :4321

# Build
yarn build                  # Generate types → Astro build → Pagefind indexing

# Preview production build
yarn preview

# Type generation (requires RustyCMS running)
yarn generate:api-types     # Regenerate src/lib/cms-api.generated.ts from OpenAPI spec

# Cache management
yarn cache:warm             # Pre-populate .cache/cms/ with all common API responses

# Storybook (UI component development)
yarn storybook              # Start Storybook on :6006

# Deploy
yarn deploy                 # Build + firebase deploy
```

There are no test commands — this project has no test suite.

## Architecture

### Data Flow

All content comes from RustyCMS via `src/lib/cms.ts`. At build time, Astro calls CMS functions in `getStaticPaths()` to generate static pages. A caching layer makes the build resilient to CMS downtime.

```
RustyCMS API → cms.ts (process cache + disk cache) → Astro pages → Static HTML
```

### CMS Client (`src/lib/cms.ts`)

The central module for all API access. Key conventions:
- `slug` = URL path (for links, routing)
- `_slug` = API/internal ID (for CMS `GET` requests)
- Slugs are normalized (leading slashes removed)
- Caching: in-process deduplication + disk cache at `.cache/cms/` (Node.js only, lazy-imported)
- Dev mode: no list-caching so new CMS entries appear immediately

### Generated Types

`src/lib/cms-api.generated.ts` is auto-generated from the OpenAPI spec — **never edit manually**. Regenerate with `yarn generate:api-types` after schema changes in RustyCMS.

### Page Routing

- `/` → `src/pages/index.astro` — lists all Pages from CMS
- `/:slug` → `src/pages/[slug].astro` — dynamic page content
- `/post/:slug` → `src/pages/post/[slug].astro` — blog post detail
- `/blog/` and `/posts/` — paginated post lists (both route variants exist)

### Content Block System

Pages contain rows of content blocks. Each block type has a corresponding Svelte component in `src/components/blocks/`. Layout is controlled by `src/lib/block-layout.ts` using a 12-column Tailwind grid — parent containers need `grid grid-cols-12`.

### i18n / Translations

All UI strings come from a CMS translation bundle, never hardcoded in components.

**Flow:**
1. `src/middleware.ts` loads the `app` bundle from CMS once per request → `Astro.locals.translations`
2. In Astro components: `const translations = Astro.locals.translations ?? {}`; use `t(translations, T.key)`
3. In Svelte (SSR): wrap with `<TranslationProvider>` and use `useTranslate()` hook
4. **In `client:load` islands:** `useTranslate()` has no Svelte context during SSR → pass `translations` as a prop from the Astro page and use static `t(translations, T.key)` instead

Translation keys are defined in `src/lib/translations.ts` as the `TRANSLATION_KEYS` array (type-safe). Strings are stored in RustyCMS under `content/de/translation_bundle/app.json5`. Placeholders use `{{name}}` syntax.

### Image Handling

`src/lib/rusty-image.ts` proxies image transforms through RustyCMS (`/api/transform`). Transformed images are cached at `public/images/transformed/` and survive builds. The `RustyImage` component exists in both `.astro` (SSR) and `.svelte` (client islands) variants.

### Layout

`src/layouts/Layout.astro` is the master layout. It:
- Wraps content in `<TranslationProvider>` for Svelte context
- Loads header navigation and footer from CMS
- Optionally renders a `TopBanner` fullwidth image
- Renders `Breadcrumbs` (supports both static labels and translation keys)

### Environment Variables

| Variable | Required | Purpose |
|---|---|---|
| `PUBLIC_CMS_URL` | Yes | RustyCMS base URL (no trailing slash) |
| `PUBLIC_SITE_URL` | No | Canonical/sitemap URL (production) |
| `PUBLIC_SITE_NAME` | No | og:site_name and JSON-LD |
| `PUBLIC_UMAMI_SCRIPT_URL` | No | Analytics |
| `PUBLIC_UMAMI_WEBSITE_ID` | No | Analytics |

### Deployment

Static build deployed to Firebase Hosting. Cache headers: 1-year immutable for assets, 1-hour for HTML. Config in `firebase.json` and `.firebaserc`.
