5.0 KiB
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.rs → expand_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:
img-Eintrag erstellen (src: "/api/assets/...")image-Eintrag erstellen (referenziert denimg-Eintrag)image-Slug inrowXContentdes Posts eintragen
Referenz-Handling
ReferenceOrInlineField (Admin UI)
valueist String → Reference-Modus (Slug-Picker)valueist Objekt ohne_slug→ Inline-Modus (Felder direkt eingeben)valueist 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_entryundupdate_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, keinedark:-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
clapbraucht Feature"env"für Env-Var-Support bei CLI-ArgsAppStateinsrc/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())