5.9 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.
Arbeitsweise: Erklärungen beim Implementieren
Beim Umsetzen von Aufgaben soll die AI kurz und nachvollziehbar erklären, was sie tut:
- Ziel und Vorgehen: Zu Beginn (oder im ersten Schritt) in 1–2 Sätzen sagen, was umgesetzt wird und wie (welche Dateien, welches Muster).
- Schritte sichtbar machen: Bei mehreren Änderungen z. B. kurz benennen: „Als Nächstes: …“, „Dann: …“, damit der Ablauf klar ist.
- Ungewöhnliche Entscheidungen begründen: Wenn etwas von Konventionen abweicht (andere Lib, anderer Ordner, Workaround), warum (z. B. „Damit Tailwind-Klassen zuverlässig greifen“).
- Am Ende zusammenfassen: In 2–4 Sätzen: Was wurde geändert, wo es liegt, was der Nutzer prüfen kann.
Die Erklärungen sollen knapp bleiben, aber so formuliert sein, dass jemand den Gedankengang und die Änderungen nachvollziehen kann, ohne alles selbst zu lesen.
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())