82 lines
3.3 KiB
Markdown
82 lines
3.3 KiB
Markdown
# 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
|
|
```mermaid
|
|
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
|