Skip to content

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.

  • 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 is the heart of the application. Here’s how the layers interact:

  • 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 service method.
    • Formats the response from the service into a JSON output using utils.HandleResponse.
  • Example: outlet_handler.go contains handlers for GET /outlets, POST /outlets, etc.
  • Rule: Handlers must not contain any business logic or direct database calls.
  • 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 repository methods to fetch or persist data.
    • Calls platform clients to interact with external services (e.g., sending an email, indexing a document in Typesense).
  • Example: outlet_service.go contains 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.
  • 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.go provides methods like FindByID, List, Create, Update.
  • Rule: Repositories should only contain database logic. They should not contain business logic or be aware of the HTTP layer.
  • 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 embed BaseFilter for pagination and use form tags.
  • Purpose: Data Transfer Objects used for API communication.
  • Contains:
    • Request DTOs: Structs used to bind incoming request bodies (ShouldBindJSON). They use binding tags for validation.
    • Response DTOs: Structs used to format the JSON response sent to the client. They use json tags.
  • 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.