436 lines
16 KiB
Markdown
436 lines
16 KiB
Markdown
# Bewerbungsaufgabe von Marco Kittel 2025
|
|
# Vorraussetzungen
|
|
|
|
Docker und Docker Compose, Posix Compatibles System und Golang >= 1.24
|
|
|
|
# CsvService
|
|
Starte mit
|
|
./starteCsvService
|
|
Zum Test einfach mal Testdaten in den New Folder
|
|
bei laufendem Betrieb schieben
|
|
|
|
# Web Api
|
|
Benötigt Datenbank
|
|
Starten mit ./starteDatenbank
|
|
Starten mit./starteWebservice
|
|
|
|
Produkte abrufen
|
|
curl -X POST localhost:8080/api/products -d '{ "products": { "A6053": 2, "B3009": 1200 }, "context": { "country": "EU", "state": "" } }'
|
|
|
|
Reservierung reservieren
|
|
curl -X POST localhost:8080/api/products/reserve -d '{ "products": { "A6053": 2, "B3009": 1200 }, "context": { "country": "EU", "state": "" } }'
|
|
|
|
Reservierung bestätigen
|
|
curl -X POST localhost:8080/api/products/confirm -d '{"id":"ab0d7184-a4ce-4802-897a-d8597335143a"}'
|
|
|
|
Reservierung abbrechen
|
|
curl -X POST localhost:8080/api/products/abort -d '{"id":"ab0d7184-a4ce-4802-897a-d8597335143a"}'
|
|
|
|
Reservierung freigeben
|
|
curl -X POST localhost:8080/api/products/release -d '{"id":"ab0d7184-a4ce-4802-897a-d8597335143a"}'
|
|
|
|
# Abschlussbesprechung der Aufgabe
|
|
[Abschlussbesprechnung](https://www.youtube.com/watch?v=psz58bMyeMM)
|
|
|
|
|
|
|
|
# Aufgabe
|
|
|
|
|
|
Organisational requirements
|
|
|
|
Objective
|
|
|
|
Application Requirements
|
|
|
|
Task 1
|
|
|
|
Task 2 - Stock Import
|
|
|
|
Task 3 - Cross Country / State Delivery Times
|
|
|
|
Task 4 - Stock and Delivery Time API
|
|
|
|
Task 5 - Reservation API
|
|
|
|
Automatic Release
|
|
Order Handling
|
|
Target
|
|
|
|
Organisational requirements
|
|
Share all your work with us by using a git-based version control platform like
|
|
github.com or gitlab.com in private mode, so we can see your development
|
|
progress and test your final results. Please always use the e-mail address for
|
|
sharing code.
|
|
|
|
|
|
Objective
|
|
Our customer is a global operator of online shops, with a presence spanning
|
|
across numerous countries worldwide. They have established country-specific
|
|
online shops tailored to serve the unique needs of customers in Germany,
|
|
Austria, and Switzerland. Additionally, they operate expansive, nation-wide
|
|
shops dedicated to serving customers across all other European Union countries,
|
|
the United States, and the rest of the world.
|
|
|
|
This global reach is supported by an extensive network of warehouses,
|
|
strategically located in several countries. These warehouses not only ensure
|
|
efficient and effective distribution of products, but also contribute to a
|
|
streamlined shopping experience for customers, regardless of their location.
|
|
|
|
|
|
For every product our customer sells, there exists a specific quantity
|
|
available in each of their warehouses. However, the availability of these
|
|
products can vary significantly; while some warehouses may hold a substantial
|
|
stock of a particular product, others may have a limited quantity, or may not
|
|
have the product in stock at all. One warehouse may provide products to several
|
|
online shops.
|
|
|
|
|
|
The warehouses generate csv files that contain the information about the
|
|
available stock per product. Right now each e-commerce application must process
|
|
all of the given stock information individually. The stock information files
|
|
generated by each warehouse are sent to all shops and are processed there. Each
|
|
shop is holding its own copy of the stock information. This is causing the
|
|
problem that false stocks and delivery times are advertise. E.g. both the
|
|
Germany and Switzerland shop knows that we have x items present in the EU
|
|
warehouse, if two customers are buying the same products in two individual
|
|
shops we oversell the item.
|
|
|
|
To avoid this we want to introduce one central instance that processes the
|
|
stock information and is asked by the shop instances via api about the
|
|
currently available stock. This application should be written in golang.
|
|
|
|
|
|
Application Requirements
|
|
The application must be written in golang
|
|
|
|
In case additional services (databases, message brokers, …) are used a
|
|
docker-compose.yml must be provided.
|
|
|
|
A readme with instructions about how to run this project must be given
|
|
|
|
A documentation about how to use the api must be given (can be in readme, api
|
|
spec, postman collection, …)
|
|
|
|
The import files used to test the application must be provided in the request
|
|
|
|
The approx duration for the implementation should be one day
|
|
|
|
Task 1
|
|
Before you start, please create a free account at https://gitlab.com/ and
|
|
create a new repository there. You will share later the repository containing
|
|
the source code with us.
|
|
|
|
Task 2 - Stock Import
|
|
We maintain detailed knowledge of the specific products and their current stock
|
|
levels in each of our warehouses. Each warehouse is operating their own
|
|
database that holds that information. There is no centralized database that
|
|
contains the stock per product and warehouse. The software used by each
|
|
warehouse cannot be modified and only allows file exports.
|
|
|
|
Each warehouse is generating every hour a csv file with the current stocks.
|
|
This csv file is synced with a centralized storage. Only full updates are
|
|
supported, which means that each file generated every hour contains all
|
|
products. The estimated size will be 700.000 products / lines per file.
|
|
|
|
Our application must read these csv files and import them into a local database.
|
|
|
|
Our application that we need to develop will read csv files from the local
|
|
filesystem. There will be one directory where all files are saved in. We do not
|
|
need to care about the centralized storage.
|
|
|
|
The filename created by each warehouse has the following structure
|
|
Time[RFC-3339, ISO_8601]-WarehouseId-stock.csv
|
|
|
|
Examples:
|
|
|
|
$ ls -a | sort
|
|
2023-11-09T15:02:17+00:00-CH-stock.csv
|
|
2023-11-09T16:01:14+00:00-CH-stock.csv
|
|
2023-11-09T16:03:02+00:00-DE-stock.csv
|
|
2023-11-09T16:03:17+00:00-AT-stock.csv
|
|
2023-11-09T16:04:44+00:00-EU-stock.csv
|
|
Text
|
|
Copy
|
|
In case there are multiple files from one warehouse present the latest file
|
|
must be processed.
|
|
|
|
Files are always full exports.
|
|
|
|
The file contains the product id which is a string and the currently available
|
|
quantity of this product in the warehouse that generated the export file.
|
|
|
|
product_id;quantity
|
|
A1000;50
|
|
B3009;80
|
|
A8771;158
|
|
|
|
The file must be processed by our application. The contents must be saved in a
|
|
database that we later use to query the currently available stocks. It is
|
|
sufficient to save the WarehouseId, ProductId and the Quantity in our database.
|
|
The data model you choose here is up to you.
|
|
|
|
Files that have been processed must be moved to another directory. For
|
|
simplification we do not care about cleanup or failed imports.
|
|
|
|
├── new
|
|
│ ├── 2023-11-09T16:03:17+00:00-AT-stock.csv
|
|
│ └── 2023-11-09T16:04:44+00:00-EU-stock.csv
|
|
└── processed
|
|
├── 2023-11-09T15:02:17+00:00-CH-stock.csv
|
|
├── 2023-11-09T16:01:14+00:00-CH-stock.csv
|
|
└── 2023-11-09T16:03:02+00:00-DE-stock.csv
|
|
Text
|
|
Copy
|
|
Target
|
|
The target of task 1 is that our go application searches for new csv files in a
|
|
predefined directory. Files are processed and the contents saved in our
|
|
database.
|
|
|
|
Task 3 - Cross Country / State Delivery Times
|
|
We have precise data on the average delivery time from each warehouse to every
|
|
eligible country and state it serves. This information is provided via csv
|
|
export that is generated by each warehouse. The exports are saved on the same
|
|
centralized storage as in task 2. Files will be saved in the same directory.
|
|
|
|
As an example: We have a warehouse in Germany - in case one product is not
|
|
available we can fallback to the european warehouse to serve the customer from
|
|
there, but we cannot fallback to our US warehouse.
|
|
|
|
Our application that we need to develop will read csv files from the local
|
|
filesystem. There will be one directory where all files are saved in.
|
|
|
|
├── new
|
|
│ ├── 2023-11-09T16:00:10+00:00-CH-delivery.csv
|
|
│ ├── 2023-11-09T16:00:20+00:00-DE-delivery.csv
|
|
│ ├── 2023-11-09T16:00:37+00:00-EU-delivery.csv
|
|
│ ├── 2023-11-09T16:01:56+00:00-AT-delivery.csv
|
|
│ ├── 2023-11-09T16:03:17+00:00-AT-stock.csv
|
|
│ └── 2023-11-09T16:04:44+00:00-EU-stock.csv
|
|
└── processed
|
|
├── 2023-11-09T15:02:17+00:00-CH-stock.csv
|
|
├── 2023-11-09T16:01:14+00:00-CH-stock.csv
|
|
└── 2023-11-09T16:03:02+00:00-DE-stock.csv
|
|
Text
|
|
Copy
|
|
The delivery time files will be saved in the same directory as the stock files
|
|
processed in task 2.
|
|
|
|
The filename created by each warehouse has the following structure
|
|
Time[RFC-3339, ISO_8601]-WarehouseId-delivery.csv
|
|
|
|
$ ls -a | sort
|
|
2023-11-09T16:00:10+00:00-CH-delivery.csv
|
|
2023-11-09T16:00:20+00:00-DE-delivery.csv
|
|
2023-11-09T16:00:37+00:00-EU-delivery.csv
|
|
2023-11-09T16:01:56+00:00-AT-delivery.csv
|
|
Text
|
|
Copy
|
|
In case there are multiple files from one warehouse present the latest file
|
|
must be processed.
|
|
|
|
Files are always full exports.
|
|
|
|
The file contains the country iso, the state and the average delivery time in
|
|
days regardless of the product.
|
|
|
|
// 2023-11-09T16:00:10+00:00-CH-delivery.csv
|
|
country;state;delivery_time
|
|
CH;;3
|
|
DE;BW;4
|
|
|
|
The here show file is generated by the swiss warehouse. The average delivery
|
|
time in switzerland (CH) are 3 days. Nevertheless products can also be delivery
|
|
to germany, but only to Baden Württemberg which will take 4 days. If a state
|
|
is specified it means that we only delivery to this specific stage. All
|
|
countries that are not present or all states that are not present are not
|
|
served by this warehouse. If the state is not given, it means that we serve the
|
|
whole country. Depending in the location of the warehouse it can be possible
|
|
that for some states the delivery time is lower than for the remaining country.
|
|
Due to that we can have an entry for the whole country and entries for the
|
|
country and a state in the same file.
|
|
|
|
The file must be processed by our application. The contents must be saved in a
|
|
database that we later need to query the currently delivery times.
|
|
|
|
Files that have been processed must be moved to another directory. For
|
|
simplification we do not care about cleanup or failed imports.
|
|
|
|
Target
|
|
The provided files are processed, the contents are stored in our database.
|
|
|
|
Task 4 - Stock and Delivery Time API
|
|
The online shops the customer operates for each country and region are
|
|
isolated. This means that their databased and the knowledge about the current
|
|
stock and delivery times are not saved in a centralized database. Each shop
|
|
must process the aforementioned file imports individually which is causing a
|
|
high load on every system every hour. Furthermore as each shop is using its own
|
|
source of truth more products than available can be sold or even wrong delivery
|
|
times can be advertised.
|
|
|
|
We now want to remove the processing of the stock and delivery time imports in
|
|
all online shop applications and replace that with an api call to our golang
|
|
application. The result of your api call is displayed in the shipping cart.
|
|
There we display per product the calculated delivery times and the available
|
|
stocks.
|
|
|
|
For that we must provide a new api endpoint which is consumed by the online
|
|
shops applications. For simplicity we do not care about authentication.
|
|
|
|
The api endpoint must accept the following parameters:
|
|
|
|
Product-IDs + Quantity: We submit the products for that we would like to know
|
|
the current instock and delivery times.
|
|
|
|
Customer Country: As the delivery times depend on the country we submit this as
|
|
part of our context
|
|
|
|
Customer State: As the delivery times may depend on the state we submit this as
|
|
part of our context
|
|
|
|
{
|
|
"products": {
|
|
"A1000": 20,
|
|
"B3009": 1200
|
|
},
|
|
"context": {
|
|
"country": "DE",
|
|
"state": "BY"
|
|
}
|
|
}
|
|
Jav
|
|
CopyThe result of this api call should contain the product numbers that we
|
|
submitted in the request and per product the information about the available
|
|
stock in each warehouse that is required. The warehouses should be picked
|
|
depending on the available stock and the lowest delivery time. If we for
|
|
example can server the products from DE and EU warehouse, we pick the one with
|
|
the lowest delivery time first and fill up the remaining quantities.
|
|
|
|
{
|
|
"products": {
|
|
"A1000": [
|
|
{"warehouse": "DE", "quantity": "5", "delivery_time": 1},
|
|
{"warehouse": "EU", "quantity": "15", "delivery_time": 8}
|
|
],
|
|
"B3009": [
|
|
{"warehouse": "DE", "quantity": "110", "delivery_time": 1}
|
|
]
|
|
}
|
|
}
|
|
|
|
As a result we receive per product the information about the possible
|
|
quantities and the delivery times.
|
|
|
|
Target
|
|
We have an api endpoint that accepts the aforementioned payload
|
|
|
|
Calculate the delivery times based in the previously imported data
|
|
|
|
Respond with the above shown result
|
|
|
|
No auth is required
|
|
|
|
Task 5 - Reservation API
|
|
After implementing the stock api the customer is facing less problems with
|
|
wrong stocks or delivery times, but the problem still exists for a small number
|
|
of customers.
|
|
|
|
To prevent this we want to introduce a reserve, confirm and release api
|
|
endpoint.
|
|
|
|
Reserve
|
|
|
|
The reservation api is called by the online shops during the checkout process.
|
|
If the customer is navigating to the last checkout step before payment the
|
|
online shop calls the reserve api endpoint. The payload will be exactly the
|
|
same as for the stock and delivery time api.
|
|
|
|
{
|
|
"products": {
|
|
"A1000": 20,
|
|
"B3009": 1200
|
|
},
|
|
"context": {
|
|
"country": "DE",
|
|
"state": "BY"
|
|
}
|
|
}
|
|
|
|
The reservation will perform a stock and delivery time lookup and will reserve
|
|
the stock in each required warehouse.
|
|
|
|
Our api must respond like before with the available stocks and the possible
|
|
delivery times. Now we receive in addition a reservation id. This id can be
|
|
used to confirm and release the reservation.
|
|
|
|
{
|
|
"id": "59e57f14-be24-43c4-8a8e-4c22f5f2154e",
|
|
"products": {
|
|
"A1000": [
|
|
{"warehouse": "DE", "quantity": "5", "delivery_time": 1},
|
|
{"warehouse": "EU", "quantity": "15", "delivery_time": 8}
|
|
],
|
|
"B3009": [
|
|
{"warehouse": "DE", "quantity": "110", "delivery_time": 1}
|
|
]
|
|
}
|
|
}
|
|
|
|
Abort
|
|
|
|
In case the customer does not finish the checkout process in one of the online
|
|
shops, the online shop calls the abort api endpoint. This removes the
|
|
previously created reservation.
|
|
|
|
The following payload is submitted to this endpoint:
|
|
|
|
{
|
|
"id": "59e57f14-be24-43c4-8a8e-4c22f5f2154e"
|
|
}
|
|
|
|
As there is no result in this api call our response will be 204 no content.
|
|
|
|
Confirm
|
|
|
|
In case the customer finishes the checkout and payment process the online shop
|
|
will now call the confirm api endpoint including the previously given
|
|
reservation id. After this request the information about the reserved stock
|
|
stays permanently in our database.
|
|
|
|
{
|
|
"id": "59e57f14-be24-43c4-8a8e-4c22f5f2154e"
|
|
}
|
|
|
|
As there is no result in this api call our response will be 204 no content.
|
|
|
|
Automatic Release
|
|
In case the reservation is not released or confirmed within one day our
|
|
application must automatically remove the reserved stock from the database.
|
|
|
|
Order Handling
|
|
The online shops submit the orders to a centralized order management system.
|
|
The online shops include the information provided by our reserve api endpoint.
|
|
The order management system will now deliver the products based on the
|
|
information our api provides. This prevents that more products than available
|
|
are sold or wrong delivery times are shown.
|
|
|
|
If the order management system is processing the orders, stocks in the
|
|
warehouses are changed. We receive the new stock information with the next file
|
|
export. To release the reserved stock the order management system will call an
|
|
api endpoint of our application (release api). The payload includes the
|
|
reservation id that we created during the reservation.
|
|
|
|
{
|
|
"id": "59e57f14-be24-43c4-8a8e-4c22f5f2154e"
|
|
}
|
|
|
|
As there is no result in this api call our response will be 204 no content.
|
|
|
|
Target
|
|
Create 4 api endpoints (reserve, abort, confirm, release)
|
|
|
|
The reservation should block a specific amount in specific warehouses
|
|
|
|
All further api calls to our stock and delivery time api or the reserve api
|
|
must use this information
|