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:
- 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 usingutils.HandleResponse. Handlers must never contain business logic or database queries. - 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. - 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.
Key Conventions
Section titled “Key Conventions”- 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 andc.Error()for handler-level errors. - Responses: All API responses must be sent using the
utils.HandleResponseutility, neverc.JSONdirectly. - Transactions: For operations involving multiple database writes, use the
utils.WithTransactionhelper to ensure atomicity.
Anti-Patterns (Do Not Use)
Section titled “Anti-Patterns (Do Not Use)”- Placing GORM or SQL queries inside handlers or services.
- Skipping workspace scoping on any query.
- Using
c.JSONfor API responses. - Creating “god” handlers or services with hundreds of lines of mixed logic.
- Bypassing the RBAC middleware on protected routes.
Architecture
Section titled “Architecture”The web dashboard is built with React, Vite, and shadcn/ui, following these key structural patterns:
src/lib/query/: Contains all TanStack Query hooks for data fetching.src/columns/: Reusable TanStack Table column definitions.src/components/ui/: Components from the shadcn/ui library.src/pages/: Route-level page components.
Data Fetching & State
Section titled “Data Fetching & State”- Server State: All asynchronous data fetching from the API must be managed by TanStack Query. Do not use
useEffectanduseStatefor this purpose. - Filter Alignment: Query parameter names in the frontend must exactly match the
form:"..."tags in the backend Go structs (e.g.,project_id, notprojectId). - Pagination: All tables displaying server data must be server-side paginated. Never fetch an entire dataset to the client.
UI & Components
Section titled “UI & Components”- Component Library: Only use components from shadcn/ui. Do not introduce new UI libraries.
- Tables: Use the reusable
CommonTableandDialogTablecomponents for displaying data. - Forms: Use React Hook Form with Zod for robust form validation.
Anti-Patterns (Do Not Use)
Section titled “Anti-Patterns (Do Not Use)”- Fetching data with
useEffectanduseState. - Client-side pagination for server data.
- Hardcoding API URLs; use the
lib/api.tsAxios instance. - Creating custom UI components when a shadcn/ui equivalent exists.
Architecture & Offline-First
Section titled “Architecture & Offline-First”The mobile app is built with React Native and is designed to be offline-first.
- Storage: MMKV is the only approved storage mechanism.
AsyncStorageandSQLiteare forbidden. - Data Sync: All server data is managed via TanStack Query with
networkMode: "offlineFirst". This ensures data is cached and available when the device is offline. - Query Gating: Queries must be gated (e.g.,
enabled: !!profile) to prevent API calls before the user is authenticated.
UI & Styling
Section titled “UI & Styling”- Component Library: React Native Paper (MD3) is the only permitted UI library.
- Styling: All styles must be created using
StyleSheet.create. Inline styles (style={{...}}) are strictly forbidden as they hurt performance. - Component Structure: Use named exports for all components and
React.memofor list items to prevent unnecessary re-renders.
State Management
Section titled “State Management”- Client State: Global client state (e.g., auth status, user profile) is managed by Jotai.
- Server State: All data originating from the server is managed by TanStack Query. Do not store server data in Jotai atoms.
Anti-Patterns (Do Not Use)
Section titled “Anti-Patterns (Do Not Use)”- Using
AsyncStorageorSQLite. - Using any UI library other than React Native Paper.
- Using inline styles.
- Using default exports for components.
- Storing API data in
useStateor Jotai atoms. - Creating TanStack Query hooks without
networkMode: "offlineFirst".