# 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 `` 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 `` 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`.