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
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 composes functions from multiple modules to enable complex workflows:

ServiceDescription
ordersCheckout workflow, order pricing sheets
productsProduct pricing calculations
usersUser-related operations
filesFile operations with storage adapters

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

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)
@unchainedshop/file-uploadFile storage adapters

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, the cart becomes an immutable order

User Conversion

  • Anonymous users can register without losing order history
  • Carts merge when a user logs in during purchase
  • Bookmarks and preferences are preserved

Package Dependency Graph

Next Steps