Эх сурвалжийг харах

feat: Adjust directory structure and add multi server support

chris 1 жил өмнө
parent
commit
9e052d7853
46 өөрчлөгдсөн 771 нэмэгдсэн , 740 устгасан
  1. 0 185
      README.md
  2. 0 216
      README_zh.md
  3. 1 1
      api/v1/errors.go
  4. 17 1
      api/v1/user.go
  5. 7 7
      api/v1/v1.go
  6. 0 19
      cmd/job/wire/wire.go
  7. 0 26
      cmd/job/wire/wire_gen.go
  8. 6 3
      cmd/migration/main.go
  9. 15 5
      cmd/migration/wire/wire.go
  10. 13 6
      cmd/migration/wire/wire_gen.go
  11. 7 10
      cmd/server/main.go
  12. 25 9
      cmd/server/wire/wire.go
  13. 18 8
      cmd/server/wire/wire_gen.go
  14. 8 6
      cmd/task/main.go
  15. 29 0
      cmd/task/wire/wire.go
  16. 33 0
      cmd/task/wire/wire_gen.go
  17. 1 0
      config/local.yml
  18. 2 1
      config/prod.yml
  19. 56 9
      docs/docs.go
  20. 55 9
      docs/swagger.json
  21. 38 9
      docs/swagger.yaml
  22. 4 3
      go.mod
  23. 18 0
      go.sum
  24. 24 24
      internal/handler/user.go
  25. 0 35
      internal/job/job.go
  26. 0 0
      internal/middleware/cors.go
  27. 4 4
      internal/middleware/jwt.go
  28. 0 1
      internal/middleware/log.go
  29. 3 3
      internal/middleware/sign.go
  30. 7 3
      internal/repository/repository.go
  31. 2 2
      internal/repository/user.go
  32. 28 21
      internal/server/http.go
  33. 25 0
      internal/server/job.go
  34. 12 4
      internal/server/migration.go
  35. 0 17
      internal/server/server.go
  36. 46 0
      internal/server/task.go
  37. 17 13
      internal/service/user.go
  38. 70 0
      pkg/app/app.go
  39. 0 48
      pkg/http/http.go
  40. 4 1
      pkg/jwt/jwt.go
  41. 61 0
      pkg/server/grpc/grpc.go
  42. 67 0
      pkg/server/http/http.go
  43. 16 0
      pkg/server/server.go
  44. 6 7
      test/mocks/service/user.go
  45. 19 16
      test/server/handler/user_test.go
  46. 7 8
      test/server/service/user_test.go

+ 0 - 185
README.md

