Migration Guide: v1.3.1
This guide helps you upgrade from v1.3.0 to v1.3.1. Version 1.3.1 has no breaking changes — all existing code continues to work without modification.
Release Date
2026-06-02
Breaking Changes Summary
There are no breaking changes in v1.3.1. The upgrade is drop-in compatible.
Pre-Migration Checklist
Before upgrading, verify the following:
- Run the full test suite after upgrading to confirm no regressions
Upgrade Steps
Step 1: Update Dependencies
npm install \
@mbc-cqrs-serverless/core@^1.3.1 \
@mbc-cqrs-serverless/tenant@^1.3.1 \
@mbc-cqrs-serverless/master@^1.3.1 \
@mbc-cqrs-serverless/sequence@^1.3.1 \
@mbc-cqrs-serverless/task@^1.3.1 \
@mbc-cqrs-serverless/cli@^1.3.1
Step 2: Run Tests
npm run test:cov
New Features in v1.3.1
Group-Based Role Authorization (Opt-In)
RolesGuard now supports resolving roles from the user's group memberships stored in the custom:groups JWT claim. Groups are resolved using a custom resolver that you implement — the mapping from group IDs to roles is not stored in the JWT.
This feature is fully opt-in. Existing @Roles() checks continue to work without any code changes. You only need to act if you want to use group-derived roles.
To Enable: Implement a GroupRoleResolver
import {
GroupRoleResolver,
IGroupRoleResolver,
ResolveGroupRolesInput,
} from "@mbc-cqrs-serverless/core";
// Do not add @Injectable() — @GroupRoleResolver() registers the singleton provider
@GroupRoleResolver()
export class AppGroupRoleResolver implements IGroupRoleResolver {
async resolveRoles({
tenantCode,
groupIds,
claims,
}: ResolveGroupRolesInput): Promise<string[]> {
// Map group IDs to roles (fetch from DB, config, or hardcode)
return groupIds.includes("admin-group") ? ["admin"] : ["user"];
}
}
Register the resolver as a provider in your AppModule:
import { Module } from "@nestjs/common";
import { AppGroupRoleResolver } from "./app-group-role-resolver";
@Module({
providers: [AppGroupRoleResolver],
})
export class AppModule {}
- Do not add
@Injectable()on the resolver class. Adding it alongside@GroupRoleResolver()causes a scope conflict (AP027 anti-pattern).@GroupRoleResolver()already registers the class as a singleton provider. - Let failures propagate — a resolver error surfaces as a 5xx, not a silent 403, making backend outages distinguishable from genuine access denials.
- Implement exactly one resolver per application.
AP027: @GroupRoleResolver + @Injectable Anti-Pattern
The new AP027 anti-pattern detector (mbc_check_anti_patterns) flags resolver classes that are annotated with both @GroupRoleResolver() and @Injectable(). If you create a resolver, make sure it has only @GroupRoleResolver().
See Authentication — Group-Based Roles for complete documentation.
Updated UserContext Fields
getUserContext() now returns two additional fields on UserContext:
| Field | Type | Description |
|---|---|---|
tenantRoles | string[] | Direct roles from the custom:roles claim for the active tenant |
tenantGroupIds | string[] | Group IDs from the custom:groups claim for the active tenant |
The existing tenantRole (singular string) is kept for backward compatibility.
Fault-Tolerant custom:groups Parsing
If the custom:groups JWT claim is malformed or missing, the framework now falls back to an empty group list (no group roles) instead of throwing. This allows the request to proceed with direct roles only.
Support
If you encounter issues during migration: