Skip to main content
EngineeringLast updated onSep 30, 2025

Feature Recipe: Blameable Changes Plugin

HAS
Housein Abo ShaarGrowth Engineer & Developer Advocate
A guide to building a Vendure plugin that automatically tracks which user creates or updates entities, using the EventBus system and custom fields for auditing.
Feature Recipe: Blameable Changes Plugin

This guide provides a recipe for a "blameable changes" plugin that automatically tracks which Administrator creates and updates product variants.

The plugin demonstrates several core Vendure concepts, including the EventBus for reacting to data changes, Custom Fields to extend core entities, and extending the GraphQL API with custom resolvers.

1. Plugin Architecture & Custom Fields

The first step is to define the custom fields that will store the user information.

This is done within the plugin's main configuration.

We will use the Vendure CLI** **to scaffold the plugin and service.

We add createdBy and updatedBy fields of type relation to the ProductVariant entity, linking them to the User entity.

*File: *src/plugins/blameable-fields/blameable-fields.plugin.ts

Typescript

Ready to build? The Vendure docs cover architecture, setup, and extension from day one.

Read the docs

2. Service for Event Handling

Next, we create a service that listens for product variant events and populates our new custom fields.

The service subscribes to the ProductVariantEvent on the EventBus. This is done inside the onModuleInit** method**, a lifecycle hook from NestJS (the framework Vendure is built on).

This hook ensures our subscription is set up once the plugin has been initialized.

Typescript

When an event is received, it checks the event type** (created or updated)**. It then updates the corresponding custom field with the ID of the active user.

Typescript

3. Exposing Data via GraphQL

To make the tracking data easily accessible, we extend the GraphQL schema.

We add createdByIdentifier** and **updatedByIdentifier fields to the ProductVariant type.

*File: *src/plugins/blameable-fields/blameable-fields.plugin.ts

Typescript

A resolver fetches the stored user ID and resolves it to a user identifier, like "superadmin". This approach uses a direct database query for better performance.

*File: *src/plugins/blameable-fields/resolvers/product-variant.resolver.ts

Typescript

You could modify the service to track changes on other entities, such as Product, Customer, or Order by subscribing to their respective events. For more detailed auditing, the logic could be extended to store a full history of changes.

Headless commerce for B2B complexity, D2C flexibility, and one backend to run both.

Explore the platform

Further Reading

Share this guide

Build for B2B complexity. Run every channel.

Vendure is an open-source, headless commerce platform. Model account hierarchies, contract pricing, and custom workflows without choosing between a rigid suite and a DIY composable stack.