@@ -13,191 +13,6 @@ Nunu is a scaffolding tool for building Go applications. Its name comes from a g
 * [Unit Testing](https://github.com/go-nunu/nunu/blob/main/docs/en/unit_testing.md)
 
 
-## Features
-- **Gin**: https://github.com/gin-gonic/gin
-- **Gorm**: https://github.com/go-gorm/gorm
-- **Wire**: https://github.com/google/wire
-- **Viper**: https://github.com/spf13/viper
-- **Zap**: https://github.com/uber-go/zap
-- **Golang-jwt**: https://github.com/golang-jwt/jwt
-- **Go-redis**: https://github.com/go-redis/redis
-- **Testify**: https://github.com/stretchr/testify
-- **Sonyflake**: https://github.com/sony/sonyflake
-- **Gocron**:  https://github.com/go-co-op/gocron
-- **Go-sqlmock**:  https://github.com/DATA-DOG/go-sqlmock
-- **Gomock**:  https://github.com/golang/mock
-- **Swaggo**:  https://github.com/swaggo/swag
-- More...
-
-## Key Features
-* **Low Learning Curve and Customization**: Nunu encapsulates popular libraries that Gophers are familiar with, allowing you to easily customize the application to meet specific requirements.
-* **High Performance and Scalability**: Nunu aims to be high-performance and scalable. It uses the latest technologies and best practices to ensure that your application can handle high traffic and large amounts of data.
-* **Security and Reliability**: Nunu uses stable and reliable third-party libraries to ensure the security and reliability of your application.
-* **Modular and Extensible**: Nunu is designed to be modular and extensible. You can easily add new features and functionality by using third-party libraries or writing your own modules.
-* **Complete Documentation and Testing**: Nunu has comprehensive documentation and testing. It provides extensive documentation and examples to help you get started quickly. It also includes a test suite to ensure that your application works as expected.
-
-## Concise Layered Architecture
-Nunu adopts a classic layered architecture. In order to achieve modularity and decoupling, it uses the dependency injection framework `Wire`.
-
-![Nunu Layout](https://github.com/go-nunu/nunu/blob/main/.github/assets/layout.png)
-
-## Nunu CLI
-
-![Nunu](https://github.com/go-nunu/nunu/blob/main/.github/assets/screenshot.jpg)
-
-
-## Directory Structure
-```
-.
-├── cmd
-│   └── server
-│       ├── wire
-│       │   ├── wire.go
-│       │   └── wire_gen.go
-│       └── main.go
-├── config
-│   ├── local.yml
-│   └── prod.yml
-├── deploy
-├── internal
-│   ├── handler
-│   │   ├── handler.go
-│   │   └── user.go
-│   ├── job
-│   │   └── job.go
-│   ├── model
-│   │   └── user.go
-│   ├── pkg
-│   ├── repository
-│   │   ├── repository.go
-│   │   └── user.go
-│   ├── server
-│   │   ├── http.go
-│   │   └── server.go
-│   └── service
-│       ├── service.go
-│       └── user.go
-├── pkg
-├── scripts
-├── storage
-├── test
-├── web
-├── Makefile
-├── go.mod
-└── go.sum
-
-```
-
-The project architecture follows a typical layered structure, consisting of the following modules:
-
-* `cmd`: This module contains the entry points of the application, which perform different operations based on different commands, such as starting the server or executing database migrations. Each sub-module has a `main.go` file as the entry file, as well as `wire.go` and `wire_gen.go` files for dependency injection.
-* `config`: This module contains the configuration files for the application, providing different configurations for different environments, such as development and production.
-* `deploy`: This module is used for deploying the application and includes deployment scripts and configuration files.
-* `internal`: This module is the core module of the application and contains the implementation of various business logic.
-
-  - `handler`: This sub-module contains the handlers for handling HTTP requests, responsible for receiving requests and invoking the corresponding services for processing.
-
-  - `job`: This sub-module contains the logic for background tasks.
-
-  - `model`: This sub-module contains the definition of data models.
-
-  - `repository`: This sub-module contains the implementation of the data access layer, responsible for interacting with the database.
-
-  - `server`: This sub-module contains the implementation of the HTTP server.
-
-  - `service`: This sub-module contains the implementation of the business logic, responsible for handling specific business operations.
-
-* `pkg`: This module contains some common utilities and functions.
-
-* `scripts`: This module contains some script files used for project build, test, and deployment operations.
-
-* `storage`: This module is used for storing files or other static resources.
-
-* `test`: This module contains the unit tests for various modules, organized into sub-directories based on modules.
-
-* `web`: This module contains the frontend-related files, such as HTML, CSS, and JavaScript.
-
-In addition, there are some other files and directories, such as license files, build files, and README. Overall, the project architecture is clear, with clear responsibilities for each module, making it easy to understand and maintain.
-
-## Requirements
-To use Nunu, you need to have the following software installed on your system:
-
-* Go 1.19 or higher
-* Git
-* Docker (optional)
-* MySQL 5.7 or higher (optional)
-* Redis (optional)
-
-### Installation
-
-You can install Nunu with the following command:
-
-```bash
-go install github.com/go-nunu/nunu@latest
-```
-
-> Tips: If `go install` succeeds but the `nunu` command is not recognized, it is because the environment variable is not configured. You can add the GOBIN directory to the environment variable.
-
-### Create a New Project
-
-You can create a new Go project with the following command:
-
-```bash
-nunu new projectName
-```
-
-By default, it pulls from the GitHub source, but you can also use an accelerated repository in China:
-
-```
-// Use the basic template
-nunu new projectName -r https://gitee.com/go-nunu/nunu-layout-basic.git
-// Use the advanced template
-nunu new projectName -r https://gitee.com/go-nunu/nunu-layout-advanced.git
-```
-
-This command will create a directory named `projectName` and generate an elegant Go project structure within it.
-
-### Create Components
-
-You can create handlers, services, repositories, and models for your project using the following commands:
-
-```bash
-nunu create handler user
-nunu create service user
-nunu create repository user
-nunu create model user
-```
-or
-```
-nunu create all user
-```
-
-These commands will create components named `UserHandler`, `UserService`, `UserRepository`, and `UserModel`, respectively, and place them in the correct directories.
-
-### Run the Project
-
-You can quickly run the project with the following command:
-
-```bash
-nunu run
-```
-
-This command will start your Go project and support hot-reloading when files are updated.
-
-### Compile wire.go
-
-You can quickly compile `wire.go` with the following command:
-
-```bash
-nunu wire
-```
-
-This command will compile your `wire.go` file and generate the required dependencies.
-
-## Contribution
-
-If you find any issues or have any improvement suggestions, please feel free to raise an issue or submit a pull request. Your contributions are highly appreciated!
-
 ## License
 
 Nunu is released under the MIT License. For more information, see the [LICENSE](LICENSE) file.

+ 0 - 216
README_zh.md

@@ -13,222 +13,6 @@ Nunu是一个基于Golang的应用脚手架,它的名字来自于英雄联盟
 * [上手教程](https://github.com/go-nunu/nunu/blob/main/docs/zh/tutorial.md)
 * [高效编写单元测试](https://github.com/go-nunu/nunu/blob/main/docs/zh/unit_testing.md)
 
-## 功能
-- **Gin**: https://github.com/gin-gonic/gin
-- **Gorm**: https://github.com/go-gorm/gorm
-- **Wire**: https://github.com/google/wire
-- **Viper**: https://github.com/spf13/viper
-- **Zap**: https://github.com/uber-go/zap
-- **Golang-jwt**: https://github.com/golang-jwt/jwt
-- **Go-redis**: https://github.com/go-redis/redis
-- **Testify**: https://github.com/stretchr/testify
-- **Sonyflake**: https://github.com/sony/sonyflake
-- **Gocron**:  https://github.com/go-co-op/gocron
-- **Go-sqlmock**:  https://github.com/DATA-DOG/go-sqlmock
-- **Gomock**:  https://github.com/golang/mock
-- **Swaggo**:  https://github.com/swaggo/swag
-- More...
-## 特性
-* **超低学习成本和定制**:Nunu封装了Gopher最熟悉的一些流行库。您可以轻松定制应用程序以满足特定需求。
-* **高性能和可扩展性**:Nunu旨在具有高性能和可扩展性。它使用最新的技术和最佳实践,确保您的应用程序可以处理高流量和大量数据。
-* **安全可靠**:Nunu使用了稳定可靠的第三方库,确保您的应用程序安全可靠。
-* **模块化和可扩展**:Nunu旨在具有模块化和可扩展性。您可以通过使用第三方库或编写自己的模块轻松添加新功能和功能。
-* **文档完善和测试完备**:Nunu文档完善,测试完备。它提供了全面的文档和示例,帮助您快速入门。它还包括一套测试套件,确保您的应用程序按预期工作。
-
-## 交流群组
-
-微信入群,请备注Nunu
-
-<p align="left"><img src="https://github.com/go-nunu/nunu/blob/main/.github/assets/qrcode.jpg" width="200"></p>
-
-## 简洁分层架构
-Nunu采用了经典的分层架构。同时,为了更好地实现模块化和解耦,采用了依赖注入框架`Wire`。
-
-![Nunu Layout](https://github.com/go-nunu/nunu/blob/main/.github/assets/layout.png)
-
-## Nunu CLI
-
-![Nunu](https://github.com/go-nunu/nunu/blob/main/.github/assets/screenshot.jpg)
-
-
-
-## 目录结构
-```
-.
-├── cmd
-│   └── server
-│       ├── wire
-│       │   ├── wire.go
-│       │   └── wire_gen.go
-│       └── main.go
-├── config
-│   ├── local.yml
-│   └── prod.yml
-├── deploy
-├── internal
-│   ├── handler
-│   │   ├── handler.go
-│   │   └── user.go
-│   ├── job
-│   │   └── job.go
-│   ├── model
-│   │   └── user.go
-│   ├── pkg
-│   ├── repository
-│   │   ├── repository.go
-│   │   └── user.go
-│   ├── server
-│   │   ├── http.go
-│   │   └── server.go
-│   └── service
-│       ├── service.go
-│       └── user.go
-├── pkg
-├── scripts
-├── storage
-├── test
-├── web
-├── Makefile
-├── go.mod
-└── go.sum
-
-```
-
-该项目的架构采用了典型的分层架构,主要包括以下几个模块:
-
-* `cmd`:该模块包含了应用的入口点,根据不同的命令进行不同的操作,例如启动服务器、执行数据库迁移等。每个子模块都有一个`main.go`文件作为入口文件,以及`wire.go`和`wire_gen.go`文件用于依赖注入。
-* `config`:该模块包含了应用的配置文件,根据不同的环境(如开发环境和生产环境)提供不同的配置。
-* `deploy`:该模块用于部署应用,包含了一些部署脚本和配置文件。
-* `internal`:该模块是应用的核心模块,包含了各种业务逻辑的实现。
-
-  - `handler`:该子模块包含了处理HTTP请求的处理器,负责接收请求并调用相应的服务进行处理。
-
-  - `job`:该子模块包含了后台任务的逻辑实现。
-
-  - `model`:该子模块包含了数据模型的定义。
-
-  - `repository`:该子模块包含了数据访问层的实现,负责与数据库进行交互。
-
-  - `server`:该子模块包含了HTTP服务器的实现。
-
-  - `service`:该子模块包含了业务逻辑的实现,负责处理具体的业务操作。
-
-* `pkg`:该模块包含了一些通用的功能和工具。
-
-* `scripts`:该模块包含了一些脚本文件,用于项目的构建、测试和部署等操作。
-
-* `storage`:该模块用于存储文件或其他静态资源。
-
-* `test`:该模块包含了各个模块的单元测试,按照模块划分子目录。
-
-* `web`:该模块包含了前端相关的文件,如HTML、CSS和JavaScript等。
-
-此外,还包含了一些其他的文件和目录,如授权文件、构建文件、README等。整体上,该项目的架构清晰,各个模块之间的职责明确,便于理解和维护。
-
-## 要求
-要使用Nunu,您需要在系统上安装以下软件:
-
-* Golang 1.19或更高版本
-* Git
-* Docker (可选)
-* MySQL5.7或更高版本(可选)
-* Redis(可选)
-
-
-
-### 安装
-
-您可以通过以下命令安装Nunu:
-
-```bash
-go install github.com/go-nunu/nunu@latest
-```
-
-国内用户可以使用`GOPROXY`加速`go install`
-
-```
-$ go env -w GO111MODULE=on
-$ go env -w GOPROXY=https://goproxy.cn,direct
-```
-
-> tips: 如果`go install`成功,却提示找不到nunu命令,这是因为环境变量没有配置,可以把 GOBIN 目录配置到环境变量中即可
-
-
-### 创建新项目
-
-您可以使用以下命令创建一个新的Golang项目:
-
-```bash
-// 推荐新用户选择Advanced Layout
-nunu new projectName
-```
-
-`nunu new`默认拉取github源,你也可以使用国内加速仓库
-```
-// 使用高级模板(推荐)
-nunu new projectName -r https://gitee.com/go-nunu/nunu-layout-advanced.git
-
-// 使用基础模板
-nunu new projectName -r https://gitee.com/go-nunu/nunu-layout-basic.git
-
-```
-
-
-> Nunu内置了两种类型的Layout:
-
-* **基础模板(Basic Layout)**
-
-Basic Layout 包含一个非常精简的架构目录结构,适合非常熟悉Nunu项目的开发者使用。
-
-* **高级模板(Advanced Layout)**
-
-**建议:我们推荐新手优先选择使用Advanced Layout。**
-
-
-Advanced Layout 包含了很多Nunu的用法示例( db、redis、 jwt、 cron、 migration等),适合开发者快速学习了解Nunu的架构思想。
-
-此命令将创建一个名为`projectName`的目录,并在其中生成一个优雅的Golang项目结构。
-
-### 创建组件
-
-您可以使用以下命令为项目创建handler、service、repository和model等组件:
-
-```bash
-nunu create handler user
-nunu create service user
-nunu create repository user
-nunu create model user
-```
-或
-```
-nunu create all user
-```
-这些命令将分别创建一个名为`UserHandler`、`UserService`、`UserRepository`和`UserModel`的组件,并将它们放置在正确的目录中。
-
-### 启动项目
-
-您可以使用以下命令快速启动项目:
-
-```bash
-nunu run
-```
-
-此命令将启动您的Golang项目,并支持文件更新热重启。
-
-### 编译wire.go
-
-您可以使用以下命令快速编译`wire.go`:
-
-```bash
-nunu wire
-```
-
-此命令将编译您的`wire.go`文件,并生成所需的依赖项。
-
-## 贡献
-
-如果您发现任何问题或有任何改进意见,请随时提出问题或提交拉取请求。我们非常欢迎您的贡献!
-
 ## 许可证
 
 Nunu是根据MIT许可证发布的。有关更多信息,请参见[LICENSE](LICENSE)文件。

+ 1 - 1
internal/pkg/response/errors.go → api/v1/errors.go

@@ -1,4 +1,4 @@
-package response
+package v1
 
 var (
 	// common errors

+ 17 - 1
internal/pkg/request/user.go → api/v1/user.go

@@ -1,4 +1,4 @@
-package request
+package v1
 
 type RegisterRequest struct {
 	Username string `json:"username" binding:"required" example:"alan"`
@@ -10,9 +10,25 @@ type LoginRequest struct {
 	Username string `json:"username" binding:"required" example:"alan"`
 	Password string `json:"password" binding:"required" example:"123456"`
 }
+type LoginResponseData struct {
+	AccessToken string `json:"accessToken"`
+}
+type LoginResponse struct {
+	Response
+	Data LoginResponseData
+}
 
 type UpdateProfileRequest struct {
 	Nickname string `json:"nickname" example:"alan"`
 	Email    string `json:"email" binding:"required,email" example:"1234@gmail.com"`
 	Avatar   string `json:"avatar" example:"xxxx"`
 }
+type GetProfileResponseData struct {
+	UserId   string `json:"userId"`
+	Nickname string `json:"nickname"`
+	Username string `json:"username"`
+}
+type GetProfileResponse struct {
+	Response
+	Data GetProfileResponseData
+}

+ 7 - 7
internal/pkg/response/response.go → api/v1/v1.go

@@ -1,8 +1,8 @@
-package response
+package v1
 
 import (
-	"errors"
 	"github.com/gin-gonic/gin"
+	"github.com/pkg/errors"
 	"net/http"
 )
 
@@ -14,9 +14,9 @@ type Response struct {
 
 func HandleSuccess(ctx *gin.Context, data interface{}) {
 	if data == nil {
-		data = map[string]string{}
+		data = map[string]interface{}{}
 	}
-	resp := Response{Code: errorCodeMap[ErrSuccess], Message: ErrSuccess.Error(), Data: data}
+	resp := Response{Code: ErrorCodeMap[ErrSuccess], Message: ErrSuccess.Error(), Data: data}
 	ctx.JSON(http.StatusOK, resp)
 }
 
@@ -24,7 +24,7 @@ func HandleError(ctx *gin.Context, httpCode int, err error, data interface{}) {
 	if data == nil {
 		data = map[string]string{}
 	}
-	resp := Response{Code: errorCodeMap[err], Message: err.Error(), Data: data}
+	resp := Response{Code: ErrorCodeMap[err], Message: err.Error(), Data: data}
 	ctx.JSON(httpCode, resp)
 }
 
@@ -33,11 +33,11 @@ type Error struct {
 	Message string
 }
 
-var errorCodeMap = map[error]int{}
+var ErrorCodeMap = map[error]int{}
 
 func newError(code int, msg string) error {
 	err := errors.New(msg)
-	errorCodeMap[err] = code
+	ErrorCodeMap[err] = code
 	return err
 }
 func (e Error) Error() string {

+ 0 - 19
cmd/job/wire/wire.go

@@ -1,19 +0,0 @@
-//go:build wireinject
-// +build wireinject
-
-package wire
-
-import (
-	"github.com/go-nunu/nunu-layout-advanced/internal/job"
-	"github.com/go-nunu/nunu-layout-advanced/pkg/log"
-	"github.com/google/wire"
-	"github.com/spf13/viper"
-)
-
-var JobSet = wire.NewSet(job.NewJob)
-
-func NewApp(*viper.Viper, *log.Logger) (*job.Job, func(), error) {
-	panic(wire.Build(
-		JobSet,
-	))
-}

+ 0 - 26
cmd/job/wire/wire_gen.go

@@ -1,26 +0,0 @@
-// Code generated by Wire. DO NOT EDIT.
-
-//go:generate go run github.com/google/wire/cmd/wire
-//go:build !wireinject
-// +build !wireinject
-
-package wire
-
-import (
-	"github.com/go-nunu/nunu-layout-advanced/internal/job"
-	"github.com/go-nunu/nunu-layout-advanced/pkg/log"
-	"github.com/google/wire"
-	"github.com/spf13/viper"
-)
-
-// Injectors from wire.go:
-
-func NewApp(viperViper *viper.Viper, logger *log.Logger) (*job.Job, func(), error) {
-	jobJob := job.NewJob(logger)
-	return jobJob, func() {
-	}, nil
-}
-
-// wire.go:
-
-var JobSet = wire.NewSet(job.NewJob)

+ 6 - 3
cmd/migration/main.go

@@ -1,6 +1,7 @@
 package main
 
 import (
+	"context"
 	"github.com/go-nunu/nunu-layout-advanced/cmd/migration/wire"
 	"github.com/go-nunu/nunu-layout-advanced/pkg/config"
 	"github.com/go-nunu/nunu-layout-advanced/pkg/log"
@@ -10,10 +11,12 @@ func main() {
 	conf := config.NewConfig()
 	logger := log.NewLog(conf)
 
-	app, cleanup, err := wire.NewApp(conf, logger)
+	app, cleanup, err := wire.NewWire(conf, logger)
+	defer cleanup()
 	if err != nil {
 		panic(err)
 	}
-	app.Run()
-	defer cleanup()
+	if err = app.Run(context.Background()); err != nil {
+		panic(err)
+	}
 }

+ 15 - 5
cmd/migration/wire/wire.go

@@ -4,23 +4,33 @@
 package wire
 
 import (
-	"github.com/go-nunu/nunu-layout-advanced/cmd/migration/internal"
 	"github.com/go-nunu/nunu-layout-advanced/internal/repository"
+	"github.com/go-nunu/nunu-layout-advanced/internal/server"
+	"github.com/go-nunu/nunu-layout-advanced/pkg/app"
 	"github.com/go-nunu/nunu-layout-advanced/pkg/log"
 	"github.com/google/wire"
 	"github.com/spf13/viper"
 )
 
-var RepositorySet = wire.NewSet(
+var repositorySet = wire.NewSet(
 	repository.NewDB,
 	repository.NewRedis,
 	repository.NewRepository,
 	repository.NewUserRepository,
 )
 
-func NewApp(*viper.Viper, *log.Logger) (*internal.Migrate, func(), error) {
+// build App
+func newApp(migrate *server.Migrate) *app.App {
+	return app.NewApp(
+		app.WithServer(migrate),
+		app.WithName("demo-migrate"),
+	)
+}
+
+func NewWire(*viper.Viper, *log.Logger) (*app.App, func(), error) {
 	panic(wire.Build(
-		RepositorySet,
-		internal.NewMigrate,
+		repositorySet,
+		server.NewMigrate,
+		newApp,
 	))
 }

+ 13 - 6
cmd/migration/wire/wire_gen.go

@@ -7,8 +7,9 @@
 package wire
 
 import (
-	"github.com/go-nunu/nunu-layout-advanced/cmd/migration/internal"
 	"github.com/go-nunu/nunu-layout-advanced/internal/repository"
+	"github.com/go-nunu/nunu-layout-advanced/internal/server"
+	"github.com/go-nunu/nunu-layout-advanced/pkg/app"
 	"github.com/go-nunu/nunu-layout-advanced/pkg/log"
 	"github.com/google/wire"
 	"github.com/spf13/viper"
@@ -16,13 +17,19 @@ import (
 
 // Injectors from wire.go:
 
-func NewApp(viperViper *viper.Viper, logger *log.Logger) (*internal.Migrate, func(), error) {
-	db := repository.NewDB(viperViper)
-	migrate := internal.NewMigrate(db, logger)
-	return migrate, func() {
+func NewWire(viperViper *viper.Viper, logger *log.Logger) (*app.App, func(), error) {
+	db := repository.NewDB(viperViper, logger)
+	migrate := server.NewMigrate(db, logger)
+	appApp := newApp(migrate)
+	return appApp, func() {
 	}, nil
 }
 
 // wire.go:
 
-var RepositorySet = wire.NewSet(repository.NewDB, repository.NewRedis, repository.NewRepository, repository.NewUserRepository)
+var repositorySet = wire.NewSet(repository.NewDB, repository.NewRedis, repository.NewRepository, repository.NewUserRepository)
+
+// build App
+func newApp(migrate *server.Migrate) *app.App {
+	return app.NewApp(app.WithServer(migrate), app.WithName("demo-migrate"))
+}

+ 7 - 10
cmd/server/main.go

@@ -1,10 +1,10 @@
 package main
 
 import (
+	"context"
 	"fmt"
 	"github.com/go-nunu/nunu-layout-advanced/cmd/server/wire"
 	"github.com/go-nunu/nunu-layout-advanced/pkg/config"
-	"github.com/go-nunu/nunu-layout-advanced/pkg/http"
 	"github.com/go-nunu/nunu-layout-advanced/pkg/log"
 	"go.uber.org/zap"
 )
@@ -19,7 +19,6 @@ import (
 // @license.name  Apache 2.0
 // @license.url   http://www.apache.org/licenses/LICENSE-2.0.html
 // @host      localhost:8000
-// @BasePath  /
 // @securityDefinitions.apiKey Bearer
 // @in header
 // @name Authorization
@@ -29,16 +28,14 @@ func main() {
 	conf := config.NewConfig()
 	logger := log.NewLog(conf)
 
-	servers, cleanup, err := wire.NewApp(conf, logger)
+	app, cleanup, err := wire.NewWire(conf, logger)
+	defer cleanup()
 	if err != nil {
 		panic(err)
 	}
-
-	logger.Info("server start", zap.String("host", "http://localhost:"+conf.GetString("http.port")))
+	logger.Info("server start", zap.String("host", "http://127.0.0.1:"+conf.GetString("http.port")))
 	logger.Info("docs addr", zap.String("addr", fmt.Sprintf("http://127.0.0.1:%d/swagger/index.html", conf.GetInt("http.port"))))
-
-	//go grpc.Run(servers.ServerGRPC, conf)
-	http.Run(servers.ServerHTTP, fmt.Sprintf(":%d", conf.GetInt("http.port")))
-	defer cleanup()
-
+	if err = app.Run(context.Background()); err != nil {
+		panic(err)
+	}
 }

+ 25 - 9
cmd/server/wire/wire.go

@@ -8,38 +8,54 @@ import (
 	"github.com/go-nunu/nunu-layout-advanced/internal/repository"
 	"github.com/go-nunu/nunu-layout-advanced/internal/server"
 	"github.com/go-nunu/nunu-layout-advanced/internal/service"
+	"github.com/go-nunu/nunu-layout-advanced/pkg/app"
 	"github.com/go-nunu/nunu-layout-advanced/pkg/helper/sid"
 	"github.com/go-nunu/nunu-layout-advanced/pkg/jwt"
 	"github.com/go-nunu/nunu-layout-advanced/pkg/log"
+	"github.com/go-nunu/nunu-layout-advanced/pkg/server/http"
 	"github.com/google/wire"
 	"github.com/spf13/viper"
 )
 
-var HandlerSet = wire.NewSet(
+var handlerSet = wire.NewSet(
 	handler.NewHandler,
 	handler.NewUserHandler,
 )
 
-var ServiceSet = wire.NewSet(
+var serviceSet = wire.NewSet(
 	service.NewService,
 	service.NewUserService,
 )
 
-var RepositorySet = wire.NewSet(
+var repositorySet = wire.NewSet(
 	repository.NewDB,
 	repository.NewRedis,
 	repository.NewRepository,
 	repository.NewUserRepository,
 )
+var serverSet = wire.NewSet(
+	server.NewHTTPServer,
+	server.NewJob,
+	server.NewTask,
+)
+
+// build App
+func newApp(httpServer *http.Server, job *server.Job) *app.App {
+	return app.NewApp(
+		app.WithServer(httpServer, job),
+		app.WithName("demo-server"),
+	)
+}
+
+func NewWire(*viper.Viper, *log.Logger) (*app.App, func(), error) {
 
-func NewApp(*viper.Viper, *log.Logger) (*server.Server, func(), error) {
 	panic(wire.Build(
-		RepositorySet,
-		ServiceSet,
-		HandlerSet,
-		server.NewServer,
-		server.NewServerHTTP,
+		repositorySet,
+		serviceSet,
+		handlerSet,
+		serverSet,
 		sid.NewSid,
 		jwt.NewJwt,
+		newApp,
 	))
 }

+ 18 - 8
cmd/server/wire/wire_gen.go

@@ -11,36 +11,46 @@ import (
 	"github.com/go-nunu/nunu-layout-advanced/internal/repository"
 	"github.com/go-nunu/nunu-layout-advanced/internal/server"
 	"github.com/go-nunu/nunu-layout-advanced/internal/service"
+	"github.com/go-nunu/nunu-layout-advanced/pkg/app"
 	"github.com/go-nunu/nunu-layout-advanced/pkg/helper/sid"
 	"github.com/go-nunu/nunu-layout-advanced/pkg/jwt"
 	"github.com/go-nunu/nunu-layout-advanced/pkg/log"
+	"github.com/go-nunu/nunu-layout-advanced/pkg/server/http"
 	"github.com/google/wire"
 	"github.com/spf13/viper"
 )
 
 // Injectors from wire.go:
 
-func NewApp(viperViper *viper.Viper, logger *log.Logger) (*server.Server, func(), error) {
+func NewWire(viperViper *viper.Viper, logger *log.Logger) (*app.App, func(), error) {
 	jwtJWT := jwt.NewJwt(viperViper)
 	handlerHandler := handler.NewHandler(logger)
 	sidSid := sid.NewSid()
 	serviceService := service.NewService(logger, sidSid, jwtJWT)
-	db := repository.NewDB(viperViper)
+	db := repository.NewDB(viperViper, logger)
 	client := repository.NewRedis(viperViper)
 	repositoryRepository := repository.NewRepository(db, client, logger)
 	userRepository := repository.NewUserRepository(repositoryRepository)
 	userService := service.NewUserService(serviceService, userRepository)
 	userHandler := handler.NewUserHandler(handlerHandler, userService)
-	engine := server.NewServerHTTP(logger, jwtJWT, userHandler)
-	serverServer := server.NewServer(engine)
-	return serverServer, func() {
+	httpServer := server.NewHTTPServer(logger, viperViper, jwtJWT, userHandler)
+	job := server.NewJob(logger)
+	appApp := newApp(httpServer, job)
+	return appApp, func() {
 	}, nil
 }
 
 // wire.go:
 
-var HandlerSet = wire.NewSet(handler.NewHandler, handler.NewUserHandler)
+var handlerSet = wire.NewSet(handler.NewHandler, handler.NewUserHandler)
 
-var ServiceSet = wire.NewSet(service.NewService, service.NewUserService)
+var serviceSet = wire.NewSet(service.NewService, service.NewUserService)
 
-var RepositorySet = wire.NewSet(repository.NewDB, repository.NewRedis, repository.NewRepository, repository.NewUserRepository)
+var repositorySet = wire.NewSet(repository.NewDB, repository.NewRedis, repository.NewRepository, repository.NewUserRepository)
+
+var serverSet = wire.NewSet(server.NewHTTPServer, server.NewJob, server.NewTask)
+
+// build App
+func newApp(httpServer *http.Server, job *server.Job) *app.App {
+	return app.NewApp(app.WithServer(httpServer, job), app.WithName("demo-server"))
+}

+ 8 - 6
cmd/job/main.go → cmd/task/main.go

@@ -1,7 +1,8 @@
 package main
 
 import (
-	"github.com/go-nunu/nunu-layout-advanced/cmd/job/wire"
+	"context"
+	"github.com/go-nunu/nunu-layout-advanced/cmd/task/wire"
 	"github.com/go-nunu/nunu-layout-advanced/pkg/config"
 	"github.com/go-nunu/nunu-layout-advanced/pkg/log"
 )
@@ -9,13 +10,14 @@ import (
 func main() {
 	conf := config.NewConfig()
 	logger := log.NewLog(conf)
-	logger.Info("start")
-
-	app, cleanup, err := wire.NewApp(conf, logger)
+	logger.Info("start task")
+	app, cleanup, err := wire.NewWire(conf, logger)
+	defer cleanup()
 	if err != nil {
 		panic(err)
 	}
-	app.Run()
-	defer cleanup()
+	if err = app.Run(context.Background()); err != nil {
+		panic(err)
+	}
 
 }

+ 29 - 0
cmd/task/wire/wire.go

@@ -0,0 +1,29 @@
+//go:build wireinject
+// +build wireinject
+
+package wire
+
+import (
+	"github.com/go-nunu/nunu-layout-advanced/internal/server"
+	"github.com/go-nunu/nunu-layout-advanced/pkg/app"
+	"github.com/go-nunu/nunu-layout-advanced/pkg/log"
+	"github.com/google/wire"
+	"github.com/spf13/viper"
+)
+
+var taskSet = wire.NewSet(server.NewTask)
+
+// build App
+func newApp(task *server.Task) *app.App {
+	return app.NewApp(
+		app.WithServer(task),
+		app.WithName("demo-task"),
+	)
+}
+
+func NewWire(*viper.Viper, *log.Logger) (*app.App, func(), error) {
+	panic(wire.Build(
+		taskSet,
+		newApp,
+	))
+}

+ 33 - 0
cmd/task/wire/wire_gen.go

@@ -0,0 +1,33 @@
+// Code generated by Wire. DO NOT EDIT.
+
+//go:generate go run github.com/google/wire/cmd/wire
+//go:build !wireinject
+// +build !wireinject
+
+package wire
+
+import (
+	"github.com/go-nunu/nunu-layout-advanced/internal/server"
+	"github.com/go-nunu/nunu-layout-advanced/pkg/app"
+	"github.com/go-nunu/nunu-layout-advanced/pkg/log"
+	"github.com/google/wire"
+	"github.com/spf13/viper"
+)
+
+// Injectors from wire.go:
+
+func NewWire(viperViper *viper.Viper, logger *log.Logger) (*app.App, func(), error) {
+	task := server.NewTask(logger)
+	appApp := newApp(task)
+	return appApp, func() {
+	}, nil
+}
+
+// wire.go:
+
+var taskSet = wire.NewSet(server.NewTask)
+
+// build App
+func newApp(task *server.Task) *app.App {
+	return app.NewApp(app.WithServer(task), app.WithName("demo-task"))
+}

+ 1 - 0
config/local.yml

@@ -1,5 +1,6 @@
 env: local
 http:
+  host: 0.0.0.0
   port: 8000
 security:
   api_sign:

+ 2 - 1
config/prod.yml

@@ -1,5 +1,6 @@
-env: local
+env: prod
 http:
+  host: 0.0.0.0
   port: 8000
 security:
   api_sign:

+ 56 - 9
docs/docs.go

@@ -43,7 +43,7 @@ const docTemplate = `{
                         "in": "body",
                         "required": true,
                         "schema": {
-                            "$ref": "#/definitions/github_com_go-nunu_nunu-layout-advanced_internal_pkg_request.LoginRequest"
+                            "$ref": "#/definitions/github_com_go-nunu_nunu-layout-advanced_api_v1.LoginRequest"
                         }
                     }
                 ],
@@ -51,7 +51,7 @@ const docTemplate = `{
                     "200": {
                         "description": "OK",
                         "schema": {
-                            "$ref": "#/definitions/github_com_go-nunu_nunu-layout-advanced_internal_pkg_response.Response"
+                            "$ref": "#/definitions/github_com_go-nunu_nunu-layout-advanced_api_v1.LoginResponse"
                         }
                     }
                 }
@@ -77,7 +77,7 @@ const docTemplate = `{
                         "in": "body",
                         "required": true,
                         "schema": {
-                            "$ref": "#/definitions/github_com_go-nunu_nunu-layout-advanced_internal_pkg_request.RegisterRequest"
+                            "$ref": "#/definitions/github_com_go-nunu_nunu-layout-advanced_api_v1.RegisterRequest"
                         }
                     }
                 ],
@@ -85,7 +85,7 @@ const docTemplate = `{
                     "200": {
                         "description": "OK",
                         "schema": {
-                            "$ref": "#/definitions/github_com_go-nunu_nunu-layout-advanced_internal_pkg_response.Response"
+                            "$ref": "#/definitions/github_com_go-nunu_nunu-layout-advanced_api_v1.Response"
                         }
                     }
                 }
@@ -112,7 +112,7 @@ const docTemplate = `{
                     "200": {
                         "description": "OK",
                         "schema": {
-                            "$ref": "#/definitions/github_com_go-nunu_nunu-layout-advanced_internal_pkg_response.Response"
+                            "$ref": "#/definitions/github_com_go-nunu_nunu-layout-advanced_api_v1.GetProfileResponse"
                         }
                     }
                 }
@@ -120,7 +120,32 @@ const docTemplate = `{
         }
     },
     "definitions": {
-        "github_com_go-nunu_nunu-layout-advanced_internal_pkg_request.LoginRequest": {
+        "github_com_go-nunu_nunu-layout-advanced_api_v1.GetProfileResponse": {
+            "type": "object",
+            "properties": {
+                "code": {
+                    "type": "integer"
+                },
+                "data": {
+                    "$ref": "#/definitions/github_com_go-nunu_nunu-layout-advanced_api_v1.GetProfileResponseData"
+                },
+                "message": {
+                    "type": "string"
+                }
+            }
+        },
+        "github_com_go-nunu_nunu-layout-advanced_api_v1.GetProfileResponseData": {
+            "type": "object",
+            "properties": {
+                "nickname": {
+                    "type": "string"
+                },
+                "userId": {
+                    "type": "string"
+                }
+            }
+        },
+        "github_com_go-nunu_nunu-layout-advanced_api_v1.LoginRequest": {
             "type": "object",
             "required": [
                 "password",
@@ -137,7 +162,29 @@ const docTemplate = `{
                 }
             }
         },
-        "github_com_go-nunu_nunu-layout-advanced_internal_pkg_request.RegisterRequest": {
+        "github_com_go-nunu_nunu-layout-advanced_api_v1.LoginResponse": {
+            "type": "object",
+            "properties": {
+                "code": {
+                    "type": "integer"
+                },
+                "data": {
+                    "$ref": "#/definitions/github_com_go-nunu_nunu-layout-advanced_api_v1.LoginResponseData"
+                },
+                "message": {
+                    "type": "string"
+                }
+            }
+        },
+        "github_com_go-nunu_nunu-layout-advanced_api_v1.LoginResponseData": {
+            "type": "object",
+            "properties": {
+                "accessToken": {
+                    "type": "string"
+                }
+            }
+        },
+        "github_com_go-nunu_nunu-layout-advanced_api_v1.RegisterRequest": {
             "type": "object",
             "required": [
                 "email",
@@ -159,7 +206,7 @@ const docTemplate = `{
                 }
             }
         },
-        "github_com_go-nunu_nunu-layout-advanced_internal_pkg_response.Response": {
+        "github_com_go-nunu_nunu-layout-advanced_api_v1.Response": {
             "type": "object",
             "properties": {
                 "code": {
@@ -185,7 +232,7 @@ const docTemplate = `{
 var SwaggerInfo = &swag.Spec{
 	Version:          "1.0.0",
 	Host:             "localhost:8000",
-	BasePath:         "/",
+	BasePath:         "",
 	Schemes:          []string{},
 	Title:            "Nunu Example API",
 	Description:      "This is a sample server celler server.",

+ 55 - 9
docs/swagger.json

@@ -16,7 +16,6 @@
         "version": "1.0.0"
     },
     "host": "localhost:8000",
-    "basePath": "/",
     "paths": {
         "/login": {
             "post": {
@@ -37,7 +36,7 @@
                         "in": "body",
                         "required": true,
                         "schema": {
-                            "$ref": "#/definitions/github_com_go-nunu_nunu-layout-advanced_internal_pkg_request.LoginRequest"
+                            "$ref": "#/definitions/github_com_go-nunu_nunu-layout-advanced_api_v1.LoginRequest"
                         }
                     }
                 ],
@@ -45,7 +44,7 @@
                     "200": {
                         "description": "OK",
                         "schema": {
-                            "$ref": "#/definitions/github_com_go-nunu_nunu-layout-advanced_internal_pkg_response.Response"
+                            "$ref": "#/definitions/github_com_go-nunu_nunu-layout-advanced_api_v1.LoginResponse"
                         }
                     }
                 }
@@ -71,7 +70,7 @@
                         "in": "body",
                         "required": true,
                         "schema": {
-                            "$ref": "#/definitions/github_com_go-nunu_nunu-layout-advanced_internal_pkg_request.RegisterRequest"
+                            "$ref": "#/definitions/github_com_go-nunu_nunu-layout-advanced_api_v1.RegisterRequest"
                         }
                     }
                 ],
@@ -79,7 +78,7 @@
                     "200": {
                         "description": "OK",
                         "schema": {
-                            "$ref": "#/definitions/github_com_go-nunu_nunu-layout-advanced_internal_pkg_response.Response"
+                            "$ref": "#/definitions/github_com_go-nunu_nunu-layout-advanced_api_v1.Response"
                         }
                     }
                 }
@@ -106,7 +105,7 @@
                     "200": {
                         "description": "OK",
                         "schema": {
-                            "$ref": "#/definitions/github_com_go-nunu_nunu-layout-advanced_internal_pkg_response.Response"
+                            "$ref": "#/definitions/github_com_go-nunu_nunu-layout-advanced_api_v1.GetProfileResponse"
                         }
                     }
                 }
@@ -114,7 +113,32 @@
         }
     },
     "definitions": {
-        "github_com_go-nunu_nunu-layout-advanced_internal_pkg_request.LoginRequest": {
+        "github_com_go-nunu_nunu-layout-advanced_api_v1.GetProfileResponse": {
+            "type": "object",
+            "properties": {
+                "code": {
+                    "type": "integer"
+                },
+                "data": {
+                    "$ref": "#/definitions/github_com_go-nunu_nunu-layout-advanced_api_v1.GetProfileResponseData"
+                },
+                "message": {
+                    "type": "string"
+                }
+            }
+        },
+        "github_com_go-nunu_nunu-layout-advanced_api_v1.GetProfileResponseData": {
+            "type": "object",
+            "properties": {
+                "nickname": {
+                    "type": "string"
+                },
+                "userId": {
+                    "type": "string"
+                }
+            }
+        },
+        "github_com_go-nunu_nunu-layout-advanced_api_v1.LoginRequest": {
             "type": "object",
             "required": [
                 "password",
@@ -131,7 +155,29 @@
                 }
             }
         },
-        "github_com_go-nunu_nunu-layout-advanced_internal_pkg_request.RegisterRequest": {
+        "github_com_go-nunu_nunu-layout-advanced_api_v1.LoginResponse": {
+            "type": "object",
+            "properties": {
+                "code": {
+                    "type": "integer"
+                },
+                "data": {
+                    "$ref": "#/definitions/github_com_go-nunu_nunu-layout-advanced_api_v1.LoginResponseData"
+                },
+                "message": {
+                    "type": "string"
+                }
+            }
+        },
+        "github_com_go-nunu_nunu-layout-advanced_api_v1.LoginResponseData": {
+            "type": "object",
+            "properties": {
+                "accessToken": {
+                    "type": "string"
+                }
+            }
+        },
+        "github_com_go-nunu_nunu-layout-advanced_api_v1.RegisterRequest": {
             "type": "object",
             "required": [
                 "email",
@@ -153,7 +199,7 @@
                 }
             }
         },
-        "github_com_go-nunu_nunu-layout-advanced_internal_pkg_response.Response": {
+        "github_com_go-nunu_nunu-layout-advanced_api_v1.Response": {
             "type": "object",
             "properties": {
                 "code": {

+ 38 - 9
docs/swagger.yaml

@@ -1,6 +1,21 @@
-basePath: /
 definitions:
-  github_com_go-nunu_nunu-layout-advanced_internal_pkg_request.LoginRequest:
+  github_com_go-nunu_nunu-layout-advanced_api_v1.GetProfileResponse:
+    properties:
+      code:
+        type: integer
+      data:
+        $ref: '#/definitions/github_com_go-nunu_nunu-layout-advanced_api_v1.GetProfileResponseData'
+      message:
+        type: string
+    type: object
+  github_com_go-nunu_nunu-layout-advanced_api_v1.GetProfileResponseData:
+    properties:
+      nickname:
+        type: string
+      userId:
+        type: string
+    type: object
+  github_com_go-nunu_nunu-layout-advanced_api_v1.LoginRequest:
     properties:
       password:
         example: "123456"
@@ -12,7 +27,21 @@ definitions:
     - password
     - username
     type: object
-  github_com_go-nunu_nunu-layout-advanced_internal_pkg_request.RegisterRequest:
+  github_com_go-nunu_nunu-layout-advanced_api_v1.LoginResponse:
+    properties:
+      code:
+        type: integer
+      data:
+        $ref: '#/definitions/github_com_go-nunu_nunu-layout-advanced_api_v1.LoginResponseData'
+      message:
+        type: string
+    type: object
+  github_com_go-nunu_nunu-layout-advanced_api_v1.LoginResponseData:
+    properties:
+      accessToken:
+        type: string
+    type: object
+  github_com_go-nunu_nunu-layout-advanced_api_v1.RegisterRequest:
     properties:
       email:
         example: 1234@gmail.com
@@ -28,7 +57,7 @@ definitions:
     - password
     - username
     type: object
-  github_com_go-nunu_nunu-layout-advanced_internal_pkg_response.Response:
+  github_com_go-nunu_nunu-layout-advanced_api_v1.Response:
     properties:
       code:
         type: integer
@@ -60,14 +89,14 @@ paths:
         name: request
         required: true
         schema:
-          $ref: '#/definitions/github_com_go-nunu_nunu-layout-advanced_internal_pkg_request.LoginRequest'
+          $ref: '#/definitions/github_com_go-nunu_nunu-layout-advanced_api_v1.LoginRequest'
       produces:
       - application/json
       responses:
         "200":
           description: OK
           schema:
-            $ref: '#/definitions/github_com_go-nunu_nunu-layout-advanced_internal_pkg_response.Response'
+            $ref: '#/definitions/github_com_go-nunu_nunu-layout-advanced_api_v1.LoginResponse'
       summary: 账号登录
       tags:
       - 用户模块
@@ -82,14 +111,14 @@ paths:
         name: request
         required: true
         schema:
-          $ref: '#/definitions/github_com_go-nunu_nunu-layout-advanced_internal_pkg_request.RegisterRequest'
+          $ref: '#/definitions/github_com_go-nunu_nunu-layout-advanced_api_v1.RegisterRequest'
       produces:
       - application/json
       responses:
         "200":
           description: OK
           schema:
-            $ref: '#/definitions/github_com_go-nunu_nunu-layout-advanced_internal_pkg_response.Response'
+            $ref: '#/definitions/github_com_go-nunu_nunu-layout-advanced_api_v1.Response'
       summary: 用户注册
       tags:
       - 用户模块
@@ -103,7 +132,7 @@ paths:
         "200":
           description: OK
           schema:
-            $ref: '#/definitions/github_com_go-nunu_nunu-layout-advanced_internal_pkg_response.Response'
+            $ref: '#/definitions/github_com_go-nunu_nunu-layout-advanced_api_v1.GetProfileResponse'
       security:
       - Bearer: []
       summary: 获取用户信息

+ 4 - 3
go.mod

@@ -19,11 +19,11 @@ require (
 	github.com/swaggo/files v1.0.1
 	github.com/swaggo/gin-swagger v1.6.0
 	github.com/swaggo/swag v1.16.2
-	go.uber.org/zap v1.24.0
+	go.uber.org/zap v1.26.0
 	golang.org/x/crypto v0.12.0
 	gopkg.in/natefinch/lumberjack.v2 v2.2.1
 	gorm.io/driver/mysql v1.5.1
-	gorm.io/gorm v1.25.1
+	gorm.io/gorm v1.25.5
 )
 
 require (
@@ -69,7 +69,7 @@ require (
 	github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
 	github.com/ugorji/go/codec v1.2.11 // indirect
 	go.uber.org/atomic v1.11.0 // indirect
-	go.uber.org/multierr v1.8.0 // indirect
+	go.uber.org/multierr v1.11.0 // indirect
 	golang.org/x/arch v0.3.0 // indirect
 	golang.org/x/net v0.14.0 // indirect
 	golang.org/x/sys v0.12.0 // indirect
@@ -78,4 +78,5 @@ require (
 	google.golang.org/protobuf v1.30.0 // indirect
 	gopkg.in/ini.v1 v1.67.0 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
+	moul.io/zapgorm2 v1.3.0 // indirect
 )

+ 18 - 0
go.sum

@@ -43,6 +43,7 @@ github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q
 github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
 github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
 github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
+github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
 github.com/bsm/ginkgo/v2 v2.7.0 h1:ItPMPH90RbmZJt5GtkcNvIRuGEdwlBItdNVoyzaNQao=
 github.com/bsm/gomega v1.26.0 h1:LhQm+AFcgV2M0WyKroMASzAzCAJVpAxQXv4SaI9a69Y=
 github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
@@ -191,6 +192,7 @@ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:
 github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
 github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
 github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
+github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
 github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
 github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
 github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
@@ -237,6 +239,7 @@ github.com/onsi/gomega v1.25.0 h1:Vw7br2PCDYijJHSfBOWhov+8cAnUf8MfMaIOV323l6Y=
 github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ=
 github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
 github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
 github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
@@ -308,10 +311,18 @@ go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
 go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
 go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
 go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
+go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
+go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
+go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
 go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8=
 go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
+go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
+go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
+go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=
 go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
 go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
+go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo=
+go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so=
 golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
 golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
 golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
@@ -530,6 +541,7 @@ golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4f
 golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
 golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
 golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
 golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
 golang.org/x/tools v0.12.0 h1:YW6HUoUmYBpwSgyaGaZq1fHjrBjX1rlpZ54T6mu2kss=
 golang.org/x/tools v0.12.0/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM=
@@ -640,6 +652,7 @@ gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST
 gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
 gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
 gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
@@ -649,8 +662,11 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gorm.io/driver/mysql v1.5.1 h1:WUEH5VF9obL/lTtzjmML/5e6VfFR/788coz2uaVCAZw=
 gorm.io/driver/mysql v1.5.1/go.mod h1:Jo3Xu7mMhCyj8dlrb3WoCaRd1FhsVh+yMXb1jUInf5o=
+gorm.io/gorm v1.23.6/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
 gorm.io/gorm v1.25.1 h1:nsSALe5Pr+cM3V1qwwQ7rOkw+6UeLrX5O4v3llhHa64=
 gorm.io/gorm v1.25.1/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
+gorm.io/gorm v1.25.5 h1:zR9lOiiYf09VNh5Q1gphfyia1JpiClIWG9hQaxB/mls=
+gorm.io/gorm v1.25.5/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
 honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
@@ -658,6 +674,8 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
 honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
 honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
 honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
+moul.io/zapgorm2 v1.3.0 h1:+CzUTMIcnafd0d/BvBce8T4uPn6DQnpIrz64cyixlkk=
+moul.io/zapgorm2 v1.3.0/go.mod h1:nPVy6U9goFKHR4s+zfSo1xVFaoU7Qgd5DoCdOfzoCqs=
 rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
 rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
 rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=

+ 24 - 24
internal/handler/user.go

@@ -2,9 +2,9 @@ package handler
 
 import (
 	"github.com/gin-gonic/gin"
-	"github.com/go-nunu/nunu-layout-advanced/internal/pkg/request"
-	"github.com/go-nunu/nunu-layout-advanced/internal/pkg/response"
+	v1 "github.com/go-nunu/nunu-layout-advanced/api/v1"
 	"github.com/go-nunu/nunu-layout-advanced/internal/service"
+	"go.uber.org/zap"
 	"net/http"
 )
 
@@ -34,22 +34,23 @@ type userHandler struct {
 // @Tags 用户模块
 // @Accept json
 // @Produce json
-// @Param request body request.RegisterRequest true "params"
-// @Success 200 {object} response.Response
+// @Param request body v1.RegisterRequest true "params"
+// @Success 200 {object} v1.Response
 // @Router /register [post]
 func (h *userHandler) Register(ctx *gin.Context) {
-	req := new(request.RegisterRequest)
+	req := new(v1.RegisterRequest)
 	if err := ctx.ShouldBindJSON(req); err != nil {
-		response.HandleError(ctx, http.StatusBadRequest, response.ErrBadRequest, nil)
+		v1.HandleError(ctx, http.StatusBadRequest, v1.ErrBadRequest, nil)
 		return
 	}
 
 	if err := h.userService.Register(ctx, req); err != nil {
-		response.HandleError(ctx, http.StatusBadRequest, response.ErrBadRequest, nil)
+		h.logger.WithContext(ctx).Error("userService.Register error", zap.Error(err))
+		v1.HandleError(ctx, http.StatusInternalServerError, err, nil)
 		return
 	}
 
-	response.HandleSuccess(ctx, nil)
+	v1.HandleSuccess(ctx, nil)
 }
 
 // Login godoc
@@ -59,24 +60,23 @@ func (h *userHandler) Register(ctx *gin.Context) {
 // @Tags 用户模块
 // @Accept json
 // @Produce json
-// @Param request body request.LoginRequest true "params"
-// @Success 200 {object} response.Response
+// @Param request body v1.LoginRequest true "params"
+// @Success 200 {object} v1.LoginResponse
 // @Router /login [post]
 func (h *userHandler) Login(ctx *gin.Context) {
-	var req request.LoginRequest
+	var req v1.LoginRequest
 	if err := ctx.ShouldBindJSON(&req); err != nil {
-		response.HandleError(ctx, http.StatusBadRequest, response.ErrBadRequest, nil)
+		v1.HandleError(ctx, http.StatusBadRequest, v1.ErrBadRequest, nil)
 		return
 	}
 
 	token, err := h.userService.Login(ctx, &req)
 	if err != nil {
-		response.HandleError(ctx, http.StatusUnauthorized, response.ErrUnauthorized, nil)
+		v1.HandleError(ctx, http.StatusUnauthorized, v1.ErrUnauthorized, nil)
 		return
 	}
-
-	response.HandleSuccess(ctx, gin.H{
-		"accessToken": token,
+	v1.HandleSuccess(ctx, v1.LoginResponseData{
+		AccessToken: token,
 	})
 }
 
@@ -88,37 +88,37 @@ func (h *userHandler) Login(ctx *gin.Context) {
 // @Accept json
 // @Produce json
 // @Security Bearer
-// @Success 200 {object} response.Response
+// @Success 200 {object} v1.GetProfileResponse
 // @Router /user [get]
 func (h *userHandler) GetProfile(ctx *gin.Context) {
 	userId := GetUserIdFromCtx(ctx)
 	if userId == "" {
-		response.HandleError(ctx, http.StatusUnauthorized, response.ErrUnauthorized, nil)
+		v1.HandleError(ctx, http.StatusUnauthorized, v1.ErrUnauthorized, nil)
 		return
 	}
 
 	user, err := h.userService.GetProfile(ctx, userId)
 	if err != nil {
-		response.HandleError(ctx, http.StatusBadRequest, response.ErrBadRequest, nil)
+		v1.HandleError(ctx, http.StatusBadRequest, v1.ErrBadRequest, nil)
 		return
 	}
 
-	response.HandleSuccess(ctx, user)
+	v1.HandleSuccess(ctx, user)
 }
 
 func (h *userHandler) UpdateProfile(ctx *gin.Context) {
 	userId := GetUserIdFromCtx(ctx)
 
-	var req request.UpdateProfileRequest
+	var req v1.UpdateProfileRequest
 	if err := ctx.ShouldBindJSON(&req); err != nil {
-		response.HandleError(ctx, http.StatusBadRequest, response.ErrBadRequest, nil)
+		v1.HandleError(ctx, http.StatusBadRequest, v1.ErrBadRequest, nil)
 		return
 	}
 
 	if err := h.userService.UpdateProfile(ctx, userId, &req); err != nil {
-		response.HandleError(ctx, http.StatusInternalServerError, response.ErrInternalServerError, nil)
+		v1.HandleError(ctx, http.StatusInternalServerError, v1.ErrInternalServerError, nil)
 		return
 	}
 
-	response.HandleSuccess(ctx, nil)
+	v1.HandleSuccess(ctx, nil)
 }

+ 0 - 35
internal/job/job.go

@@ -1,35 +0,0 @@
-package job
-
-import (
-	"fmt"
-	"github.com/go-co-op/gocron"
-	"github.com/go-nunu/nunu-layout-advanced/pkg/log"
-	"time"
-)
-
-type Job struct {
-	log *log.Logger
-}
-
-func NewJob(log *log.Logger) *Job {
-	return &Job{
-		log: log,
-	}
-}
-func (j *Job) Run() {
-	s := gocron.NewScheduler(time.UTC)
-	_, err := s.CronWithSeconds("0/3 * * * * *").Do(func() {
-		j.log.Info("I'm a Task1.")
-	})
-	if err != nil {
-		fmt.Println(err)
-	}
-	_, err = s.Every("3s").Do(func() {
-		j.log.Info("I'm a Task2.")
-	})
-	if err != nil {
-		fmt.Println(err)
-	}
-
-	s.StartBlocking()
-}

+ 0 - 0
internal/pkg/middleware/cors.go → internal/middleware/cors.go


+ 4 - 4
internal/pkg/middleware/jwt.go → internal/middleware/jwt.go

@@ -2,7 +2,7 @@ package middleware
 
 import (
 	"github.com/gin-gonic/gin"
-	"github.com/go-nunu/nunu-layout-advanced/internal/pkg/response"
+	"github.com/go-nunu/nunu-layout-advanced/api/v1"
 	"github.com/go-nunu/nunu-layout-advanced/pkg/jwt"
 	"github.com/go-nunu/nunu-layout-advanced/pkg/log"
 	"go.uber.org/zap"
@@ -17,7 +17,7 @@ func StrictAuth(j *jwt.JWT, logger *log.Logger) gin.HandlerFunc {
 				"url":    ctx.Request.URL,
 				"params": ctx.Params,
 			}))
-			response.HandleError(ctx, http.StatusUnauthorized, response.ErrUnauthorized, nil)
+			v1.HandleError(ctx, http.StatusUnauthorized, v1.ErrUnauthorized, nil)
 			ctx.Abort()
 			return
 		}
@@ -27,8 +27,8 @@ func StrictAuth(j *jwt.JWT, logger *log.Logger) gin.HandlerFunc {
 			logger.WithContext(ctx).Error("token error", zap.Any("data", map[string]interface{}{
 				"url":    ctx.Request.URL,
 				"params": ctx.Params,
-			}))
-			response.HandleError(ctx, http.StatusUnauthorized, response.ErrUnauthorized, nil)
+			}), zap.Error(err))
+			v1.HandleError(ctx, http.StatusUnauthorized, v1.ErrUnauthorized, nil)
 			ctx.Abort()
 			return
 		}

+ 0 - 1
internal/pkg/middleware/log.go → internal/middleware/log.go

@@ -13,7 +13,6 @@ import (
 
 func RequestLogMiddleware(logger *log.Logger) gin.HandlerFunc {
 	return func(ctx *gin.Context) {
-
 		// The configuration is initialized once per request
 		trace := md5.Md5(uuid.GenUUID())
 		logger.NewContext(ctx, zap.String("trace", trace))

+ 3 - 3
internal/pkg/middleware/sign.go → internal/middleware/sign.go

@@ -2,7 +2,7 @@ package middleware
 
 import (
 	"github.com/gin-gonic/gin"
-	"github.com/go-nunu/nunu-layout-advanced/internal/pkg/response"
+	v1 "github.com/go-nunu/nunu-layout-advanced/api/v1"
 	"github.com/go-nunu/nunu-layout-advanced/pkg/helper/md5"
 	"github.com/go-nunu/nunu-layout-advanced/pkg/log"
 	"github.com/spf13/viper"
@@ -18,7 +18,7 @@ func SignMiddleware(logger *log.Logger, conf *viper.Viper) gin.HandlerFunc {
 		for _, header := range requiredHeaders {
 			value, ok := ctx.Request.Header[header]
 			if !ok || len(value) == 0 {
-				response.HandleError(ctx, http.StatusBadRequest, response.ErrBadRequest, nil)
+				v1.HandleError(ctx, http.StatusBadRequest, v1.ErrBadRequest, nil)
 				ctx.Abort()
 				return
 			}
@@ -44,7 +44,7 @@ func SignMiddleware(logger *log.Logger, conf *viper.Viper) gin.HandlerFunc {
 		str += conf.GetString("security.api_sign.app_security")
 
 		if ctx.Request.Header.Get("Sign") != strings.ToUpper(md5.Md5(str)) {
-			response.HandleError(ctx, http.StatusBadRequest, response.ErrBadRequest, nil)
+			v1.HandleError(ctx, http.StatusBadRequest, v1.ErrBadRequest, nil)
 			ctx.Abort()
 			return
 		}

+ 7 - 3
internal/repository/repository.go

@@ -8,6 +8,7 @@ import (
 	"github.com/spf13/viper"
 	"gorm.io/driver/mysql"
 	"gorm.io/gorm"
+	"moul.io/zapgorm2"
 	"time"
 )
 
@@ -25,11 +26,14 @@ func NewRepository(db *gorm.DB, rdb *redis.Client, logger *log.Logger) *Reposito
 	}
 }
 
-func NewDB(conf *viper.Viper) *gorm.DB {
-	db, err := gorm.Open(mysql.Open(conf.GetString("data.mysql.user")), &gorm.Config{})
+func NewDB(conf *viper.Viper, l *log.Logger) *gorm.DB {
+	logger := zapgorm2.New(l.Logger)
+	logger.SetAsDefault()
+	db, err := gorm.Open(mysql.Open(conf.GetString("data.mysql.user")), &gorm.Config{Logger: logger})
 	if err != nil {
-		panic(fmt.Sprintf("mysql error: %s", err.Error()))
+		panic(err)
 	}
+	db = db.Debug()
 	return db
 }
 func NewRedis(conf *viper.Viper) *redis.Client {

+ 2 - 2
internal/repository/user.go

@@ -2,8 +2,8 @@ package repository
 
 import (
 	"context"
+	v1 "github.com/go-nunu/nunu-layout-advanced/api/v1"
 	"github.com/go-nunu/nunu-layout-advanced/internal/model"
-	"github.com/go-nunu/nunu-layout-advanced/internal/pkg/response"
 	"github.com/pkg/errors"
 	"gorm.io/gorm"
 )
@@ -44,7 +44,7 @@ func (r *userRepository) GetByID(ctx context.Context, userId string) (*model.Use
 	var user model.User
 	if err := r.db.Where("user_id = ?", userId).First(&user).Error; err != nil {
 		if errors.Is(err, gorm.ErrRecordNotFound) {
-			return nil, response.ErrNotFound
+			return nil, v1.ErrNotFound
 		}
 		return nil, errors.Wrap(err, "failed to get user by ID")
 	}

+ 28 - 21
internal/server/http.go

@@ -2,64 +2,71 @@ package server
 
 import (
 	"github.com/gin-gonic/gin"
+	apiV1 "github.com/go-nunu/nunu-layout-advanced/api/v1"
 	"github.com/go-nunu/nunu-layout-advanced/docs"
 	"github.com/go-nunu/nunu-layout-advanced/internal/handler"
-	"github.com/go-nunu/nunu-layout-advanced/internal/pkg/middleware"
-	"github.com/go-nunu/nunu-layout-advanced/internal/pkg/response"
+	"github.com/go-nunu/nunu-layout-advanced/internal/middleware"
 	"github.com/go-nunu/nunu-layout-advanced/pkg/jwt"
 	"github.com/go-nunu/nunu-layout-advanced/pkg/log"
+	"github.com/go-nunu/nunu-layout-advanced/pkg/server/http"
+	"github.com/spf13/viper"
 	swaggerfiles "github.com/swaggo/files"
 	ginSwagger "github.com/swaggo/gin-swagger"
 )
 
-func NewServerHTTP(
+func NewHTTPServer(
 	logger *log.Logger,
+	conf *viper.Viper,
 	jwt *jwt.JWT,
 	userHandler handler.UserHandler,
-) *gin.Engine {
-	gin.SetMode(gin.ReleaseMode)
-	r := gin.Default()
+) *http.Server {
+	gin.SetMode(gin.DebugMode)
+	s := http.NewServer(
+		gin.Default(),
+		logger,
+		http.WithServerHost(conf.GetString("http.host")),
+		http.WithServerPort(conf.GetInt("http.port")),
+	)
 
 	// swagger doc
-	docs.SwaggerInfo.BasePath = "/"
-	r.GET("/swagger/*any", ginSwagger.WrapHandler(
+	docs.SwaggerInfo.BasePath = "/v1"
+	s.GET("/swagger/*any", ginSwagger.WrapHandler(
 		swaggerfiles.Handler,
 		//ginSwagger.URL(fmt.Sprintf("http://localhost:%d/swagger/doc.json", conf.GetInt("app.http.port"))),
 		ginSwagger.DefaultModelsExpandDepth(-1),
 	))
 
-	r.Use(
+	s.Use(
 		middleware.CORSMiddleware(),
 		middleware.ResponseLogMiddleware(logger),
 		middleware.RequestLogMiddleware(logger),
 		//middleware.SignMiddleware(log),
 	)
+	s.GET("/", func(ctx *gin.Context) {
+		logger.WithContext(ctx).Info("hello")
+		apiV1.HandleSuccess(ctx, map[string]interface{}{
+			":)": "Thank you for using nunu!",
+		})
+	})
 
+	v1 := s.Group("/v1")
 	// No route group has permission
-	noAuthRouter := r.Group("/")
+	noAuthRouter := v1
 	{
-
-		noAuthRouter.GET("/", func(ctx *gin.Context) {
-			logger.WithContext(ctx).Info("hello")
-			response.HandleSuccess(ctx, map[string]interface{}{
-				":)": "Thank you for using nunu!",
-			})
-		})
-
 		noAuthRouter.POST("/register", userHandler.Register)
 		noAuthRouter.POST("/login", userHandler.Login)
 	}
 	// Non-strict permission routing group
-	noStrictAuthRouter := r.Group("/").Use(middleware.NoStrictAuth(jwt, logger))
+	noStrictAuthRouter := v1.Use(middleware.NoStrictAuth(jwt, logger))
 	{
 		noStrictAuthRouter.GET("/user", userHandler.GetProfile)
 	}
 
 	// Strict permission routing group
-	strictAuthRouter := r.Group("/").Use(middleware.StrictAuth(jwt, logger))
+	strictAuthRouter := v1.Use(middleware.StrictAuth(jwt, logger))
 	{
 		strictAuthRouter.PUT("/user", userHandler.UpdateProfile)
 	}
 
-	return r
+	return s
 }

+ 25 - 0
internal/server/job.go

@@ -0,0 +1,25 @@
+package server
+
+import (
+	"context"
+	"github.com/go-nunu/nunu-layout-advanced/pkg/log"
+)
+
+type Job struct {
+	log *log.Logger
+}
+
+func NewJob(
+	log *log.Logger,
+) *Job {
+	return &Job{
+		log: log,
+	}
+}
+func (j *Job) Start(ctx context.Context) error {
+	// eg: kafka consumer
+	return nil
+}
+func (j *Job) Stop(ctx context.Context) error {
+	return nil
+}

+ 12 - 4
cmd/migration/internal/migration.go → internal/server/migration.go

@@ -1,10 +1,12 @@
-package internal
+package server
 
 import (
+	"context"
 	"github.com/go-nunu/nunu-layout-advanced/internal/model"
 	"github.com/go-nunu/nunu-layout-advanced/pkg/log"
 	"go.uber.org/zap"
 	"gorm.io/gorm"
+	"os"
 )
 
 type Migrate struct {
@@ -18,10 +20,16 @@ func NewMigrate(db *gorm.DB, log *log.Logger) *Migrate {
 		log: log,
 	}
 }
-func (m *Migrate) Run() {
+func (m *Migrate) Start(ctx context.Context) error {
 	if err := m.db.AutoMigrate(&model.User{}); err != nil {
 		m.log.Error("user migrate error", zap.Error(err))
-		return
+		return err
 	}
-	m.log.Info("AutoMigrate end")
+	m.log.Info("AutoMigrate success")
+	os.Exit(0)
+	return nil
+}
+func (m *Migrate) Stop(ctx context.Context) error {
+	m.log.Info("AutoMigrate stop")
+	return nil
 }

+ 0 - 17
internal/server/server.go

@@ -1,17 +0,0 @@
-package server
-
-import (
-	"github.com/gin-gonic/gin"
-)
-
-type Server struct {
-	ServerHTTP *gin.Engine
-	//ServerGRPC *grpc.Server
-	//ServerWS   *ws.Server
-}
-
-func NewServer(serverHTTP *gin.Engine) *Server {
-	return &Server{
-		ServerHTTP: serverHTTP,
-	}
-}

+ 46 - 0
internal/server/task.go

@@ -0,0 +1,46 @@
+package server
+
+import (
+	"context"
+	"github.com/go-co-op/gocron"
+	"github.com/go-nunu/nunu-layout-advanced/pkg/log"
+	"go.uber.org/zap"
+	"time"
+)
+
+type Task struct {
+	log       *log.Logger
+	scheduler *gocron.Scheduler
+}
+
+func NewTask(log *log.Logger) *Task {
+	return &Task{
+		log: log,
+	}
+}
+func (t *Task) Start(ctx context.Context) error {
+	// eg: crontab task
+	t.scheduler = gocron.NewScheduler(time.UTC)
+
+	_, err := t.scheduler.CronWithSeconds("0/3 * * * * *").Do(func() {
+		t.log.Info("I'm a Task1.")
+	})
+	if err != nil {
+		t.log.Error("Task1 error", zap.Error(err))
+	}
+
+	_, err = t.scheduler.Every("3s").Do(func() {
+		t.log.Info("I'm a Task2.")
+	})
+	if err != nil {
+		t.log.Error("Task2 error", zap.Error(err))
+	}
+
+	t.scheduler.StartBlocking()
+	return nil
+}
+func (t *Task) Stop(ctx context.Context) error {
+	t.scheduler.Stop()
+	t.log.Info("Task stop...")
+	return nil
+}

+ 17 - 13
internal/service/user.go

@@ -2,9 +2,8 @@ package service
 
 import (
 	"context"
+	v1 "github.com/go-nunu/nunu-layout-advanced/api/v1"
 	"github.com/go-nunu/nunu-layout-advanced/internal/model"
-	"github.com/go-nunu/nunu-layout-advanced/internal/pkg/request"
-	"github.com/go-nunu/nunu-layout-advanced/internal/pkg/response"
 	"github.com/go-nunu/nunu-layout-advanced/internal/repository"
 	"github.com/pkg/errors"
 	"golang.org/x/crypto/bcrypt"
@@ -12,10 +11,10 @@ import (
 )
 
 type UserService interface {
-	Register(ctx context.Context, req *request.RegisterRequest) error
-	Login(ctx context.Context, req *request.LoginRequest) (string, error)
-	GetProfile(ctx context.Context, userId string) (*model.User, error)
-	UpdateProfile(ctx context.Context, userId string, req *request.UpdateProfileRequest) error
+	Register(ctx context.Context, req *v1.RegisterRequest) error
+	Login(ctx context.Context, req *v1.LoginRequest) (string, error)
+	GetProfile(ctx context.Context, userId string) (*v1.GetProfileResponseData, error)
+	UpdateProfile(ctx context.Context, userId string, req *v1.UpdateProfileRequest) error
 }
 
 func NewUserService(service *Service, userRepo repository.UserRepository) UserService {
@@ -30,10 +29,10 @@ type userService struct {
 	*Service
 }
 
-func (s *userService) Register(ctx context.Context, req *request.RegisterRequest) error {
+func (s *userService) Register(ctx context.Context, req *v1.RegisterRequest) error {
 	// check username
 	if user, err := s.userRepo.GetByUsername(ctx, req.Username); err == nil && user != nil {
-		return response.ErrUsernameAlreadyUse
+		return v1.ErrUsernameAlreadyUse
 	}
 
 	hashedPassword, err := bcrypt.GenerateFromPassword([]byte(req.Password), bcrypt.DefaultCost)
@@ -49,6 +48,7 @@ func (s *userService) Register(ctx context.Context, req *request.RegisterRequest
 	user := &model.User{
 		UserId:   userId,
 		Username: req.Username,
+		Nickname: req.Username,
 		Password: string(hashedPassword),
 		Email:    req.Email,
 	}
@@ -59,10 +59,10 @@ func (s *userService) Register(ctx context.Context, req *request.RegisterRequest
 	return nil
 }
 
-func (s *userService) Login(ctx context.Context, req *request.LoginRequest) (string, error) {
+func (s *userService) Login(ctx context.Context, req *v1.LoginRequest) (string, error) {
 	user, err := s.userRepo.GetByUsername(ctx, req.Username)
 	if err != nil || user == nil {
-		return "", response.ErrUnauthorized
+		return "", v1.ErrUnauthorized
 	}
 
 	err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(req.Password))
@@ -77,16 +77,20 @@ func (s *userService) Login(ctx context.Context, req *request.LoginRequest) (str
 	return token, nil
 }
 
-func (s *userService) GetProfile(ctx context.Context, userId string) (*model.User, error) {
+func (s *userService) GetProfile(ctx context.Context, userId string) (*v1.GetProfileResponseData, error) {
 	user, err := s.userRepo.GetByID(ctx, userId)
 	if err != nil {
 		return nil, errors.Wrap(err, "failed to get user by ID")
 	}
 
-	return user, nil
+	return &v1.GetProfileResponseData{
+		UserId:   user.UserId,
+		Nickname: user.Nickname,
+		Username: user.Username,
+	}, nil
 }
 
-func (s *userService) UpdateProfile(ctx context.Context, userId string, req *request.UpdateProfileRequest) error {
+func (s *userService) UpdateProfile(ctx context.Context, userId string, req *v1.UpdateProfileRequest) error {
 	user, err := s.userRepo.GetByID(ctx, userId)
 	if err != nil {
 		return errors.Wrap(err, "failed to get user by ID")

+ 70 - 0
pkg/app/app.go

@@ -0,0 +1,70 @@
+package app
+
+import (
+	"context"
+	"github.com/go-nunu/nunu-layout-advanced/pkg/server"
+	"log"
+	"os"
+	"os/signal"
+	"syscall"
+)
+
+type App struct {
+	name    string
+	servers []server.Server
+}
+
+type Option func(a *App)
+
+func NewApp(opts ...Option) *App {
+	a := &App{}
+	for _, opt := range opts {
+		opt(a)
+	}
+	return a
+}
+
+func WithServer(servers ...server.Server) Option {
+	return func(a *App) {
+		a.servers = servers
+	}
+}
+func WithName(name string) Option {
+	return func(a *App) {
+		a.name = name
+	}
+}
+
+func (a *App) Run(ctx context.Context) error {
+	ctx, cancel := context.WithCancel(ctx)
+	signals := make(chan os.Signal, 1)
+	signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM)
+	endpoints := make([]string, 0)
+	for _, srv := range a.servers {
+		if s, ok := srv.(server.Endpointer); ok {
+			e, err := s.Endpoint()
+			if err != nil {
+				return err
+			}
+			endpoints = append(endpoints, e.String())
+		}
+		go func(srv server.Server) {
+			err := srv.Start(ctx)
+			if err != nil {
+				cancel()
+				log.Fatal("app start err:", err)
+			}
+		}(srv)
+	}
+
+	<-signals
+	cancel()
+	for _, srv := range a.servers {
+		err := srv.Stop(ctx)
+		if err != nil {
+			log.Fatal("app stop err:", err)
+		}
+	}
+
+	return nil
+}

+ 0 - 48
pkg/http/http.go

@@ -1,48 +0,0 @@
-package http
-
-import (
-	"context"
-	"github.com/gin-gonic/gin"
-	"log"
-	"net/http"
-	"os"
-	"os/signal"
-	"syscall"
-	"time"
-)
-
-func Run(r *gin.Engine, addr string) {
-
-	srv := &http.Server{
-		Addr:    addr,
-		Handler: r,
-	}
-
-	// Initializing the server in a goroutine so that
-	// it won't block the graceful shutdown handling below
-	go func() {
-		if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
-			log.Fatalf("listen: %s\n", err)
-		}
-	}()
-
-	// Wait for interrupt signal to gracefully shutdown the server with
-	// a timeout of 5 seconds.
-	quit := make(chan os.Signal, 1)
-	// kill (no param) default send syscall.SIGTERM
-	// kill -2 is syscall.SIGINT
-	// kill -9 is syscall.SIGKILL but can't be catch, so don't need add it
-	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
-	<-quit
-	log.Println("Shutting down server...")
-
-	// The context is used to inform the server it has 5 seconds to finish
-	// the request it is currently handling
-	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
-	defer cancel()
-	if err := srv.Shutdown(ctx); err != nil {
-		log.Fatal("Server forced to shutdown: ", err)
-	}
-
-	log.Println("Server exiting")
-}

+ 4 - 1
pkg/jwt/jwt.go

@@ -1,6 +1,7 @@
 package jwt
 
 import (
+	"github.com/pkg/errors"
 	"regexp"
 	"time"
 
@@ -46,10 +47,12 @@ func (j *JWT) GenToken(userId string, expiresAt time.Time) (string, error) {
 func (j *JWT) ParseToken(tokenString string) (*MyCustomClaims, error) {
 	re := regexp.MustCompile(`(?i)Bearer `)
 	tokenString = re.ReplaceAllString(tokenString, "")
+	if tokenString == "" {
+		return nil, errors.New("token is empty")
+	}
 	token, err := jwt.ParseWithClaims(tokenString, &MyCustomClaims{}, func(token *jwt.Token) (interface{}, error) {
 		return j.key, nil
 	})
-
 	if claims, ok := token.Claims.(*MyCustomClaims); ok && token.Valid {
 		return claims, nil
 	} else {

+ 61 - 0
pkg/server/grpc/grpc.go

@@ -0,0 +1,61 @@
+package grpc
+
+import (
+	"context"
+	"fmt"
+	"github.com/go-nunu/nunu-layout-advanced/pkg/log"
+	"google.golang.org/grpc"
+	"net"
+	"time"
+)
+
+type Server struct {
+	*grpc.Server
+	host   string
+	port   int
+	logger *log.Logger
+}
+
+type Option func(s *Server)
+
+func NewServer(logger *log.Logger, opts ...Option) *Server {
+	s := &Server{
+		Server: grpc.NewServer(),
+		logger: logger,
+	}
+	for _, opt := range opts {
+		opt(s)
+	}
+	return s
+}
+func WithServerHost(host string) Option {
+	return func(s *Server) {
+		s.host = host
+	}
+}
+func WithServerPort(port int) Option {
+	return func(s *Server) {
+		s.port = port
+	}
+}
+
+func (s *Server) Start(ctx context.Context) error {
+	lis, err := net.Listen("tcp", fmt.Sprintf("%s:%d", s.host, s.port))
+	if err != nil {
+		s.logger.Sugar().Fatalf("Failed to listen: %v", err)
+	}
+	if err = s.Server.Serve(lis); err != nil {
+		s.logger.Sugar().Fatalf("Failed to serve: %v", err)
+	}
+	return nil
+
+}
+func (s *Server) Stop(ctx context.Context) error {
+	ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
+	defer cancel()
+	s.Server.GracefulStop()
+
+	s.logger.Info("Server exiting")
+
+	return nil
+}

+ 67 - 0
pkg/server/http/http.go

@@ -0,0 +1,67 @@
+package http
+
+import (
+	"context"
+	"fmt"
+	"github.com/gin-gonic/gin"
+	"github.com/go-nunu/nunu-layout-advanced/pkg/log"
+	"net/http"
+	"time"
+)
+
+type Server struct {
+	*gin.Engine
+	httpSrv *http.Server
+	host    string
+	port    int
+	logger  *log.Logger
+}
+type Option func(s *Server)
+
+func NewServer(engine *gin.Engine, logger *log.Logger, opts ...Option) *Server {
+	s := &Server{
+		Engine: engine,
+		logger: logger,
+	}
+	for _, opt := range opts {
+		opt(s)
+	}
+	return s
+}
+func WithServerHost(host string) Option {
+	return func(s *Server) {
+		s.host = host
+	}
+}
+func WithServerPort(port int) Option {
+	return func(s *Server) {
+		s.port = port
+	}
+}
+
+func (s *Server) Start(ctx context.Context) error {
+	s.httpSrv = &http.Server{
+		Addr:    fmt.Sprintf("%s:%d", s.host, s.port),
+		Handler: s,
+	}
+
+	if err := s.httpSrv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
+		s.logger.Sugar().Fatalf("listen: %s\n", err)
+	}
+
+	return nil
+}
+func (s *Server) Stop(ctx context.Context) error {
+	s.logger.Sugar().Info("Shutting down server...")
+
+	// The context is used to inform the server it has 5 seconds to finish
+	// the request it is currently handling
+	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
+	defer cancel()
+	if err := s.httpSrv.Shutdown(ctx); err != nil {
+		s.logger.Sugar().Fatal("Server forced to shutdown: ", err)
+	}
+
+	s.logger.Sugar().Info("Server exiting")
+	return nil
+}

+ 16 - 0
pkg/server/server.go

@@ -0,0 +1,16 @@
+package server
+
+import (
+	"context"
+	"net/url"
+)
+
+type Server interface {
+	Start(context.Context) error
+	Stop(context.Context) error
+}
+
+// Endpointer is registry endpoint.
+type Endpointer interface {
+	Endpoint() (*url.URL, error)
+}

+ 6 - 7
test/mocks/service/user.go

@@ -8,8 +8,7 @@ import (
 	context "context"
 	reflect "reflect"
 
-	model "github.com/go-nunu/nunu-layout-advanced/internal/model"
-	request "github.com/go-nunu/nunu-layout-advanced/internal/pkg/request"
+	v1 "github.com/go-nunu/nunu-layout-advanced/api/v1"
 	gomock "github.com/golang/mock/gomock"
 )
 
@@ -37,10 +36,10 @@ func (m *MockUserService) EXPECT() *MockUserServiceMockRecorder {
 }
 
 // GetProfile mocks base method.
-func (m *MockUserService) GetProfile(ctx context.Context, userId string) (*model.User, error) {
+func (m *MockUserService) GetProfile(ctx context.Context, userId string) (*v1.GetProfileResponseData, error) {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "GetProfile", ctx, userId)
-	ret0, _ := ret[0].(*model.User)
+	ret0, _ := ret[0].(*v1.GetProfileResponseData)
 	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
@@ -52,7 +51,7 @@ func (mr *MockUserServiceMockRecorder) GetProfile(ctx, userId interface{}) *gomo
 }
 
 // Login mocks base method.
-func (m *MockUserService) Login(ctx context.Context, req *request.LoginRequest) (string, error) {
+func (m *MockUserService) Login(ctx context.Context, req *v1.LoginRequest) (string, error) {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "Login", ctx, req)
 	ret0, _ := ret[0].(string)
@@ -67,7 +66,7 @@ func (mr *MockUserServiceMockRecorder) Login(ctx, req interface{}) *gomock.Call
 }
 
 // Register mocks base method.
-func (m *MockUserService) Register(ctx context.Context, req *request.RegisterRequest) error {
+func (m *MockUserService) Register(ctx context.Context, req *v1.RegisterRequest) error {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "Register", ctx, req)
 	ret0, _ := ret[0].(error)
@@ -81,7 +80,7 @@ func (mr *MockUserServiceMockRecorder) Register(ctx, req interface{}) *gomock.Ca
 }
 
 // UpdateProfile mocks base method.
-func (m *MockUserService) UpdateProfile(ctx context.Context, userId string, req *request.UpdateProfileRequest) error {
+func (m *MockUserService) UpdateProfile(ctx context.Context, userId string, req *v1.UpdateProfileRequest) error {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "UpdateProfile", ctx, userId, req)
 	ret0, _ := ret[0].(error)

+ 19 - 16
test/server/handler/user_test.go

@@ -4,11 +4,12 @@ import (
 	"bytes"
 	"encoding/json"
 	"fmt"
+	v1 "github.com/go-nunu/nunu-layout-advanced/api/v1"
 	"github.com/go-nunu/nunu-layout-advanced/internal/handler"
-	"github.com/go-nunu/nunu-layout-advanced/internal/pkg/middleware"
-	"github.com/go-nunu/nunu-layout-advanced/internal/pkg/request"
+	"github.com/go-nunu/nunu-layout-advanced/internal/middleware"
 	jwt2 "github.com/go-nunu/nunu-layout-advanced/pkg/jwt"
 	"github.com/go-nunu/nunu-layout-advanced/test/mocks/service"
+	"time"
 
 	"net/http"
 	"net/http/httptest"
@@ -16,7 +17,6 @@ import (
 	"testing"
 
 	"github.com/gin-gonic/gin"
-	"github.com/go-nunu/nunu-layout-advanced/internal/model"
 	"github.com/go-nunu/nunu-layout-advanced/pkg/config"
 	"github.com/go-nunu/nunu-layout-advanced/pkg/log"
 	"github.com/golang/mock/gomock"
@@ -24,9 +24,7 @@ import (
 )
 
 var (
-	userId = "yhs6HesfgF"
-
-	token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVc2VySWQiOiJ5aHM2SGVzZmdGIiwiZXhwIjoxNjkzOTE0ODgwLCJuYmYiOjE2ODYxMzg4ODAsImlhdCI6MTY4NjEzODg4MH0.NnFrZFgc_333a9PXqaoongmIDksNvQoHzgM_IhJM4MQ"
+	userId = "xxx"
 )
 var logger *log.Logger
 var hdl *handler.Handler
@@ -64,7 +62,7 @@ func TestUserHandler_Register(t *testing.T) {
 	ctrl := gomock.NewController(t)
 	defer ctrl.Finish()
 
-	params := request.RegisterRequest{
+	params := v1.RegisterRequest{
 		Username: "xxx",
 		Password: "123456",
 		Email:    "xxx@gmail.com",
@@ -88,13 +86,13 @@ func TestUserHandler_Login(t *testing.T) {
 	ctrl := gomock.NewController(t)
 	defer ctrl.Finish()
 
-	params := request.LoginRequest{
+	params := v1.LoginRequest{
 		Username: "xxx",
 		Password: "123456",
 	}
 
 	mockUserService := mock_service.NewMockUserService(ctrl)
-	mockUserService.EXPECT().Login(gomock.Any(), &params).Return(token, nil)
+	mockUserService.EXPECT().Login(gomock.Any(), &params).Return("", nil)
 
 	userHandler := handler.NewUserHandler(hdl, mockUserService)
 	router.POST("/login", userHandler.Login)
@@ -111,20 +109,17 @@ func TestUserHandler_GetProfile(t *testing.T) {
 	defer ctrl.Finish()
 
 	mockUserService := mock_service.NewMockUserService(ctrl)
-	mockUserService.EXPECT().GetProfile(gomock.Any(), userId).Return(&model.User{
-		Id:       1,
+	mockUserService.EXPECT().GetProfile(gomock.Any(), userId).Return(&v1.GetProfileResponseData{
 		UserId:   userId,
 		Username: "xxxxx",
 		Nickname: "xxxxx",
-		Password: "xxxxx",
-		Email:    "xxxxx@gmail.com",
 	}, nil)
 
 	userHandler := handler.NewUserHandler(hdl, mockUserService)
 	router.Use(middleware.NoStrictAuth(jwt, logger))
 	router.GET("/user", userHandler.GetProfile)
 	req, _ := http.NewRequest("GET", "/user", nil)
-	req.Header.Set("Authorization", "Bearer "+token)
+	req.Header.Set("Authorization", "Bearer "+genToken(t))
 
 	resp := httptest.NewRecorder()
 
@@ -137,7 +132,7 @@ func TestUserHandler_UpdateProfile(t *testing.T) {
 	ctrl := gomock.NewController(t)
 	defer ctrl.Finish()
 
-	params := request.UpdateProfileRequest{
+	params := v1.UpdateProfileRequest{
 		Nickname: "alan",
 		Email:    "alan@gmail.com",
 		Avatar:   "xxx",
@@ -152,7 +147,7 @@ func TestUserHandler_UpdateProfile(t *testing.T) {
 	paramsJson, _ := json.Marshal(params)
 
 	req, _ := http.NewRequest("PUT", "/user", bytes.NewBuffer(paramsJson))
-	req.Header.Set("Authorization", "Bearer "+token)
+	req.Header.Set("Authorization", "Bearer "+genToken(t))
 	req.Header.Set("Content-Type", "application/json")
 	resp := httptest.NewRecorder()
 
@@ -168,3 +163,11 @@ func performRequest(r http.Handler, method, path string, body *bytes.Buffer) *ht
 	r.ServeHTTP(resp, req)
 	return resp
 }
+func genToken(t *testing.T) string {
+	token, err := jwt.GenToken(userId, time.Now().Add(time.Hour*24*90))
+	if err != nil {
+		t.Error(err)
+		return token
+	}
+	return token
+}

+ 7 - 8
test/server/service/user_test.go

@@ -4,7 +4,7 @@ import (
 	"context"
 	"errors"
 	"fmt"
-	"github.com/go-nunu/nunu-layout-advanced/internal/pkg/request"
+	v1 "github.com/go-nunu/nunu-layout-advanced/api/v1"
 	"github.com/go-nunu/nunu-layout-advanced/pkg/jwt"
 	"github.com/go-nunu/nunu-layout-advanced/test/mocks/repository"
 	"os"
@@ -54,7 +54,7 @@ func TestUserService_Register(t *testing.T) {
 	userService := service.NewUserService(srv, mockUserRepo)
 
 	ctx := context.Background()
-	req := &request.RegisterRequest{
+	req := &v1.RegisterRequest{
 		Username: "testuser",
 		Password: "password",
 		Email:    "test@example.com",
@@ -77,7 +77,7 @@ func TestUserService_Register_UsernameExists(t *testing.T) {
 	userService := service.NewUserService(srv, mockUserRepo)
 
 	ctx := context.Background()
-	req := &request.RegisterRequest{
+	req := &v1.RegisterRequest{
 		Username: "testuser",
 		Password: "password",
 		Email:    "test@example.com",
@@ -99,7 +99,7 @@ func TestUserService_Login(t *testing.T) {
 	userService := service.NewUserService(srv, mockUserRepo)
 
 	ctx := context.Background()
-	req := &request.LoginRequest{
+	req := &v1.LoginRequest{
 		Username: "testuser",
 		Password: "password",
 	}
@@ -127,7 +127,7 @@ func TestUserService_Login_UserNotFound(t *testing.T) {
 	userService := service.NewUserService(srv, mockUserRepo)
 
 	ctx := context.Background()
-	req := &request.LoginRequest{
+	req := &v1.LoginRequest{
 		Username: "testuser",
 		Password: "password",
 	}
@@ -161,7 +161,6 @@ func TestUserService_GetProfile(t *testing.T) {
 	assert.NoError(t, err)
 	assert.Equal(t, userId, user.UserId)
 	assert.Equal(t, "testuser", user.Username)
-	assert.Equal(t, "test@example.com", user.Email)
 }
 
 func TestUserService_UpdateProfile(t *testing.T) {
@@ -174,7 +173,7 @@ func TestUserService_UpdateProfile(t *testing.T) {
 
 	ctx := context.Background()
 	userId := "123"
-	req := &request.UpdateProfileRequest{
+	req := &v1.UpdateProfileRequest{
 		Nickname: "testuser",
 		Email:    "test@example.com",
 	}
@@ -201,7 +200,7 @@ func TestUserService_UpdateProfile_UserNotFound(t *testing.T) {
 
 	ctx := context.Background()
 	userId := "123"
-	req := &request.UpdateProfileRequest{
+	req := &v1.UpdateProfileRequest{
 		Nickname: "testuser",
 		Email:    "test@example.com",
 	}