Skip to content

Commit fb430db

Browse files
committed
docs(skills): add Coze Studio backend Go DDD skill bundle (v0.5.1)
1 parent 8de249d commit fb430db

19 files changed

Lines changed: 1010 additions & 0 deletions
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
## Coze Backend Go + DDD - Skill
2+
3+
This is the Coze Studio backend engineering conventions
4+
5+
### What this skill covers
6+
7+
- **IDL-first API design** (Thrift → Hertz codegen)
8+
- **DDD layering boundaries** (Handler / Application / Domain / Repository / DAL)
9+
- **DB DDL → `gorm/gen` reverse generation**
10+
- **Domain-scoped error codes (errno)** and layered error-handling rules
11+
- **crossdomain** interface-based calls
12+
- **Middleware and session** conventions
13+
- **Transactions**, **mocks/tests**, and **ID generation**
14+
15+
### Files
16+
17+
- Entry: `SKILL.md`
18+
- SOP: `checklist.md`
19+
- Notes: `notes.md`
20+
- Code pointers: `citations.md`
21+
- Detailed topics: `skill-01-*.md``skill-13-*.md`
22+
23+
### How to use
24+
25+
This is a **tool-agnostic** prompt+documentation bundle. You can install it in either:
26+
27+
- **Project-level**: put this directory anywhere inside the target repo, then point your AI coding tool to load it as repository knowledge/instructions.
28+
- **Global-level**: store it in your personal prompt library, and attach/reference it when working on `coze-studio/backend`.
29+
30+
### Common tool setups (optional)
31+
32+
Assume you vendor these skills under `docs/skills/` in your repository (for example: `docs/skills/coze-backend-go/`).
33+
34+
#### Cursor
35+
36+
Project root:
37+
38+
```bash
39+
mkdir -p .cursor && ln -snf ../docs/skills .cursor/skills
40+
```
41+
42+
Windows: copy to `.cursor/skills/` instead of symlink.
43+
44+
#### Claude Code
45+
46+
Project root:
47+
48+
```bash
49+
mkdir -p .claude && ln -snf ../docs/skills .claude/skills
50+
```
51+
52+
Windows: copy to `.claude/skills/` instead of symlink.
53+
54+
#### Codex
55+
56+
Copy the skill directory into your global skills home, then restart your tool:
57+
58+
```bash
59+
cp -r docs/skills/coze-backend-go "$CODEX_HOME/skills/"
60+
```
61+
62+
If you have multiple skills, copy multiple subdirectories.
63+
64+
Suggested trigger keywords (when asking an AI coding tool for help):
65+
"backend", "DDD", "IDL", "Thrift", "errno", "gorm/gen", "DAL", "crossdomain", "middleware", "session", "transaction", etc.
66+
67+
### Alignment with official standards
68+
69+
This skill is derived from:
70+
71+
- The official Coze Studio [Development Standards](https://github.com/coze-dev/coze-studio/wiki/7.-Development-Standards)
72+
- The actual structure and code of this repository
73+
74+
Where they differ, this skill follows **the real repository** (for example, using `mockgen` for Go mocks rather than introducing other mock libraries).
75+
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
---
2+
name: coze-backend-go
3+
description: "Documentation of Coze Studio backend Go + DDD conventions. Use when editing `backend/`, implementing APIs (IDL-first), working with Domain/Application/Repository/DAL boundaries, generating DAL via gorm/gen, handling errno and layered errors, crossdomain calls, sessions/middleware, transactions, mocks/tests, and ID generation."
4+
---
5+
6+
# Coze Studio Backend Go + DDD
7+
8+
This skill documents the Coze Studio backend conventions as **actionable AI-coding guidelines**: **Go practices**, **DDD layering**, **IDL-driven development**, DB reverse generation via `gorm/gen`, and Coze-specific patterns such as **domain-scoped error codes**, **space/session isolation**, and **workflow-domain conventions**.
9+
10+
> This skill is aligned with `coze-studio` backend **v0.5.1**. If the repository evolves (structure/codegen commands), treat the repo as the source of truth and refresh this skill accordingly.
11+
12+
## Emphasis
13+
14+
- **Go**: interface vs implementation separation, Functional Options, error-as-value, `internal` packages, `mockgen`, context propagation, and chunked batch queries.
15+
- **DDD**: business invariants live in the Domain layer; API/Application layers orchestrate and map models only.
16+
- **Coze conventions**: IDL-first, unified `{code,msg,data}` responses, errno ranges per domain, crossdomain interfaces, and workflow-specific error handling.
17+
- **Multi-space (tenant-like)**: most resources are scoped by `SpaceID` and must enforce access control (user ↔ space membership) at the Application boundary; never query/update cross-space data without explicit checks.
18+
19+
---
20+
21+
## Skill 0: Architecture and layering overview
22+
23+
```
24+
idl/ ← (1) IDL definitions (Thrift)
25+
backend/
26+
api/
27+
handler/coze/ ← (2) HTTP handlers (generated stubs + manual bodies)
28+
router/coze/ ← (3) Route registration (generated)
29+
model/ ← (4) API request/response structs (generated)
30+
middleware/ ← (5) Middleware (session/auth/log/etc.)
31+
application/{domain}/ ← (6) Application services (orchestration only)
32+
domain/{domain}/
33+
entity/ ← (7) Domain entities
34+
service/ ← (8) Domain service interfaces + implementations
35+
repository/ ← (9) Repository interfaces + implementations
36+
internal/dal/
37+
model/ ← (10) gorm/gen models (*.gen.go)
38+
query/ ← (11) gorm/gen query APIs (*.gen.go)
39+
dto/ ← (12) Domain DTOs
40+
crossdomain/ ← (13) Cross-domain per-domain packages (ACL)
41+
{domain}/
42+
contract.go ← cross-domain interface definitions (anti-corruption layer)
43+
impl/ ← concrete implementations
44+
model/ ← cross-domain models (stable, avoid domain entities)
45+
*mock/ ← mocks (generated)
46+
infra/ ← (14) Infrastructure capabilities (interface + impl/)
47+
{capability}/
48+
*.go ← capability interfaces/types (acts as "contract")
49+
entity/ ← (optional) infra-level entities/VOs
50+
impl/ ← implementations (mysql/redis/nsq/...)
51+
types/
52+
ddl/ ← (15) DB reverse-generation scripts (gen_orm_query.go)
53+
errno/ ← (16) Global/domain error codes
54+
consts/ ← (17) Global constants
55+
```
56+
57+
Boot entry: `backend/main.go``application.Init(ctx)``router.GeneratedRegister(s)`
58+
59+
Cross-domain calls must go through the `crossdomain/{domain}/contract.go` interfaces instead of directly depending on other domains’ `service` packages.
60+
61+
---
62+
63+
## Documents index
64+
65+
| Topic | File |
66+
|------|------|
67+
| End-to-end “add a module” SOP | [checklist.md](checklist.md) |
68+
| Notes and caveats | [notes.md](notes.md) |
69+
| Code pointers (paths + line ranges) | [citations.md](citations.md) |
70+
| Skill 1: IDL-first API design | [skill-01-idl.md](skill-01-idl.md) |
71+
| Skill 2: DB DDL → gorm/gen DAL generation | [skill-02-dal.md](skill-02-dal.md) |
72+
| Skill 3: Domain module structure (DDD) | [skill-03-domain.md](skill-03-domain.md) |
73+
| Skill 4: Application layer conventions | [skill-04-application.md](skill-04-application.md) |
74+
| Skill 5: Transaction patterns | [skill-05-transaction.md](skill-05-transaction.md) |
75+
| Skill 6: Errno + layered validation/error handling | [skill-06-errno.md](skill-06-errno.md) |
76+
| Skill 7: Handler conventions | [skill-07-handler.md](skill-07-handler.md) |
77+
| Skill 8: Middleware & session conventions | [skill-08-middleware.md](skill-08-middleware.md) |
78+
| Skill 9: crossdomain conventions | [skill-09-crossdomain.md](skill-09-crossdomain.md) |
79+
| Skill 10: DTO conventions | [skill-10-dto.md](skill-10-dto.md) |
80+
| Skill 11: Mocks & tests | [skill-11-mock.md](skill-11-mock.md) |
81+
| Skill 12: ID generation rules | [skill-12-id.md](skill-12-id.md) |
82+
| Skill 13: Mermaid flowcharts & architecture diagrams | [skill-13-flowchart-generator.md](skill-13-flowchart-generator.md) |
83+
| Skill 14: Eino conventions | [skill-14-eino.md](skill-14-eino.md) |
84+
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# End-to-end Development Checklist (AI Coding SOP)
2+
3+
```
4+
Full steps to add a new feature/module:
5+
6+
Step 1: Database DDL
7+
- Create/upgrade tables in the test database (DDL/DDL_UPGRADE)
8+
- Add mapping in types/ddl/gen_orm_query.go: path2Table2Columns2Model
9+
- Run: go run types/ddl/gen_orm_query.go (requires MYSQL_DSN env var)
10+
- Generates:
11+
domain/{X}/internal/dal/model/*.gen.go
12+
domain/{X}/internal/dal/query/*.gen.go
13+
14+
Step 2: IDL definition
15+
- Define Service/Request/Response in idl/{module}/*.thrift
16+
- Run Hertz codegen (repo uses `hz`, see `backend/.hz`):
17+
- `hz update -idl idl/api.thrift -enable_extends`
18+
- Note: `-enable_extends` is critical for the master entry `idl/api.thrift` (otherwise route generation may be empty). See coze-studio issue #372.
19+
- Generates:
20+
api/router/coze/api.go (routes)
21+
api/model/{gen_path}/*.go (API structs)
22+
api/handler/coze/{service}_service.go (handler stubs)
23+
24+
Step 3: Domain layer implementation
25+
- entity/ domain entities (embed crossdomain model + domain methods)
26+
- dto/ service input/output DTOs (domain-scoped)
27+
- service/
28+
- service.go Service interface (with //go:generate mockgen)
29+
- service_impl.go impl struct + NewService (dependency injection)
30+
- {feature}.go split by responsibility (multiple files)
31+
- repository/
32+
- {X}_repository.go Repository interface
33+
- {X}_impl.go implementation (holds DAL/DAO)
34+
- option.go Functional Options (field projection)
35+
- internal/dal/
36+
- {table}.go DAO implementation (CRUD + WithTX variants)
37+
38+
Step 4: Register errno
39+
- Add error-code constants in types/errno/{domain}.go (allocate within range)
40+
- Register in init(): code.Register(...)
41+
42+
Step 5: Application layer
43+
- application/{X}/init.go InitService + dependency injection
44+
- application/{X}/*.go orchestrate, call Domain services
45+
46+
Step 6: Implement handler bodies
47+
- api/handler/coze/{service}_service.go fill handler function bodies
48+
49+
Step 7: Register crossdomain (if needed)
50+
- crossdomain/{X}/ define interface contracts
51+
- application/application.go SetDefaultSVC(...)
52+
```
53+
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# Citations (code pointer index)
2+
3+
This repository’s code changes over time. To avoid copying stale code into the docs, this file provides **file paths + line ranges** you can open on-demand.
4+
5+
All paths are relative to the repo root; `backend/` is the backend directory.
6+
7+
---
8+
9+
## Skill 0 / Boot and layering
10+
11+
| What | Path and lines |
12+
|------|---------------|
13+
| main entry, `application.Init`, `startHttpServer`, middleware ordering | `backend/main.go` (L43-104) |
14+
| Route registration (generated) | `backend/api/router/coze/api.go` (L17-80) |
15+
| `GeneratedRegister` | `backend/api/router/register.go` (L34-39) |
16+
17+
---
18+
19+
## Skill 1: IDL
20+
21+
| What | Path and lines |
22+
|------|---------------|
23+
| Base / `BaseResp`, `EmptyResp` (code+msg+data) | `idl/base.thrift` (L1-42) |
24+
| Service methods and `api.post` / `api.gen_path` annotations | `idl/plugin/plugin_develop.thrift` (L6-50) |
25+
26+
---
27+
28+
## Skill 2: DAL generation
29+
30+
| What | Path and lines |
31+
|------|---------------|
32+
| `path2Table2Columns2Model` config | `backend/types/ddl/gen_orm_query.go` (L44-225) |
33+
| generator main, DSN, FieldModify | `backend/types/ddl/gen_orm_query.go` (L231-326) |
34+
| PO models (`*.gen.go`) | `backend/domain/plugin/internal/dal/model/plugin_draft.gen.go` (L1-33) |
35+
| Query APIs (`*.gen.go`) | `backend/domain/plugin/internal/dal/query/plugin_draft.gen.go` (L1-46) |
36+
37+
---
38+
39+
## Skill 3: DDD (4 layers)
40+
41+
| What | Path and lines |
42+
|------|---------------|
43+
| Entity embeds crossdomain model | `backend/domain/plugin/entity/plugin.go` (L24-54) |
44+
| Service interface, `//go:generate mockgen` | `backend/domain/plugin/service/service.go` (L27-92) |
45+
| `service_impl`, `NewService` DI | `backend/domain/plugin/service/service_impl.go` (L30-65) |
46+
| Repository interface | `backend/domain/plugin/repository/plugin_repository.go` (L27-53) |
47+
| Functional Options (`option.go`) | `backend/domain/plugin/repository/option.go` (L23-86) |
48+
| DAO Create, `ToDO`, `genPluginID` | `backend/domain/plugin/internal/dal/plugin_draft.go` (L39-138) |
49+
| Keyset-pagination list | `backend/domain/plugin/internal/dal/plugin_draft.go` (L158-190) |
50+
| MGet, `slices.Chunks` | `backend/domain/plugin/internal/dal/plugin_draft.go` (L192-212) |
51+
| `CreateWithTX` | `backend/domain/plugin/internal/dal/plugin_draft.go` (L287-315) |
52+
| Repository impl (holds DAO) | `backend/domain/plugin/repository/plugin_impl.go` (L45-72) |
53+
| Transaction template (Begin/defer Rollback/Commit) | `backend/domain/plugin/repository/plugin_impl.go` (L133-170) |
54+
| Multi-table transaction: PublishPlugin | `backend/domain/plugin/repository/plugin_impl.go` (L283-351) |
55+
| DTO definitions | `backend/domain/plugin/dto/plugin.go` (L27-96) |
56+
| Repository mocks | `backend/domain/plugin/repository/mock/` |
57+
58+
---
59+
60+
## Skill 4: Application
61+
62+
| What | Path and lines |
63+
|------|---------------|
64+
| Application struct, DomainSVC | `backend/application/plugin/plugin.go` (L49-59) |
65+
| InitService and DI | `backend/application/plugin/init.go` (L38-89) |
66+
| `basicServices``primaryServices``complexServices`, `SetDefaultSVC` | `backend/application/application.go` (L84-171) |
67+
68+
---
69+
70+
## Skill 6: Errors and handlers
71+
72+
| What | Path and lines |
73+
|------|---------------|
74+
| errno constants and range | `backend/types/errno/plugin.go` (L25-54) |
75+
| `init`, `code.Register`, `WithAffectStability` | `backend/types/errno/plugin.go` (L56-103) |
76+
| `StatusError` interface | `backend/pkg/errorx/error.go` (L26-36) |
77+
| `errorx.New`, `WrapByCode`, `Wrapf` | `backend/pkg/errorx/error.go` (L54-78) |
78+
| HTTP error response mapping | `backend/api/internal/httputil/error_resp.go` (L35-54) |
79+
| `invalidParamRequestResponse`, `internalServerErrorResponse` | `backend/api/handler/coze/base.go` (L27-33) |
80+
| Handler example: BindAndValidate, validation, calling Application | `backend/api/handler/coze/plugin_develop_service.go` (L34-77) |
81+
| `GetUIDFromCtx`, `MustGetUIDFromCtx` | `backend/application/base/ctxutil/session.go` (L36-52) |
82+
| Session auth middleware | `backend/api/middleware/session.go` (L41-75) |
83+
84+
---
85+
86+
Open the files above at the referenced line ranges. If line numbers drift due to edits, search nearby for the mentioned symbols.
87+
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Notes
2+
3+
1. **Generated code vs handwritten code**: files under `api/router/coze/api.go`, `api/model/`, `dal/model/*.gen.go`, and `dal/query/*.gen.go` are **generated** and must **not** be edited manually. Handler function bodies, middleware bodies, the `application/` layer, and the `domain/` layer are handwritten.
4+
5+
2. **Framework choices**: HTTP uses [Hertz](https://github.com/cloudwego/hertz) (CloudWeGo), ORM uses gorm + `gorm/gen`, and IDL uses Apache Thrift.
6+
7+
3. **The Application layer is not a mandatory “classic DDD” layer**, but in this codebase it acts as the DDD Application Service: API model mapping, cross-domain orchestration, and event publishing.
8+
9+
4. **`internal/` packages** enforce Go access boundaries: `domain/{X}/internal/dal/` can only be used by code within the same domain module. The Application layer must not call DAL directly; it must go through repository interfaces.
10+
11+
5. **Batch MGet**: for bulk reads, use `slices.Chunks(ids, 20)` to chunk requests and avoid overly large `IN (...)` clauses.
12+
13+
6. **Go error handling**: business errors should be returned as `error` (via `errorx` + `errno`). Avoid `panic` on business paths; reserve `panic` for unrecoverable programming errors. The Application layer may use `defer` + `recover` as a final safety net and convert panics to standard error codes.
14+
15+
7. **Errors must carry a business code**: the Application and Domain layers must not return bare `errors.New(...)` or `fmt.Errorf(...)` for expected business errors. Use `errorx.New(errno.ErrXxx, ...)` for business errors; otherwise the Handler layer will treat it as a system error and respond with HTTP 500, which is both non-actionable and hard to distinguish from real incidents. When propagating errors, use `errorx.Wrapf` / `errorx.WrapByCode` (or `github.com/pkg/errors` Wrap/Wrapf) to preserve call context; before returning to HTTP, ensure it is converted to a status error with a proper errno code.
16+
17+
8. **File header comments**: new files do not need to add legacy copyright headers (this is an internal project). Keep existing headers in old files as-is.
18+
19+
9. **When to use `pkg/`**: small generic utilities (e.g., time/json/file/lang helpers) without business semantics and without direct external system access. Do not put DB/Redis/HTTP SDK integrations into `pkg/`; those belong to `infra/` or domain-specific adapters.
20+
21+
10. **Avoid reinventing wheels**: before adding “utility” code, check whether `pkg/` already provides a similar helper.
22+
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# Skill 1: Design APIs starting from IDL (IDL-first)
2+
3+
## Rules
4+
5+
1. **All APIs start from `.thrift` files under `idl/`.**
6+
2. Each service method’s annotations define the HTTP route, category, and generated code path.
7+
3. `base.thrift` defines the shared `Base` (request) and `BaseResp` (response) structures.
8+
4. Responses follow a unified `{code, msg, data}` shape and include `base.BaseResp` as the tail field.
9+
5. **One method parameter and one return value only**, both must be custom `struct` types.
10+
6. Request/response naming follows `{Method}Request` / `{Method}Response`.
11+
7. Each `Request` struct must include a `Base` field (`base.Base`, field id `255`, `optional`).
12+
8. Each `Response` struct must include a `BaseResp` field (`base.BaseResp`, field id `255`, `optional`).
13+
9. New fields should be declared as `optional`; avoid `required` for forward compatibility.
14+
15+
## Codegen (Hertz `hz`)
16+
17+
`coze-studio` backend v0.5.1 uses `hz` (Hertz toolkit) to generate routes, handler stubs, and `api/model` structs from Thrift IDL. See `backend/.hz` for the configured output directories (handler/model/router).
18+
19+
Common command (run from repo root):
20+
21+
```bash
22+
# Update the master IDL (aggregation/extends) generated routes + handler/model
23+
hz update -idl idl/api.thrift -enable_extends
24+
```
25+
26+
Notes:
27+
- `idl/api.thrift` is usually the master IDL aggregating multiple services (incl. `extends`); in practice `-enable_extends` is required, otherwise route generation may be empty.
28+
- `hz update` only needs the IDL file that defines the `service`; dependent IDLs will be generated automatically.
29+
30+
**IDL template** (see `plugin_develop.thrift` as reference):
31+
32+
```thrift
33+
service XxxService {
34+
XxxResponse XxxMethod(1: XxxRequest request)
35+
(api.post='/api/xxx/yyy', api.category="xxx", api.gen_path="xxx")
36+
}
37+
struct XxxRequest {
38+
1: optional i64 id (api.js_conv = "str"),
39+
255: optional base.Base Base
40+
}
41+
struct XxxResponse {
42+
1: i64 code,
43+
2: string msg,
44+
3: XxxData data,
45+
255: optional base.BaseResp BaseResp
46+
}
47+
```
48+
49+
## Conventions
50+
51+
- Service names and method names use **camelCase**.
52+
- Typically, one service per `.thrift` file (except for explicit aggregation via `extends`).
53+
- APIs follow a **RESTful** style for paths; when adding new endpoints, use existing modules as a style reference instead of inventing new patterns.
54+
55+
## Generated code artifacts
56+
57+
- `backend/api/router/coze/api.go` — route registration (**generated**; do not edit)
58+
- `backend/api/router/coze/middleware.go` — middleware stubs (can be manually filled)
59+
- `backend/api/model/{gen_path}/` — request/response structs (**generated**)
60+
- `backend/api/handler/coze/` — handler stubs (implement handler bodies manually)
61+
62+
See [citations.md](citations.md) for code pointers.
63+

0 commit comments

Comments
 (0)