A compact full-stack starter with:
- Backend: Go + Gin + GORM + Wire + OpenAPI
- Frontend: Next.js App Router + TypeScript + Tailwind + Zustand + TanStack Query
- Contract-first API:
api/openapi.yamldrives generated frontend types and backend server stubs
Requirements:
- Go 1.25+
- Node.js 20+
cp .env.example .env
make init
make dev- Frontend:
http://localhost:3000 - Backend:
http://localhost:8080 - Swagger UI:
http://localhost:8080/swagger/index.html
- AI-facing playbook:
AGENTS.md - Runtime topology:
ARCHITECTURE.md - Coding/testing rules:
CONVENTIONS.md - Human bilingual docs index:
docs/README.md - API contract:
api/openapi.yaml
- Contract-first: update
api/openapi.yamlbefore or alongside API behavior changes. - Type refresh: run
make gen-typesafter contract changes; runmake genwhen generated Go server/docs artifacts must also change. - Layering rule: handlers → services → repositories; keep handlers thin and services orchestrating logic.
- Response envelope: use helpers in
backend/pkg/responseinstead of raw JSON writes. - Generated files: treat artifacts such as
frontend/types/api.tsandbackend/internal/api/server.gen.goas outputs, never the source of truth.
make init(once) bootstraps.env, installs dependencies and local folders, runs the backend bootstrap (AutoMigrate convenience), and refreshes generated artifacts.make dev(runs backend + frontend watchers). Keep editing UI or Go sources.- Run
make check(linters, architecture guardrails, typecheck, tests, scaffold regression, and builds) whenever you change logic/code paths to verify the full gate. - If the change touches runtime behavior or APIs, re-run
make e2eto exercise the register → login → CRUD cycle. - Pull requests that touch backend/API/runtime paths also run
make e2ein CI before merge; the merge-validation workflow keeps the same smoke coverage post-merge. - Repeat: edit → lint/type/test →
make check→make e2e(if needed) → commit.
- Default (local): keep
STORAGE_DRIVER=localand uploaded files are saved underUPLOAD_DIR, served by backend/uploads/.... - Object storage (S3-compatible): set
STORAGE_DRIVER=s3and configure:S3_BUCKET,S3_REGIONS3_ACCESS_KEY_ID,S3_SECRET_ACCESS_KEY- Optional:
S3_ENDPOINT(for MinIO/custom endpoints),S3_PREFIX,S3_USE_SSL,S3_FORCE_PATH_STYLE
UPLOAD_PUBLIC_BASE_URLis optional in both modes. When set, upload responses use that public base URL (useful for CDN/custom domains).
Example MinIO settings:
STORAGE_DRIVER=s3
S3_BUCKET=gonext-uploads
S3_REGION=us-east-1
S3_ENDPOINT=http://localhost:9000
S3_ACCESS_KEY_ID=minioadmin
S3_SECRET_ACCESS_KEY=minioadmin
S3_PREFIX=uploads
S3_USE_SSL=false
S3_FORCE_PATH_STYLE=true-
Prometheus scraping is opt-in. Set
METRICS_ENABLED=trueto exposehttp://localhost:8080/metrics. -
/metricsis an operational endpoint (not part ofapi/openapi.yamlor frontend codegen). -
Baseline backend metric families:
http_requests_total{method,route,status}http_request_duration_seconds{method,route}
-
Scrape output also includes default Go/runtime + process metrics from the Prometheus Go client.
-
Local check:
METRICS_ENABLED=true make dev curl -s http://localhost:8080/metrics | head -n 40 -
Production note: protect
/metricswith network/proxy controls where needed.
make docker-build
make docker-up
make docker-downServices & ports (per docker-compose.yml services):
frontend:http://localhost:3000backend:http://localhost:8080db(PostgreSQL):localhost:5432
- Update
api/openapi.yamlfirst whenever you touch API behavior, then refresh downstream artifacts. - Run
make gen-typesas the standard TypeScript refresh; it always writes the API shapes tofrontend/types/api.tsand should follow any contract change that affects the frontend. - Run
make genonly when you need to regenerate the Go server stubs and Swagger docs in addition to the TypeScript types (it runsgen-server,gen-types, andswagger). - Before pushing a PR that changes OpenAPI/codegen inputs, run
make check-codegen-driftto execute the same regeneration drift rule as CI. - If
make check-codegen-driftfails, runmake gen, inspectgit status, commit all generated artifact changes, then rerunmake check-codegen-drift. - Run
make swaggerwhenever you adjust OpenAPI metadata or docs, keepingbackend/docs/swagger.*in sync.
Run make new-module name=product to generate convention-aligned handler/service/repository/model/dto boilerplate, baseline tests, and a follow-up checklist. Then:
- Update
api/openapi.yamlif the module is API-backed. - Implement the backend chain in
backend/internal/{handler,service,repository,model,dto}. - Wire dependencies through
backend/cmd/server/{providers.go,wire.go}. - Register generated/manual routes in
backend/cmd/server/main.go. - Register the new model in development
AutoMigrateand add deployable migrations when persistence changes ship. - Refresh generated artifacts as needed (
make gen-types/make gen). - Run
make check, andmake e2eif runtime/API behavior changed.