Project directory design is a further implementation of code layering design. It is recommended that you read carefully first: Code Layering
This is a directory design for business projects with the GoFrame framework. The main idea originates from the three-layer architecture but has been improved and refined in practice to better fit engineering practices and modern advancements.
1. Project Directory Structure
The basic directory structure of GoFrame business projects is as follows (taking Single Repo as an example):
/
├── api
├── hack
├── internal
│ ├── cmd
│ ├── consts
│ ├── controller
│ ├── dao
│ ├── logic
│ ├── model
│ | ├── do
│ │ └── entity
│ └── service
├── manifest
├── resource
├── utility
├── go.mod
└── main.go
🔥 Important Tip 🔥: The framework's project directory adopts a generalized design to meet the needs of projects with varying levels of complexity, but you can increase or decrease the default directories as needed in actual projects. For example, in scenarios lacking i18n/template/protobuf requirements, you can directly delete the corresponding directories. Similarly, for very simple business projects (such as validation/demonstration projects) that do not require strict use of dao/logic/model directories and features, you can directly delete the corresponding directories and implement business logic directly in the controller. Everything can be flexibly chosen and assembled by the developer!
| Directory/File Name | Explanation | Description |
|---|---|---|
api | External Interface | The input/output data structure definition for providing external services. Considering version management needs, it often exists as api/xxx/v1.... |
hack | Tool Script | Contains project development tools, scripts, etc. For example, configuration for CLI tools, and various shell/bat script files. |
internal | Internal Logic | The directory for storing business logic. Hidden visibility to the outside through Golang internal feature. |
- cmd | Entry Command | Directory for command-line management. Can manage multiple command lines. |
- consts | Constant Definitions | Defines all constants for the project. |
- controller | Interface Handling | Entrance/interface layer for receiving and parsing user input parameters. |
- dao | Data Access | Data Access Object, an abstract object for interacting with the underlying database containing only the basic CRUD methods. |
- logic | Business Encapsulation | Management of business logic encapsulation, specific business logic implementation, and encapsulation, often the most complex part of the project. |
- model | Structure Model | Data structure management module, managing data entity objects and input/output data structure definitions. |
- do | Domain Object | Used for converting business models and instance models in dao data operations, maintained by tools, and cannot be modified by users. |
- entity | Data Model | Data model is a one-to-one relationship between the model and data collection, maintained by tools, and cannot be modified by users. |
- service | Business Interface | Interface definition layer for decoupling business modules. Specific interface implementations are injected in logic. |
manifest | Delivery Manifest | Contains files for program compilation, deployment, operation, and configuration. Common contents are: |
- config | Configuration Management | Directory for storing configuration files. |
- docker | Image Files | Files related to Docker images, script files, etc. |
- deploy | Deployment Files | Files related to deployment. By default, provides a Yaml template for Kubernetes cluster deployment, managed through kustomize. |
- protobuf | Protocol Files | protobuf protocol definition files used during GRPC protocol, compiled protocol files are generated in api directory. |
resource | Static Resources | Static resource files. These files can be injected into release files in the form of resource packing/image compilation. |
go.mod | Dependency Management | Dependency description file using Go Module package management. |
main.go | Entry File | Program entry file. |
External Interface
The external interface includes two parts: Interface Definition (api) + Interface Implementation (controller).
The responsibility of the service interface is similar to the UI representation layer in three-layer architecture design, responsible for receiving and responding to client inputs and outputs, including filtering, converting, and validating input parameters, maintaining the output data structure, and calling service for business logic processing.
Interface Definition - api
The api package is used for defining data structure inputs and outputs agreed with the client, often closely bound to specific business scenarios.
Interface Implementation - controller
The controller receives the input from the api, can directly implement business logic within controller, or call one or more service packages to implement business logic and encapsulate the execution results into an agreed api output data structure.
Business Implementation
Business implementation includes two parts: business interface (service) + business encapsulation (logic).
The responsibility of business implementation is similar to the BLL business logic layer in three-layer architecture design, responsible for implementing and encapsulating specific business logic.
In the following chapters, we will uniformly refer to business implementation as service, and note that it actually includes two parts.
Business Interface - service
The service package is used to decouple business module calls. Business modules often do not directly call the corresponding business module resources to implement business logic but do so by calling service interfaces. The service layer contains only interface definitions, with specific interface implementations injected into the business modules.
Business Encapsulation - logic
The logic package is responsible for implementing and encapsulating specific business logic. Codes from various levels of the project do not directly call the business modules of the logic layer but do so through the service interface layer.
Structure Model
The model package serves a role similar to the Model definition layer in the three-layer architecture. It only contains the global, common data structure definitions for reference by all business modules in the project.
Data Model - entity
Defined data structures bound to the data collection, often corresponding one-to-one with data tables.
Business Model - model
Common data structure definitions related to business, including most method input and output definitions.
Data Access - dao
The role of the dao package is similar to the DAL data access layer in three-layer architecture, responsible for converging all data access.

