Skip to content

6. Code development and testing

kidkidkid edited this page Aug 25, 2025 · 5 revisions

In the Coze Loop open-source edition, both the front-end and back-end code need to follow the coding style and specifications provided in this document.

Project structure

├── backend/          # Backend code
│   ├── api/          # API interface definition and implementation
│   │   ├── handler/  # API handling
│   │   └── router/   # API routing
│   ├── cmd/          # Application entry and service startup
│   │   └── main.go   # Entry function
│   ├── modules/      # Core business modules
│   │   ├── data/     # Data set module
│   │   │   ├── application/ # Application service layer
│   │   │   ├── domain/      # Domain model layer
│   │   │   ├── pkg /        # Public utility layer
│   │   │   └── infra/       # Infrastructure layer
│   │   ├── evaluation/    # Evaluation module
│   │   ├── foundation/    # Infrastructure module
│   │   ├── llm/           # LLM module
│   │   ├── observability/ # Observability module
│   │   └── prompt/        # PE module
│   ├── pkg/            # General utility package and library
│   └── script/         # Scripts
│       ├── errorx/     # Error code definition and generation tool
│       └── kitex/      # Kitex code generation tool
├── frontend/         # Frontend code
├── release/          # Deployment related
└── idl/              # IDL interface definition files

Development specifications

Code structure

The repository uses a Monorepo approach, where both the front-end and back-end code are housed in the same repository. The back-end code design adopts a DDD approach, following a layered architecture. Each business module adheres to the following layered architecture:

  • application: App service layer, coordinating domain objects to complete business processes
  • domain: Domain model layer, defining core business entities and business logic
  • Infra: The infrastructure layer provides technical implementation and external service integration
  • Pkg: Module-specific public packages

Go specifications

Go language code specifications can refer to Google specifications. It is recommended to use formatting tools such as gofmt for code formatting.

IDL specifications

Category Note
Service definition * Service naming uses camel case
* Each Thrift file defines only one Service, except for extends aggregation
Method definition * API naming uses camel case
* An API can only have one parameter and one return value, and it must be a custom Struct type
* Input parameters must be named {Method}Request, and return values named {Method}Response
* Each Request type must include a Base field, of type base.Base, with a field number of 255, and it should be an optional type
* Each Response type must include a BaseResp field, of type base.BaseResp, with a field number of 255
Struct definition * Struct names use camel case naming
* Field names use snake case naming
* New fields are set to optional; required is prohibited
* Modifying existing field IDs and types is prohibited
Enumeration definitions * It is recommended to use typedef to define enumeration values
* Enumeration value names use camel case naming, with an underscore connecting the type and name
API definitions * Define APIs using the RESTful style
* Refer to the existing module's API definitions, maintaining a consistent style
Annotation definition * Refer to Kitex supported annotations
* Refer to Hertz supported annotations

Specification examples are as follows:

 # 单个Service
 typedef string EnumType(ts.enum="true") 

 const EnumType EnumType_Text = "Text"

 struct ExampleRequest {
     1: optional i64 id
 
     255: optional base.Base base
 }

 struct ExampleResponse {
     1: optional string name
     2: optional EnumType enum_type

     255: base.BaseResp base_resp
 }

 service ExampleService {
     ExampleMethod(1: ExampleRequest) (2: ExampleResponse)
 }

 # 多个Service
 service ExampleAService extends idl_a.AService{}
 service ExampleBService extends idl_b.BService{}

Unit test specifications

Category Specification description
UT function naming * Normal functions are named as Test{FunctionName}(t *testing.T)
* Object methods are named as Test{ObjectName}{MethodName}(t *testing.T)
* Benchmark function naming as Benchmark{FunctionName}(b *testing.B)
* Benchmark objects naming as Benchmark{ObjectName}
{MethodName}(b *testing.B)
File naming The test file and the file being tested should have the same name, with the suffix _test.go, and be in the same directory
Test design * It is recommended to use a table-driven approach to define inputs/outputs and cover multiple scenarios
* Use github.com/stretchr/testify to simplify assertion logic
* Use github.com/uber-go/mock to generate mock objects and avoid using patch stubbing whenever possible

Test examples are as follows:

func TestRetryWithMaxTimes1(t *testing.T) {
    type args struct {
        ctx context.Context
        max int
        fn  func() error
    }
    tests := []struct {
        name    string
        args    args
        wantErr bool
    }{
        {
            name: "test1",
            args: args{
                max: 3,
                fn: func() error {
                    return nil
                }
            },
            wantErr: false,
        }
        // Add more test cases.
    }
    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            err := RetryWithMaxTimes(tt.args.ctx, tt.args.max, tt.args.fn)
            assert.Equal(t, tt.wantErr, err != nil)
        })
    }
}

