Datenmodell und Codegenerierung
Änderungen an herd/_model.goat und erneutes Generieren der Anwendung.
Datenmodell und Codegenerierung
Die Datei:
herd/_model.goatbeschreibt die Struktur der Anwendung und ist die wichtigste Informationsquelle, die vom Goat-Generator verwendet wird.
Das Modell definiert unter anderem:
- Anwendungsmetadaten,
- unterstützte Sprachen,
- Benutzerrollen,
- Entitäten,
- Entitätseigenschaften,
- Beziehungen,
- Datenbeschränkungen,
- Lese- und Schreibberechtigungen,
- Entitäten zugewiesene Module,
- CRUD-Verhalten,
- SEO- und SSR-Elemente.
Auf Grundlage dieser Informationen kann Goat konsistente Elemente für viele Anwendungsschichten generieren, unter anderem:
- Go-Modelle,
- DAOs und Repositories,
- DTOs,
- APIs,
- CRUD-Befehle,
- SQL-Migrationen,
- Formulare,
- Listen und Verwaltungsansichten,
- Frontend-Elemente.
Der wichtigste Vorteil besteht nicht allein in der Dateigenerierung. Das Modell ermöglicht es, eine bestimmte Struktur einmal zu beschreiben und diese Definition anschließend in vielen Teilen der Anwendung zu verwenden.
Statt Backend, Datenbank, API und Frontend manuell zu synchronisieren, kannst du das Modell ändern und den Generator die daraus resultierenden Anpassungen erstellen lassen.
Das Modell als Anwendungsbeschreibung
herd/_model.goat sollte vor allem die Absicht und Struktur der Anwendung beschreiben, nicht die Implementierungsdetails jeder generierten Datei.
Vereinfacht dargestellt:
_model.goat
↓
Domänenmodell
↓
Generator
↓
Backend + Datenbank + API + FrontendBeispielsweise kann die Definition eines Feldes:
add --name=title --type=web_titlenicht nur das Backend-Modell beeinflussen, sondern auch die Art der Datenspeicherung, die generierten DTOs, Formulare und Ansichten.
Dadurch muss dieselbe Information nicht mehrfach in verschiedenen Technologien deklariert werden.
Anwendungsmetadaten
Das Modell beginnt mit der grundlegenden Konfiguration der Anwendung:
app --name goat \
--version 0.0.1 \
--path app \
--go-prefix code.pozoga.eu/spozoga/goatcms.com \
--terminal-prefix APP \
--default-language=en \
--supported-languages=pl,en,deDie Definition legt unter anderem fest:
- den Namen der Anwendung,
- die Version,
- den Projektpfad,
- das Präfix der Go-Module,
- das vom Terminal verwendete Präfix,
- die Standardsprache,
- die Liste der unterstützten Sprachen.
Diese Informationen können später vom Generator sowie von einzelnen Anwendungsmodulen verwendet werden.
Rollen und Berechtigungen
Rollen werden direkt im Modell definiert.
Beispiel:
role:add --name=admin --super
role:add --name=manager
role:add --name=userIn diesem Fall verfügt die Anwendung über drei Rollen:
admin,manager,user.
Das Flag:
--superkennzeichnet eine Rolle mit erweiterten Systemberechtigungen.
Rollen können später bei der Definition des Zugriffs auf Entitätseigenschaften verwendet werden.
Beispiel:
def --write=admin,manager --read=userermöglicht es festzulegen, welche Rollen Daten ändern und welche sie lesen dürfen.
Dadurch können grundlegende Zugriffsregeln bereits auf Modellebene definiert werden, statt sie unabhängig in API, Formularen und Backend zu wiederholen.
Basisentitäten
Wenn mehrere Entitäten eine gemeinsame Struktur besitzen, empfiehlt es sich, diese in eine Basisentität auszulagern.
Ein Beispiel ist content:
entity:base:add --name content \
--label slug \
--base base_entityEine Basisentität kann gemeinsame Elemente definieren:
- Eigenschaften,
- Beziehungen,
- Beschränkungen,
- Zugriffsregeln.
Im Projekt content repräsentiert die grundlegende Struktur von in der Anwendung veröffentlichten Inhalten.
Sie kann anschließend verwendet werden von:
- Seiten,
- Dokumentation,
- Artikeln,
- anderen Inhaltstypen.
Entitätseigenschaften
Eigenschaften werden innerhalb des Abschnitts --properties definiert.
Beispiel:
--properties=<<PROPERTIESEOF
def --write=admin,manager --read=user --list
add --name=title \
--type=web_title \
--doc="Title is a short heading that describes the content."
add --name=slug \
--type=web_slug \
--required \
--doc="Slug is a URL-friendly name for the content."
add --name=lang \
--type=language \
--required \
--doc="Language of the current content."
PROPERTIESEOFJede Eigenschaft kann unter anderem festlegen:
- den Namen,
- den Typ,
- die Pflichtangabe,
- die Darstellungsweise,
- den Zugriff,
- die Dokumentation,
- zusätzliches Generatorverhalten.
Der Eigenschaftstyp enthält mehr Informationen als allein der Spaltentyp in der Datenbank.
Beispielsweise:
web_title
web_slug
language
seo_description
block_content
file_setkönnen auch die Art der Validierung, Serialisierung und Darstellung von Daten in der Benutzeroberfläche bestimmen.
Vererbung von Entitäten
Entitäten können Basisentitäten erweitern.
Beispiel einer Dokumentationsentität:
entity:extended --name doc --base contentbedeutet, dass doc die für content definierten Eigenschaften und Verhaltensweisen erbt.
Dadurch lässt sich die Wiederholung von Feldern wie:
title
slug
lang
description
bodyin jeder Entität vermeiden, die Inhalte repräsentiert.
Eine Entität kann gleichzeitig eigene Eigenschaften hinzufügen.
Beispiel:
--properties=<<PROPERTIESEOF
def --write=admin,manager --read=user --list
add --name=ver \
--type=short_text \
--doc="Goat CLI version number for the page"
PROPERTIESEOFAuf diese Weise behält doc das gesamte Modell von content bei, speichert jedoch zusätzlich die Version der Dokumentation.
Beziehungen
Beziehungen zwischen Entitäten können direkt im Modell definiert werden.
Beispiel:
--relations=<<RELATIONSEOF
def --onremove
add --name=owner \
--to=user \
--doc="Owner is the author of the article."
RELATIONSEOFDie Definition bestimmt eine owner-Beziehung zur Entität user.
Der Generator kann solche Informationen an vielen Stellen verwenden:
- im Datenmodell,
- im SQL-Schema,
- in der API,
- im DAO,
- in Formularen,
- in administrativen Ansichten.
Dadurch wird die Beziehung an einer Stelle beschrieben, statt unabhängig in jeder Anwendungsschicht.
Datenbeschränkungen
Das Modell kann auch Beschränkungen für Daten definieren.
Beispiel:
--constraints=<<CONSTRAINTSEOF
unique:add --fields=lang,slug
CONSTRAINTSEOFbedeutet, dass die Kombination:
lang + slugeindeutig sein muss.
Dadurch kann derselbe Slug für verschiedene Sprachen gespeichert werden:
pl / architektura
en / architecture
de / architekturund gleichzeitig wird verhindert, dass zwei Datensätze mit derselben Sprache und demselben Slug erstellt werden.
Entitätsmodule
Eine Entität kann durch Module zusätzliches Verhalten erhalten.
Beispielsweise verwendet die Entität doc:
module:add --name=seo
module:add --name=ssr
module:add --name=crudModule ermöglichen es, eine Entität zu erweitern, ohne die gesamte Implementierung wiederholen zu müssen.
In der Praxis kann das Entitätsmodell somit nicht nur ihre Daten beschreiben, sondern auch die Art und Weise, wie sie von der Anwendung verwendet werden soll.
SEO-Modul
Das Modul:
module:add --name=seofügt Verhalten im Zusammenhang mit Seitenmetadaten hinzu.
Bei einer Entität, die von content erbt, kann es unter anderem Folgendes verwenden:
title
descriptionum die für Suchmaschinen und Mechanismen zur Inhaltsfreigabe benötigten Informationen vorzubereiten.
Dadurch kann die grundlegende SEO-Unterstützung aus dem Modell hervorgehen, statt für jede Seite manuell implementiert zu werden.
SSR-Rendering
Das Modul:
module:add --name=ssrermöglicht es, einen Entitätsdatensatz mit einer öffentlichen Anwendungsroute zu verknüpfen.
Beispiel für die Dokumentation:
module:add \
--name=ssr \
--slug=doc \
--route="/doc/{lang}/{slug}" \
--property:list:list="title,description" \
--property:list:details="title,body"Die Definition gibt unter anderem Folgendes an:
- den öffentlichen Pfad,
- die Art der Datensatzidentifikation,
- die für die Liste benötigten Felder,
- die für die Detailansicht benötigten Felder.
Für ein Beispieldokument kann der resultierende Pfad wie folgt aussehen:
/doc/de/projektarchitekturDas SSR-Modul kann anschließend die Entitätsdaten verwenden, um eine serverseitig gerenderte Seite vorzubereiten.
CRUD-Modul
Das Modul:
module:add --name=crudbestimmt die Art der Behandlung einer Entität durch generierte administrative Operationen.
Beispiel:
module:add \
--name=crud \
--property:list:list="ver,lang,title" \
--property:list:persist="title,slug,lang,description,body,ver"property:list:list bestimmt die Eigenschaften, die bei der Darstellung der Datensatzliste verwendet werden.
property:list:persist bestimmt die Felder, die beim Erstellen und Aktualisieren eines Datensatzes verwendet werden.
Das Modul crud definiert den WebUI/API-Vertrag. Konsolenfelder werden separat mit crud_cli konfiguriert:
module:add \
--name=crud_cli \
--property:list:list="username,email" \
--property:list:persist="password,role,username,email"Die generierten Befehle behalten den Namespace crud:<entity>:*. crud_cli.list steuert die Felder von crud:<entity>:list, während crud_cli.persist die Flags zum Erstellen und Aktualisieren steuert. Der List-Befehl gibt ein JSON-Objekt pro Zeile aus und unterstützt --limit, --order-by, --order-direction und --search.
Erweiterbare Module
Goat ermöglicht außerdem die Definition eigener Modultypen.
Beispiel:
entity:module:def \
--type=top_box_counter \
--query:count=<<QUERYDEFEOF
def --required
QUERYDEFEOF \
--short_text:label=<<LABELDEFEOF
def --required
LABELDEFEOFDie Definition erstellt den Modultyp top_box_counter, der Folgendes erfordert:
- die Abfrage
count, - die Beschriftung
label.
Darauf basierend können anschließend konkrete Module erstellt werden.
Beispiel:
module:add \
--name=admin_counter \
--type=top_box_counter \
--label=Administrators \
--query:count=<<QUERYEOF
where:and --conditions=<<WHEREEOF
eq --field=role --value=admin
WHEREEOF
QUERYEOFDadurch lassen sich wiederverwendbare Anwendungselemente auf einer höheren Abstraktionsebene erstellen.
Anstatt einen Benutzerzähler jedes Mal im Backend und Frontend zu implementieren, kann seine Struktur als Modellmodul definiert werden.
Beispiel eines Dashboard-Moduls
Mehrere Module können zu einer größeren Struktur kombiniert werden.
Beispiel:
entity:module:def \
--type=summary_cards \
--modules:list=<<MODULESLISTEOF
def --types=top_box_counter --required
MODULESLISTEOFAnschließend kann die Entität user eine Reihe von Zählern erhalten:
module:add \
--name=summary_cards \
--type=summary_cards \
--modules:list=<<SUMMARYCARDSOF
module:add \
--name=admin_counter \
--type=top_box_counter \
--label=Administrators \
--query:count=<<QUERYEOF
where:and --conditions=<<WHEREEOF
eq --field=role --value=admin
WHEREEOF
QUERYEOF
module:add \
--name=manager_counter \
--type=top_box_counter \
--label=Managers \
--query:count=<<QUERYEOF
where:and --conditions=<<WHEREEOF
eq --field=role --value=manager
WHEREEOF
QUERYEOF
module:add \
--name=user_counter \
--type=top_box_counter \
--label=Users \
--query:count=<<QUERYEOF
where:and --conditions=<<WHEREEOF
eq --field=role --value=user
WHEREEOF
QUERYEOF
SUMMARYCARDSOFDas Modell beschreibt hier nicht nur die Datenstruktur, sondern auch ein Dashboard-Element und die zu seiner Befüllung benötigten Abfragen.
Dies zeigt, dass herd/_model.goat nicht nur dem Äquivalent einer Datenbankschemadefinition entspricht. Es kann auch eine höhere Ebene des Anwendungsverhaltens beschreiben.
Unabhängige Entitäten
Nicht jede Entität muss von content erben.
Ein Beispiel ist eine Galerie:
entity:add \
--name gallery \
--label title \
--base base_entityIhre Eigenschaften können wie folgt aussehen:
--properties=<<PROPERTIESEOF
def --write=admin,manager --read=user --list
add --name=title \
--type=nice_name \
--doc="Title is a short heading that describes the content."
def --write=admin,manager --read=user
add --name=slug \
--type=web_slug \
--unique \
--doc="Slug is a URL-friendly name for the content."
add --name=files \
--type=file_set \
--doc="Files for the gallery"
PROPERTIESEOFDies zeigt, dass das Modell sowohl auf einer gemeinsamen Basis aufbauende Entitäten als auch vollständig unabhängige Domänenstrukturen beschreiben kann.
Codegenerierung
Nach einer Änderung:
herd/_model.goatstarte den Generator:
goat reoder direkt:
go run ./scripts reDer Generator liest das aktuelle Modell und erstellt die daraus resultierenden Änderungen in der Anwendung.
Der Prozess lässt sich vereinfacht wie folgt darstellen:
herd/_model.goat
↓
herd/gen.goat
↓
Vorlagen
↓
Generator
↓
AnwendungscodeGeneriert werden können unter anderem:
- Modelle,
- Repositories,
- APIs,
- CLI-Befehle,
- Frontend,
- SQL-Migrationen.
Das grundlegende Datenbankschema wird außerdem generiert nach:
app/static/raw/data/sql/migrations/0001_schema.sqlKonfiguration des Generators
Vor größeren Änderungen an der Generierungsweise sollte Folgendes geprüft werden:
herd/gen.goatDie Datei beschreibt den Generierungsprozess, die verwendeten Vorlagen sowie die Orte, an die deren Ergebnisse geschrieben werden.
Wenn du die Generierung vieler ähnlicher Elemente ändern möchtest, ist es in der Regel besser, die entsprechende Vorlage anzupassen, als dieselbe Änderung manuell in vielen Dateien zu wiederholen.
Vereinfacht gesagt:
_model.goatlegt fest, was generiert werden soll,
während:
herd/gen.goat
herd/gen/templates/festlegen, wie das Ergebnis aussehen soll.
Generierter Code kann bearbeitet werden
Der von Goat erzeugte Code bleibt gewöhnlicher Quellcode des Projekts.
Du kannst ihn:
- ändern,
- refaktorieren,
- erweitern,
- um eigene Logik ergänzen,
- wie jeden anderen Code committen.
Der Generator soll die Arbeit beschleunigen und den Benutzer nicht in seinem Generierungsmodell einschränken.
Daher muss nicht jede Änderung in herd/_model.goat abgebildet werden.
Wenn du eine einmalige, für eine bestimmte Funktionalität spezifische Anpassung benötigst, kann die direkte Bearbeitung des generierten Codes die einfachste Lösung sein.
Wenn du jedoch bemerkst, dass du dieselbe Änderung wiederholt ausführst, lohnt es sich, sie eine Ebene höher zu verschieben — in das Modell oder die Generatorvorlage.
Wann sollte das Modell geändert werden?
Ändere herd/_model.goat, wenn die Anpassung die Struktur oder das Verhalten der Domäne betrifft.
Beispiele:
- Hinzufügen einer Entität,
- Hinzufügen einer Eigenschaft,
- Ändern einer Beziehung,
- Hinzufügen einer Einschränkung,
- Ändern von Berechtigungen,
- Hinzufügen eines Moduls,
- Ändern der CRUD-Konfiguration,
- Ändern der öffentlichen Route einer Entität.
Beispiel:
add \
--name=published_at \
--type=datetimeWenn published_at ein Element des Domänenmodells ist, sollte es genau hier beschrieben werden.
Wann sollte die Vorlage geändert werden?
Ändere die Generatorvorlage, wenn die Änderung alle Elemente eines bestimmten Typs betreffen soll.
Beispiele:
- alle Formulare sollen eine zusätzliche Struktur erhalten,
- jeder generierte Endpoint soll einen neuen Mechanismus verwenden,
- alle Entitäten sollen zusätzlichen Hilfscode erhalten,
- du möchtest die Konvention des generierten Frontends ändern.
Solche Änderungen sollten am besten in:
herd/gen/templates/vorgenommen werden, anstatt viele generierte Dateien einzeln zu korrigieren.
Wann sollte der Code direkt bearbeitet werden?
Die direkte Bearbeitung ist angebracht, wenn die Änderung spezifisch für einen konkreten Fall ist.
Beispielsweise:
- ungewöhnliche Geschäftslogik,
- zusätzliche Integration,
- spezieller Endpoint,
- besonderes Verhalten eines einzelnen Formulars,
- komplexe Abfrage,
- manuelle Optimierung,
- benutzerdefiniertes UI-Element.
Es besteht keine Notwendigkeit, den Generator nur deshalb zu verkomplizieren, um eine einzelne Ausnahme zu behandeln.
Ein gutes Kriterium ist die Frage:
Beschreibt diese Änderung eine Projektregel oder eine Ausnahme, die für eine einzelne Funktionalität charakteristisch ist?
Regeln sollten in das Modell oder den Generator übernommen werden. Ausnahmen können direkt im Code verbleiben.
Sicherer Änderungsprozess
Eine typische Modelländerung sieht wie folgt aus:
Änderung von _model.goat
↓
goat re
↓
git diff
↓
manuelle Nachbearbeitung des Codes
↓
Tests
↓
CommitIn der Praxis:
# ändere das Modell
vim herd/_model.goat
# generiere die Änderungen
goat re
# prüfe das Ergebnis
git diff
# führe die Tests aus
goat run:script --path=herd/test.goatgit diff ist besonders wichtig, da es ermöglicht, den tatsächlichen Umfang der vom Generator vorbereiteten Änderungen zu sehen.
Behandle die Generierung nicht als Operation, deren Ergebnis ohne Kontrolle übernommen werden sollte.
Der Generator bereitet den Code vor, aber die endgültige Entscheidung über die Änderung liegt beim Entwickler.
Modell und bestehende Datenbank
Eine Modelländerung kann eine Änderung des generierten SQL-Schemas verursachen.
Das bedeutet nicht automatisch, dass sie für eine bestehende Datenbank sicher ist.
Beispielsweise:
Änderung von _model.goat
↓
Änderung des Zielschemasist nicht dasselbe wie:
sichere Migration bestehender DatenBesondere Aufmerksamkeit erfordern unter anderem:
- das Entfernen von Feldern,
- Typänderungen,
- das Hinzufügen erforderlicher Felder,
- Änderungen von Beziehungen,
- neue Einschränkungen,
- Änderungen von Indizes.
Überprüfe vor der Bereitstellung einer solchen Änderung das generierte SQL und bereite einen geeigneten Migrationspfad vor.
Das Modell als Schicht für KI
Das deklarative Anwendungsmodell bietet bei der Arbeit mit KI einen zusätzlichen Vorteil.
In vielen Fällen muss das Modell nicht separat analysieren:
Go-Modell
DAO
DTO
API
Migrationen
Formular
Angular-AnsichtStattdessen kann es eine einzige Definition ändern:
herd/_model.goatund anschließend Goat die Folgen dieser Änderung generieren lassen.
Beispielsweise:
„Dokument sollte ein Veröffentlichungsdatum besitzen“
↓
KI ändert _model.goat
↓
goat re
↓
Aktualisierung der erforderlichen SchichtenDies reduziert die für die Analyse erforderliche Code-Menge und begrenzt das Risiko, eine der Schichten zu übersehen.
Nicht jede Änderung sollte jedoch über das Modell erfolgen. Wenn die Aufgabe einen einzelnen Teil der Implementierung betrifft, kann eine direkte Bearbeitung des Codes effizienter sein.
Beispielmodell
Der folgende Ausschnitt zeigt einige grundlegende Möglichkeiten des Goat-Modells:
# App metadata
app --name goat \
--version 0.0.1 \
--path app \
--go-prefix code.pozoga.eu/spozoga/goatcms.com \
--terminal-prefix APP \
--default-language=en \
--supported-languages=pl,en,de
# Roles
role:add --name=admin --super
role:add --name=manager
role:add --name=user
# Dashboard module types
entity:module:def --type=top_box_counter --query:count=<<QUERYDEFEOF
def --required
QUERYDEFEOF --short_text:label=<<LABELDEFEOF
def --required
LABELDEFEOF
entity:module:def --type=summary_cards --modules:list=<<MODULESLISTEOF
def --types=top_box_counter --required
MODULESLISTEOF
# User
entity:overwrite --name=user --base=user_base_entity --system=<<ENTITYSYSTEMEOF
module:add --name=summary_cards --type=summary_cards --modules:list=<<SUMMARYCARDSOF
module:add --name=admin_counter --type=top_box_counter --label=Administrators --query:count=<<QUERYEOF
where:and --conditions=<<WHEREEOF
eq --field=role --value=admin
WHEREEOF
QUERYEOF
module:add --name=manager_counter --type=top_box_counter --label=Managers --query:count=<<QUERYEOF
where:and --conditions=<<WHEREEOF
eq --field=role --value=manager
WHEREEOF
QUERYEOF
module:add --name=user_counter --type=top_box_counter --label=Users --query:count=<<QUERYEOF
where:and --conditions=<<WHEREEOF
eq --field=role --value=user
WHEREEOF
QUERYEOF
SUMMARYCARDSOF
module:add --name=crud \
--property:list:list="username,email" \
--property:list:persist="role,username,email"
module:add --name=crud_cli \
--property:list:list="username,email" \
--property:list:persist="password,role,username,email"
ENTITYSYSTEMEOF
# Base content entity
entity:base:add --name content --label slug --base base_entity --properties=<<PROPERTIESEOF
def --write=admin,manager --read=user --list
add --name=title \
--type=web_title \
--doc="Title is a short heading that describes the content."
add --name=slug \
--type=web_slug \
--required \
--doc="Slug is a URL-friendly name for the content."
add --name=lang \
--type=language \
--required \
--doc="Language of the current content."
def --write=admin,manager --read=user
add --name=description \
--type=seo_description \
--doc="Short description for SEO and social media."
add --name=body \
--type=block_content \
--doc="Body contains the content data structured into blocks."
PROPERTIESEOF --relations=<<RELATIONSEOF
def --onremove
add --name=owner \
--to=user \
--doc="Owner is the author of the article."
RELATIONSEOF --constraints=<<CONSTRAINTSEOF
unique:add --fields=lang,slug
CONSTRAINTSEOF
# Page
entity:extended --name page --base content --doc=<<DOCEOF
Pages are the main sections of the website.
They contain essential content that rarely changes and
plays an important role in the overall structure and context of the website.
DOCEOF --system=<<ENTITYSYSTEMEOF
module:add --name=seo
module:add --name=ssr \
--slug=page \
--property:list:list="title,description" \
--property:list:details="title,body"
module:add --name=crud \
--property:list:list="title,description" \
--property:list:persist="title,slug,lang,description,body"
module:add --name=crud_cli \
--property:list:list="title,description" \
--property:list:persist="title,slug,lang,description,body"
ENTITYSYSTEMEOF
# Documentation
entity:extended --name doc --base content --doc=<<DOCEOF
The document contains comprehensive project documentation,
including available commands, configuration details,
usage examples and other information required to work
with the project effectively.
DOCEOF --properties=<<PROPERTIESEOF
def --write=admin,manager --read=user --list
add --name=ver \
--type=short_text \
--doc="Goat CLI version number for the page"
PROPERTIESEOF --system=<<ENTITYSYSTEMEOF
module:add --name=seo
module:add --name=ssr \
--slug=doc \
--route="/doc/{lang}/{slug}" \
--property:list:list="title,description" \
--property:list:details="title,body"
module:add --name=crud \
--property:list:list="ver,lang,title" \
--property:list:persist="title,slug,lang,description,body,ver"
module:add --name=crud_cli \
--property:list:list="ver,lang,title" \
--property:list:persist="title,slug,lang,description,body,ver"
ENTITYSYSTEMEOF
# Gallery
entity:add --name gallery --label title --base base_entity --properties=<<PROPERTIESEOF
def --write=admin,manager --read=user --list
add --name=title \
--type=nice_name \
--doc="Title is a short heading that describes the content."
def --write=admin,manager --read=user
add --name=slug \
--type=web_slug \
--unique \
--doc="Slug is a URL-friendly name for the content."
add --name=files \
--type=file_set \
--doc="Files for the gallery"
PROPERTIESEOFDieses Beispiel zeigt die wichtigste Idee des Goat-Modells: Eine einzige deklarative Definition kann nicht nur die Datenbank beschreiben, sondern auch Berechtigungen, Beziehungen, CRUD, Routing, SEO, SSR und Elemente der Benutzeroberfläche.
Wichtigste Regel
Das Modell sollte diejenigen Elemente der Anwendung übernehmen, die sich wiederholen und deklarativ beschreiben lassen.
Der Generator übersetzt sie in eine konkrete Implementierung, und der generierte Code bleibt vollständig unter der Kontrolle des Entwicklers.
In der Praxis kannst du auf drei Ebenen arbeiten:
Modell — wenn die Änderung die Struktur und Regeln der Anwendung betrifft,
Generator und Vorlagen — wenn du die Art ändern möchtest, wie eine ganze Klasse von Elementen erstellt wird,
Anwendungscode — wenn du eine individuelle Implementierung benötigst.
Es geht nicht darum, um jeden Preis möglichst große Teile des Projekts zu generieren.
Goat soll das generieren, was sich wiederholt, damit mehr Zeit für Code bleibt, der die Anwendung tatsächlich auszeichnet.