Skip to content

Conventions & Code Style

This document outlines the strict coding conventions and architectural patterns that must be followed when contributing to the Merq platform. These rules are enforced to ensure consistency, maintainability, and quality across the entire codebase.

Architecture: Handler → Service → Repository

Section titled “Architecture: Handler → Service → Repository”

The backend follows a strict three-layer architecture to separate concerns:

  1. Handler (*_handler.go): The outermost layer responsible for handling HTTP requests. It binds and validates incoming data, calls the appropriate service method, and formats the HTTP response using utils.HandleResponse. Handlers must never contain business logic or database queries.
  2. Service (*_service.go): This layer contains the core business logic. It orchestrates operations, enforces business rules, and calls repository methods to interact with the database.
  3. Repository (*_repository.go): The data access layer. It is responsible for all database operations, primarily using GORM. All GORM queries, including filtering and pagination, are encapsulated here.
  • Workspace Scoping: All database queries for tenant-specific data must include a .Where("workspace_id = ?", workspaceID) clause.
  • Error Handling: Use customerror.New() for domain-specific errors and c.Error() for handler-level errors.
  • Responses: All API responses must be sent using the utils.HandleResponse utility, never c.JSON directly.
  • Transactions: For operations involving multiple database writes, use the utils.WithTransaction helper to ensure atomicity.
  • Placing GORM or SQL queries inside handlers or services.
  • Skipping workspace scoping on any query.
  • Using c.JSON for API responses.
  • Creating “god” handlers or services with hundreds of lines of mixed logic.
  • Bypassing the RBAC middleware on protected routes.