Frontend development specifications

Development preparation

Before modifying the Coze Loop Open-source Edition frontend code, please ensure that the development environment meets the following requirements:

  • Node.js 18+ (recommended lts/iron version)
  • pnpm 8.15.8
  • Rush 5.147.1

You can refer to the following steps to prepare the frontend development environment.

  1. Install Node.js 18+.

    nvm install lts/iron
    nvm alias default lts/iron # Set the default Node version
    nvm use lts/iron
  2. Open the frontend directory.

    # Switch directory
    cd frontend
  3. Install global dependencies.

    npm i -g pnpm@8.15.8 @microsoft/rush@5.147.1
  4. Install or update project dependencies.

    rush update

Develop front-end code

Run

Execute the following commands under the Coze Loop Open-source Edition directory to start the development task and run the development environment.

  • It is recommended to use rushx instead of pnpm run or npm run.
  • The Coze Loop project is located in the apps/cozeloop directory and is a React app.
cd apps/cozeloop

rushx dev

After execution, open http://localhost:8090/ in the browser to view the page.

Build

The Coze Loop project is built using Rsbuild, and the configuration file is located at apps/cozeloop/rsbuild.config.ts. Execute the following commands to build the project.

cd apps/cozeloop

rushx build

Workspace dependencies

As you can see, there are many dependencies in apps/cozeloop/package.json set to workspace:* versions, meaning they are maintained within this repository. The Coze Loop project relies on the source code of these projects rather than the build artifacts. Typically, modifying the source code of these workspace dependencies will take effect immediately. In extremely rare cases, the project needs to be rerun.

How to develop AI-powered apps

  1. Create a feature branch. It is recommended that each feature corresponds to a feature branch.

    git checkout -b feat/your-feature-name
  2. Develop new features.

    • If you need to modify IDL, make changes according to the specifications, then use the script to generate code. At this time, kitex and hertz code will be generated.

      cd ./backend/script/cloudwego
      ./code_gen.sh
    • If you need to modify dependency injection, follow the current wire-based dependency injection method, modify wire.go under the corresponding directory, and then regenerate the code.

      # Modify the overall initialization dependency injection
      cd ./backend/api/handler/coze/loop/apis
      wire
      # Modify the submodule dependency injection
      cd ./backend/modules/observability/application
      wire
    • If you need to add a new database/Add a new MQ Topic:

      • Add a MySQL table: Add table creation SQL under release/deployment/docker-compose/bootstrap/mysql-init/init-sql, and make sure to include IF NOT EXISTS.
      • Add a Clickhouse table: Add table creation SQL under release/deployment/docker-compose/bootstrap/clickhouse-init/init-sql, and make sure to include IF NOT EXISTS.
      • Add a RocketMQ Topic: Add a Topic under release/deployment/docker-compose/bootstrap/rmq-init/init-subscription/subscriptions.cfg, with the format {topic}={consumer}
    • Develop back-end services according to Go development standards. Make sure app service could start.

      make compose-up
    • Before submitting code, add unit tests, ensure the incremental coverage rate is above 80%, and confirm all existing unit tests pass.

      cd backend/
      go test -gcflags="all=-N -l" -count=1 -v ./...
  3. Submit code.

       git add .
       git commit -m "feat: add new feature"
  4. Merge request.

    1. Push to the remote repository
    2. Create a Pull Request
    3. Ensure the CI for the code passes
    4. Wait for Code Review

Test process

Unit test

  1. Run the test. Execute the following commands to run the unit test.

    # Run all tests to ensure they pass
    cd backend/
    go test -gcflags="all=-N -l" -count=1 -v ./...
  2. Test coverage. Execute the following commands to generate the test coverage report.

    # Generate a test coverage report
    cd backend/
    go test -gcflags="all=-N -l" -coverprofile=coverage.out ./...
    go tool cover -html=coverage.out

Functional test

After local deployment, you can open the platform and test whether the functionalities of each module are normal:

Feature module Note
Prompt development and debugging * The Playground can debug properly
* Prompt creation and management meet expectations
Evaluation experiments * Create a new dataset
* Add a new evaluator
* Add a new experiment to evaluate the newly created Prompt
* Complete the experiment and view the analysis report
Trace reporting and query In the Trace interface, select the Prompt tab to check if Trace is displayed.
Clone this wiki locally