The application I worked on is designed for distributors who distribute regulated goods, such as medical devices, pharmaceutical and cosmetical products. Distributors take care of the stock management on batch levels, prepare orders and ship them. The goal was to digitalize good import, good export and goods transfer processes.
The objectives of the project were to:
- Centralize the inventory of batches and products.
- Order preparation through DataMatrix product scanning.
- Automatically generate shipping labels, compliant with postal standards.
- Update order state.
- Make sure that regulatory needs are met with enforcement of processes.
đź“„ Order overview
In practice, the user workflow unfolds as follows:
By default, the distributor has access to an overview of all ongoing orders. This view displays:
To make navigation easier, a filter system is available at the top of the interface. When clicking the “Processed” filter, the distributor can access the list of orders that have already been handled.
The “All” filter displays the complete list of orders, regardless of their status.
In addition, the order list is paginated. Pagination prevents performance issues when the number of orders becomes large and also helps reduce the risk of denial-of-service (DoS) or distributed denial-of-service (DDoS) attacks, which could occur if the entire dataset were loaded at once.
📷​ DataMatrix product scanning
In addition to the order overview, the distributor has access to a “Scan” button that opens a dedicated page for scanning the DataMatrix codes printed on the packaging of the product. A DataMatrix is a type of 2D barcode commonly used in the regulated industry industry. It encodes product information such as the product code, batch number, and expiration date in a compact and highly reliable format. This makes it particularly well suited for tracking and logistics.
❌​ Advanced error handling
During the scanning process, several error cases are handled in order to secure the workflow and guide the distributor. If the user scans a DataMatrix whose format does not match the expected structure, the application immediately displays the message “Invalid Data Matrix”.
đź”’ Secure communication
To ensure the confidentiality and integrity of exchanges with external services, communication with the Swiss Post API is secured through the OAuth2 protocol. Implementing this mechanism makes it possible to:
- Enhance security: Unlike static API keys, OAuth2 provides timelimited access tokens, reducing the risk of credential leaks or misuse.
- Support scalability: OAuth2 is an industry standard, which makes it easier to integrate with other APIs in the future without changing the security model.
- Improve robustness: Token refresh mechanisms prevent service interruptions when an access token expires.
The authentication flow is based on the Client Credentials Grant, suitable for server-to-server communication. The backend first sends a request to the Swiss Post authorization server with its client ID and client secret. In return, it receives an access token, which is then attached to every API call.
A simplified sequence is as follows:
- Spring Boot backend requests a token from Swiss Post
- Swiss Post returns an access token
- The backend uses this token in all subsequent requests to the Swiss Post API
In the Spring Boot backend, this logic is encapsulated in a dedicated OAuth2 service. The service is responsible for:
- Obtaining the initial token when the application starts.
- Storing the token.
🖨️​ Printing Management
The second part of the project, focused on enabling distributors to manage their printers in order to print the shipping labels generated by the application.
To achieve this, I designed a system based on two key components:
- A Rust service deployed on a Raspberry Pi, acting as a bridge between the application backend and the printers.
- A Zebra printer connected to the local network
The Printing Management module gives distributors full control over their printing setup. Each distributor can register a Printer Bridge (a Raspberry Pi) to their account, which the backend recognizes as a bridge to one or more Zebra printers. An overview screen provides the current state of the Printer Bridge (connected or offline), allowing the distributor to check at a glance whether printing is available.
From this view, the distributor can also add a new printer by filling out a form with the printer’s details (name or alias, IP address…).
The same interface also supports the removal of existing printers when they are no longer in use. Each time an add or delete action is performed, the backend immediately sends a WebSocket message to the Printer Bridge so that its configuration is updated in real time and stays synchronized with the database. This design ensures that the printer list displayed in the interface, stored in the backend, and loaded by the Raspberry Pi service are always consistent, while giving distributors the autonomy to manage their own hardware without leaving the application.
📊​ Storage Mangement
The third part of the project focused on inventory management, a module designed for both the manufacturer and the distributors. For the manufacturer, it provides an overview of distributor stock levels acrossmultiple warehouses, ensuring visibility and control over the supply chain. It also allows administrators to consult the resources associated with each product—such as PDF documents, images, or even audio files—and to add, update, or remove them when needed. On the distributor side, the module makes it possible to access the detailed view of a product, modify its information (such as name or category), and keep stock data up to date.
​📉 Stock overview
Through the overview screen, the manufacturer can check the full list of products, monitor available quantities by batch, and see in how many countries each product is distributed.
📄​ Product Details
From this page, it is also possible to switch to edit mode, where the product information can be modified. The edit form provides structured fields for attributes such as product name, type, risk class…
The form includes a dynamic element: the Risk Class dropdown list, which automatically updates based on the selected Product Type. This dependency ensures consistency and reduces the risk of input errors.
📂​ File manager
In the resources section, the user can see an overview of all resources linked to a product. As shown in the screenshot above, they are displayed as a list of cards, each with an icon depending on the file type: a PDF logo for documents, an MP3 logo for audio files, an image thumbnail for pictures, etc.
A search bar lets the user type the name of a resource to quickly find it.
At the top of the page, there is a menu button (three-bar icon) that opens a small panel with two options.
When an item is clicked, it rises above the others and options appear.
📝​ Edit a resource
On this page, it is possible to pick a file with a standard HTML input. The system checks the format and only accepts valid types such as audio, images, or documents (e.g., PDFs). The user can also enter a resource name and select the audience by choosing from radio buttons (for example: admin, distributor, or therapist). This way, each resource is clearly identified, easy to add, and properly assigned to the right type of user.