feat(shared-skills): batch 85 (10 files)

This commit is contained in:
YeonGyu-Kim
2026-05-30 19:12:15 +09:00
parent b7ed2a9484
commit 43383342d4
10 changed files with 297 additions and 0 deletions
@@ -0,0 +1,13 @@
root = true
[*]
indent_style = tab
indent_size = 4
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.{yml,yaml,json,md}]
indent_style = space
indent_size = 2
@@ -0,0 +1,95 @@
version: "2"
run:
timeout: 5m
tests: true
modules-download-mode: readonly
linters:
default: none
enable:
- govet
- staticcheck
- errcheck
- errorlint
- nilerr
- nilnil
- bodyclose
- rowserrcheck
- sqlclosecheck
- contextcheck
- fatcontext
- copyloopvar
- intrange
- usetesting
- testifylint
- gofumpt
- goimports
- whitespace
- misspell
- unconvert
- unparam
- ineffassign
- dupword
- gocognit
- gocyclo
- funlen
- lll
- nestif
- dupl
- revive
- unused
- exhaustive
- gosec
- sloglint
- perfsprint
- prealloc
- makezero
linters-settings:
errcheck:
check-type-assertions: true
check-blank: true
errorlint:
errorf: true
asserts: true
comparison: true
gocognit:
min-complexity: 25
gocyclo:
min-complexity: 15
funlen:
lines: 90
statements: 60
lll:
line-length: 120
tab-width: 4
nestif:
min-complexity: 4
exhaustive:
default-signifies-exhaustive: false
check: [switch, map]
sloglint:
no-mixed-args: true
attr-only: true
no-global: all
context: scope
static-msg: true
no-raw-keys: true
key-naming-case: snake
formatters:
enable:
- gofumpt
- goimports
issues:
max-issues-per-linter: 0
max-same-issues: 0
exclude-rules:
- path: _test\\.go
linters: [funlen, lll, dupl, gosec]
- path: \\.pb\\.go$
linters: [all]
- path: \\.connect\\.go$
linters: [all]
@@ -0,0 +1,24 @@
# AGENTS.md
Go 1.23+ $short_purpose service.
## Commands
- `task` — fmt + lint + test
- `task build` — produce ./bin/server
- `task ci` — full CI pipeline locally
## Architecture
- `cmd/server/main.go` — entrypoint, ≤50 LOC
- `internal/cmd/` — root command, signal wiring
- `internal/api/` — HTTP handlers + middleware (gin)
- `internal/domain/` — smart-constructor types, no I/O
- `internal/store/` — DB layer (sqlc-generated, never hand-edited)
- `internal/config/` — env-driven Config
- `internal/obs/` — slog setup, observability
## Conventions
- `slog` for all logs; never `log.*`, never `fmt.Println` in libs
- `context.Context` first arg for every public function with I/O
- Errors wrapped with `%w`; check with `errors.Is/As`
- 250 pure LOC ceiling per file
- Tests follow Given/When/Then; less mock the better
@@ -0,0 +1,12 @@
# $name
Bootstrapped with the `programming` skill's Go scaffold.
## Run
```bash
task # fmt + lint + test
task run # build + run server
```
See `AGENTS.md` for architecture conventions.
@@ -0,0 +1,40 @@
version: '3'
vars:
BINARY: server
PKG: ./cmd/server
tasks:
default:
deps: [fmt, lint, test]
fmt:
cmds:
- gofumpt -w .
- goimports -w -local "$(go list -m)" .
lint:
cmds:
- golangci-lint run --timeout 5m ./...
- nilaway ./... || true
test:
cmds:
- go test -race -shuffle=on -count=1 ./...
test-cover:
cmds:
- go test -race -shuffle=on -count=1 -coverprofile=coverage.out ./...
- go tool cover -html=coverage.out -o coverage.html
build:
cmds:
- go build -trimpath -ldflags="-s -w" -o bin/{{.BINARY}} {{.PKG}}
run:
deps: [build]
cmds:
- ./bin/{{.BINARY}}
ci:
deps: [fmt, lint, test, build]
@@ -0,0 +1,37 @@
name: ci
on:
pull_request:
push:
branches: [main]
jobs:
ci:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: '1.23'
cache: true
- name: Install tools
run: |
go install mvdan.cc/gofumpt@latest
go install github.com/golangci/golangci-lint/cmd/golangci-lint@v2.0.0
go install go.uber.org/nilaway/cmd/nilaway@latest
go install github.com/go-task/task/v3/cmd/task@latest
- name: Format check
run: gofumpt -l . | (! grep .)
- name: Lint
run: golangci-lint run --timeout 5m ./...
- name: Nilaway
run: nilaway ./... || true
- name: Test
run: go test -race -shuffle=on -count=1 ./...
- name: Build
run: go build -trimpath ./...
@@ -0,0 +1,24 @@
// Package config loads typed config from env.
package config
import (
"time"
"github.com/caarlos0/env/v11"
)
type Config struct {
Host string `env:"HOST" envDefault:"0.0.0.0"`
Port int `env:"PORT" envDefault:"8080"`
ShutdownTimeout time.Duration `env:"SHUTDOWN_TIMEOUT" envDefault:"20s"`
LogLevel string `env:"LOG_LEVEL" envDefault:"info"`
LogFormat string `env:"LOG_FORMAT" envDefault:"json"`
}
func Load() (Config, error) {
var cfg Config
if err := env.Parse(&cfg); err != nil {
return Config{}, err
}
return cfg, nil
}
@@ -0,0 +1,15 @@
bin/
coverage.out
coverage.html
*.test
*.prof
.idea/
.vscode/
*.swp
.env
.env.local
*.pem
*.key
@@ -0,0 +1,22 @@
package main
import (
"context"
"log/slog"
"os"
"os/signal"
"syscall"
"$module/internal/cmd"
)
func main() {
ctx, stop := signal.NotifyContext(context.Background(),
syscall.SIGINT, syscall.SIGTERM)
defer stop()
if err := cmd.Execute(ctx); err != nil {
slog.Error("fatal", slog.Any("err", err))
os.Exit(1)
}
}
@@ -0,0 +1,15 @@
// Package cmd wires the root command and subcommands.
package cmd
import (
"context"
"log/slog"
"os"
)
// Execute runs the root command. Wire cobra/subcommands here.
func Execute(ctx context.Context) error {
slog.New(slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{Level: slog.LevelInfo}))
slog.InfoContext(ctx, "starting")
return nil
}