Skip to content

E-Commerce store

How we transformed legacy store into bleeding edge system

Waveshop Split Croatia

Wave Shop Split

When we started collaboration with Wave Shop Split, we had a meet and greet with a legacy Magento webshop. Outdated design, bad checkout flow, no support for online payments were just a few challenges the client had. In 2026 this kind of monolithic architecture means huge load times, outdated PHP version and security concerns.

How We Built a Distributed E-Commerce Platform That Scales Without Breaking a Sweat

Seven specialized systems, one coherent product. Here is a technical walkthrough of how each component earns its place and how they all talk to each other.

The problem with monolithic thinking

Most e-commerce platforms start the same way: a single server doing everything. It handles the storefront, processes orders, resizes images, runs search queries, sends emails, and caches data, all in one place. That works fine until traffic spikes or a long-running background job starts slowing down the checkout experience for everyone.

We took a different approach from the beginning. Instead of one system trying to be everything, we built a platform where each component does exactly one thing, does it well, and communicates with the others. The result is a setup that is resilient under heavy load.

The architecture at a glance

The platform splits into two top-level concerns: what visitors see (the Storefront) and what makes everything work (the Backend). These are distinct applications with their own databases, which means a problem in one does not cascade into the other.

The Backend itself splits further into two instances, Server and Worker, which is where a lot of the platform's resilience comes from. The Server handles all data concerns and the Worker handles every action. Keeping these two responsibilities separate means a heavy background job can never slow down a live user request.

Surrounding this core are five specialized systems: Redis for caching, Meilisearch for search, MinIO for image storage and Tolgee for translation management, each connected to the Server and Worker.

Every system runs in its own isolated Docker container. This means each component can be deployed, restarted, scaled, or updated independently without touching anything else. A container issue with one service does not bring down the others, and the entire stack can be reproduced consistently across environments.

Every component, explained

Storefront

The Storefront is the CMS application, built in Node.js and Next.js, that your visitors interact with. It has its own dedicated database, completely separate from the backend. This isolation matters: a slow backend operation cannot affect the Storefront's ability to serve pages, and vice versa. The Storefront requests what it needs from the backend, renders it, and stays out of the way.

Server

The Server is the data-handling half of the backend, powered by MedusaJS, a modern, open-source e-commerce engine built for exactly this kind of distributed setup. It receives requests from the Storefront, reads from and writes to the backend database, and returns structured responses. It does not run background jobs. Its single responsibility is to be fast and always available for data operations.

Worker

The Worker is the action-processing half of the backend, also running on MedusaJS. Every operation that does not need to happen in real time. Order processing, inventory updates, email dispatching, sync jobs and more is handled here. By separating this work into its own instance, we ensure that a heavy or long-running task never blocks a live user request on the Server. Under high traffic, this distinction makes the difference between a smooth experience and a degraded one.

Redis

Redis sits between the systems as a shared cache. Responses from the Storefront, Server, and Worker are all cached here. Frequently accessed data lives in memory, which means the underlying databases are hit far less often. The result is dramatically lower response times across the entire platform, especially under concurrent load.

Meilisearch

Meilisearch is a dedicated search engine, completely separate from the main database. Product search, filtering, and faceting are all handled here, which means the backend database never has to run expensive full-text queries. Meilisearch is built for search, so it is fast at it in a way a general-purpose database simply cannot match. It receives index updates from the Server and Worker whenever product data changes.

MinIO

MinIO is an S3-compatible object storage system used exclusively for images. Product photos and media assets live here, completely outside the Server, Worker, and Storefront. None of those systems are burdened with storing, serving, or processing images. When the Storefront needs an image, it fetches it directly from MinIO. When the backend stores an image, it goes straight to MinIO. The rest of the platform never has to think about it.

Tolgee

Tolgee is the translation management system. It handles all localization needs for the platform and integrates directly with Azure Cognitive AI to automate translation. When new content enters the system, Tolgee picks it up, passes it through Azure's translation engine, and makes the localized versions available without any manual work. The Server and Worker are connected to Tolgee so that translation updates flow automatically as content changes.

Custom integrations built for this platform

Ritam ERP integration

One of the more complex pieces of this project was a fully custom integration with Ritam ERP. The business system the client uses to manage inventory, invoicing, and order data. We built a two-way sync between MedusaJS and Ritam: products and stock levels flow from Ritam into the webshop automatically, and every new order placed on the platform is pushed back into Ritam for fulfilment and accounting. This eliminates double data entry entirely and keeps the webshop's inventory in sync with the source of truth at all times.

Custom shipping modules: Hrvatska Pošta and DPD

