A simple guess the least unique positive integer number implementation.
The following components are needed for the fluent working environment.
- install docker: https://docs.docker.com/get-docker/
- install docker-compose: https://docs.docker.com/compose/install/
- install poetry (for development): https://python-poetry.org/docs/
Tested with the following versions:
- Python: 3.8.3
- Pip: 19.2.3
- Docker: 19.03.11 build 42e35e61f3
- Docker Compose: 1.26.0, build d4451659
- Linux/Mint/Ubuntu(18.04)
- Chrome: 83, Firefox: 77
The full environment is managed by docker compose it will spin up a database and the service too.
- Check the
example.env
file, create an.env
file based on that. (The database will be created with those values.) - Install the needed components in the prerequisites section.
make start-production
to start the application.- Reach the api on
localhost:APP_EXTERNAL_PORT
(APP_EXTERNAL_PORT is set up in the.env
file.) - Open
localhost:APP_EXTERNAL_PORT/game
in your borwser for the game. (Only latest Firefox and Chrome is supported.) - Test the proper setup:
curl localhost:APP_EXTERNAL_PORT/rounds
.{payload: []}
should be received.
- Check the logs:
make production-logs
- Stop the application:
make stop-production
Check the Makefile for available commands. Even if no Makefile is used, the general usage of the repo is documented there.
.env
file is used by the application "inside" and by the docker outside.
The package management is poetry, so the requirements.txt
is git ignored.
The dependencies are listed in the pyproject.toml
, the deep dependency tree is freezed in poetry.lock
. If a new dependency is added to the project, a lockfile should be updated with make update-dependencies
.
Hovewer when the app's container is built by docker, it uses the requriements.txt
, it is generated from the poetry.lock
with the make create-requirements-txt
. This makefile target is called automatically when
start-production targer is invoked.
The DB init sql is located in ./sql/init
. When first time the docker spin up the environment, all the sql scripts are executed from this location to the DB.
The data is persistent in a docker volume between the container restarts, however if the related docker volume is deleted, the data will be lost.
make install-dev
make run-dev-server
Currently only integration tests are available. The integration tests uses a real postgre db. They fill it with test data defined in the scripts, and remove the data after the test case is executed.
Test's environment variables are defined in the test.env
.
A running postgre instance is needed for the tests, and its settings
must match with the test.env
.
Two make targets optionally create the test server based on the test.env
file.
make start-dev-db
make stop-dev-db
To run the test
make run-tests
Some random test data found in ./sql/test_data.sql
. The init.sql
must be executed first.
The design decisions and a short REST API design document is in the design.md.
- Single Global Playground
- Trusted players (no registration)
- Explicit start of a round
- Within an active round:
- A user can add their number with a name as part of the game. The name is unique and cannot be reused in the round.
- All users vote is collected.
- Compete the Round, return roundID
- Round Results: winner, and the number
- Listing all rounds with IDs and start date, end date, number of participants
- Querying the results of any rounds including the most recent one: Winner and winning number
- Querying the statistics of any round: distribution of votes from 1 to the max number voted for in that round.
- create project skeleton
- create Flask skeleton
- basic development runtime env
- routes and blueprints
- config
- error handling
- input validation
- add integration tests
- database: postgresql
- create a running database
- integrate the db access to Flask
- create a data access layer
- develop a scheme
- create scheme sql
- create test data
- REST API
- design
-
HTTP GET /rounds
: list rounds -
HTTP POST /rounds
: create a new round -
HTTP POST or PUT /rounds/<id>/finish
: finish a given round -
HTTP POST /rounds/<id>/vote
: add a new vote to an active round -
HTTP GET /rounds/<id>
: get the one round document -
HTTP GET /rounds/<id>/stat
: get a stat document
- static file serving
- frontend
- deployment to production
The project was made for an exercise for a job interview. On the other hand, I wanted to make a Flask boilerplate for future use and also wanted to practice the SQL queries and REST API design.