diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..0eacff4 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,108 @@ +# 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`.