Backend Folder Structure
Backend Folder Structure
Section titled “Backend Folder Structure”The merq-backend codebase is organized using a layer-based clean architecture. This means that files are grouped by their architectural layer (e.g., handler, service, repository) rather than by feature. This approach promotes separation of concerns and makes the codebase easier to navigate and maintain.
High-Level Structure
Section titled “High-Level Structure”Directorycmd/ - Application entry points.
Directoryserver/ - The main Gin REST API server.
- …
Directorymigrator/ - The database migration runner.
- …
Directoryseeder-v2/ - The database seeder.
- …
Directoryinternal/ - The core application code, not intended to be imported by other projects.
Directoryhandler/ - HTTP handlers that process requests and responses.
- …
Directoryservice/ - Business logic and orchestration layer.
- …
Directoryrepository/ - Data access layer for database interactions.
- …
Directorydomain/ - Core domain models (structs) and filter objects.
- …
Directorydto/ - Data Transfer Objects for request binding and response formatting.
- …
Directorymiddleware/ - Gin middleware for auth, RBAC, and workspace scoping.
- …
Directoryplatform/ - Clients for external services (Redis, Typesense, S3, etc.).
- …
Directoryconfig/ - Application configuration loading.
- …
Directorytest_utils/ - Shared utilities for integration tests.
- …
Directorypkg/ - Shared utility packages that can be used by other projects.
- …
Directoryscripts/ - Helper scripts for development and CI/CD.
- …
- Dockerfile - Instructions for building the production Docker image.
- go.mod - Go module definition and dependencies.
The internal/ Directory in Detail
Section titled “The internal/ Directory in Detail”The internal/ directory is the heart of the application. Here’s how the layers interact:
handler/
Section titled “handler/”- Purpose: The entry point for all HTTP requests.
- Responsibilities:
- Binds and validates request data (path parameters, query strings, JSON bodies) into DTOs.
- Extracts context from middleware (e.g.,
workspace_id,user_id). - Calls the appropriate
servicemethod. - Formats the response from the service into a JSON output using
utils.HandleResponse.
- Example:
outlet_handler.gocontains handlers forGET /outlets,POST /outlets, etc. - Rule: Handlers must not contain any business logic or direct database calls.
service/
Section titled “service/”- Purpose: Contains all business logic.
- Responsibilities:
- Orchestrates complex operations that may involve multiple data sources.
- Enforces business rules and validation (e.g., checking if a user has permission to perform an action).
- Calls
repositorymethods to fetch or persist data. - Calls
platformclients to interact with external services (e.g., sending an email, indexing a document in Typesense).
- Example:
outlet_service.gocontains the logic for creating an outlet, which might involve validating the data, calling the repository to save it, and then calling a platform client to index it for search.
repository/
Section titled “repository/”- Purpose: The data access layer.
- Responsibilities:
- All interactions with the PostgreSQL database using the GORM library.
- Building and executing queries (create, read, update, delete).
- Applying filters, pagination, and sorting to list queries.
- Managing database transactions.
- Example:
outlet_repository.goprovides methods likeFindByID,List,Create,Update. - Rule: Repositories should only contain database logic. They should not contain business logic or be aware of the HTTP layer.
domain/
Section titled “domain/”- Purpose: Defines the core data structures of the application.
- Contains:
- Model structs: Go structs that map directly to database tables (e.g.,
User,Outlet,Project). These contain GORM tags. - Filter structs: Structs that define the available query parameters for list endpoints (e.g.,
UserFilter,OutletFilter). These embedBaseFilterfor pagination and useformtags.
- Model structs: Go structs that map directly to database tables (e.g.,
- Purpose: Data Transfer Objects used for API communication.
- Contains:
- Request DTOs: Structs used to bind incoming request bodies (
ShouldBindJSON). They usebindingtags for validation. - Response DTOs: Structs used to format the JSON response sent to the client. They use
jsontags.
- Request DTOs: Structs used to bind incoming request bodies (
middleware/
Section titled “middleware/”- Purpose: Gin middleware functions that process requests before they reach the main handler.
- Key Middleware:
AuthMiddleware: Validates the JWT token and extracts user information.RBACMiddleware: Checks if the user’s role has the required permission for the route.WorkspaceMiddleware: Enforces data isolation by ensuring all requests are tied to a workspace.