Skip to main content

Developer Guide: Contributing to Ciyex

· 6 min read
Siva (Lead Dev)
Lead Architect

Contributing to healthcare software is one of the most meaningful things a developer can do. Every bug fix, every performance improvement, every accessibility enhancement directly impacts patient care. This guide walks you through setting up a Ciyex development environment, understanding the project structure, and making your first contribution.

Prerequisites

Before you begin, ensure you have the following installed:

  • Java 21 (we recommend Eclipse Temurin)
  • Gradle 8.x (included via the Gradle Wrapper, so no separate install is needed)
  • Docker and Docker Compose for running PostgreSQL, Keycloak, and HAPI FHIR locally
  • Node.js 20+ and npm for the frontend (if contributing to the React UI)
  • Git for version control
  • A Java IDE such as IntelliJ IDEA (Community Edition is sufficient) or VS Code with Java extensions

Cloning and Project Structure

Start by cloning the repository:

git clone https://github.com/ciyex-org/ciyex.git
cd ciyex

The monorepo is organized as follows:

ciyex/
ciyex-api/ # Spring Boot backend (Java 21)
ehr-ui/ # React frontend (TypeScript)
ciyex-hapi-fhir/ # Custom HAPI FHIR server with interceptors
ciyex-codes/ # Medical code reference service (ICD-10, CPT, etc.)
marketplace/ # Ciyex Hub app marketplace service
telehealth/ # Jitsi-based telehealth service
ciyex-files/ # File storage service (Vaultik)
k8s/ # Kubernetes manifests
.github/workflows/ # CI/CD pipelines

Each service is a standalone Gradle project with its own build.gradle, database migrations, and Docker configuration.

Starting the Development Environment

The fastest way to get a working environment is Docker Compose, which starts all required infrastructure services:

docker compose -f docker-compose.dev.yml up -d

This starts:

  • PostgreSQL 17 on port 5432 with the required databases pre-created
  • Keycloak on port 8180 with a pre-configured realm, test users, and client registrations
  • HAPI FHIR on port 8082 with partitioned multi-tenancy enabled

Once infrastructure is running, start the API server:

cd ciyex-api
./gradlew bootRun

The API server starts on port 8080. On first boot, Flyway runs all database migrations automatically, creating tables, seed data, and permission configurations.

Environment Configuration

The backend reads configuration from a .env file in the service root directory. Create one based on the provided template:

cp .env.example .env

Key variables include:

# Database
SPRING_DATASOURCE_URL=jdbc:postgresql://localhost:5432/ciyex
SPRING_DATASOURCE_USERNAME=postgres
SPRING_DATASOURCE_PASSWORD=postgres

# Keycloak
SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_ISSUER_URI=http://localhost:8180/realms/ciyex

# FHIR Server
FHIR_SERVER_URL=http://localhost:8082/fhir

# Config Server (optional for local dev)
SPRING_CLOUD_CONFIG_ENABLED=false

In production, these values come from Spring Cloud Config Server backed by HashiCorp Vault. For local development, the .env file provides everything needed.

Database Migrations with Flyway

All schema changes are managed through Flyway versioned migrations. Migration files live in src/main/resources/db/migration/ and follow the naming convention:

V1__initial_schema.sql
V2__add_role_permissions.sql
V46__add_app_installations.sql

Migrations run automatically on application startup. To add a new migration:

  1. Find the highest existing version number (e.g., V46)
  2. Create a new file with the next number: V47__your_description.sql
  3. Write your SQL (CREATE TABLE, ALTER TABLE, INSERT seed data, etc.)
  4. Restart the application. Flyway detects and applies the new migration.

Important: Never modify an existing migration file after it has been merged. Flyway checksums each migration. If the checksum changes, the application will fail to start. If you need to change something, create a new migration.

For complex data loading (parsing CSV files, generating reference data), Ciyex also supports Java-based Flyway migrations in the db.migration package:

public class V3__LoadICD10Codes extends BaseJavaMigration {
@Override
public void migrate(Context context) throws Exception {
// Parse ICD10_2026.csv and insert 98,000 codes
}
}

Keycloak Realm Configuration

The development Docker Compose includes a pre-configured Keycloak realm with test users for multiple organizations:

UsernameOrganizationRole
michael.chenSunrise Family MedicineADMIN
dr.sarah.williamsSunrise Family MedicinePROVIDER
nurse.johnsonSunrise Family MedicineNURSE
david.thompsonLakeside PediatricsADMIN
dr.robert.garciaLakeside PediatricsPROVIDER

All test users share the same password. The realm export file is located in docker/keycloak/realm-export.json and is automatically imported when the Keycloak container starts.

Understanding the Generic FHIR Resource Pattern

Ciyex uses a metadata-driven architecture for clinical data. Instead of creating custom controllers and DTOs for each resource type (PracticeController, VitalsController, etc.), all FHIR resources flow through a single generic path:

// One controller handles ALL resource types
@GetMapping("/api/fhir-resource/{tabKey}/patient/{patientId}")
public ResponseEntity<?> getPatientResources(
@PathVariable String tabKey,
@PathVariable String patientId
) {
// tabKey = "vitals", "conditions", "medications", etc.
// Field mappings come from tab_field_config table
}

The tab_field_config table defines what fields each resource type has, how form fields map to FHIR paths, and what options are available in dropdowns. Adding a new clinical form is a database insert, not a code change.

Running Tests

# Run all tests
./gradlew test

# Run a specific test class
./gradlew test --tests "org.ciyex.api.service.GenericFhirResourceServiceTest"

# Run with test coverage report
./gradlew test jacocoTestReport

Tests use an embedded H2 database and WireMock for FHIR server interactions, so no external services are needed to run the test suite.

Making Your First Contribution

1. Find an Issue

Browse the GitHub Issues page. Issues labeled good-first-issue are specifically chosen for new contributors. Common categories include:

  • Frontend components: Building React UI components with TypeScript and Tailwind CSS
  • FHIR mappings: Adding new resource type support to the generic mapper
  • Accessibility: Ensuring clinical interfaces meet WCAG 2.1 AA standards
  • Documentation: Translating docs, writing tutorials, improving API documentation
  • Medical code data: Adding or correcting ICD-10, SNOMED CT, or LOINC mappings

2. Create a Branch

git checkout -b feature/your-feature-name

3. Make Your Changes

Follow the existing code patterns. Key conventions:

  • Use the existing GenericFhirResourceService for new clinical data, not custom services
  • Add UI configuration through tab_field_config migrations, not hardcoded constants
  • Keep field options, dropdown values, and display labels in the database, not in React components
  • Write tests for any new service methods

4. Submit a Pull Request

git push origin feature/your-feature-name

Open a pull request against the main branch. The PR template will guide you through describing your changes, linking to the related issue, and confirming that tests pass.

GitHub Actions will automatically:

  • Run the full test suite
  • Check code formatting
  • Build the Docker image to verify the build succeeds
  • Post the results on your PR

Code of Conduct

Ciyex is a healthcare project. The people who use our software are caring for patients. We hold our community to a high standard of professionalism, inclusivity, and respect. Please read our Code of Conduct before contributing.

Where to Get Help

  • GitHub Discussions: For questions about architecture, design decisions, or implementation approaches
  • Issue comments: For questions specific to a particular task
  • Documentation site: docs.ciyex.org for architecture guides and API references

Every contribution matters. A typo fix in the documentation, a CSS adjustment for better readability, a test case that catches an edge case. All of it improves the software that clinics depend on to care for their patients. Welcome to Ciyex.