From 7ef080ba88ca6432b42b3a2b476be54ce6a7dbc0 Mon Sep 17 00:00:00 2001 From: Sebastian Frank Date: Mon, 5 Oct 2026 18:30:22 +0000 Subject: [PATCH] =?UTF-8?q?docs(agent):=20meta.agent=20Anleitungen=20plus?= =?UTF-8?q?=20Design-Guide=20f=C3=BCr=20freie=20Bl=C3=B6cke?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ohne Repo verständlich: Routen, Lookup-Pfade, Upload-Format src/path, translationKey-Falle, SSR-Cache, Tailwind/Svelte-Regeln. --- api/collections/comment.yml | 7 +++++++ api/collections/content.yml | 10 ++++++++++ api/collections/medialib.yml | 8 ++++++++ api/collections/navigation.yml | 8 ++++++++ api/collections/tag.yml | 5 +++++ api/config.yml | 9 +++++++++ 6 files changed, 47 insertions(+) diff --git a/api/collections/comment.yml b/api/collections/comment.yml index 159147fa..ebd48fd8 100644 --- a/api/collections/comment.yml +++ b/api/collections/comment.yml @@ -7,6 +7,13 @@ meta: muiIcon: chat group: community imageUrl: "https://images.unsplash.com/photo-1522096823084-2d1aa8411c13?auto=format&fit=crop&q=80&w=800" + agent: + purpose: "Page comments counted via aggregate and listed per contentId." + instructions: "Required: contentId (content.id), author, message. App loads aggregate commentCount plus list {active:true, contentId}. Only active:true is public." + fieldHints: + contentId: "content.id the comment belongs to" + examples: [{ author: "Demo", message: "Nice page", active: true }] + hints: ["mutations invalidate SSR via clear_cache hooks"] preview: label: author secondary: message diff --git a/api/collections/content.yml b/api/collections/content.yml index 39b08a03..c9270ed1 100644 --- a/api/collections/content.yml +++ b/api/collections/content.yml @@ -30,6 +30,16 @@ meta: - group: seo label: { de: "SEO", en: "SEO" } viewHint: cards + agent: + purpose: "CMS pages rendered by App.svelte + BlockRenderer (hero, features, richtext, accordion, contact-form)." + instructions: "Required: name, path, lang. Always set translationKey (unique per lang, avoids null/de collision) and active:true for public. path pattern ^/[a-z0-9-/]*$. Blocks: hero needs headline + heroImage.image (medialib ID); richtext needs text + imagePosition none/left/right + image (medialib ID, only shown when lookup resolves file.src); features needs featureBoxes[{icon,title,text}] with icon in lightning/palette/database/globe/monitor/flask; accordion needs accordionItems[{question,answer,open}]; contact-form needs headline + anchorId. Always request lookup blocks.heroImage.image:medialib,blocks.image:medialib." + fieldHints: + path: "lowercase, e.g. /ueber-uns; stored without language prefix" + translationKey: "required, e.g. home/ueber-uns/kontakt; unique per lang" + blocks: "type selects visible fields via dependsOn $parent.type" + examples: [{ name: "Startseite", path: "/", lang: "de", translationKey: "home", active: true }] + workflows: ["filter before create (path+lang) to stay idempotent; 409 means exists", "after PUT/DELETE verify /de and /api/content?lookup; SSR invalidates via clear_cache hooks"] + hints: ["richtext image only renders when _lookup.image.file.src exists", "hero fallback is gradient when no image"] hooks: get: diff --git a/api/collections/medialib.yml b/api/collections/medialib.yml index 6f4218d5..80bec97b 100644 --- a/api/collections/medialib.yml +++ b/api/collections/medialib.yml @@ -40,6 +40,14 @@ meta: muiIcon: file_document filter: file.type_like: ^(?!image/|video/|audio/).+ + agent: + purpose: "Reusable uploads referenced via foreignMedia (blocks.heroImage.image, blocks.image)." + instructions: "Upload file as object {src:'data:;base64,...', path:'name.jpg'} (path optional). Stored as {src:'/name.jpg', path, type}. Never {filename,data}, never file as plain string. Public read URL: /api/medialib// plus ?filter=l-webp for raster images. downscale max 2048px applies on upload." + fieldHints: + file: "required, widget file, max 50MB" + alt: "object {de,en}, used by MedialibImage for accessibility" + examples: [{ title: "Demo Hero 1200", file: { src: "data:image/jpeg;base64,...", path: "demo-hero-1200.jpg" } }] + hints: ["list with select excluding file.data to avoid context bloat", "verify file.src starts with / after create"] permissions: public: diff --git a/api/collections/navigation.yml b/api/collections/navigation.yml index 802934b9..1a3d5644 100644 --- a/api/collections/navigation.yml +++ b/api/collections/navigation.yml @@ -49,6 +49,14 @@ meta: sidebar: - group: settings label: { de: "Einstellungen", en: "Settings" } + agent: + purpose: "Header/footer trees per language, rendered by App.svelte from elements." + instructions: "Singletons: type header/footer x language de/en (unique type+language). elements: {name, page->content.id} internal, {name, external:true, externalUrl} external, optional hash without #. Always request lookup elements.page:content; href = localizedPath(_lookup.page.path) + hash." + fieldHints: + type: "header or footer" + language: "de or en" + examples: [{ language: "de", type: "header", elements: [{ name: "Start", page: "" }] }] + hints: ["page holds content.id, resolve via _lookup.page.path", "never hardcode /de prefix in DB"] hooks: get: diff --git a/api/collections/tag.yml b/api/collections/tag.yml index 399b3237..faf8ef16 100644 --- a/api/collections/tag.yml +++ b/api/collections/tag.yml @@ -50,6 +50,11 @@ meta: return 'background:' + raw + ';color:' + text + ';border:1px solid ' + border })() //!js + agent: + purpose: "Managed keywords referenced by medialib.tags." + instructions: "No public filter hook by design (no active field); keep names short, group system/kategorie. Mutations invalidate SSR via clear_cache hooks." + examples: [{ name: "hero", group: "system" }] + hints: ["name is unique"] permissions: public: diff --git a/api/config.yml b/api/config.yml index db5836b8..78aa46f3 100644 --- a/api/config.yml +++ b/api/config.yml @@ -1,6 +1,15 @@ namespace: __TIBI_NAMESPACE__ meta: + agent: + description: "Tibi Svelte starter: Svelte 5 SPA with pagebuilder blocks, goja SSR, per-language navigation." + frontend: + routes: "/:lang/* (e.g. /de/, /de/ueber-uns); / redirects to browser language; content.path stored without language prefix" + lookup: "content: blocks.heroImage.image:medialib, blocks.image:medialib; navigation: elements.page:content; comments via aggregate on comment.contentId" + rendering: "App.svelte loads getCachedEntries(content, {lang, path, active:true} + lookup); BlockRenderer maps Hero/Features/Richtext/Accordion/ContactForm; images only via widgets/MedialibImage.svelte" + designGuide: "Future free code/HTML blocks: add block type in content.blocks (type + fields with dependsOn $parent.type), Svelte component in frontend/src/blocks/ + case in BlockRenderer.svelte, keep admin preview contract; Svelte 5 runes ($props/$state/$derived, never destructure block), SSR-safe (window guards), MedialibImage is the only image boundary (file.src or data URI, no ?filter on data URIs), Tailwind v4 canonical (bg-linear-to-*, aspect-video/square else arbitrary, trailing ! e.g. bg-brand-600!), i18n via svelte-i18n ($_), always pass foreignMedia lookup explicitly" + workflows: ["Create page (name, path, lang, translationKey, active:true) -> fill blocks -> link navigation -> verify /de plus /api/content?lookup -> respect SSR cache (POST creates, PUT/DELETE invalidate via clear_cache hooks)", "Upload image (medialib file {src:data URI, path}) -> put ID into heroImage.image or blocks.image -> verify with lookup (file.src must be /)"] + hints: ["Public reads need active:true plus publication window (filter_public)", "path pattern ^/[a-z0-9-/]*$ (lowercase, no umlauts)", "translationKey+lang and path+lang are unique: always set translationKey, else second doc collides on null/de", "File upload: {src:'data:;base64,...', path:'n.jpg'} (path optional); stored {src:'/n.jpg', type}; never {filename,data}, never file as plain string", "Reads with select/projection excluding file.data (else context bloat); file.src is enough", "SSR cache lives in ssr collection with dependencies content:/content:*/medialib:*/navigation:*/comment:*; after manual MCP writes use ssr?clear=1 if needed"] imageUrl: eval: "$projectBase + '_/assets/img/admin-pic.svg'" i18n: