From 810a50c6064206abf1f52f8bbd8eabaffb355dfa Mon Sep 17 00:00:00 2001 From: mkelvers Date: Sat, 11 Apr 2026 16:10:53 +0200 Subject: [PATCH] chore: remove agents.md --- AGENTS.md | 172 ------------------------------------------------------ 1 file changed, 172 deletions(-) delete mode 100644 AGENTS.md diff --git a/AGENTS.md b/AGENTS.md deleted file mode 100644 index 70b5cca..0000000 --- a/AGENTS.md +++ /dev/null @@ -1,172 +0,0 @@ -# mal - -personal anime tracking platform. go/htmx rewrite. - -## stack - -- go standard library (`net/http`) -- htmx + templ templates -- sqlite + sqlc -- tailwind (dark theme) -- jikan api (myanimelist) - -## structure - -``` -cmd/server/ main entry -internal/ - auth/ sessions, passwords - database/ sqlc generated, migrations - handlers/ http handlers by domain - middleware/ auth, logging - jikan/ api client - templates/ templ components -migrations/ sql files -static/ css, js -``` - -## go patterns - -### errors - -always handle errors explicitly. wrap with context using `fmt.Errorf`: - -```go -if err != nil { - return fmt.Errorf("failed to fetch user: %w", err) -} -``` - -use `errors.Is` and `errors.As` to check wrapped errors. - -### early returns - -reduce nesting. check errors first, return early: - -```go -func getUser(id string) (*User, error) { - if id == "" { - return nil, ErrInvalidID - } - - user, err := db.FindUser(id) - if err != nil { - return nil, err - } - - return user, nil -} -``` - -### defer for cleanup - -always close resources with defer: - -```go -resp, err := http.Get(url) -if err != nil { - return err -} -defer resp.Body.Close() -``` - -### interfaces - -accept interfaces, return structs. keep interfaces small: - -```go -type Reader interface { - Read(p []byte) (n int, err error) -} -``` - -### naming - -- short, lowercase package names: `auth`, `jikan`, `db` -- `MixedCaps` for exports, `mixedCaps` for internal -- getters: `Owner()` not `GetOwner()` -- interfaces: single method = method name + `er` suffix (`Reader`, `Writer`) - -### zero values - -design structs so zero value is useful: - -```go -var buf bytes.Buffer // ready to use, no init needed -buf.WriteString("hello") -``` - -### composition over inheritance - -embed types to compose behavior: - -```go -type Handler struct { - db *database.Queries - jikan *jikan.Client - logger *slog.Logger -} -``` - -## htmx - -check for htmx requests: - -```go -func isHTMX(r *http.Request) bool { - return r.Header.Get("HX-Request") == "true" -} -``` - -return partials for htmx, full pages otherwise. use `hx-swap-oob` for multiple updates. trigger toasts with `HX-Trigger` header. - -## templ - -render components directly to response: - -```go -func (h *Handler) Home(w http.ResponseWriter, r *http.Request) { - templates.HomePage(data).Render(r.Context(), w) -} -``` - -pass data explicitly. keep components focused. use layouts. - -## database - -sqlc generates type-safe queries. always use parameterized queries. - -tables: `user`, `session`, `account`, `anime`, `watch_list_entry` - -watch statuses: `watching`, `completed`, `on_hold`, `dropped`, `plan_to_watch` - -## jikan api - -rate limit: 3 req/sec max. stagger batch requests. cache in local db. - -## commands - -```bash -make dev # hot reload (air) -make build # binary -make test # tests -make migrate # run migrations -make sqlc # generate code -make create-user # cli user creation -``` - -## env - -```bash -DATABASE_FILE=mal.db -SESSION_SECRET=min_32_chars_random -PORT=3000 -``` - -## avoid - -- panics in handlers -- forgetting `defer resp.Body.Close()` -- unstaggered jikan requests (429 errors) -- globals for config/state -- large monolithic templates