xiaohongshu
xiaohongshu
kratos-new-service
Creates a new go-kratos microservice skeleton with clean architecture (server/service/biz/data), minimal Wire setup, HTTP + gRPC metrics, and complete project structure. Use when scaffolding new services in the brizy-go-services monorepo.
Full skill instructions
<quick_start> When invoked, this skill will:
services/{service-name}/The service will be ready to build but will need proto definitions added separately. </quick_start>
<workflow> ## Step 1: Get and Validate Service NameAsk the user for the service name:
What is the name of the new service?
Requirements:
- Lowercase letters, numbers, and hyphens only
- Must be a valid Go module name
- Will be used for directory name, module path, and service identification
Example: auth, user-management, notification-service
Validate the input:
If invalid, explain the issue and ask again.
Verify that services/{service-name}/ does not already exist:
ls services/{service-name} 2>/dev/null
If it exists, inform the user and stop. Do not overwrite existing services.
Create the complete directory structure:
mkdir -p services/{service-name}/cmd/{service-name}
mkdir -p services/{service-name}/internal/biz
mkdir -p services/{service-name}/internal/data/model
mkdir -p services/{service-name}/internal/data/repo
mkdir -p services/{service-name}/internal/service
mkdir -p services/{service-name}/internal/server
mkdir -p services/{service-name}/internal/conf
mkdir -p services/{service-name}/configs
mkdir -p services/{service-name}/bin
syntax = "proto3";
package conf;
option go_package = "services/{service-name}/internal/conf;conf";
import "google/protobuf/duration.proto";
message Bootstrap {
Server server = 1;
Data data = 2;
Metrics metrics = 3;
}
message Server {
message HTTP {
string network = 1;
string addr = 2;
google.protobuf.Duration timeout = 3;
}
message GRPC {
string network = 1;
string addr = 2;
google.protobuf.Duration timeout = 3;
}
HTTP http = 1;
GRPC grpc = 2;
}
message Data {
message Database {
string driver = 1;
string source = 2;
}
Database database = 1;
}
message Metrics {
bool enabled = 1;
string service_name = 2;
string path = 3;
bool include_runtime = 4;
}
server:
http:
addr: 0.0.0.0:8000
timeout: 5s
grpc:
addr: 0.0.0.0:9000
timeout: 5s
data:
database:
driver: postgres
source: postgres://user:password@localhost:5432/{service-name}?sslmode=disable
metrics:
enabled: true
path: /metrics
include_runtime: true
Replace {service-name} with the actual service name in the YAML.
package data
import (
"github.com/go-kratos/kratos/v2/log"
"github.com/google/wire"
"services/{service-name}/internal/conf"
)
// ProviderSet is data providers.
var ProviderSet = wire.NewSet(
NewData,
)
// Data encapsulates all data access dependencies.
type Data struct {
log *log.Helper
// db *gorm.DB - uncomment when adding GORM
}
// NewData creates a new Data instance.
func NewData(c *conf.Data, logger log.Logger) (*Data, func(), error) {
logHelper := log.NewHelper(log.With(logger, "module", "data"))
d := &Data{
log: logHelper,
}
cleanup := func() {
logHelper.Info("closing data resources")
}
return d, cleanup, nil
}
Replace {service-name} with the actual service name.
package biz
// Repository interfaces will be defined here
// Example:
// type ExampleRepo interface {
// Save(ctx context.Context, example *Example) error
// FindByID(ctx context.Context, id int64) (*Example, error)
// }
package biz
import (
"github.com/go-kratos/kratos/v2/log"
"github.com/google/wire"
)
// ProviderSet is business logic providers.
var ProviderSet = wire.NewSet()
package service
import (
"github.com/google/wire"
"services/{service-name}/internal/biz"
)
// ProviderSet is service providers.
var ProviderSet = wire.NewSet(
NewService,
)
// Service encapsulates business logic dependencies.
type Service struct {
log *log.Helper
}
// NewService creates a new Service instance.
func NewService(logger log.Logger) *Service {
return &Service{
log: log.NewHelper(log.With(logger, "module", "service")),
}
}
Replace {service-name} with the actual service name.
package server
import (
"github.com/go-kratos/kratos/v2/log"
"github.com/go-kratos/kratos/v2/middleware/logging"
"github.com/go-kratos/kratos/v2/middleware/recovery"
"github.com/go-kratos/kratos/v2/transport/http"
"platform/metrics"
"services/{service-name}/internal/conf"
"services/{service-name}/internal/service"
)
// NewHTTPServer creates a new HTTP server.
func NewHTTPServer(
c *conf.Server,
logger log.Logger,
svc *service.Service,
metricsRegistry *metrics.Registry,
) *http.Server {
var opts = []http.ServerOption{
http.Middleware(
recovery.Recovery(),
logging.Server(logger),
metrics.HTTPMiddleware(metricsRegistry),
),
}
if c.Http.Network != "" {
opts = append(opts, http.Network(c.Http.Network))
}
if c.Http.Addr != "" {
opts = append(opts, http.Address(c.Http.Addr))
}
if c.Http.Timeout != nil {
opts = append(opts, http.Timeout(c.Http.Timeout.AsDuration()))
}
srv := http.NewServer(opts...)
// Register service handlers here
// Example:
// v1.RegisterExampleServiceHTTPServer(srv, svc)
return srv
}
Replace {service-name} with the actual service name.
package server
import (
"github.com/go-kratos/kratos/v2/log"
"github.com/go-kratos/kratos/v2/middleware/logging"
"github.com/go-kratos/kratos/v2/middleware/recovery"
"github.com/go-kratos/kratos/v2/transport/grpc"
"platform/metrics"
"services/{service-name}/internal/conf"
"services/{service-name}/internal/service"
)
// NewGRPCServer creates a new gRPC server.
func NewGRPCServer(
c *conf.Server,
logger log.Logger,
svc *service.Service,
metricsRegistry *metrics.Registry,
) *grpc.Server {
var opts = []grpc.ServerOption{
grpc.Middleware(
recovery.Recovery(),
logging.Server(logger),
metrics.GRPCMiddleware(metricsRegistry),
),
}
if c.Grpc.Network != "" {
opts = append(opts, grpc.Network(c.Grpc.Network))
}
if c.Grpc.Addr != "" {
opts = append(opts, grpc.Address(c.Grpc.Addr))
}
if c.Grpc.Timeout != nil {
opts = append(opts, grpc.Timeout(c.Grpc.Timeout.AsDuration()))
}
srv := grpc.NewServer(opts...)
// Register service handlers here
// Example:
// v1.RegisterExampleServiceServer(srv, svc)
return srv
}
Replace {service-name} with the actual service name.
package server
import (
"github.com/google/wire"
)
// ProviderSet is server providers.
var ProviderSet = wire.NewSet(
NewHTTPServer,
NewGRPCServer,
NewMetricsRegistry,
)
package server
import (
"platform/metrics"
"services/{service-name}/internal/conf"
)
// NewMetricsRegistry creates a new metrics registry.
func NewMetricsRegistry(c *conf.Metrics) *metrics.Registry {
if !c.Enabled {
return nil
}
return metrics.NewRegistry(c.ServiceName, c.IncludeRuntime)
}
Replace {service-name} with the actual service name.
package main
import (
"flag"
"os"
"github.com/go-kratos/kratos/v2"
"github.com/go-kratos/kratos/v2/config"
"github.com/go-kratos/kratos/v2/config/file"
"github.com/go-kratos/kratos/v2/log"
"github.com/go-kratos/kratos/v2/transport/http"
"services/{service-name}/internal/conf"
)
// go build -ldflags "-X main.Version=x.y.z"
var (
// Name is the name of the compiled software.
Name string = "symbol-service"
// Version is the version of the compiled software.
Version string = "1.0"
// configFile is the config flag.
configFile string
id, _ = os.Hostname()
)
func init() {
flag.StringVar(&configFile, "conf", "configs/config.yaml", "config path, eg: --conf config.yaml")
}
var buildInfo = build.NewBuildInfo(Name, Version)
func main() {
flag.Parse()
logger := log.With(log.NewStdLogger(os.Stdout),
"ts", log.DefaultTimestamp,
"caller", log.DefaultCaller,
"service.name", "{service-name}",
)
c := config.New(
config.WithSource(
file.NewSource(flagconf),
),
)
defer c.Close()
if err := c.Load(); err != nil {
panic(err)
}
var bc conf.Bootstrap
if err := c.Scan(&bc); err != nil {
panic(err)
}
app, cleanup, err := wireApp(buildInfo, bc.Server, bc.Data, bc.Metrics, logger)
if err != nil {
panic(err)
}
defer cleanup()
// Start and wait for stop signal
if err := app.Run(); err != nil {
panic(err)
}
}
func newApp(logger log.Logger, hs *http.Server, gs *grpc.Server) *kratos.App {
return kratos.New(
kratos.ID(id),
kratos.Name(Name),
kratos.Version(Version),
kratos.Metadata(map[string]string{}),
kratos.Logger(logger),
kratos.Server(
gs,
hs,
),
)
}
Replace {service-name} with the actual service name.
//go:build wireinject
// +build wireinject
package main
import (
platform_build_info "platform/build"
platform_logger "platform/logger"
"github.com/go-kratos/kratos/v2"
"github.com/go-kratos/kratos/v2/log"
"github.com/google/wire"
"services/{service-name}/internal/biz"
"services/{service-name}/internal/conf"
"services/{service-name}/internal/data"
"services/{service-name}/internal/server"
"services/{service-name}/internal/service"
)
// wireApp builds the application with dependency injection.
func wireApp(*platform_build_info.ServiceBuildInfo, *conf.Data, *conf.Metrics, log.Logger) (*kratos.App, func(), error) {
panic(wire.Build(
platform_logger.ProviderSet,
server.ProviderSet,
service.ProviderSet,
biz.ProviderSet,
data.ProviderSet,
newApp,
))
}
Replace {service-name} with the actual service name.
module services/{service-name}
go 1.25.0
require (
github.com/envoyproxy/protoc-gen-validate v1.3.0
github.com/go-kratos/kratos/contrib/middleware/validate/v2 v2.0.0-20251217105121-fb8e43efb207
github.com/go-kratos/kratos/v2 v2.9.2
github.com/go-playground/validator/v10 v10.30.1
github.com/google/wire v0.7.0
github.com/gorilla/handlers v1.5.2
github.com/stretchr/testify v1.11.1
go.uber.org/automaxprocs v1.6.0
google.golang.org/protobuf v1.36.11
gorm.io/driver/mysql v1.6.0
gorm.io/driver/sqlite v1.6.0
gorm.io/gorm v1.31.1
)
Replace {service-name} with the actual service name.
GOHOSTOS:=$(shell go env GOHOSTOS)
GOPATH:=$(shell go env GOPATH)
VERSION=$(shell git describe --tags --always)
ifeq ($(GOHOSTOS), windows)
#the `find.exe` is different from `find` in bash/shell.
#to see https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/find.
#changed to use git-bash.exe to run find cli or other cli friendly, caused of every developer has a Git.
#Git_Bash= $(subst cmd\,bin\bash.exe,$(dir $(shell where git)))
Git_Bash=$(subst \,/, $(subst cmd\,bin\bash.exe,$(dir $(shell where git))))
INTERNAL_PROTO_FILES=$(shell $(Git_Bash) -c "find internal -name *.proto")
API_PROTO_FILES=$(shell $(Git_Bash) -c "find api -name *.proto")
else
INTERNAL_PROTO_FILES=$(shell find internal -name *.proto)
API_PROTO_FILES=$(shell find api -name *.proto)
endif
.PHONY: init config api build generate all test coverage help
APP_NAME := symbols
BIN_DIR := bin
# init env
init:
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
go install github.com/go-kratos/kratos/cmd/kratos/v2@latest
go install github.com/go-kratos/kratos/cmd/protoc-gen-go-http/v2@latest
go install github.com/google/gnostic/cmd/protoc-gen-openapi@latest
go install github.com/google/wire/cmd/wire@latest
go install github.com/envoyproxy/protoc-gen-validate@latest
# generate internal proto
config:
buf dep update
buf lint
buf format -w
buf generate
# build
build: service worker
service: generate
go build -o $(BIN_DIR)/$(APP_NAME) ./cmd/$(APP_NAME)
# generate wire files
generate:
wire ./cmd/symbols
go mod tidy
# generate all
all:
make config;
make generate;
# run unit tests
test:
go test -v -race -coverprofile=coverage.out ./internal/...
# generate coverage report
coverage:
go test -v -coverprofile=coverage.out ./...
go tool cover -html=coverage.out -o coverage.html
@echo "Coverage report generated: coverage.html"
# show help
help:
@echo ''
@echo 'Usage:'
@echo ' make [target]'
@echo ''
@echo 'Targets:'
@awk '/^[a-zA-Z\-\_0-9]+:/ { \
helpMessage = match(lastLine, /^# (.*)/); \
if (helpMessage) { \
helpCommand = substr($$1, 0, index($$1, ":")); \
helpMessage = substr(lastLine, RSTART + 2, RLENGTH); \
printf "\033[36m%-22s\033[0m %s\n", helpCommand,helpMessage; \
} \
} \
{ lastLine = $$0 }' $(MAKEFILE_LIST)
.DEFAULT_GOAL := help
Replace {service-name} with the actual service name.
version: v2
modules:
- path: internal/conf/
deps:
- buf.build/envoyproxy/protoc-gen-validate
lint:
use:
- STANDARD
breaking:
use:
- FILE
version: v2
managed:
enabled: true
plugins:
# Generate Go protobuf code for service configuration schema
# Used to define strongly-typed config loaded from YAML at runtime
- remote: buf.build/protocolbuffers/go
out: internal/conf/gen
opt: paths=source_relative
# Generate validation code from protoc-gen-validate annotations
- local: protoc-gen-validate
out: internal/conf/gen
opt: paths=source_relative,lang=go
inputs:
- directory: internal/conf
Replace {service-name} with the actual service name.
# Binaries
bin/
# Wire generated
wire_gen.go
# Test coverage
coverage.out
coverage.html
# IDE
.idea/
.vscode/
*.swp
*.swo
*~
# OS
.DS_Store
Thumbs.db
# {Service Name}
{Brief description of what this service does}
## Architecture
This service follows clean architecture with the following layers:
- **cmd/** - Application entry point and dependency injection (Wire)
- **internal/server/** - HTTP and gRPC server setup
- **internal/service/** - Service handlers (implements proto service interfaces)
- **internal/biz/** - Business logic and use cases
- **internal/data/** - Data access layer (repositories, database)
- **internal/conf/** - Configuration protobuf definitions
## Development
### Prerequisites
```bash
make init
make generate
make build
./bin/{service-name} -conf configs/config.yaml
make test
make coverage
Configuration is defined in internal/conf/conf.proto and loaded from configs/config.yaml.
Prometheus metrics exposed at /metrics:
Proto definitions should be added to api/service/{service-name}/v1/ in the monorepo root.
After defining protos:
make contracts-generate from monorepo rootinternal/server/http.go and internal/server/grpc.gointernal/biz/interfaces.gointernal/biz/my_usecase.gobiz.ProviderSetinternal/data/repo/my_repo.godata.ProviderSetinternal/data/data.gointernal/data/model/internal/data/repo/
Replace `{Service Name}` and `{service-name}` with the actual service name.
## Step 11: Generate Wire Code
Navigate to the cmd directory and generate Wire code:
```bash
cd services/{service-name}/cmd/{service-name}
GOWORK=off go generate
This will create wire_gen.go with the dependency injection graph.
Build the service to verify everything is wired correctly:
cd services/{service-name}
make build
If there are any import or compilation errors, fix them before proceeding.
Inform the user of what was created:
✓ Created new service: {service-name}
✓ Location: services/{service-name}/
✓ Structure: Clean architecture with server/service/biz/data layers
✓ Config: Complete config with Server, Data, Metrics
✓ Wire: Dependency injection configured and generated
✓ Metrics: HTTP and gRPC metrics enabled
✓ Build: Makefile with all standard targets
Next steps:
1. Define proto API in api/service/{service-name}/v1/
2. Run 'make contracts-generate' from monorepo root
3. Implement service handlers in internal/service/
4. Add business logic in internal/biz/
5. Implement repositories in internal/data/
The service is ready to build and run, but needs proto definitions to be useful.
</workflow>
<success_criteria> Service skeleton is complete when:
make build{service-name} replaced with actual service namexiaohongshu
technical spec
product ux expert
database patterns
Conduct multi-agent task orchestration and workflow coordination.
Initialize project with Conductor artifacts (product definition,
Expert in web animations, transitions, and motion design using Framer Motion and CSS
Creates Mermaid and ASCII diagrams for flowcharts, architecture, ERDs, state machines, mindmaps, and more. Use when user mentions diagram, flowchart, mermaid, ASCII diagram, text diagram, terminal diagram, visualize, C4, mindmap, architecture diagram, sequence diagram, ERD, or needs visual docume...
PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.
Context-Driven Development skill for projects using Conductor. Use this skill when you detect a `conductor/` directory in the project, when working on tasks defined in a `plan.md` file, or when the user asks about tracks, specs, or plans. Automatically applies TDD workflow, tracks task completion...
Display project status, active tracks, and next actions
Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.
Generate, edit, and beat-sync AI video with leading models in one workspace.
The world's fastest calendar for remote work
Transform Your Design with AI Designer by ImgCreator.ai
Revolutionizing Video Production with AI-Powered Creativity
Extend an image past the frame and let AI fill the new aspect ratio.
Discover your celebrity doppelgänger with StarByFace!
ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.
Opus.ai: Revolutionize Your Web Experience