| name | api-generator |
| description | Specialized skill for developing and refactoring the DST (Don't Starve Together) Admin Go project. Use this skill whenever the user mentions DST, game server management, API refactoring, adding handlers/services, creating CRUD endpoints, or working within the dst-admin-go codebase. This skill ensures all code follows the project's architectural patterns including dependency injection, layered architecture (Handler → Service → Model), and specific naming conventions. Make sure to use this skill when the user asks to refactor existing APIs, add new features, fix bugs, or modify any part of the dst-admin-go project structure. |
| license | MIT |
| metadata | {"author":"DST Admin Go Team","version":"2.0.0","domain":"application","triggers":"DST, dst-admin-go, Don't Starve Together, game server, refactor API, add handler, create service, GORM, Gin, cluster management, backup service, player management, mod management, CRUD generator, generate API, create endpoint, 生成API, 创建接口","role":"specialist","scope":"implementation","output-format":"code","related-skills":"golang-pro, golang-patterns"} |
DST Admin Go API Generator
Specialized skill for developing and refactoring the DST (Don't Starve Together) Admin Go project. Use this skill whenever the user mentions DST, game server management, API refactoring, adding handlers/services, creating CRUD endpoints, or working within the dst-admin-go codebase. This skill ensures all code follows the project's architectural patterns including dependency injection, layered architecture (Handler → Service → Model), and specific naming conventions.
Project Context
DST Admin Go is a web-based management panel for "Don't Starve Together" game servers written in Go. It follows a three-layer architecture:
- Handler Layer (
internal/api/handler/): HTTP request handling, validation, response formatting
- Service Layer (
internal/service/): Business logic, orchestration
- Model Layer (
internal/model/): Database entities (GORM)
Architecture Patterns
- Dependency Injection: All services instantiated in
internal/api/router.go, injected via constructors
- No Global Variables: Pass config and dependencies through constructors
- Platform Abstraction: Factory patterns for Linux/Windows differences
- Naming Conventions:
- Files:
snake_case.go (e.g., backup_service.go)
- Structs:
PascalCase without suffix (e.g., BackupInfo, NOT BackupInfoVO)
- Constructors:
New{Name} (e.g., NewBackupService)
- Interfaces: Simple names (e.g.,
Config, Process)
Project Structure
dst-admin-go/
├── cmd/server/main.go # Entry point
├── internal/
│ ├── api/
│ │ ├── handler/ # HTTP handlers (controllers)
│ │ │ └── {entity}_handler.go
│ │ └── router.go # Route registration & DI
│ ├── model/ # GORM models
│ │ └── {entity}.go
│ ├── service/ # Business logic
│ │ └── {domain}/
│ │ ├── {domain}_service.go
│ │ ├── factory.go # (if platform-specific)
│ │ ├── linux_{domain}.go
│ │ └── window_{domain}.go
│ └── pkg/
│ ├── response/ # Standard responses
│ └── utils/ # Utilities
└── config.yml # Application config
Your Instructions
You are an expert Go developer specializing in the DST Admin Go project. When the user requests creating a CRUD module, refactoring APIs, or adding new functionality:
Step 1: Gather Requirements
Ask the user for the following information (use a friendly, concise tone):
- Entity/Model Name: What is the entity called? (e.g., "Announcement", "ModConfig", "Player")
- Chinese Name: What is the Chinese name for Swagger docs? (e.g., "公告", "模组配置")
- Database Fields: What fields does this entity have?
- Field name, type (string, int, bool, time.Time, etc.)
- GORM constraints (e.g.,
unique, not null, default)
- JSON tag name (camelCase for API responses)
- Example:
Title string, required, JSON: "title" or IsActive bool, default true, JSON: "isActive"
- Operations Needed: Which operations should be available?
- Standard CRUD: Create, Read (Get by ID), Update, Delete, List (with pagination)
- Custom operations: Batch delete, toggle status, search, etc.
- Business Logic Notes: Any special validation, processing, or relationships?
- E.g., "Must validate expiresAt is in the future", "Needs to interact with game process"
- Cluster Context: Does this entity belong to a specific cluster/server?
- If yes: Endpoints will be under
/api/{clusterName}/{entity} and need cluster middleware
Step 2: Analyze Dependencies
Based on the requirements, determine:
- Always needed:
*gorm.DB for database operations
- Game-related: If interacting with game state →
game.Process
- File operations: If handling files/archives →
archive.PathResolver
- DST config: If reading/writing DST configs →
dstConfig.Config
- Level config: If working with world configs →
levelConfig.LevelConfigUtils
- Platform-specific: If operations differ on Linux vs Windows → factory pattern
Step 3: Generate Model File
Create internal/model/{entity}.go:
package model
import (
"gorm.io/gorm"
"time"
)
type {EntityName} struct {
gorm.Model
Title string `json:"title" gorm:"type:varchar(255);not null"`
Content string `json:"content" gorm:"type:text"`
IsActive bool `json:"isActive" gorm:"default:true"`
ExpiresAt *time.Time `json:"expiresAt"`
}
Guidelines:
- Always embed
gorm.Model (provides ID, CreatedAt, UpdatedAt, DeletedAt)
- Use GORM tags for constraints:
type:, not null, unique, default:
- Use JSON tags in camelCase
- Add struct comment with Chinese description
- Use pointer types for nullable fields (e.g.,
*time.Time, *string)
Step 4: Generate Service File
Create internal/service/{domain}/{domain}_service.go:
package {domain}
import (
"dst-admin-go/internal/model"
"gorm.io/gorm"
)
type {Entity}Service struct {
db *gorm.DB
}
func New{Entity}Service(db *gorm.DB ) *{Entity}Service {
return &{Entity}Service{
db: db,
}
}
func (s *{Entity}Service) List{Entity}(page, pageSize int) ([]model.{Entity}, int64, error) {
var list []model.{Entity}
var total int64
offset := (page - 1) * pageSize
err := s.db.Model(&model.{Entity}{}).Count(&total).Error
if err != nil {
return nil, 0, err
}
err = s.db.Offset(offset).Limit(pageSize).Find(&list).Error
return list, total, err
}
func (s *{Entity}Service) Get{Entity}(id uint) (*model.{Entity}, error) {
var entity model.{Entity}
err := s.db.First(&entity, id).Error
return &entity, err
}
func (s *{Entity}Service) Create{Entity}(entity *model.{Entity}) error {
return s.db.Create(entity).Error
}
func (s *{Entity}Service) Update{Entity}(entity *model.{Entity}) error {
return s.db.Save(entity).Error
}
func (s *{Entity}Service) Delete{Entity}(id uint) error {
return s.db.Delete(&model.{Entity}{}, id).Error
}
Guidelines:
- Constructor accepts all dependencies
- Chinese comments for all exported methods
- Use GORM for database operations
- Add pagination support for List (offset/limit)
- Return errors, don't handle them here
- Add custom business logic methods as needed
Step 5: Generate Handler File
Create internal/api/handler/{entity}_handler.go:
package handler
import (
"dst-admin-go/internal/model"
"dst-admin-go/internal/pkg/response"
"dst-admin-go/internal/service/{domain}"
"github.com/gin-gonic/gin"
"net/http"
"strconv"
)
type {Entity}Handler struct {
service *{domain}.{Entity}Service
}
func New{Entity}Handler(service *{domain}.{Entity}Service) *{Entity}Handler {
return &{Entity}Handler{service: service}
}
func (h *{Entity}Handler) RegisterRoute(router *gin.RouterGroup) {
router.GET("/api/{entity}/list", h.List)
router.GET("/api/{entity}/:id", h.Get)
router.POST("/api/{entity}", h.Create)
router.PUT("/api/{entity}/:id", h.Update)
router.DELETE("/api/{entity}/:id", h.Delete)
}
func (h *{Entity}Handler) List(ctx *gin.Context) {
page, _ := strconv.Atoi(ctx.DefaultQuery("page", "1"))
pageSize, _ := strconv.Atoi(ctx.DefaultQuery("pageSize", "10"))
if page < 1 {
page = 1
}
if pageSize < 1 || pageSize > 100 {
pageSize = 10
}
list, total, err := h.service.List{Entity}(page, pageSize)
if err != nil {
response.FailWithMessage("获取列表失败: "+err.Error(), ctx)
return
}
response.OkWithData(gin.H{
"list": list,
"total": total,
"page": page,
"pageSize": pageSize,
}, ctx)
}
func (h *{Entity}Handler) Get(ctx *gin.Context) {
id, err := strconv.ParseUint(ctx.Param("id"), 10, 32)
if err != nil {
response.FailWithMessage("无效的ID", ctx)
return
}
entity, err := h.service.Get{Entity}(uint(id))
if err != nil {
response.FailWithMessage("获取详情失败: "+err.Error(), ctx)
return
}
response.OkWithData(entity, ctx)
}
func (h *{Entity}Handler) Create(ctx *gin.Context) {
var entity model.{Entity}
if err := ctx.ShouldBindJSON(&entity); err != nil {
response.FailWithMessage("参数错误: "+err.Error(), ctx)
return
}
if err := h.service.Create{Entity}(&entity); err != nil {
response.FailWithMessage("创建失败: "+err.Error(), ctx)
return
}
response.OkWithData(entity, ctx)
}
func (h *{Entity}Handler) Update(ctx *gin.Context) {
id, err := strconv.ParseUint(ctx.Param("id"), 10, 32)
if err != nil {
response.FailWithMessage("无效的ID", ctx)
return
}
var entity model.{Entity}
if err := ctx.ShouldBindJSON(&entity); err != nil {
response.FailWithMessage("参数错误: "+err.Error(), ctx)
return
}
entity.ID = uint(id)
if err := h.service.Update{Entity}(&entity); err != nil {
response.FailWithMessage("更新失败: "+err.Error(), ctx)
return
}
response.OkWithData(entity, ctx)
}
func (h *{Entity}Handler) Delete(ctx *gin.Context) {
id, err := strconv.ParseUint(ctx.Param("id"), 10, 32)
if err != nil {
response.FailWithMessage("无效的ID", ctx)
return
}
if err := h.service.Delete{Entity}(uint(id)); err != nil {
response.FailWithMessage("删除失败: "+err.Error(), ctx)
return
}
response.OkWithMessage("删除成功", ctx)
}
Guidelines:
- Complete Swagger annotations for every handler
- Use
response.Response helpers: OkWithData, FailWithMessage, OkWithMessage
- Validate all input parameters
- Chinese error messages
- Parse ID from path parameter as uint
- Bind JSON request body with
ShouldBindJSON
- Return HTTP 200 even for errors (error code in response body)
Step 6: Update Router
Read internal/api/router.go and make these changes:
- Add import (if not exists):
"{domain}" "dst-admin-go/internal/service/{domain}"
- In
Register() function, add service initialization (after existing services):
{entity}Service := {domain}.New{Entity}Service(db )
- Add handler initialization (after existing handlers):
{entity}Handler := handler.New{Entity}Handler({entity}Service)
- Add route registration (after existing routes):
{entity}Handler.RegisterRoute(router)
Important: Maintain the existing order and formatting. Add new code at the end of each section.
Step 7: Handle Platform-Specific Code (if needed)
If the service needs platform-specific behavior:
- Create
internal/service/{domain}/factory.go:
package {domain}
import (
"gorm.io/gorm"
"runtime"
)
func New{Entity}Service(db *gorm.DB) {Entity}Service {
if runtime.GOOS == "windows" {
return &Windows{Entity}Service{db: db}
}
return &Linux{Entity}Service{db: db}
}
- Create interface in
{domain}_service.go:
type {Entity}Service interface {
List{Entity}(page, pageSize int) ([]model.{Entity}, int64, error)
}
- Create platform implementations:
internal/service/{domain}/linux_{domain}.go
internal/service/{domain}/window_{domain}.go
Step 8: Verify and Test
After generating all files:
- Run compilation check:
go mod tidy
go build cmd/server/main.go
-
Report to user:
- List all generated files
- Show modified files (router.go)
- Provide curl test commands
- Mention Swagger UI location
-
Provide test commands:
curl -X GET "http://localhost:8082/api/{entity}/list?page=1&pageSize=10"
curl -X POST "http://localhost:8082/api/{entity}" \
-H "Content-Type: application/json" \
-d '{"field1": "value1", "field2": "value2"}'
curl -X GET "http://localhost:8082/api/{entity}/1"
curl -X PUT "http://localhost:8082/api/{entity}/1" \
-H "Content-Type: application/json" \
-d '{"field1": "new_value"}'
curl -X DELETE "http://localhost:8082/api/{entity}/1"
- Remind user: Access Swagger UI at
http://localhost:8082/swagger/index.html (after running the server)
Common Patterns Reference
Response Helpers
Located in internal/pkg/response/response.go:
response.OkWithData(data, ctx)
response.OkWithMessage("操作成功", ctx)
response.FailWithMessage("操作失败: "+err.Error(), ctx)
Common Dependencies
*gorm.DB: Database access
*gin.Context: HTTP request context
dstConfig.Config: DST configuration interface
game.Process: Game process management interface
archive.PathResolver: Archive path resolution
levelConfig.LevelConfigUtils: Level config parsing
Cluster-Aware Endpoints
If entity belongs to a cluster, routes should be:
router.GET("/api/:cluster_name/{entity}/list", h.List)
router.GET("/api/:cluster_name/{entity}/:id", h.Get)
IMPORTANT: Handler should use cluster context helper to get clusterName:
import "dst-admin-go/internal/pkg/context"
clusterName := context.GetClusterName(ctx)
DO NOT use ctx.Query("clusterName") or ctx.Param("cluster_name") directly. Always use context.GetClusterName(ctx) which retrieves the clusterName set by the cluster middleware.
Pagination Pattern
Always use this pattern for list endpoints:
page, _ := strconv.Atoi(ctx.DefaultQuery("page", "1"))
pageSize, _ := strconv.Atoi(ctx.DefaultQuery("pageSize", "10"))
if page < 1 {
page = 1
}
if pageSize < 1 || pageSize > 100 {
pageSize = 10
}
offset := (page - 1) * pageSize
GORM Common Tags
type:varchar(255) - String with length
type:text - Long text
not null - Required field
unique - Unique constraint
default:true - Default value
index - Create index
foreignKey:UserID - Foreign key
Examples
Example 1: Simple Announcement System
User Input:
- Entity: Announcement
- Chinese: 公告
- Fields: Title (string, required), Content (text), IsActive (bool, default true), ExpiresAt (time, nullable)
- Operations: Full CRUD + List
- Cluster context: No
Generated Files:
internal/model/announce.go
internal/service/announce/announce_service.go
internal/api/handler/announce_handler.go
- Modified:
internal/api/router.go
Example 2: Mod Management (Game-Related)
User Input:
- Entity: ModInfo
- Chinese: 模组信息
- Fields: ModId (string, unique), Name (string), Author (string), Version (string), IsEnabled (bool), ClusterName (string)
- Operations: Full CRUD + List + Toggle status
- Business logic: Needs to interact with game process when toggling
- Cluster context: Yes
Generated Files:
internal/model/modInfo.go
internal/service/mod/mod_service.go (with game.Process dependency)
internal/api/handler/mod_handler.go (with cluster-aware routes)
- Modified:
internal/api/router.go
Additional method in service:
func (s *ModService) ToggleModStatus(clusterName, modId string) error {
return nil
}
Critical Checklist
Before completing the task, verify:
DST-Specific Domain Knowledge
Cluster Architecture
A cluster contains multiple levels (worlds):
- Master - Overworld (surface world)
- Caves - Underground world
Each level runs as a separate process with its own configuration.
Important Paths
pathResolver.ClusterPath(clusterName)
pathResolver.LevelPath(clusterName, "Master")
pathResolver.SavePath(clusterName, "Master")
Configuration Files
cluster.ini - Cluster settings (game mode, max players, passwords)
leveldataoverride.lua - World generation settings (Lua table format)
modoverrides.lua - Enabled mods configuration (Lua table format)
server.ini - Server-specific settings
Use luaUtils package to parse/generate Lua configuration files.
Process Management
Linux: Uses screen sessions
screenName := fmt.Sprintf("dst_%s_%s", clusterName, levelName)
Windows: Uses custom CLI wrapper (windowGameCli.go)
Common Utilities
File Operations
import "dst-admin-go/internal/pkg/utils/fileUtils"
fileUtils.PathExists(path)
fileUtils.CreateDir(path)
fileUtils.CopyFile(src, dst)
fileUtils.Unzip(zipPath, destPath)
Shell Commands
import "dst-admin-go/internal/pkg/utils/shellUtils"
output, err := shellUtils.ExecuteCommand("ls", "-la")
Lua Configuration
import "dst-admin-go/internal/pkg/utils/luaUtils"
config, err := luaUtils.ParseLuaTable(luaContent)
luaContent := luaUtils.GenerateLuaTable(configMap)
Tips
- Be concise: Don't over-explain. Generate code efficiently.
- Follow patterns: Always reference existing code in the project for consistency.
- Chinese comments: Use Chinese for inline comments and method descriptions, English for Swagger and exported names.
- Dependency detection: Ask about business logic to determine dependencies accurately.
- Platform awareness: Ask if operations differ on Windows vs Linux.
- Cluster context: Ask if entity belongs to a specific cluster/server.
- Validation: Add appropriate validation in handlers (required fields, format checks).
- Error messages: Always include the original error in Chinese messages: "操作失败: " + err.Error()
When NOT to Use This Skill
Don't use this skill if:
- User is asking general Go questions (not specific to DST Admin Go)
- User wants to modify frontend code
- User is asking about Docker, deployment, or infrastructure
- Task doesn't involve creating/modifying handlers, services, or models
In those cases, handle the request normally without the skill context.
Summary
This skill automates the creation of complete CRUD modules in DST Admin Go following the project's three-layer architecture. It handles model generation, service creation with dependency injection, handler implementation with Swagger docs, and router integration. Always gather complete requirements first, analyze dependencies, generate code following established patterns, and verify compilation before reporting success to the user.