Harmonia is an instructor-facing application designed to provide transparent, data-driven insights into how student teams collaborate on programming assignments. It analyzes Git repositories to compute metrics, visualize evidence, detect anomalies, and generate short written summaries — helping instructors understand team dynamics at a glance.
Harmonia serves as a decision support system by automatically analyzing Git repository activity for student teams and computing a quantifiable Collaboration Quality Index (CQI). The tool centralizes all collaboration evidence and metrics into a single platform, enabling course staff to ensure fair and evidence-based assessment of teamwork.
-
On-Demand Analysis: Instructors can trigger a new analysis job course-wide or per-team, with a high-performance
target completion time of
$\sim 15$ minutes for typical course sizes ($\sim 200$ teams). -
Teams Overview Table: A sortable and filterable dashboard of all teams, featuring key metrics:
- Course Averages are prominently displayed to provide context for team-specific scores.
- Quantitative data like Total Commits, Lines Written, and Team Members.
- Collaboration Quality Index (CQI) (0-100 score).
-
Team Detail View: An in-depth page providing comprehensive collaboration evidence, including:
- The final CQI and all contributing sub-scores.
- A concise, AI-generated Short Narrative Report summarizing activity and referencing key commits.
Harmonia is built as a Java/Spring-based monolith, prioritizing stability and job orchestration performance.
| Component | Technology |
|---|---|
| Client | React 19.2 + TypeScript |
| Server | Spring Boot (Jave) |
| Database | PostgreSQL 18 with Hibernate |
| AI | Spring AI (OpenAI) |
Use the provided startup scripts for an automated setup:
macOS/Linux:
./scripts/docker_start.shWindows (PowerShell):
.\scripts\docker_start.ps1 The scripts will:
- Check if Docker is running
- Clean up any existing containers
- Build and start all services (database, server, client)
- Wait for services to be ready
- Display access URLs and helpful commands
Alternatively, you can manually build and launch everything:
-
Build and launch:
docker compose -f docker/docker-compose.yml up --build
-
Access the services:
- Client (served by nginx): http://localhost:5173
- Spring Boot server: http://localhost:8080
- PostgreSQL: localhost:5432 (user
postgres, passwordharmonia)
The Compose setup builds the Gradle boot jar inside docker/server.Dockerfile, bundles the React client with Vite via
docker/client.Dockerfile, and proxies /api + /actuator calls from nginx to the server container. All images
restart automatically unless stopped.
If you only need the database for local development you can start just the PostgreSQL service:
docker compose -f docker/docker-compose.yml up -d postgresThe application uses Gradle for dependency management and building. Assuming you have Java 25 installed, use the following commands to build and run the server locally:
-
Make sure to run the Docker container.
-
Build the Project: Compile the server application.
./gradlew clean build -x test -
Run the Server: Start the Spring Boot application.
./gradlew bootRun
Harmonia uses SpringDoc to automatically generate an OpenAPI 3.0 specification, which is then used to generate a fully typed React client (TypeScript + Axios).
Whenever you update server-side code (controllers, DTOs, response models, etc.), you must regenerate:
- The OpenAPI YAML file
- The React service code
⸻
Run the following command to start the application in the special openapi profile and produce the latest openapi.yaml file:
./gradlew generateApiDocs -x webapp --stacktraceThe generated file will be located at: ./openapi/openapi.yaml
Once the OpenAPI spec is updated, generate the React API services:
./gradlew openApiGenerateThis will generate fully typed API clients and models in:
./src/main/webapp/src/app/generated/
These files are overwritten each time you run the generator and should be committed to version control to keep client and server in sync.
- Merges Tailwind classes and resolves conflicts (e.g.,
px-2vs.px-4) - Needed for shadcn/ui components that combine base & conditional styles
- Example:
const classes = twMerge( "px-4 py-2 text-sm text-gray-500", // base styles isActive && "text-blue-600 font-bold" // conditional styles );
- Utility for conditional className construction
- Cleaner and more readable than manual string concatenation
