3.2 KiB
3.2 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Commands
# Development (hot-reload via air)
air
# Build production binary
go build -o ./build/emly-api.exe .
# Run directly
go run .
# Run tests
go test ./...
# Run a single test
go test ./internal/... -run TestName -v
Architecture
This is a Go REST API for a bug reporting system ("EMLy"). It uses:
- Router:
go-chi/chi/v5 - Database: MySQL via
jmoiron/sqlx - Auth: Header-based API key (
X-API-Key) and admin key (X-Admin-Key) - Rate limiting:
go-chi/httprate(global: 100/min, route groups: 30/min by IP)
Request flow
main.go → chi router → global middleware → route group middleware → handler
Global middleware order: RequestID → RealIP → Logger → Recoverer → Timeout(30s) → RateLimitByIP
Route groups
- Public:
GET /(ping),GET /v1/health - API key only:
POST /v1/api/bug-reports/,GET /v1/api/bug-reports/count - API key + admin key: All other
/v1/api/bug-reports/*endpoints
Package layout
internal/config/— Loads config from env vars (via godotenv). Key vars:PORT,DB_DSN,DATABASE_NAME,API_KEY,ADMIN_KEY.internal/database/— MySQL connection pool setup with configurable limits.internal/database/schema/— Conditional migration system:init.sqlbootstraps tables,migrations/tasks.jsondefines conditional tasks (e.g.column_not_exists),migrations/*.sqlare the individual migration files.internal/handlers/— Factory functions returninghttp.HandlerFunc. The*sqlx.DBis passed in at construction. Response helpers (jsonOK,jsonCreated,jsonError) live inresponse.go.internal/middleware/— API key and admin key auth middleware; each loads allowed keys into a map at startup for O(1) lookup.internal/models/— Structs withdb:andjson:tags. Sensitive fields usejson:"-".
Handler conventions
- Each handler file is named
<resource>.route.go. - Handlers are factory functions:
func CreateBugReport(db *sqlx.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { ... } }. - All responses are JSON. Use
jsonOK,jsonCreated, orjsonErrorfromresponse.go. - File uploads use
r.ParseMultipartForm(32 << 20). File streams must be explicitly closed. - ZIP downloads: in-memory
archive/zipwith template-rendered report text viainternal/handlers/templates/report.txt.tmpl.
Database migrations
The migrator in internal/database/schema/migrator.go runs on startup:
- Executes
init.sqlto ensure base tables exist. - Reads
migrations/tasks.jsonfor conditional tasks. - Checks each task's condition (e.g.
column_not_exists) against the DB before running its SQL file.
Supported condition types: column_not_exists, column_exists, index_not_exists, index_exists, table_not_exists, table_exists.
Environment
Copy .env.example to .env. Required vars: DB_DSN, DATABASE_NAME, API_KEY, ADMIN_KEY.
The DB_DSN must include parseTime=true&loc=UTC, e.g.:
DB_DSN=root:secret@tcp(127.0.0.1:3306)/emly?parseTime=true&loc=UTC