chore: remove agents.md
This commit is contained in:
172
AGENTS.md
172
AGENTS.md
@@ -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
|
|
||||||
Reference in New Issue
Block a user