Skip to main content

Architecture

Unchained Engine is built using a layered architecture that separates concerns and enables customization at every level.

Layered Approach​

LayerDescription
AppYour project-specific code
PlatformOrchestration, GraphQL API, configuration
Service GatewayCross-module workflows (checkout, pricing)
Core ModulesBusiness logic and database abstractions

App Layer​

The user-land app is where your project-specific code lives. Unchained Engine is loaded as a framework into a Node.js project.

import { startPlatform } from '@unchainedshop/platform';

// Your app boots the platform. All arguments are optional —
// the core modules are loaded by default.
const engine = await startPlatform({
modules: { /* custom modules */ },
services: { /* custom services */ },
options: { /* configuration */ },
});

Platform Layer​

The platform layer (@unchainedshop/platform and @unchainedshop/api) handles:

  • Loading all default core modules
  • Defining the GraphQL schema and resolvers
  • Starting the API server (Express or Fastify)
  • Managing the work queue for background jobs
  • Orchestrating module configuration
  • Email templates and messaging
  • Authentication and session management

In rare cases, you might skip this layer to directly access core modules for:

  • Federated microservices
  • Custom non-GraphQL APIs
  • Batch processing scripts

Service Gateway Layer​

The service gateway (services on the Unchained API object) composes functions from multiple modules to enable complex workflows. Services are grouped by domain: bookmarks, delivery, enrollments, files, filters, orders, payment, products, quotations, users, warehousing, worker — e.g. services.orders.checkoutOrder or services.products.simulateProductPricing.

You can modify services by:

  1. Using existing plugins
  2. Writing custom plugins
  3. Adding functions to startPlatform options
await startPlatform({
services: {
orders: {
// Custom order service methods
},
},
});

Core Modules Layer​

Core modules contain business logic and database abstractions. Each module is responsible for a specific domain:

ModulePackageDescription
Products@unchainedshop/core-productsProduct catalog management
Orders@unchainedshop/core-ordersOrder lifecycle and cart
Users@unchainedshop/core-usersUser accounts and auth
Payment@unchainedshop/core-paymentPayment providers
Delivery@unchainedshop/core-deliveryShipping providers
Assortments@unchainedshop/core-assortmentsCategories and collections
Filters@unchainedshop/core-filtersProduct search and filtering
Warehousing@unchainedshop/core-warehousingInventory management
Enrollments@unchainedshop/core-enrollmentsSubscriptions
Quotations@unchainedshop/core-quotationsRequest for quote (RFQ)
Bookmarks@unchainedshop/core-bookmarksWishlists
Worker@unchainedshop/core-workerBackground jobs
Files@unchainedshop/core-filesFile metadata
Events@unchainedshop/core-eventsEvent history
Countries@unchainedshop/core-countriesCountries
Currencies@unchainedshop/core-currenciesCurrencies
Languages@unchainedshop/core-languagesLanguages

You can modify modules through:

  1. Configuration options at startup
  2. Plugins (Director/Adapter pattern)
  3. Custom module implementations

Infrastructure Layer​

Foundation utilities used across all layers:

PackageDescription
@unchainedshop/mongodbDatabase lifecycle, queries, migrations
@unchainedshop/eventsEvent emitter with pluggable backends
@unchainedshop/loggerHigh-performance logging
@unchainedshop/utilsCommon utilities and base classes
@unchainedshop/rolesRole-based access control (RBAC)

The private @unchainedshop/shared workspace contains the monorepo's TypeScript configuration.

File handling is coordinated by FileDirector and file services in @unchainedshop/core, with metadata in @unchainedshop/core-files and storage adapters in @unchainedshop/plugins.

API Design Principles​

  1. Stateless: All data stored in MongoDB, no server-side sessions
  2. Guest Users: Anonymous users use loginAsGuest mutation for cart operations
  3. Server-side Logic: All business logic remains server-side for omni-channel support

Implications​

Carts as Open Orders

  • Carts are stored server-side as orders with status: null
  • Users can add items on one device and checkout on another
  • After checkout, cart-editing operations are restricted while payment and fulfillment continue

User Conversion

  • Logging into an existing account from a guest session migrates guest data through the user migration service
  • Carts merge on login when mergeUserCartsOnLogin is enabled
  • createUser creates a fresh account; registration does not automatically migrate the current guest's cart or order history

Package Dependency Graph​

Note that @unchainedshop/api depends on @unchainedshop/core and directly on every core-* package — the GraphQL resolvers use the module APIs and types of the individual domain modules, not just the core orchestration layer.

Next Steps​