Nowy projekt: od goat init do pierwszego modelu
Tworzenie projektu goatcms-child, konfiguracja .env, uruchomienie przez herd/dev.goat, pierwsza encja i dobre praktyki.
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) wPATH, - Docker (uruchomiony),
- Git,
- Python 3 i
qtc— tylko dla skryptówchild/*.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| Flaga | Znaczenie |
--template | Wbudowany 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. |
--name | Nazwa projektu (litery, cyfry, ., _, -). Wymagana. |
--git-repo | Adres repozytorium. Wymagany; zostaje ustawiony jako origin. |
--default-language, --supported-languages | Języki aplikacji (domyślnie en oraz pl,en,de). |
--terminal-prefix | Prefiks 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-childzachowuje na razie oryginalną ścieżkę modułu Go (code.pozoga.eu/spozoga/goatcms.com) i nazwę binarkigoatcms. Projekt działa bez zmian; jeśli chcesz je zmienić, zrób to od razu wgo.mod, w--go-prefixwherd/_model.goati w importach wchild/, 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 .envUzupełnij co najmniej GOAT_JWT_SECRET_KEY, np. wartością z:
openssl rand -hex 32Najważniejsze zmienne:
| Zmienna | Przykład | Uwagi |
GOAT_DEV_APP_PORT | 8091 | Port aplikacji w developmencie. |
GOAT_HOST | :8091 | Adres nasłuchu; trzymaj zgodny z portem. |
GOAT_URL_BASE | http://localhost:8091 | Publiczny adres — linki w mailach, SEO. |
GOAT_DOMAIN | localhost | Domena środowiska (bez protokołu i portu). |
GOAT_DB_MAIN_HOST / PORT | localhost / 55432 | Baza deweloperska. Inny port dla każdego projektu. |
GOAT_DB_MAIN_NAME / USER / PASS | starter | Dane dostępowe tworzonego kontenera PostgreSQL. |
GOAT_JWT_SECRET_KEY | losowy hex | Wymagany. 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_* | puste | Opcjonalne. Bez SMTP maile nie są wysyłane. |
GOAT_AI_OPENAI_API_KEY, GOAT_AI_OPENAI_MODEL | puste, gpt-4o-mini | Opcjonalne — 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.goatSkrypt wczytuje .env i uruchamia child/dev/runtime.goat, który:
- wykonuje
re— pobiera moduły zherd/_modules.goatdo.goat/modules/i generujegoatapp/, - 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, ładujeherd/fixture.goati uruchamiaserve, - frontend — instaluje zależności i uruchamia watchery Angular (panel,
child-app, elementy foundation) wedługherd/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:
| Adres | Co 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.goatgeneruje 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), potembash child/dev.sh. Supervisor korzysta z własnego konteneragoat-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ęcznieZasada 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"
ENTITYSYSTEMEOFDodaj link w nawigacji dashboardu (w bloku --navigation w app:module:add --name=dashboard):
link:add --label="Tasks" --entity=taskCo dają moduły:
crud— API i formularze w panelu/app/,crud_cli— komendycrud:task:*, w tymcrud:task:persistdo fixture'ów,harness— narzędzia asystenta AI dla tej encji (pomiń, jeśli nie chcesz udostępniać danych AI),seoissr— tylko dla treści publicznych (wzór: encjapage).
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.goatMigracja 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=falsei podepnij go w herd/fixture.goat:
run:script --path herd/fixtures/tasks/fixture.goatPeł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ólnegoshort_texttam, gdzie pasują — dają walidację i właściwe kontrolki. - Wspólne pola wyciągaj do bazy (
entity:base:add) i dziedzicz przezentity:extended, jakcontent→page. - Unikalność deklaruj w modelu (
--uniquelubunique:add --fields=lang,slug) — na niej opierają się idempotentne fixture'ypersist. - 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 wherd/gen/. - Logikę biznesową, własne trasy i serwisy pisz w
child/, importując foundation pełną ścieżką pakietu. - Commituj
herd/ichild/;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:*:persistz 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)