To run the entire project, execute docker-compose up -d. This will start the backend, frontend, and database. The compose file also contains a test database which can be commented out if you don't plan on running any tests locally.
WARNING: sometimes, it takes a while for everything to get started even after the containers load. So if the frontend loaded but is showing errors, show it some patience and reload after 30 seconds or so :).
This project has a Gitlab CI pipeline that contains the following stages:
- Build
- Test
- Deploy
The build stage builds both frontend and backend. The test stage runs automated jest tests on the backend as well as a linter (for both backend and frontend) to ensure the code adheres to predefined coding standards and to catch potential errors or bugs. If the pipeline is being run on the main branch, the backend and frontend are then built and pushed as separate images to Docker hub to my personal repository.
This section contains information about the backend part of the project.
The backend allows CRUD operations on the following endpoints:
/journeys: Journeys (Reisen) are containers for planned travel destinations (Reiseziele). They can be searched for by ID, name, start date, or end date./travel-destinations: Travel destinations (Reiseziele) represent the travel destinations that one wants to undertake during a journey./locations: Locations contain the exact location of a travel destination (e.g. if it's a specific park). This is an optional attribute of a travel destination. Only one location per travel destination can be defined.
There is also one endpoint that only allows GET requests:
/journey-routes: The routes endpoint only supports one GET request that accepts a travel destination ID in the request, and replies with a list of all the journeys that contain the specified travel destination.
The backend allows basic CRUD operations for journey, travel destination, and location entities. The journey can also be searched for by ID, name, start date, or end date (they are given as query parameters). The backend returns the relevant error response codes such as 400 in case of a bad request (e.g. when a required field is missing in the body), 404 in case a resource wasn't found, or 500 when an internal error occurs. The backend also catches when required fields aren't missing, but are sent as empty strings. In that case, a 400 response code is also thrown.
There are three main entities in the backend: journey, travel destination, and location. A journey can contain 0 to * travel destinations, while a travel destination HAS to be assigned to at least one journey. That is why when making PUT requests, a travel destination can only be deleted from journey by sending requests to the /journeys endpoint.
For a more detailed documentation, refer to the OpenAPI documentation.
The /journey-routes endpoint allows retrieving a list of journeys that contain a specific travel destination. It accepts a travel destination ID as a request parameter and returns a list of journeys.
For a more detailed documentation, refer to the OpenAPI documentation.
For the freestyle task 2 (where an external API has to be consumed), I created an additional endpoint route called locations in the backend. The location entity contains a name, the country it's in, and the exact position defined by latitude and longitude. A singular location can be added to a travel destination to specify an exact location (e.g. a specific park or restaurant one wants to visit in the destination). One location can be added to many travel destinations. When creating the location, the latitude and longitude can be input manually in the frontend, or the user can use an input field "Add a location". The input field has an autocomplete feature and consumes the Google Maps API to offer relevant locations. As soon as the user selects a location, the latitude and longitude are automatically updated based on the selected location. Then, when viewing either the location or travel destination (which has that location) in the frontend, a view of Google Maps is displayed with a pin in the specified location (this is also done by consuming the Google Maps API). The key for the Google Maps API can be found in local configuration, and has already been added in docker-compose as an environment variable.
The purpose of this additional entity is so that one doesn't have to manually input an address when traveling and wanting to go to a destination (especially with confusing names, one might end up going to a wrong location altogether!). Instead, the location data is saved in the journey manager, and the user can simply use Google Maps to go to the predefined location. Here is how the view looks when a travel destination is opened with a specified location:
The API is being consumed in the frontend. However, both backend and frontend had to be changed to implement this freestyle task. I checked with Daniel Wohlfarth if that was alright, and he gave me the go-ahead.
To install and run the backend locally, follow these steps:
- Clone the repository.
- Navigate to the backend directory:
cd backend. - Install the dependencies:
npm install. - Build the backend:
npm run build. - Start the database in docker (
docker-compose up -d) and runnpm run schema:fresh.- Note: the docker-compose will also start the containerized backend and frontend automatically. If you want to only start the database and/or the test database, comment the rest out.
- Configure the environment variables.
- Start the server:
npm start.
The backend can be configured using the following environment variables:
PORT: The port number on which the server will run (if none provided, port 4000 is taken as default).DB_HOST: The database hostname. For running locally, uselocalhost. For running in docker, use the database container name (e.g.travelDB). For running in Gitlab CI, usepostgres.DB_PORT(required): The port of the database (hosted on Docker).DB_NAME(required): The name of the database.DB_USER(required): The database username.DB_PASSWORD(required): The database password.
Make sure to set these variables before running the server. If the required variables are not set, an error will be thrown.
Create a .env file in the backend/ directory to set the environment variables, for example:
PORT=4000
DB_HOST="localhost"
DB_PORT=5433 # required
DB_NAME="travelDB" # required
DB_USER="travelDBUser" # required
DB_PASSWORD="fweSS24" # required
All the necessary configurations for starting the backend have been set in the docker-compose.
To start the tests manually, run npm test. For the tests to run correctly, you have to also start the testing database defined in the docker compose file. The tests are also automatically executed in the Gitlab pipeline whenever a new commit is pushed.
All the tests were written with jest except for the POST requests, which always threw an error. That is why the POST requests have been created separately in a Postman collection. I cleared this with Daniel Wohlfarth.
When opening the frontend in the browser, the page automatically redirects to the /journeys route, making the table view of all journeys the main landing page:
As the screenshot shows, the journeys can be searched by name, start date, or end date. To clear the search of dates, the button clear dates can be used. Journey-specific actions are listed in the table view, while the button to create a new journey is found under the table.
The edit view of journeys allows all relevant properties to be set, and also offering an image preview, in case an image URL was provided. A journey can be given from 0 to multiple travel destinations, which is done using an input field that allows multiple options to be selected.
The backend also throws an error (which is shown in the frontend) when, for example, a journey is updated in a way that will leave a travel destination journey-less. See example:
The table view of travel destinations shows a similar view to the journey main page, and allows the travel destinations to be managed (and new ones to be created). A travel destination has to be added to a journey when created! Otherwise an error is thrown:
The location is part of travel destination. For more information see freestyle task 2.
The route page shows a route for all journeys that contain a given travel destination. The travel destination can be selected based from a list of available travel destinations.
To install and run the frontend locally, follow these steps:
- Start the backend
- Navigate to the frontend directory:
cd frontend. - Install the dependencies:
npm install. - Configure the environment variables
- Start the server in dev mode:
npm run dev.
The backend can be configured using the following environment variables:
PORT: The port number on which the server will run (if none provided, port 5000 is taken as default).VITE_REST_API_URL: The URL of the backend (if none provided,http://localhost:4000is taken as default).VITE_GOOGLE_API_KEY: The API key for freestyle task 2.
Make sure to set these variables before running the server. If the required variables are not set, an error will be thrown.
Create a .env file in the frontend/ directory to set the environment variables, for example:
PORT=5000
VITE_REST_API_URL=http://localhost:4000
VITE_GOOGLE_API_KEY=AIzaSyAMxm56Y-dfR-BJBP4AGpouPkAxvZjkQdE # required
All the necessary configurations for starting the frontend have been set in the docker-compose.





