Files
rustycms/CLAUDE.md

5.0 KiB
Raw Blame History

RustyCMS AI Context

Für AI-Tools: Diese Datei (CLAUDE.md) wird von Claude Code gelesen. Cursor liest .cursor/rules/project.mdc. Beide Dateien haben identischen Inhalt — beim Ändern bitte beide aktualisieren.


Projektstruktur

rustycms/
├── src/                  # Rust API
│   ├── api/
│   │   ├── handlers.rs   # AppState + alle Content-Handler
│   │   ├── response.rs   # format_references, expand/collapse_asset_urls
│   │   ├── assets.rs     # Asset-Endpoints (Upload, Serve, Delete, Folders)
│   │   └── routes.rs     # Axum-Router
│   ├── schema/
│   │   └── validator.rs  # normalize_reference_arrays (single + array refs)
│   └── store/            # FileStore / SqliteStore
├── types/                # Schema-Definitionen (*.json5)
├── content/              # Inhalte als JSON5-Dateien
│   └── assets/           # Bild-Assets (mit Unterordnern)
└── admin-ui/             # Next.js Admin UI (Port 3001)
    ├── src/components/   # React-Komponenten
    ├── src/lib/api.ts    # API-Client
    └── messages/         # i18n (en.json, de.json)

Dev starten

./dev.sh                        # API (Port 3000) + Admin UI (Port 3001)
cd admin-ui && npm run dev      # nur Admin UI
cargo run                       # nur API

Konfiguration

Alle Optionen per Env-Variable (.env.example als Vorlage) oder CLI-Flag:

Env-Variable CLI-Flag Default Zweck
RUSTYCMS_TYPES_DIR --types-dir ./types Schema-Definitionen
RUSTYCMS_CONTENT_DIR --content-dir ./content Content-Dateien
RUSTYCMS_BASE_URL http://host:port Öffentliche API-URL (für Asset-URLs)
RUSTYCMS_API_KEY unset Auth für POST/PUT/DELETE
RUSTYCMS_LOCALES unset z.B. de,en (erstes = Default)
RUSTYCMS_STORE file file oder sqlite
RUSTYCMS_CORS_ORIGIN * Erlaubte CORS-Origin
RUSTYCMS_CACHE_TTL_SECS 60 Response-Cache TTL (0 = aus)

Asset-URL-Strategie

Assets werden immer mit relativem Pfad auf Disk gespeichert:

src: "/api/assets/ordner/datei.jpg"

Die API expandiert beim Ausliefern automatisch abhängig vom Kontext:

  • GET mit _resolve (Frontend-Consumer): relativ → https://api.example.com/api/assets/...
  • GET ohne _resolve (Admin UI bearbeitet): Pfad bleibt relativ
  • POST/PUT (Speichern): absolute URLs werden vor dem Schreiben kollabiert

Implementierung: src/api/response.rsexpand_asset_urls() / collapse_asset_urls()

Collection-Hierarchie (wichtig!)

Collection Zweck Pflichtfelder
img Rohes Bild-Asset src (relativer Pfad), description
image Layout-Komponente name, img (Referenz auf img-Collection)

Regel: postImage → referenziert img direkt. row1Content / row2Content etc. → erwarten image-Einträge, nicht img.

Workflow beim Hinzufügen eines Bildes zu einer Content-Row:

  1. img-Eintrag erstellen (src: "/api/assets/...")
  2. image-Eintrag erstellen (referenziert den img-Eintrag)
  3. image-Slug in rowXContent des Posts eintragen

Referenz-Handling

ReferenceOrInlineField (Admin UI)

  • value ist String → Reference-Modus (Slug-Picker)
  • value ist Objekt ohne _slug → Inline-Modus (Felder direkt eingeben)
  • value ist Objekt mit _slug → aufgelöste Referenz vom API → wird automatisch zu Reference-Modus normalisiert

Normalisierung: admin-ui/src/components/ReferenceOrInlineField.tsx via normalizedValue memo.

Normalisierung beim Schreiben (Rust)

validator::normalize_reference_arrays() konvertiert vor dem Speichern:

  • Einzelne reference/referenceOrInline-Felder: {_slug: "foo", ...}"foo"
  • Array-Items: gleiche Normalisierung per Element
  • Aufgerufen in create_entry und update_entry

Admin UI Konventionen

  • i18n: next-intl, Cookie-basiert. Neue Keys immer in beiden Dateien eintragen: admin-ui/messages/en.json + messages/de.json
  • Tailwind v4: @plugin "tailwindcss-animate" (nicht @import)
  • Kein Dark Mode: @media (prefers-color-scheme: dark) wurde entfernt, keine dark:-Klassen
  • Scroll: html, body { height: 100%; overflow: hidden } — Sidebar scrollt unabhängig von der Seite
  • Neue Komponente: immer prüfen ob Übersetzungs-Namespace in beiden Message-Dateien vorhanden

Axum Routing

Literale Routen haben Vorrang vor Wildcard-Routen — Reihenfolge egal, Axum löst korrekt auf:

.route("/api/assets/folders", get(...).post(...))   // matcht vor:
.route("/api/assets/*path", get(...).delete(...))

Rust-spezifisch

  • clap braucht Feature "env" für Env-Var-Support bei CLI-Args
  • AppState in src/api/handlers.rs — alle neuen geteilten Ressourcen hier hinzufügen
  • Hot-Reload: Änderungen in types/ werden automatisch geladen (kein Neustart nötig)
  • Cache wird bei Schreib-Operationen invalidiert (cache.invalidate_collection())