Development workflow
1. Start the server locally
Before making changes, ensure the server runs locally:2. Create a new branch
feature/- New featuresfix/- Bug fixesrefactor/- Code refactoringdocs/- Documentation changes
3. Write tests first (TDD approach)
Before implementing your feature, write tests that define the expected behavior.Add integration tests
Create or update test files intests/integration/:
Run tests (they should fail)
4. Implement the feature
Now implement the actual feature to make the tests pass.Example: Adding a new endpoint
Step 1: Define the DTO (Data Transfer Object) Createinternal/your_feature/dto/your_dto.go:
internal/your_feature/handler.go:
internal/your_feature/routes.go:
cmd/serve.go:
5. Run tests again (they should pass)
6. Make SQL changes (if needed)
If your feature requires database changes, follow the Working with SQL guide: Step 1: Update schema Editdatabase/schema.sql:
internal/your_feature/sql/queries.sql:
7. Create error handlers (if needed)
Createinternal/your_feature/handler_errors.go:
8. Commit your changes
Lefthook will automatically run pre-commit checks:- goimports: Formats your code
- golangci-lint: Lints your code
9. Push and create a pull request
main.
Pull request checks
When you create a PR, the following checks run automatically:| Check | Description | Must pass |
|---|---|---|
| Go Lint | Code quality and style checks | ✅ Yes |
| Go Format | Code formatting with goimports | ✅ Yes |
| Check Build | Ensures code compiles | ✅ Yes |
| Sqlc Lint | SQL query validation | ✅ Yes |
| Migrations Lint | Database migration validation | ✅ Yes |
| Integration Tests | Full integration test suite | ✅ Yes |
Common check failures
Migrations Lint fails
Error: “Missing schema migration” Fix: You modifieddatabase/schema.sql but didn’t create a migration:
Integration Tests fail
Error: Test failures in CI Fix: Run tests locally to debug:Merging your PR
Once all checks pass and your PR is approved:- Squash and merge (preferred) - Combines all commits into one
- Merge commit - Keeps all commits separate
- Rebase and merge - Replays commits on top of main
main does NOT deploy anything. It only updates the main branch.
Deployment
After your PR is merged, you need to create a release to deploy:Deploy to staging
- Go to Releases → Create a new release
- Tag:
v0.1.0-rc.1(increment version) - Check: Set as a pre-release
- Click: Publish release
- Build Docker image
- Push to ECR
- Deploy to staging ECS
- Run database migrations
- Run smoke tests
Deploy to production
- Go to the staging release
- Click: Edit release
- Check: Set as the latest release
- Uncheck: Set as a pre-release
- Click: Update release
Git hooks with Lefthook
Lefthook automatically runs checks before commits and pushes:Pre-commit hooks
- goimports-fix: Automatically formats staged Go files
- goimports-check: Verifies all files are formatted
- go-lint: Runs golangci-lint
Pre-push hooks
- go-build: Ensures code compiles
Best practices
Code style
- Follow Go conventions (Lefthook enforces this)
- Use meaningful variable names
- Add comments for complex logic
- Keep functions small and focused
Testing
- Write tests before implementation (TDD)
- Test both success and error cases
- Use table-driven tests for multiple scenarios
- Prioritize integration tests over unit tests
Database
- Always create migrations for schema changes
- Never modify existing migrations
- Test migrations on a local database first
- Use transactions for data consistency
Security
- Validate all input
- Use parameterized queries (sqlc does this automatically)
- Never log sensitive data (passwords, API keys)
- Follow principle of least privilege for API keys
Getting help
- Questions: Ask in the team Slack channel
- Bugs: Create a GitHub issue
- Documentation: Check this documentation or the infrastructure README