Thank you for considering contributing to Connapse! This document provides guidelines and instructions for contributing to this project.
- 🐛 Report bugs - Found a bug? Open an issue!
- 💡 Suggest features - Have an idea? Start a discussion!
- 📖 Improve documentation - Fix typos, clarify explanations, add examples
- 🧪 Write tests - Increase test coverage, add edge cases
- 💻 Submit code - Fix bugs, implement features, refactor code
- 🎨 Improve UI/UX - Design improvements, accessibility fixes
- 🔍 Review pull requests - Help review code from other contributors
- Check existing issues and PRs to avoid duplicate work
- Read the Code of Conduct - we expect all contributors to be respectful
- Review the Architecture Guide - system design and component overview
- Read SECURITY.md - understand current security limitations
Before submitting a bug report:
- Search existing issues to see if it's already reported
- Test with the latest code on the
mainbranch - Check SECURITY.md - some limitations are known and documented
When submitting a bug report, include:
- Description: Clear, concise description of the bug
- Steps to reproduce: Numbered list to reproduce the issue
- Expected behavior: What you expected to happen
- Actual behavior: What actually happened
- Environment:
- OS (Windows, macOS, Linux + version)
- .NET version (
dotnet --version) - Docker version (
docker --version) - Browser (if UI-related)
- Logs: Relevant error messages or stack traces
- Screenshots: If applicable
Use this template:
### Description
[Brief description of the bug]
### Steps to Reproduce
1. [First step]
2. [Second step]
3. [...]
### Expected Behavior
[What should happen]
### Actual Behavior
[What actually happens]
### Environment
- OS: [e.g., Windows 11, Ubuntu 22.04]
- .NET: [e.g., 10.0.1]
- Docker: [e.g., 24.0.7]
- Browser: [e.g., Chrome 120, Firefox 121]
### Logs[Paste relevant logs here]
### Additional Context
[Any other information, screenshots, etc.]
Before suggesting a feature:
- Check existing discussions and issues
- Review the roadmap to see if it's already planned
- Consider whether it fits the project's scope and vision
When suggesting a feature:
- Use Case: Describe the problem this feature solves
- Proposed Solution: How you envision it working
- Alternatives: Other solutions you've considered
- Implementation Ideas: Technical approach (if you have thoughts)
- Willing to Implement: Let us know if you'd like to work on it!
Submit as a GitHub Discussion first, not an issue. This allows for community feedback before committing to implementation.
# 1. Fork the repository on GitHub
# 2. Clone your fork
git clone https://github.com/YOUR-USERNAME/Connapse.git
cd Connapse
# 3. Add upstream remote
git remote add upstream https://github.com/Destrayon/Connapse.git
# 4. Start backing services with dev overrides (exposes ports to host)
docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d
# 5. Build the solution
dotnet build
# 6. Run tests to ensure everything works
dotnet test
# 7. Run the web app
dotnet run --project src/Connapse.Web# Fetch upstream changes
git fetch upstream
# Merge upstream/main into your local main
git checkout main
git merge upstream/main
# Push to your fork
git push origin main# Always branch from main
git checkout main
git pull upstream main
# Create a descriptive branch name
git checkout -b feature/your-feature-name
# OR
git checkout -b fix/bug-descriptionBranch naming conventions:
feature/description- New featuresfix/description- Bug fixesdocs/description- Documentation changesrefactor/description- Code refactoringtest/description- Test additions/changes
Follow the code conventions below.
- All new features MUST have tests
- Bug fixes SHOULD include tests that prevent regression
- We use:
- xUnit for test framework
- FluentAssertions for assertions
- NSubstitute for mocking
- Testcontainers for integration tests
Test naming convention:
public void MethodName_Scenario_ExpectedResult()
{
// Arrange
var sut = new SystemUnderTest();
// Act
var result = sut.MethodName();
// Assert
result.Should().Be(expectedValue);
}# Run all tests
dotnet test
# Run just unit tests (fast)
dotnet test --filter "Category=Unit"
# Run just integration tests
dotnet test --filter "Category=Integration"
# Run tests with coverage
dotnet test --collect:"XPlat Code Coverage"All tests must pass before submitting a PR.
Commit message format:
<type>: <short summary> (max 72 chars)
<optional detailed explanation>
Co-Authored-By: Your Name <your.email@example.com>
Types:
feat:- New featurefix:- Bug fixdocs:- Documentation changestest:- Test additions/changesrefactor:- Code refactoringperf:- Performance improvementschore:- Maintenance tasks (dependencies, build config)
Examples:
git commit -m "feat: Add folder creation API endpoint"
git commit -m "fix: Handle null values in search results"
git commit -m "docs: Update API examples in README"
git commit -m "test: Add integration tests for container deletion"git push origin feature/your-feature-name- Go to github.com/Destrayon/Connapse
- Click "New Pull Request"
- Select your fork and branch
- Fill out the PR template:
## Description
[Brief description of changes]
## Related Issue
Fixes #[issue-number]
## Type of Change
- [ ] Bug fix (non-breaking change that fixes an issue)
- [ ] New feature (non-breaking change that adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to change)
- [ ] Documentation update
## Testing
- [ ] Unit tests added/updated
- [ ] Integration tests added/updated
- [ ] All tests pass locally
- [ ] Manual testing performed
## Checklist
- [ ] Code follows project conventions (see CLAUDE.md)
- [ ] Self-review completed
- [ ] Comments added for complex logic
- [ ] Documentation updated (if needed)
- [ ] No new warnings introduced
- [ ] Tested on local environment- A maintainer will review your PR
- Feedback may be provided via comments
- Make requested changes and push to your branch
- The PR will update automatically
- Once approved, a maintainer will merge your PR
Be patient and respectful during the review process.
- File-scoped namespaces:
namespace Connapse.Core;(notnamespace Connapse.Core { ... }) - Nullable enabled: All projects have
<Nullable>enable</Nullable> - Records for DTOs: Use
recordfor immutable data transfer objects - Primary constructors: Use where appropriate (classes with dependency injection)
- Async all the way: Never block with
.Resultor.Wait() - IOptions pattern: Use
IOptions<T>orIOptionsMonitor<T>for configuration
Example:
namespace Connapse.Core;
public class DocumentStore(IDbContextFactory<AppDbContext> contextFactory) : IDocumentStore
{
public async Task<Document?> FindAsync(Guid id, CancellationToken ct = default)
{
await using var context = await contextFactory.CreateDbContextAsync(ct);
return await context.Documents.FindAsync([id], ct);
}
}- Interactive Server mode: For real-time features
- Inject services: Use
@injectdirective, not constructor injection - Keep components thin: Extract logic to services
- Component naming: PascalCase, descriptive (e.g.,
FileUploadDialog.razor)
- Framework: xUnit
- Assertions: FluentAssertions (
.Should()syntax) - Mocking: NSubstitute
- Naming:
MethodName_Scenario_ExpectedResult - Categorize tests:
[Trait("Category", "Unit")]for unit tests[Trait("Category", "Integration")]for integration tests
Example:
[Fact]
[Trait("Category", "Unit")]
public void ParseDocument_WithPdfFile_ReturnsTextContent()
{
// Arrange
var parser = new PdfParser();
var pdfBytes = TestHelpers.GetSamplePdf();
// Act
var result = parser.Parse(pdfBytes);
// Assert
result.Should().NotBeNull();
result.Text.Should().Contain("expected content");
}- EF Core: Use
DbContextwith dependency injection - Migrations: Create migrations for schema changes:
dotnet ef migrations add MigrationName - Parameterized queries: Always use parameters, never string interpolation
- Async queries: Use
ToListAsync(),FirstOrDefaultAsync(), etc.
- Minimal APIs: Use
MapGet,MapPost, etc. inProgram.csor endpoint extensions - Validation: Validate inputs and return
Results.ValidationProblem()on failure - Error handling: Use
Results.Problem()for 500 errors - DTOs: Use records for request/response objects
- Naming: RESTful conventions (
GET /api/containers,POST /api/containers/{id}/files)
- Code comments: Add XML documentation comments (
///) for public APIs - Complex logic: Explain "why", not "what" in code comments
- README updates: Update README if you change functionality or add features
- API docs: Update
docs/api.mdif you change API endpoints - Architecture docs: Update
docs/architecture.mdif you change system design
- ❌ Don't commit secrets (API keys, passwords, etc.)
- ❌ Don't commit large files (>5 MB)
- ❌ Don't use
dynamickeyword - ❌ Don't use
varfor primitive types (useint,string, etc.) - ❌ Don't block async code with
.Resultor.Wait() - ❌ Don't share
DbContextacross threads/requests - ❌ Don't submit PRs with failing tests
- ❌ Don't include unrelated changes in a single PR
We use these labels to categorize issues:
bug- Something isn't workingfeature- New feature requestdocumentation- Documentation improvementsgood-first-issue- Good for newcomershelp-wanted- Extra attention neededsecurity- Security-related issueperformance- Performance improvementquestion- Question or discussionwontfix- This will not be worked onduplicate- This issue already exists
New to the project? Look for issues labeled good-first-issue. These are small, well-defined tasks perfect for getting started.
- 📖 Read the Architecture Guide for system design and conventions
- 💡 Start a GitHub Discussion
- 🐛 Open an issue if you're stuck
By contributing, you agree that your contributions will be licensed under the MIT License.
Thank you for contributing to Connapse! 🎉