A backend API built with Play Framework and Slick, designed to manage employees and their contracts.
- Overview
- Run Locally
- Database Setup
- Config Overview
- API Endpoints
- What I Learned
- Future Improvements
- Author
This is a backend-only MVP for managing employees and their contracts.
Built with Scala, Play Framework, Slick, and MySQL.
Uses a clean structure with seeding logic triggered on startup.
- MySQL installed and running
- SBT installed → https://www.scala-sbt.org/download.html
git clone https://github.com/edpau/scl-employee-api.git
cd scl-employee-api
sbt runYou should see output like:
Runs on startup
Seeding succeeded
Make sure MySQL is running, then create the database:
CREATE DATABASE scl_employee_db
DEFAULT CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;This ensures support for all Unicode characters (e.g. emojis, multilingual text).
# DB config
slick.dbs.default.profile = "slick.jdbc.MySQLProfile$"
slick.dbs.default.db.driver = "com.mysql.cj.jdbc.Driver"
slick.dbs.default.db.url = "jdbc:mysql://localhost:3306/scl_employee_db?characterEncoding=UTF-8&useUnicode=true"
slick.dbs.default.db.user = "root"
slick.dbs.default.db.user = ${?DB_USER}
slick.dbs.default.db.password = ""
slick.dbs.default.db.password = ${?DB_PASSWORD}
# Evolutions
play.evolutions.db.default.autoApply = true
play.evolutions.enabled = true
# Application Secret
play.http.secret.key = "changeme"
play.http.secret.key = ${?APPLICATION_SECRET}
# --- Play Modules ---
play.modules.enabled += "Module"✅ This supports environment variable overrides — great for production.
Base URL: http://localhost:9000
| Method | Endpoint | Description |
|---|---|---|
| GET | /employees | Get all employees |
| GET | /employees/:id | Get a specific employee |
| POST | /employees | Create a new employee |
| PUT | /employees/:id | Update an employee |
| DELETE | /employees/:id | Delete an employee |
{
"firstName": "Peter",
"lastName": "Pan",
"email": "peter.pan@example.com",
"mobileNumber": "07123456789",
"address": "Neverland"
}{
"firstName": "Peter",
"lastName": "Pan",
"email": "peter.pan@example.com",
"mobileNumber": "07987654321",
"address": "London, UK"
}| Method | Endpoint | Description |
|---|---|---|
| GET | /contracts | Get all contracts |
| GET | /contracts/:id | Get a specific contract |
| POST | /contracts | Create a new contract |
| PUT | /contracts/:id | Update a contract |
| DELETE | /contracts/:id | Delete a contract |
{
"employeeId": 1,
"contractType": "Permanent",
"employmentType": "Full-time",
"startDate": "2023-08-01",
"endDate": null,
"hoursPerWeek": 40
}{
"employeeId": 1,
"contractType": "Fixed-term",
"employmentType": "Part-time",
"startDate": "2023-08-01",
"endDate": "2024-08-01",
"hoursPerWeek": 20
}For this learning project, id fields are defined as Int for simplicity and readability.
In production systems, Long (BIGINT) is typically used to support very large datasets and prevent overflow.
- How to structure a Play + Slick backend using domain-based layering
- How Play Evolutions version and manage schema changes
- How to implement startup seed logic using Guice and Play's lifecycle
- How to combine DTOs with custom insert projections in Slick
- How to securely configure Play with environment variable fallback
See full log → docs/DEVLOG.md
- Enum on Contract type
- Soft delete (archiving) for employees
- Add
fullNamefield toEmployeeAPI response - Role-based access control (admin vs. HR vs. viewer)