Nowy projekt: od goat init do pierwszego modelu

Ten przewodnik prowadzi przez utworzenie projektu na starterze goatcms-child, konfigurację .env, uruchomienie środowiska przez herd/dev.goat i dodanie pierwszej własnej encji.

Wymagania

  • Goat CLI (goat) w PATH,
  • Docker (uruchomiony),
  • Git,
  • Python 3 i qtc — tylko dla skryptów child/*.sh,
  • Go 1.25+ — opcjonalnie, do uruchamiania testów na hoście.

PostgreSQL, Node.js i kompilator Go dla backendu działają w kontenerach.

1. Utwórz projekt

goat init ./my-app \
  --template goatcms-child \
  --name my-app \
  --git-repo https://github.com/acme/my-app.git
FlagaZnaczenie
--templateWbudowany szablon. goatcms-child to mały starter aplikacji: logowanie, panel admina, strony, przykładowy model note, frontend Angular. Domyślny goatcms to pełny serwis z blogiem, dokumentacją i sklepem.
--nameNazwa projektu (litery, cyfry, ., _, -). Wymagana.
--git-repoAdres repozytorium. Wymagany; zostaje ustawiony jako origin.
--default-language, --supported-languagesJęzyki aplikacji (domyślnie en oraz pl,en,de).
--terminal-prefixPrefiks zmiennych terminala (domyślnie APP).

Katalog docelowy musi być pusty lub nie istnieć. goat init kopiuje szablon, wykonuje git init i dodaje origin — niczego nie buduje ani nie pobiera.

Starter goatcms-child zachowuje na razie oryginalną ścieżkę modułu Go (code.pozoga.eu/spozoga/goatcms.com) i nazwę binarki goatcms. Projekt działa bez zmian; jeśli chcesz je zmienić, zrób to od razu w go.mod, w --go-prefix w herd/_model.goat i w importach w child/, zanim projekt urośnie.

Zrób od razu pierwszy commit — każda późniejsza regeneracja będzie wtedy czytelna w git diff.

2. Skonfiguruj .env

cd my-app
cp .env.example .env

Uzupełnij co najmniej GOAT_JWT_SECRET_KEY, np. wartością z:

openssl rand -hex 32

Najważniejsze zmienne:

ZmiennaPrzykładUwagi
GOAT_DEV_APP_PORT8091Port aplikacji w developmencie.
GOAT_HOST:8091Adres nasłuchu; trzymaj zgodny z portem.
GOAT_URL_BASEhttp://localhost:8091Publiczny adres — linki w mailach, SEO.
GOAT_DOMAINlocalhostDomena środowiska (bez protokołu i portu).
GOAT_DB_MAIN_HOST / PORTlocalhost / 55432Baza deweloperska. Inny port dla każdego projektu.
GOAT_DB_MAIN_NAME / USER / PASSstarterDane dostępowe tworzonego kontenera PostgreSQL.
GOAT_JWT_SECRET_KEYlosowy hexWymagany. Zmiana unieważnia sesje.
GOAT_DIR_TMP, GOAT_DIR_DATA, GOAT_DIR_DIST, GOAT_DIR_SHARED_TMP./data itd.Katalogi robocze; zostaw domyślne.
GOAT_SMTP_*pusteOpcjonalne. Bez SMTP maile nie są wysyłane.
GOAT_AI_OPENAI_API_KEY, GOAT_AI_OPENAI_MODELpuste, gpt-4o-miniOpcjonalne — włącza asystenta AI w panelu.

Dane do commitów i pushy wykonywanych przez skrypty Goat trzymaj w .private.env (wzór: .example.private.env).

.env i .private.env nigdy nie trafiają do repozytorium. Gdy uruchamiasz kilka projektów naraz, zmień GOAT_DEV_APP_PORT, GOAT_HOST, GOAT_URL_BASE i GOAT_DB_MAIN_PORT razem.

Więcej: [konfiguracja środowiska](/doc/pl/konfiguracja).

3. Uruchom projekt przez herd/dev.goat

goat run:script --path herd/dev.goat

Skrypt wczytuje .env i uruchamia child/dev/runtime.goat, który:

  1. wykonuje re — pobiera moduły z herd/_modules.goat do .goat/modules/ i generuje goatapp/,
  2. równolegle startuje trzy zadania:
  • database — PostgreSQL 17 na GOAT_DB_MAIN_PORT, dane w .cache/postgres,
  • backend — buduje binarkę w kontenerze Go, czeka na bazę, wykonuje db:migrate, child:db:migrate, ładuje herd/fixture.goat i uruchamia serve,
  • frontend — instaluje zależności i uruchamia watchery Angular (panel, child-app, elementy foundation) według herd/dev/frontends.json.

Pierwsze uruchomienie trwa kilka minut (obrazy Dockera, zależności npm, pierwsze buildy Angulara). Poczekaj, aż watchery zakończą pierwszy build, zanim otworzysz frontend.

Po starcie:

AdresCo tam jest
http://localhost:8091/Publiczne strony (SSR), /pl dla polskiej wersji
http://localhost:8091/app/Panel administracyjny
http://localhost:8091/child/Własna aplikacja Angular projektu

Konta deweloperskie z fixture'ów: admin / starter-dev-123 i user / starter-dev-123. Zmień hasła, zanim udostępnisz instancję komukolwiek.

Praktyczne uwagi:

  • Baza jest zachowywana między uruchomieniami; wykonywane są tylko brakujące migracje. Fixture'y ładują się przy każdym starcie backendu, więc muszą być idempotentne.
  • herd/dev.goat generuje kod raz, przy starcie. Po zmianie modelu zatrzymaj skrypt (Ctrl+C) i uruchom go ponownie.
  • Jeśli chcesz automatycznego restartu po zmianach modelu, szablonów i backendu, użyj supervisora: bash child/setup.sh (jednorazowo), potem bash child/dev.sh. Supervisor korzysta z własnego kontenera goat-starter-<port> na tym samym porcie — nie uruchamiaj obu wariantów jednocześnie (docker stop goat-starter-55432).
  • Błąd „port is already allocated” prawie zawsze oznacza drugi projekt albo drugi wariant dev na tym samym porcie.

4. Gdzie co jest

herd/_model.goat        model: encje, role, moduły, dashboard
herd/_modules.goat      moduły frameworka (goatcore, goatcms)
herd/fixtures/          dane przykładowe ładowane przez herd/fixture.goat
child/app/              Twój kod Go: layout, trasy, serwisy, komendy, migracje
child/web/              Twoja aplikacja Angular (/child/)
child/static/raw/       Twoje statyczne zasoby (CSS motywu, obrazy)
goatapp/                kod generowany — nigdy nie edytuj ręcznie

Zasada podziału: to, co wynika z modelu, opisujesz w herd/; to, co jest specyficzne dla aplikacji, piszesz w child/. Wszystko w goatapp/ zostanie nadpisane przy następnym goat re.

5. Pierwsza własna encja

Dodaj do herd/_model.goat encję zadania przypisanego do użytkownika:

entity:add --name=task --label=title --base=base_entity --doc=<<DOCEOF
    A task assigned to a team member.
DOCEOF --properties=<<PROPERTIESEOF
    def --write=admin,manager --read=admin,manager,user
    add --name=title --type=short_text --required --doc="Short task name."
    add --name=description --type=short_text
    add --name=due_at --type=date_time
    add --name=done --type=bool
PROPERTIESEOF --relations=<<RELATIONSEOF
    def --onremove
    add --name=assignee --to=user --doc="User responsible for the task."
RELATIONSEOF --system=<<ENTITYSYSTEMEOF
    module:add --name=crud --property:list:list="title,due_at,done" --property:list:persist="title,description,due_at,done"
    module:add --name=crud_cli --property:list:list="title,done" --property:list:persist="title,description,due_at,done"
    module:add --name=harness --property:list:list="title,done" --property:list:persist="title,description,due_at,done"
ENTITYSYSTEMEOF

Dodaj link w nawigacji dashboardu (w bloku --navigation w app:module:add --name=dashboard):

link:add --label="Tasks" --entity=task

Co dają moduły:

  • crud — API i formularze w panelu /app/,
  • crud_cli — komendy crud:task:*, w tym crud:task:persist do fixture'ów,
  • harness — narzędzia asystenta AI dla tej encji (pomiń, jeśli nie chcesz udostępniać danych AI),
  • seo i ssr — tylko dla treści publicznych (wzór: encja page).

Następnie:

goat re                 # regeneracja goatapp/
git diff                # przejrzyj zmiany w herd/ i child/

Na istniejącej bazie wygeneruj migrację modelu, przejrzyj SQL i zrestartuj herd/dev.goat:

goat run:script --path=@goatcms/herd/db/migration_generate.goat

Migracja trafia do child/app/migrations/sql/0000_goatmigrations/. Sprawdź konwersje typów, operacje usuwające dane i blokady tabel. Ręczny SQL aplikacji umieszczaj w 0001_childigrations/.

Na koniec dodaj dane przykładowe, np. herd/fixtures/tasks/fixture.goat:

crud:task:persist --title="Prepare release notes" --done=false

i podepnij go w herd/fixture.goat:

run:script --path herd/fixtures/tasks/fixture.goat

Pełna składnia modelu: [model danych i generowanie kodu](/doc/pl/model-i-generowanie).

Dobre praktyki

Model

  • Zaczynaj od modelu. Encje, pola, relacje, uprawnienia i listy kolumn opisuj w herd/_model.goat, a nie w ręcznym kodzie.
  • Każdej encji i polu dodawaj --doc. Te opisy trafiają do kodu, API i asystenta AI.
  • Uprawnienia ustawiaj jawnie w def --write=... --read=.... Nie polegaj na domyślnych.
  • Używaj typów semantycznych (web_slug, seo_description, language, image, block_content) zamiast ogólnego short_text tam, gdzie pasują — dają walidację i właściwe kontrolki.
  • Wspólne pola wyciągaj do bazy (entity:base:add) i dziedzicz przez entity:extended, jak content → page.
  • Unikalność deklaruj w modelu (--unique lub unique:add --fields=lang,slug) — na niej opierają się idempotentne fixture'y persist.
  • Zmieniaj model małymi krokami: jedna zmiana → goat re → git diff → testy → commit.

Kod

  • Nigdy nie edytuj goatapp/. Jeżeli wygenerowany kod się nie nadaje, zmień model albo szablon w herd/gen/.
  • Logikę biznesową, własne trasy i serwisy pisz w child/, importując foundation pełną ścieżką pakietu.
  • Commituj herd/ i child/; goatapp/ jest generowany i ignorowany przez Git.

Baza i dane

  • Nie zmieniaj nazw ani treści zastosowanych już migracji — dodawaj nowe.
  • Fixture'y pisz tylko przez crud:*:persist z kluczem unikalnym, tak aby wielokrotne uruchomienie dawało ten sam stan.
  • Fixture'y deweloperskie (konta, hasła) nigdy nie mogą trafić na produkcję.

Środowisko

  • Jeden projekt — jeden zestaw portów w .env.
  • Sekrety tylko w .env / .private.env, nigdy w repozytorium.
  • Przed commitem uruchom testy: goat run:script --path=herd/test.goat.

Następne kroki

  • [Architektura projektu](/doc/pl/architektura)
  • [Model danych i generowanie kodu](/doc/pl/model-i-generowanie)
  • [Baza danych i migracje](/doc/pl/baza-danych)
  • [Dane testowe i fixture'y](/doc/pl/dane-testowe)
  • [Moduł harness: asystent AI](/doc/pl/modul-harness)