A backend for Papagei — a spaced-repetition flashcard service for language learning.
The repository contains a Kotlin + Ktor HTTP API (with WebSocket support) backed by PostgreSQL and using Exposed as the database toolkit.
- Language & framework: Kotlin, Ktor
- Design patterns: Clean architecture, RESTful API
- Storage: PostgreSQL (incl. automatic. DB schema migrations)
- Authentication:
- JWT-based API keys (strong & regular)
- Session-based user authentication
- CRUD operations for collections, cards and examples
- WebSocket API for spaced-repetition card answering
- API docs: OpenAPI + Swagger UI available at
/docs - Testing: JUnit (coverage >85%)
- Automation:
- Docker Compose config files for testing and deployment
- GitHub Actions workflows for testing and version control
Run the tests (Linux/MacOS)
- Open the
env/test.envfile. Set the value of variableDB_HOSTtolocalhost.
DB_HOST=localhost
- Start the PostgreSQL container via Docker with the
env/test.envfile.
docker run -d \
--name papagei-test-db \
-p 5432:5432 \
--env-file ./env/test.env \
postgres:18-alpine3.23- Run the application with the environment variables:
(set -a && source ./env/test.env && set +a && ./gradlew :test)Run the server (Linux/MacOS)
-
Navigate to the
envdirectory and create a new fileprod.env. -
Copy all of the contents from the
prod.env.examplefile and paste them into theprod.envfile.
JWT_SECRET=
PEPPER=
PORT=
DB_HOST=
DB_PORT=
DB_NAME=
DB_USER=
DB_PASSWORD=
POSTGRES_DB=
POSTGRES_USER=
POSTGRES_PASSWORD=
- Assign values to variables by analogy with the
test.envfile. Set the value for theDB_HOSTvariable tolocalhostandDB_PORTto5432. Other values should be different and unique.
[!WARNING] The values of the variables in this file must be kept strictly confidential. They must differ from the values of the variables in the
test.envfile and be difficult to guess.
-
Navigate back to the root of the project.
-
Start the PostgreSQL container via Docker with the
env/prod.envfile.
docker run -d \
--restart always \
--name papagei-prod-db \
-p 5432:5432 \
--env-file ./env/prod.env \
-v papagei_prod_db:/var/lib/postgresql/data \
postgres:18-alpine3.23- Run the application with the environment variables:
(set -a && source ./env/prod.env && set +a && ./gradlew :run)- Check if the server is working and accepting requests. Follow the link http://127.0.0.1:8080/docs. This should take you to a page with the API specification, which looks like this.
Run the tests (Linux/MacOS)
- Open the
env/test.envfile. Set the value of variableDB_HOSTtopapagei-test-db.
DB_HOST=papagei-test-db
- Start the PostgreSQL and backend containers via Docker Compose.
docker compose -f ./compose/docker-compose.test.yaml up \
--build \
--abort-on-container-exitRun the server (Linux/MacOS)
-
Navigate to the
envdirectory and create a new fileprod.env. -
Copy all of the contents from the
prod.env.examplefile and paste them into theprod.envfile.
JWT_SECRET=
PEPPER=
PORT=
DB_HOST=
DB_PORT=
DB_NAME=
DB_USER=
DB_PASSWORD=
POSTGRES_DB=
POSTGRES_USER=
POSTGRES_PASSWORD=
- Assign values to variables by analogy with the
test.envfile. Set the value for theDB_HOSTvariable tolocalhostandDB_PORTto5432. Other values should be different and unique.
[!WARNING] The values of the variables in this file must be kept strictly confidential. They must differ from the values of the variables in the
test.envfile and be difficult to guess.
-
Navigate back to the root of the project.
-
Start the PostgreSQL and backend containers via Docker Compose.
docker compose -f ./compose/docker-compose.prod.yaml up --build- Check if the server is working and accepting requests. Follow the link http://127.0.0.1:8080/docs. This should take you to a page with the API specification, which looks like this.
- Follow existing code patterns (Kotlin + Ktor idioms)
- Add SQL migration scripts to
migrations/when DB schema changes; name them with a prefix likeV02__...sql. - Add tests for new features and test locally.
- Open PRs targeting
mainand ensure CI checks pass.
This project is licensed under the Apache 2.0 License — see the LICENSE file.
