Thank you for your interest in contributing to DefiFundr! This document provides guidelines and instructions for contributing to the project, explains our architecture, and details the data flow within the application.
- Architecture Overview
- Project Structure
- Data Flow
- Development Environment Setup
- Coding Standards
- Testing Requirements
- Pull Request Process
- Issue Guidelines
- Documentation
- License
DefiFundr follows the Hexagonal Architecture (also known as Ports and Adapters) pattern. This architecture emphasizes separation of concerns by dividing the codebase into three main layers:
- Core Domain - Contains the business logic and domain models
- Ports - Interfaces that define how the core domain interacts with external systems
- Adapters - Implementations that connect the core domain to external systems
This approach allows us to:
- Keep the business logic independent of external concerns
- Easily replace or update external dependencies
- Test business logic in isolation
- Maintain a clean and organized codebase
- API Layer: RESTful endpoints for client communication
- Service Layer: Business logic implementation
- Repository Layer: Data access operations
- Domain Layer: Core business entities and rules
- Infrastructure: Cross-cutting concerns like logging, validation, and authentication
The project follows a structured organization:
├── cmd # Application entrypoints
│ ├── api # API server
│ │ ├── docs # Swagger documentation (generated with `make swagger`)
│ │ └── main.go # API server entry point
│ └── seed # Database seeding tool
├── config # Application configuration
├── db # Database-related code
│ ├── migrations # SQL migration files (managed with goose)
│ ├── query # SQL query files (for sqlc)
│ └── sqlc # Generated database code (via `make sqlc`)
├── docs # Project documentation
│ └── db_diagram # Database schema visualization
├── infrastructure # Cross-cutting concerns
│ ├── common # Shared utilities
│ │ ├── logging # Logging utilities
│ │ ├── utils # General utilities
│ │ └── validation # Input validation
│ ├── hash # Password hashing
│ └── middleware # HTTP middleware
├── internal # Application core code
│ ├── adapters # Implementation of ports
│ │ ├── dto # Data Transfer Objects
│ │ │ ├── request # Request models
│ │ │ └── response # Response models
│ │ ├── handlers # HTTP handlers
│ │ ├── repositories # Data access implementations
│ │ └── routers # HTTP route definitions
│ └── core # Core business logic
│ ├── domain # Domain models
│ ├── ports # Interface definitions
│ └── services # Business logic implementation
├── pkg # Reusable packages
│ ├── app_errors # Error handling
│ ├── pagination # Pagination utilities
│ ├── random # Random data generation
│ ├── token_maker # Authentication token handling
│ └── tracing # Distributed tracing
├── scripts # Utility scripts
├── smart-contracts # Smart contract source code
│ └── ethereum # Ethereum contracts
├── test # Test code
│ ├── e2e # End-to-end tests
│ ├── integration # Integration tests
│ └── unit # Unit tests
├── .env # Environment variables (loaded by Makefile)
├── docker-compose.yml # Docker services configuration
├── Dockerfile # Application container definition
├── go.mod # Go module definition
├── Makefile # Build and development commands
└── sqlc.yaml # SQLC configuration
The data flow in DefiFundr follows the principles of hexagonal architecture:
-
HTTP Request Lifecycle:
- Request arrives at the API server (started with
make serverormake air) - Middleware processes the request (authentication, rate limiting)
- Router directs the request to the appropriate handler
- Handler validates input and transforms it into domain objects
- Service layer applies business logic
- Repository layer performs data access operations
- Response flows back through the layers to the client
- Request arrives at the API server (started with
-
Authentication Flow:
- User submits credentials via auth endpoints
auth_handler.govalidates the request formatauth_service.govalidates credentials using the hash package- On successful validation, token_maker creates a PASETO token
- Session is created and stored via
session_repository.go - Token is returned to the client for subsequent requests
- Future requests are authenticated via
auth_middleware.go
-
Database Access Flow:
- Service layer calls repository methods
- Repository uses generated sqlc code (created via
make sqlc) - SQL queries defined in
db/query/*.sqlfiles - Database migrations in
db/migrations/*.sql(managed withmake migrate-*commands) - Database can be seeded with test data using
make seed
-
Blockchain Interaction Flow:
- Service layer calls blockchain adapter methods
- Adapter uses generated Go bindings (created via
make gencontract) - Smart contracts (Payroll.sol, Invoice.sol) define on-chain logic
- Transactions are signed and submitted to the blockchain
- Events are monitored for transaction confirmation
Client Request → Router → Handler → Service → Repository → Database
↑ ↓ ↓ ↓
└─────────────────────┴─────────┴──────────┘
Response
- Go 1.21+
- Docker and Docker Compose
- PostgreSQL 14+
- Make
- Migrate CLI
-
Clone the repository:
git clone https://github.com/your-org/defifundr.git cd defifundr -
Install required development tools:
make install-toolsThis installs:
- air (for hot reloading)
- goose (for migrations)
- sqlc (for SQL code generation)
- mockgen (for test mocks)
- golangci-lint (for linting)
-
Start the development environment:
make docker-up -
Set up the database:
make postgres make createdb -
Run database migrations:
make migrate-up -
Generate SQL code:
make sqlc -
Start the API server (choose one):
make server # Standard mode make air # Hot reload mode -
Seed the database with test data (optional):
make seed
DefiFundr follows these coding standards:
-
Go Guidelines:
- Follow the Go Code Review Comments
- Use
gofmtfor code formatting - Run
make lintto ensure code quality - Maintain 80-100% test coverage for business logic
- Document all exported functions, types, and packages
-
Commit Messages:
- Follow the Conventional Commits specification
- Link to relevant issues where applicable
-
Error Handling:
- Use the custom
app_errorspackage for application errors - Provide meaningful error messages
- Ensure proper error propagation
- Use the custom
-
Testing:
- Write unit tests for business logic (run with
make test) - Write integration tests for external dependencies
- Use table-driven tests where appropriate
- Use mocks (generate with
make mock) for dependency isolation
- Write unit tests for business logic (run with
-
SQL & Database:
- Define queries in
db/query/*.sqlfiles - Generate Go code with
make sqlc - Create migrations with
make migrate-create - Test migrations with
make migrate-upandmake migrate-down
- Define queries in
-
Solidity & Smart Contracts:
- Follow Solidity best practices
- Regenerate Go bindings with
make gencontractafter contract changes
Before submitting a PR, ensure:
-
All unit tests pass:
make test -
Generate and update mocks if necessary:
make mock -
Run linting to check code quality:
make lint -
Ensure your code builds without errors:
make build
Please follow these steps for submitting contributions:
- Create a feature branch from
main - Implement your changes with appropriate tests
- Ensure all tests pass and code coverage requirements are met
- Update documentation as necessary
- Submit a pull request following our PR guidelines
For detailed guidance on creating and managing issues, please refer to our Issue and PR Guidelines.
We value comprehensive documentation:
-
Code Documentation:
- Document all exported functions, types, and packages
- Provide examples for complex functionality
- Update API documentation when endpoints change
-
Architecture Documentation:
- Update diagrams when architecture changes
- Document design decisions and trade-offs
- Maintain up-to-date data flow documentation
- Update database documentation:
make db_docs # Generate DB documentation make db_schema # Generate SQL schema from DBML - Update API documentation:
make swagger # Generate Swagger documentation
By contributing to DefiFundr, you agree that your contributions will be licensed under the project's license.
DefiFundr provides a comprehensive set of Makefile commands to streamline development. You can see all available commands with:
make help
make docker-up- Start all Docker containersmake docker-down- Stop and remove all Docker containersmake docker-logs- View logs from all Docker containersmake docker-ps- List running Docker containersmake docker-build- Rebuild Docker imagesmake docker-restart- Restart all Docker containers
make postgres- Run PostgreSQL containermake createdb- Create databasemake dropdb- Drop databasemake dockerlogs- View PostgreSQL container logs
make migrate-create- Create a new migration filemake migrate-up- Run all pending migrationsmake migrate-down- Revert the last migrationmake migrate-status- Show migration statusmake migrate-reset- Revert all migrations
make sqlc- Generate SQL code with sqlcmake mock- Generate mock code for testingmake server- Run the API servermake air- Run the server with hot reloadmake test- Run testsmake lint- Run lintersmake build- Build the applicationmake clean- Clean build artifactsmake seed- Seed the database with test data
make gencontract- Generate Go bindings for smart contracts
make db_docs- Generate DB documentation with dbdocsmake db_schema- Generate SQL schema from DBMLmake swagger- Generate Swagger documentation
If you have questions about contributing, please:
- Run
make helpto see available commands - Check existing documentation
- Open a discussion on GitHub
- Reach out to project maintainers
Thank you for contributing to DefiFundr!