myfreight-assessment/README.md

3.3 KiB

MyFreight Assessment

How to run

Easiest way to run this project is using docker compose: docker compose up

It is possible that this will give some database connection issues on the first try, but after a couple of seconds, it should automatically reconnect.

Alternatively, it is possible to use your own mysql database, and run the code locally:

  1. Import the database/entrypoint/init.sql into your own database
  2. Update the .env file with the database credentials
  3. Run npm ci to install all npm packages
  4. Run npm run build to build the nestjs application
  5. Run npm run start:prod to start the nestjs application

After starting the application will run on http://localhost:3000/

Documentation

The full endpoint documentation can be found on http://localhost:3000/api. Here you can find which endpoints there are, and how to authenticate.

Authentication

For the Authentication I went with an base64 encoded authentication string consisting of 2 parts. The first part is the ApiKey, which is stored in the authentication database. The second part is a secret that is being used as a password.

In the database we have stored 2 values, the ApiKey and a digest. This digest is creating by using HMAC with the api secret as password, using a sha256 to hash the ApiKey.

This way there is no full api key stored in the database.

Demo example

In this demo you can use eG5nVnZGaWtCMFN6NjRRaWQ2TUJsUTJWaDpjeGg1R3FKRUl0UTlzSGRQdElGMGg0bFJp for the requests.

This decodes to xngVvFikB0Sz64Qid6MBlQ2Vh:cxh5GqJEItQ9sHdPtIF0h4lRi. The first part xngVvFikB0Sz64Qid6MBlQ2Vh is stored in the database, but the second part is not stored anywhere.

Receiving Tracking information

When receiving Tracking information, the following steps need to be completed to process the data

flowchart TD
    receiveTracking(["Receive Tracking"])
    findContainerAndShipment["SELECT container JOIN Shipment"]
    updateShipment[/Update shipment\]
    isArrivingSoon{{"Is arrival estimate between now and now + 24h?"}}
    hasArrived{{"Is arrival estimate <=now?"}}
    isDelayed{{Is arrival estimate > original arrival + 24h?}}
    sendNotification[/Send notification\]

    
    receiveTracking -- "`**Tracking data**
carrierName:**string**
destinationUnLoCode:**string**
departureDate:**string[_datetime_]**
arrivalDateEstimate:**string[_datetime_]**
containerNumber:**string**
`" -->  findContainerAndShipment
    findContainerAndShipment --> |WHERE containers.containerNumber = :trackingData.containerNumber| updateShipment
    updateShipment --> isArrivingSoon & hasArrived & isDelayed
    isDelayed -->|set delayed flag| sendNotification
    hasArrived  --> |set has arrived flag| sendNotification
    isArrivingSoon -->|set is arriving soon flag| sendNotification
    
%%    isArrivingSoon -->|yes| sendArriveSoon

Possible improvements

  • Sending the actual notification, there should be a more general way to setup notifiers
  • Moving some variables to config files
    • when is a shipment "arriving soon"
    • mock date
  • Use the uuid package
    • was not possible since the uuid's from the sample data were invalid uuid's
  • Add end-to-end tests as well
  • Get shipments should be paginated
    • Could use a package like typeorm-crud
  • Cleanup duplicate OpenApi decorators, perhaps consolidate them in a custom decorator