A simple personal task and todo manager.
To run the application locally copy env.sample
into .env
and add values for
blank variables, i.e secrets, and override any defaults you would like to
change and then run npm start
.
Please ensure that you have docker
installed and that there are no containers, either running or stopped, that have the same name or use the same ports as the database docker container.
cp env.sample .env
# add secrets and override defaults
npm install .
npm start
# on another terminal window
# to run tests
npm test
The service is documented using OpenAPI 3.1, and has a companion Postman collection which can also be used as API documentation. All of the data models are present in the OpenAPI spec. It is recommended that the OpenAPI schema and Postman collection are both imported into Postman and explored in the Postman app.
To import the specs into Postman (this assumes you already have a Postman account and have the app installed)
- Inside a workspace, create a new API, Just Task It.
- In that API, import
postman/schemas/just-task-it.openapi.yaml
. - Import a collection into the API from
postman/collections/just-task-it.postman_collection.json
.
Now you can explore the API documentation and schema of the service inside Postman.
If you wish to run API tests from Postman, then you should import the collection from postman/collections/api-tests.postman_collection.json
into Postman, along with the environment at postman/environments/api-tests.postman_environment.json
. Though this is not strictly necessary as these tests can also be run by the newman
cli as well. The npm run test-api
command runs these API tests using newman
under the hood.
Currently there is no CI environment setup for the application. And there are no list tests either. Both these need to be addressed.
There are two kinds of tests in the application
- unit tests: these are tests for the functional / non-side effect causing parts of the application that can be run independentally without needing to start the entire application.
- api tests: these test individual endpoints and their responses against the spec and are defined in a postman collection is run via newman.
A lot of end points have insufficient or non-existent validation. This was done due to time constraints and need to be addressed.
Postgres is the database used in the project, with Sequelize as the ORM. The database schema is available in db/schemas/jti-schema.sql
, and the ORM models inside src/models
.
The ORM is not used to create or update database schemas, and this is a deliberate choice. Having control of and visibility over the database schema is important, and is extremely useful when scaling - both for query performance and for sanely managing schema updates on large tables.
Another deliberate choice is to not use foreign keys to define relation ships between models in the database. These constraints can be managed on the application and reduces the headache of having to deal with FK contraints in future schema migrations.
One improvement for the future would be to wrap database calls within the same API in a transaction to make the operations atomic.
Right now todos are not paginated and that can lead to issues in the future. Pagination support needs to be added soon.
External integrations could not be worked on due to time constraints and are the next thing that will be worked on.
The integrations will sync todos created in the external services and not todos created in JTI. That is, any todo created in a 3rd party service will be synced into JTI and a two way sync for that todo will be maintained. However all todos created inside JTI will not be synced to 3rd party services.
To accomplish this, we will first need APIs to add / update / delete external intergrations, and data models to store them.
column | type | description |
---|---|---|
id | BIGSERIAL | This is the auto increment integer primary key of the table |
user | BIGINT | The id of the user who created the integration |
integration_name | VARCHAR(16) | The name of the integration or 3rd party |
webhook_identifier | VARCHAR(32) | A unique path parameter for the incomming webhook for the integration. |
data | TEXT | JSON data stored as a blob. This would consist of any data we need to connect with the integration, for example url, api key, user id, etc. |
Once a integration is successfully added, a incoming webhook will be enabled to allow the external service to sync updates to JTI.
To keep track of which todos are linked with 3rd party todos, we need to create a table that will store the link between them
column | type | description |
---|---|---|
id | BIGSERIAL | This is the auto increment integer primary key of the table |
integration_id | BIGINT | This stores the id of the integration |
external_todo_id | varchar(128) | This stores the id or primary key of the todo in the 3rd party service |
todo_id | BIGSERIAL | Todo id in JTI |
Additionally we need to create a unique constraint on (integration_id, external_to_id, task_id), and have an additional index on task_it.
With this done, we can
- Sync any updates made in JTI to todos with external integrations
- Receive notifications of updates to a todo in a 3rd party service via a webhook 2.1 Using the webhook id, we can get the integration id 2.2 From the external_todo_id present in the webhook data, we can get the JTI todo_id 2.3 Fetch the latest state of the todo from the external service 2.4 Update the todo in JTI