Kotlin + Spring Boot backend API for collaborative event scheduling.
Eventshuffle enables users to create events with possible dates, collect participant availability, and view the best matching dates, persisted using SQLite for durable storage.
Note:
This project was developed as a technical coding assignment for Futurice.
The original task description and API specifications are included inINSTRUCTIONS.md.
The following tools and versions are used during local development of the Eventshuffle project.
| Component | Version / Description |
|---|---|
| Language | Kotlin 1.9.25 |
| Framework | Spring Boot 3.5.6 |
| JDK | Java 21.0.8 (Temurin) |
| Build Tool | Gradle 8.14.3 (via included wrapper) |
| Database | SQLite 3 (driver: org.xerial:sqlite-jdbc:3.50.3.0) |
| ORM Dialect | Hibernate 6.6.26.Final (community dialects) |
To run Eventshuffle locally, you only need:
- Java 21 (JDK 21 or newer)
Everything else (Gradle, Kotlin compiler, and SQLite database) is handled automatically by the included Gradle wrapper.
Optional tools for development:
curlor Postman for testing API requests- IntelliJ IDEA / VS Code for Kotlin development
Clone and execute:
git clone https://github.com/TyostoKarry/Eventshuffle.git
cd Eventshuffle
./gradlew bootRunThis will start the backend at:
On first launch, a local SQLite database file eventshuffle.db is created automatically in the project root.
| Purpose | Method | Endpoint | Description |
|---|---|---|---|
| List all events | GET | /api/v1/event/list |
Returns all created events |
| Create event | POST | /api/v1/event |
Create a new event |
| Show event | GET | /api/v1/event/{id} |
Retrieve event details including votes |
| Add vote | POST | /api/v1/event/{id}/vote |
Submit participant votes |
| Get results | GET | /api/v1/event/{id}/results |
Return dates suitable for all participants |
Note:
The example curl commands below are provided in single‑line form for cross‑platform compatibility.
The accompanying JSON blocks illustrate the same request bodies for readability.
Endpoint: /api/v1/event/list
Method: GET
Body:
{
"events": [
{
"id": 1,
"name": "Jake's secret party"
},
{
"id": 2,
"name": "Bowling night"
},
{
"id": 3,
"name": "Tabletop gaming"
}
]
}curl -X GET http://localhost:8080/api/v1/event/listEndpoint: /api/v1/event
Method: POST
Body:
{
"name": "Jake's secret party",
"dates": ["2014-01-01", "2014-01-05", "2014-01-12"]
}Body:
{
"id": 1
}curl -X POST http://localhost:8080/api/v1/event -H "Content-Type: application/json" -d "{\"name\": \"Jake's secret party\", \"dates\": [\"2014-01-01\", \"2014-01-05\", \"2014-01-12\"]}"Endpoint: /api/v1/event/{id}
Method: GET
Parameters: id, long
Body:
{
"id": 1,
"name": "Jake's secret party",
"dates": ["2014-01-01", "2014-01-05", "2014-01-12"],
"votes": [
{
"date": "2014-01-01",
"people": ["John", "Julia", "Paul", "Daisy"]
}
]
}curl -X GET http://localhost:8080/api/v1/event/1Endpoint: /api/v1/event/{id}/vote
Method: POST
Parameters: id, long
Body:
{
"name": "Dick",
"votes": ["2014-01-01", "2014-01-05"]
}{
"id": 1,
"name": "Jake's secret party",
"dates": ["2014-01-01", "2014-01-05", "2014-01-12"],
"votes": [
{
"date": "2014-01-01",
"people": ["John", "Julia", "Paul", "Daisy", "Dick"]
},
{
"date": "2014-01-05",
"people": ["Dick"]
}
]
}curl -X POST http://localhost:8080/api/v1/event/1/vote -H "Content-Type: application/json" -d "{\"name\": \"Dick\", \"votes\": [\"2014-01-01\", \"2014-01-05\"]}"Endpoint: /api/v1/event/{id}/results
Responds with dates that are suitable for all participants.
Method: GET
Parameters: id, long
{
"id": 1,
"name": "Jake's secret party",
"suitableDates": [
{
"date": "2014-01-01",
"people": ["John", "Julia", "Paul", "Daisy", "Dick"]
}
]
}curl -X GET http://localhost:8080/api/v1/event/1/resultsEventshuffle uses SQLite with Spring Data JPA and Hibernate for persistence.
All data (events and event votes) is stored locally in eventshuffle.db inside the repository root.
The persistence model consists of two main entities:
- Event – represents an event with its name and possible dates.
- EventVote – represents a participant’s availability for selected event dates.
Each entity is automatically mapped by Hibernate into database tables
(event, event_dates, event_vote, and event_vote_dates),
and relationships are maintained via JPA annotations.
The database schema is generated automatically — no manual configuration is required.
Eventshuffle applies a layered architecture following
Controller → Service → Repository, promoting clear separation of concerns.
graph LR
Client[(API Client)] --> Controller
Controller --> Service
Service --> Repository
Repository --> SQLite[(SQLite Database)]
Each layer has distinct responsibilities:
- Controllers handle HTTP input/output and map domain objects to DTOs
- DTOs define the structure of client request and response models
- Services encapsulate business operations (e.g., saving events, handling votes)
- Repositories manage persistence with Spring Data JPA
While requests flow downward through these layers, responses propagate upward — from repository results back through the service and controller layers, returning API DTOs to the client.
Every pull request to the main branch is automatically verified by a GitHub Actions workflow defined in .github/workflows/verify-pr.yml.
The workflow performs the following checks:
- Validates the Gradle wrapper integrity
- Sets up JDK 21 using Temurin distribution
- Runs
ktlintCheckto ensure code style compliance - Runs all tests (
./gradlew test) - Builds the project (
./gradlew assemble)
This ensures that all pull requests are properly formatted, tested, and buildable before merging.
- Clean architecture following Controller → Service → Repository structure
- DTOs define stable API boundaries
- Exception handling centralized with
GlobalExceptionHandler - Modular design easily extendable for authentication or alternative databases
While the current implementation fully meets the functional requirements of the assignment, several enhancements could be introduced to evolve Eventshuffle into a more production-ready backend service.
-
Security and Authentication
Add basic authentication or API key–based access control to prevent unauthorized event creation or voting. -
Comprehensive KDoc and API Documentation
Expand KDoc throughout the codebase, particularly for DTOs and service methods, to ensure consistent documentation coverage.
Introduce automated API documentation generation with SpringDoc OpenAPI / Swagger UI. -
Integration and End‑to‑End Testing
Extend test suite with integration tests verifying full API workflows against the SQLite persistence layer. -
Deployment and Containerization
Package the service as a Docker image and define a lightweight compose setup to simplify local and production deployments. -
Frontend or API Client
Develop a minimal web or mobile client consuming the REST endpoints to demonstrate usability and user flow.