We built native shipping modules for both Hrvatska Pošta (HP) and DPD, integrated directly into the checkout flow. These modules communicate with each carrier's API to generate shipments, retrieve tracking numbers, and pass the relevant data back into the order. Customers see accurate shipping options at checkout, and the fulfilment team gets everything they need without leaving the platform.

Custom order confirmation emails with Ritam invoice data

Order confirmation emails are generated dynamically using invoice data pulled directly from Ritam ERP. As soon as an order is confirmed and pushed to Ritam, the Worker retrieves the corresponding invoice details and includes them in the confirmation email sent to the customer. This means customers receive a proper, accurate invoice in their inbox immediately after purchase, no manual step required on the client's end.

How the systems talk to each other

The data flow through the platform follows a clear pattern. A visitor interacts with the Storefront. The Storefront makes a request to the Server. Before the Server hits the database, it checks Redis if the data is cached, it returns immediately. If not, it queries the backend database, stores the result in Redis for next time, and responds.

When a visitor performs an action, placing an order for example, the Server receives it, validates the data, and hands the actual processing off to the Worker. The Worker executes the job asynchronously: updating inventory, triggering notifications, syncing with external systems. The visitor's session is not held waiting for any of this.

Search queries bypass the backend database entirely and go straight to Meilisearch. Image requests go directly to MinIO. Translations are resolved through Tolgee. Each specialized system handles its domain, and the Server and Worker act as the orchestration layer that keeps everything synchronized.

A typical scenario, step by step

Here is what happens when a visitor searches for a product, views it, and places an order.

1. Search request: The visitor types a query into the Storefront. The Storefront sends the query to Meilisearch directly. Meilisearch returns ranked results in milliseconds. The Storefront renders them. The backend database was never involved. We utilize Instant Search, making the searched query instantly visible to the customer.

2. Product page load: The visitor clicks a product. The Storefront fetches the pre-rendered page. The response is instant.

3. Order placement: The visitor submits an order. The Server validates the request and writes the order to the backend database. It immediately hands the order processing job to the Worker and returns a confirmation to the Storefront. The visitor sees a success screen.

4. Background processing: The Worker picks up the job. It updates inventory, syncs the order to Ritam ERP, generates the shipment with Hrvatska Pošta or DPD, and dispatches the confirmation email with full invoice data retrieved from Ritam. It also updates the relevant Redis cache keys so that next page loads reflect current stock. None of this touches the Server's availability for other requests.

5. Translation: If the product description was recently added or updated, Tolgee detects the change via the Server, passes the content to Azure Cognitive AI, and stores the translated versions. The next visitor in a different locale sees the localized content automatically.

Edge cases and how the architecture handles them

Traffic spike: Redis absorbs the surge. The vast majority of read requests never reach the database. The Server and Worker scale independently, so read traffic and job processing do not compete for the same resources.

Worker backlog: If the Worker falls behind on a queue of jobs, the Server continues serving live requests without interruption. The separation of concerns means one does not starve the other.

Cache invalidation: When data changes, the relevant Redis keys are invalidated by the Worker as part of the same job that made the change. Stale data is handled at the source, not discovered later by the Storefront.

Image storage failure: MinIO is self-hosted and isolated. A storage issue affects image delivery only, not the ability to browse, search, or purchase. The rest of the platform continues operating.

Translation lag: If Azure Cognitive AI is slow or temporarily unavailable, the platform continues serving content in the available languages. Untranslated content falls back gracefully rather than blocking the page render.

Search index out of sync: Meilisearch indexes are updated by the Worker after every relevant data change. If a re-index is needed, it runs as a background job without affecting the Server or Storefront availability.

ERP or carrier API unavailable: If Ritam ERP or a carrier API is temporarily unreachable, the Worker retries the job without blocking order confirmation to the customer. The order is safely stored and the sync completes as soon as the external service recovers.

Why this setup is worth the complexity

Running seven systems instead of one is a deliberate trade-off. Each system adds operational surface area. But what you get in return is a platform where failures are contained, performance is consistent, and each component can be scaled, replaced, or upgraded independently.

Redis can be scaled up without touching the application code. Meilisearch can be tuned for search relevance without involving the backend team. MinIO can be migrated to a different storage provider without changing a single line of Storefront logic. Tolgee can support new languages by adding a configuration, not a code deployment. And because every service runs in its own Docker container, the entire infrastructure is portable, reproducible, and straightforward to maintain.

The orchestration between Server and Worker is what makes it feel like one system to the end user. The separation of concerns is what makes it maintainable to the team building it.

That balance, invisible complexity, visible reliability is what this architecture is designed to achieve.

Everything runs on a VPS hosted at our Croatian partner's datacenter, Proaxis. Local infrastructure, local accountability, full control. No hyperscaler middleman in between, and no hyperscaler pricing to match.

Check it out: https://waveshop.hr

Other use cases

Planning a new project?