[teamai] Push 87 resource(s) from XingfenD

This commit is contained in:
2026-09-10 16:10:45 +08:00
parent 425c9c078a
commit 65c04def51
1314 changed files with 211681 additions and 0 deletions
@@ -0,0 +1,51 @@
# Application Configuration with Cobra + Viper
→ See `samber/cc-skills-golang@golang-cli` skill for complete Cobra+Viper setup, flag binding, precedence rules, and configuration layering.
## Where Config Lives
```
myapp/
├── cmd/myapp/
│ ├── main.go # Entry point
│ ├── root.go # Root command + Viper init
│ ├── serve.go # Subcommand with flags
│ └── config.go # Config struct + loader
└── configs/
└── config.yaml # Default config file
```
## Config Struct
Define configuration as a struct with `mapstructure` tags matching your YAML keys:
```go
// cmd/myapp/config.go
package main
import (
"fmt"
"github.com/spf13/viper"
)
type Config struct {
Port int `mapstructure:"port"`
Host string `mapstructure:"host"`
LogLevel string `mapstructure:"log-level"`
Database struct {
DSN string `mapstructure:"dsn"`
MaxConn int `mapstructure:"max-conn"`
} `mapstructure:"database"`
}
func loadConfig() (Config, error) {
var cfg Config
if err := viper.Unmarshal(&cfg); err != nil {
return Config{}, fmt.Errorf("unmarshaling config: %w", err)
}
return cfg, nil
}
```
Configuration MUST be loaded from env vars, files, or flags — NEVER hardcoded. Sensitive values MUST come from env vars or secret managers, NEVER config files.
@@ -0,0 +1,151 @@
# Directory Layouts
## Universal Layout (Most Projects)
```
project/
├── cmd/ # Entry points - ONE subdirectory per main package
│ ├── server/ # Main application #1
│ │ └── main.go
│ ├── client/ # Main application #2
│ │ └── main.go
│ └── migrate/ # Main application #3
│ └── main.go
│ └── cli/ # Main application #4
│ └── main.go
│ └── worker/ # Main application #5
│ └── main.go
├── internal/ # Private application code (`internal/` MUST be used for non-exported packages)
│ ├── app/ # Application initialization
│ ├── config/ # Configuration loading
│ ├── handler/ # HTTP/request handlers
│ ├── model/ # Data models/domain
│ └── service/ # Business logic
├── pkg/ # Public libraries (optional - only if useful to others)
│ └── logger/
│ └── logger.go
├── api/ # API definitions (optional)
│ └── openapi.yaml
├── configs/ # Configuration files (optional)
│ └── config.yaml
├── scripts/ # Build/deployment scripts (optional)
├── go.mod
├── go.sum
├── Makefile # Build automation
├── .gitignore # Git ignore patterns
├── .golangci.yml # Linter configuration
├── LICENSE # License file
└── README.md
```
## Small Projects (Single Binary)
For simple tools, keep it minimal:
```
my-tool/
├── cmd/
│ └── my-tool/
│ └── main.go # Single main package
├── internal/
│ └── core.go # Application logic
├── go.mod
├── Makefile # Build automation (optional but recommended)
├── .gitignore # Git ignore patterns
├── .golangci.yml # Linter configuration (optional)
├── LICENSE # License file (recommended)
└── README.md
```
## Libraries (Reusable Code)
```
my-library/
├── example/ # Example
├── logger/ # Public package
│ ├── logger.go
│ └── logger_test.go
├── internal/
│ └── impl/ # Private implementation details
│ └── core.go
├── go.mod
├── go.sum
├── Makefile # Build automation
├── .gitignore # Git ignore patterns
├── .golangci.yml # Linter configuration
├── LICENSE # License file
└── README.md
```
**Key points for libraries:**
- Put public API in root-level directories (e.g., `logger/`)
- Use `internal/` for private implementation
- Don't use `cmd/` (unless you have example binaries)
## The cmd/ Directory Convention
**CRITICAL**: All `main` packages must reside in `cmd/`. `cmd/` MUST contain only `main.go` with minimal logic — parse flags, wire dependencies, call `Run()`. NEVER put business logic in `cmd/` — it belongs in `internal/` or `pkg/`.
### Single Application
```
cmd/
└── myapp/
└── main.go // package main
```
### Multiple Applications
When you need multiple binaries (e.g., server, CLI tool, migration utility):
```
cmd/
├── server/
│ └── main.go // Runs the API server
├── client/
│ └── main.go // CLI client tool
├── worker/
│ └── main.go // Background worker
└── migrate/
└── main.go // Database migration utility
```
Each `main.go`:
- Declares `package main`
- Has its own `func main()`
- Can be built independently: `go build ./cmd/...`
**Building all binaries:**
```bash
go build ./cmd/... # Build all main packages
go build ./cmd/server # Build specific binary
```
## Common Mistakes to Avoid
### Don't Do This
```
myproject/
├── src/ # Go doesn't use /src (Java pattern)
├── main.go # Don't put main at root
├── utils/ # Generic package name
├── helpers/ # Generic package name
└── common/ # Generic package name
```
### Do This Instead
```
myproject/
├── cmd/
│ └── myapp/
│ └── main.go # Main in cmd/
├── internal/
│ ├── util/ # Specific utility names
│ └── format/ # Or domain-specific names
└── pkg/ # Only if useful to others
```
@@ -0,0 +1,215 @@
# Tests, Benchmarks, and Examples
## File Naming Conventions
Go uses suffix-based naming for test-related files:
| Suffix | Purpose | Build Tag |
| --- | --- | --- |
| `_test.go` | Tests | Not included in normal builds |
| `_bench_test.go` | Benchmarks | Not included in normal builds |
| `_example_test.go` | Examples that verify output | Not included in normal builds |
| No suffix | Regular code | Included in all builds |
## Where to Place Tests
**Co-locate tests with the code they test:**
```
internal/
├── handler/
│ ├── handler.go # Production code
│ ├── handler_test.go # Tests for handler
│ └── handler_bench_test.go # Benchmarks (optional)
├── service/
│ ├── service.go
│ └── service_test.go
└── model/
├── user.go
└── user_test.go
pkg/
└── logger/
├── logger.go
└── logger_test.go
```
**Key principles:**
- Tests live in the **same package** as the code (e.g., `package handler`)
- Test files are in the **same directory** as the code they test
- Use `_test.go` suffix for all test files
## Test Package Options
When writing tests, you have two options for the package declaration:
**Option 1: Same package (white-box testing)**
```go
package handler // Same package, can access unexported
import "testing"
func TestHandler(t *testing.T) {
// Can access unexported functions and types
internalFunction()
}
```
**Option 2: Package with `_test` suffix (black-box testing)**
```go
package handler_test // Different package, only exported API
import "testing"
func TestHandler(t *testing.T) {
// Can only access exported functions and types
handler.PublicMethod()
}
```
**When to use each:**
- Use **same package** for unit tests that need to test internals
- Use **`_test` suffix** for integration/behavioral tests
## Benchmarks
Benchmarks use the `_bench_test.go` suffix and contain functions with the `Benchmark` prefix.
## Examples
Examples serve two purposes: documentation and verification.
**In libraries** - use `*_example_test.go` files:
```
pkg/
└── logger/
├── logger.go
├── logger_test.go
└── logger_example_test.go # Examples
```
**Example function format:**
```go
package logger
import "fmt"
func ExampleLogger_Info() {
log := New()
log.Info("processing started")
log.Info("processing complete")
// Output:
// INFO: processing started
// INFO: processing complete
}
```
**Key points:**
- Example functions must start with `Example`
- The `// Output:` comment verifies the output
- Examples are runnable tests: `go test` will fail if output doesn't match
- `godoc` displays examples as documentation
- File name format: `{package}_example_test.go` (e.g., `logger_example_test.go`)
**For executable examples** (standalone demo programs):
```
examples/
└── basic-usage/
└── main.go # Executable example
```
## Test Utilities
When you have shared test helpers, use a dedicated package:
```
test/
└── testutils/
├── mock.go
└── fixtures.go
```
Or use the `internal/testutil` pattern:
```
internal/
└── testutil/
├── mock.go
└── fixtures.go
```
## Test Fixtures
Fixtures are test data files used across multiple tests. Use one of these patterns:
**Option 1: Local testdata directory** (package-specific fixtures)
```
internal/
└── handler/
├── handler.go
├── handler_test.go
└── testdata/
├── users.json
├── request_valid.json
└── request_invalid.json
```
**Option 2: Global test directory** (shared across packages)
```
test/
└── fixtures/
├── users.json
├── products.json
└── responses/
├── success.json
└── error.json
```
**Option 3: Embedded fixtures** (Go 1.16+, use `//go:embed`)
```
internal/
└── handler/
├── handler.go
├── handler_test.go
└── testdata/
└── users.json
```
**Important notes:**
- Go ignores the `testdata` directory when building regular packages
- Use `testdata/` for package-specific test data
- Use `test/fixtures/` for cross-package shared fixtures
- Don't put `.go` files in `testdata/` - they will be ignored
## Running Tests
```bash
go test ./... # Run all tests
go test ./internal/handler # Test specific package
go test -v ./... # Verbose output
go test -race ./... # Race detection
go test -cover ./... # Coverage report
go test -short ./... # Skip long-running tests
```
## Test File Summary
| File Type | Suffix | Package | Purpose |
| --- | --- | --- | --- |
| Test | `*_test.go` | `package X` or `package X_test` | Unit/integration tests |
| Benchmark | `*_bench_test.go` | Same as code | Performance tests |
| Example (godoc) | `*_example_test.go` | Same as code | Documentation + verification |
| Executable example | No suffix | `package main` | Standalone demo programs |
| Test utilities | `*_test.go` | `package testutil` | Shared test helpers |
@@ -0,0 +1,106 @@
<!-- markdownlint-disable ol-prefix -->
# Go Workspaces for Multi-Package Repositories
## When to Use Workspaces
Use Go workspaces (`go.work`) when:
- Developing multiple related modules that import each other
- Building a monorepo with separate Go modules
- Testing local changes across module boundaries
- Avoiding `replace` directives in every module
**Don't use workspaces for:**
- Single-module projects
- Projects that only use external dependencies
- Simple applications
## Workspace Structure
Example monorepo with multiple modules:
```
my-monorepo/
├── go.work # Workspace file (see below)
├── pkg/
│ ├── auth/ # Module 1: github.com/user/my-monorepo/pkg/auth
│ │ ├── go.mod
│ │ ├── cmd/
│ │ │ └── auth-server/
│ │ │ └── main.go
│ │ └── internal/
│ │ └── handler/
│ │ └── auth.go
│ └── user/ # Module 2: github.com/user/my-monorepo/pkg/user
│ ├── go.mod
│ ├── cmd/
│ │ └── user-server/
│ │ └── main.go
│ └── internal/
│ └── handler/
│ └── user.go
├── cmd/
│ └── api/ # Module 3: github.com/user/my-monorepo/cmd/api
│ ├── go.mod
│ └── main.go
└── tools/
└── cli/ # Module 4: github.com/user/my-monorepo/tools/cli
├── go.mod
└── cmd/
└── mycli/
└── main.go
```
## Creating a Workspace
1. **Initialize the workspace:**
```bash
go work init
```
This creates `go.work`:
```go
go 1.21
use (
./services/auth
./services/user
./shared/libs
./tools/cli
)
```
2. **Add modules to workspace:**
```bash
go work use ./services/auth
go work use ./services/user
go work use ./shared/libs
```
3. **Use modules without replace directives:**
In `services/user/go.mod`:
```go
module github.com/user/my-monorepo/services/user
go 1.21
require github.com/user/my-monorepo/shared/libs v0.0.0
```
The workspace automatically resolves `shared/libs` to the local directory.
## Workspace Commands
```bash
go work init # Initialize new workspace
go work use ./path/to/mod # Add module to workspace
go work use -rm ./path # Remove module from workspace
go work sync # Sync workspace with module changes
```