Mapping relationship between three-layer architecture design and framework code layering
2. Request Layer Flow

cmd
The cmd layer is responsible for guiding the program startup, its significant tasks being initialization logic, registering route objects, starting the server listener, and blocking the program operation until the server exits.
api
The upper layer server service receives client requests, converts them to Req receiving objects defined in api, performs request parameter-to-Req object attribute type conversions, executes basic validation bound to Req objects, and hands over the Req request objects to the controller layer.
controller
The controller layer is responsible for receiving Req request objects, conducting some business logic validations, can directly implement business logic within controller, or call one or more services to implement business logic, and encapsulate results into the agreed Res data structure objects for return.
model
The model layer manages all common business models.
service
service is an interface layer used for business module decoupling. service contains no specific business logic implementation, relying on the logic layer for injection of specific business logic.
logic
The business logic of the logic layer needs to perform data operations by calling dao. When calling dao, do data structure objects need to be passed for delivering query conditions and input data. After dao execution, Entity data models return data results to the service layer.
dao
The dao layer interacts with the underlying real database through the ORM abstraction component of the framework.
3. FAQ
Does the framework support common MVC development model
Of course!
As a foundational development framework with modular design, GoFrame does not constrain code design patterns and provides a powerful template engine core component for rapid template rendering development commonly seen in MVC mode. Compared to the MVC development model, we recommend using the three-layer architecture design model in complex business scenarios.
How to maintain when api and model layers have duplicate data structures
Data structures defined in api are for external use, bound to specific business scenarios (such as specific page interaction logic, single interface function), and data structures are pre-set by upper-layer display layers; data structures defined in model are for internal use only, allowing for internal modifications without affecting external api interface compatibility.
Note that data structures in model should not be directly exposed for external use, and the framework's project design deliberately places the model directory under the internal directory. Nor should alias type definitions of model data structures be provided in the api layer for external access. Once the model data structure is applied to the api layer, changes to internal model data structures will directly affect api interface compatibility.
If duplicate data structures (or even constants, enumerations) appear in both, it is recommended to define data structures at the api layer. Internal service logic can directly access data structures at the api layer. The model layer's data structures can also directly reference those from the api layer, but not vice versa.
Let's see an example for better understanding:


How to clearly define and manage the layering responsibilities between service and controller
The controller layer handles Req/Res external interface requests. It is responsible for receiving, validating request parameters, can directly implement business logic within controller, or call one or more services to implement business logic and encapsulate execution results into the agreed api output data structures for return. The service layer processes Input/Output internal method calls. It is responsible for internal reusable business logic encapsulation, with methods often being more granular.
Typically, when developing an interface, only implementing the business logic in the controller layer is needed, and when there is repetitive code logic, it is abstractly settled into the service layer from various controller interfaces. If Req objects are directly passed from the controller layer to service, and service directly returns Res data structure objects, this approach is coupled with external interfaces and only serves external interface services, making it difficult to reuse, thus increasing technical debt costs.
How to clearly define and manage the layering responsibilities between service and dao
This is a classic question.
Pain Point:
Commonly, developers encapsulate business logic related to data within dao code layer while service code layer only makes simple dao calls. This approach can make the dao layer, originally meant to maintain data, more burdensome, while the business logic service layer code appears light. Developers are confused, questioning where to put their business logic code, in dao or service?
Often, business logic mostly involves CRUD operations on data, causing nearly all business logic to gradually accumulate in the dao layer. Business logic changes frequently necessitate modifications to dao layer code. For instance: for data query requirements, initially it may seem like a simple logic to place code in dao, but as query requirements increase or change complexity, inevitably, existing dao code requires further maintenance and modifications, possibly leading to updates in service code as well. Originally limited to service layer business logic code responsibility becomes unclear and heavily coupled with dao layer code responsibilities, leading to increased development and maintenance costs later in the project.
Suggestion:
Our suggestion: dao layer code should strive to maintain general applicability, with most scenarios not requiring additional methods, instead assembling with some generalized chain operation methods. Business logic, including what appears to be simple data operation logic, should be encapsulated within service. service contains multiple business modules, with each module managing its dao object independently. Ideally, service communicates data through method calls between services rather than arbitrarily calling dao objects of other service modules.
Why use the internal directory to contain business code
The internal directory is a feature unique to Golang language that prevents references from directories outside the peer directory. The purpose of this directory in business projects is to avoid unlimited unrestricted access between multiple projects if there are multiple sub-projects (especially in large repository management mode), making it difficult to prevent coupling of packages across different projects.