Thank you for your interest in contributing to Codeagogo! This document provides guidelines and information for contributors.
- Code of Conduct
- Getting Started
- Development Setup
- Making Changes
- Code Style
- Testing
- Submitting Changes
- Reporting Issues
This project follows the Contributor Covenant Code of Conduct. Please be respectful and constructive in all interactions.
- macOS 13+ (Ventura or later)
- Xcode 15+ with Swift 5.9+
- Git
- Basic familiarity with SwiftUI and macOS development
Before contributing, familiarize yourself with:
- README.md — Project overview and features
- ARCHITECTURE.md — Technical design and component responsibilities
- PRIVACY.md — Privacy considerations and constraints
# Fork the repository on GitHub, then clone your fork
git clone https://github.com/YOUR_USERNAME/codeagogo.git
cd "codeagogo/Codeagogo"open "Codeagogo.xcodeproj"- Open the project settings
- Select the "Codeagogo" target
- Under "Signing & Capabilities", select your development team
The ECL functionality uses @aehrc/ecl-core bundled as JavaScript. The committed ecl-core-bundle.js works out of the box. To update ecl-core after a new release:
cd scripts
npm install
node bundle-ecl-core.mjsThe scheme pre-build action runs this automatically if Node.js is installed.
When running the app:
- Grant Accessibility permission when prompted
- If selection capture fails, re-add the app in System Settings → Privacy & Security → Accessibility
# Build the project
xcodebuild build -scheme "Codeagogo" -destination "platform=macOS"
# Run all tests
xcodebuild test -scheme "Codeagogo" -destination "platform=macOS"Use descriptive branch names:
feature/— New features (e.g.,feature/batch-lookup)fix/— Bug fixes (e.g.,fix/cache-expiration)docs/— Documentation changes (e.g.,docs/api-reference)refactor/— Code refactoring (e.g.,refactor/extract-fhir-parser)test/— Test additions or improvements (e.g.,test/edge-cases)
Write clear, descriptive commit messages:
<type>: <short summary>
<optional longer description>
<optional footer>
Types:
feat— New featurefix— Bug fixdocs— Documentationrefactor— Code refactoringtest— Test changeschore— Build, CI, or tooling changes
Examples:
feat: add batch concept lookup support
Allows users to look up multiple concept IDs at once by selecting
a comma-separated list. Results are displayed in a scrollable list.
Closes #42
fix: correct cache TTL calculation
The cache was using creation time instead of last access time for
TTL checks, causing premature cache misses.
Follow the Swift API Design Guidelines:
- Use clear, descriptive names
- Prefer clarity over brevity
- Use camelCase for functions and properties
- Use PascalCase for types and protocols
Add documentation comments for:
- All public types, methods, and properties
- Complex private implementations
- Non-obvious logic
/// Looks up a SNOMED CT concept by its identifier.
///
/// This method first checks the cache, then queries the FHIR server
/// if the concept is not cached or has expired.
///
/// - Parameter conceptId: The SNOMED CT concept identifier (6-18 digits)
/// - Returns: The concept result containing FSN, PT, and status
/// - Throws: `OntoserverError.conceptNotFound` if the concept doesn't exist
/// in any available edition
func lookup(conceptId: String) async throws -> ConceptResultUse MARK comments to organize code:
// MARK: - Properties
// MARK: - Initialization
// MARK: - Public Methods
// MARK: - Private Methods
// MARK: - Helper Types- Extract reusable views into separate types
- Use
@StateObjectfor owned objects,@ObservedObjectfor passed objects - Add accessibility labels and hints to interactive elements
- Keep views focused on a single responsibility
- Use typed errors with
LocalizedErrorconformance - Provide descriptive error messages
- Handle errors gracefully in the UI
enum MyError: LocalizedError {
case invalidInput(String)
var errorDescription: String? {
switch self {
case .invalidInput(let details):
return "Invalid input: \(details)"
}
}
}Tests are organized into three tiers using Xcode Test Plans:
| Tier | Test Plan | Scope | When to Run |
|---|---|---|---|
| 1 — Unit | Codeagogo-Unit |
Pure logic tests, no network or GUI | Every commit, CI |
| 2 — Integration | Codeagogo-Integration |
Real network calls to Ontoserver | Nightly / on-demand |
| 3 — UI | Codeagogo-UI |
XCUITest for Settings and MenuBar | Pre-release / manual |
# Run unit tests (default for development)
xcodebuild test -scheme "Codeagogo" -testPlan "Codeagogo-Unit" \
-destination "platform=macOS"
# Run integration tests (requires network access to Ontoserver)
xcodebuild test -scheme "Codeagogo" -testPlan "Codeagogo-Integration" \
-destination "platform=macOS"
# Run UI tests (requires GUI session)
xcodebuild test -scheme "Codeagogo" -testPlan "Codeagogo-UI" \
-destination "platform=macOS"
# Run specific test class
xcodebuild test -scheme "Codeagogo" -destination "platform=macOS" \
-only-testing:"CodeagogoTests/ConceptCacheTests"
# Run with code coverage
xcodebuild test -scheme "Codeagogo" -testPlan "Codeagogo-Unit" \
-destination "platform=macOS" -enableCodeCoverage YES- Add tests for new functionality
- Update tests when modifying existing behavior
- Use descriptive test method names following
test<Unit>_<scenario>_<expected>convention - Place view data model tests in
CodeagogoTests/ViewTests/
func testLookupReturnsConceptFromCache() async {
// Arrange
let cache = TestableConceptCache()
await cache.set("123456", result: mockConcept)
// Act
let result = await cache.get("123456", ttl: 3600)
// Assert
XCTAssertNotNil(result)
XCTAssertEqual(result?.conceptId, "123456")
}| Area | Tests | What's Covered |
|---|---|---|
| Concept extraction | ConceptIdExtractionTests |
Regex extraction, SCTID validation |
| Caching | ConceptCacheTests |
TTL, LRU eviction, thread safety |
| FHIR client | OntoserverClientTests |
Response parsing, errors, retry, multi-system |
| ECL | ECLFormatterTests |
Lexer, parser, formatter, minifier |
| Diagram rendering | DiagramRendererUnitTests |
SVG generation, normal form, text wrap |
| Lookup | LookupViewModelTests |
ID extraction, lookup coordination |
| Visualization | VisualizationViewModelTests, VisualizationModelsTests |
Property loading, data models |
| Settings | HotKeySettingsTests, FHIROptionsTests |
Hotkey config, FHIR endpoint config |
| Views | ViewTests/ (4 files) |
Data models driving view display logic |
| Settings UI | SettingsViewTests |
SwiftUI view inspection via ViewInspector |
- ViewInspector (MIT, test target only) — Used for headless SwiftUI view testing of
SettingsView
Target meaningful coverage of:
- Core business logic (FHIR parsing, concept extraction, ECL)
- Error handling paths
- Edge cases and boundary conditions
- Data models that drive view display
Current coverage: ~54% overall, with key modules at 75–90%.
Due to a Swift concurrency back-deploy runtime issue, creating LookupViewModel, SearchViewModel, or VisualizationViewModel in new test source files triggers a malloc crash. Existing test files are unaffected. New view tests should test data models (e.g., ConceptResult, SearchResult, VisualizationData) directly rather than instantiating these view models.
-
Ensure all unit tests pass
xcodebuild test -scheme "Codeagogo" -testPlan "Codeagogo-Unit" \ -destination "platform=macOS"
-
Verify no compiler warnings
xcodebuild build -scheme "Codeagogo" -destination "platform=macOS" 2>&1 | grep warning
-
Update documentation if needed
- README.md for user-facing changes
- ARCHITECTURE.md for design changes
- CHANGELOG.md for all notable changes
-
Add or update tests for your changes
-
Create a pull request from your feature branch to
main -
Fill out the PR template with:
- Description of changes
- Related issue numbers
- Testing performed
- Screenshots (for UI changes)
-
Address review feedback promptly
-
Squash commits if requested, keeping a clean history
Use the same format as commit messages:
feat: add batch concept lookup support
fix: correct cache TTL calculation
docs: update API documentation
Include:
- macOS version
- App version
- Steps to reproduce
- Expected vs actual behavior
- Relevant logs (use Cmd+Shift+D to copy diagnostics)
Include:
- Use case description
- Proposed solution
- Alternative approaches considered
- Impact on existing functionality
For security vulnerabilities, please follow the process described in SECURITY.md.
All Swift source files must include the Apache 2.0 license header. Run ./scripts/license-header.sh --check to verify, or ./scripts/license-header.sh --apply to add missing headers automatically.
If you have questions about contributing, feel free to:
- Open a discussion on GitHub
- Review existing issues and pull requests
- Check the documentation
Thank you for contributing to Codeagogo!