strapi-rbac-component-manager
v1.0.1
Published
This plugin provides a centralized role-based access control layer for managing component configurations within Strapi.
Readme
Strapi RBAC Component Manager
A Strapi 5 plugin that provides centralized role-based access control for managing component asset configurations. It allows administrators to define default images at a global level for reuse across multiple component variants, while supporting per-entry overrides when individual customization is needed.
Overview
Some component variants (e.g., a Banner with type "text only") intentionally hide their image fields in the CMS — the image is managed centrally rather than per-entry. This plugin solves that by providing:
- Global Asset Mappings — set a single default image for a component + variant combination that applies everywhere
- Asset Overrides — assign a custom image to a specific component instance on a specific entry, overriding the global default
The BFF (Backend for Frontend) layer queries these records and resolves the correct image: override → global default → null.
Features
- Global default image assignment per component variant
- Per-entry override capability for one-off customizations
- Dynamic component introspection (auto-discovers components with
typeenum fields) - Admin settings page with two-tab UI (Global Defaults / Overrides)
- Cascading dropdown UX for overrides (Collection → Entry → Component Instance → Image)
- RBAC-gated access with custom permissions
- Multi-domain plugin compatible (domain-scoped data segregation)
- Lifecycle hooks for cascade-deleting overrides when entries are removed
- REST content-type API endpoints for BFF consumption
Installation
The plugin is located at src/plugins/strapi-rbac-component-manager and registered in config/plugins.ts:
// config/plugins.ts
'strapi-rbac-component-manager': {
enabled: true,
resolve: './src/plugins/strapi-rbac-component-manager',
},After registering, restart Strapi. The plugin will automatically:
- Create the database tables (
global_asset_mappings,asset_overrides) - Register its admin settings page
- Register RBAC permissions
Building
cd src/plugins/strapi-rbac-component-manager
npm run buildThe plugin must be rebuilt after any source changes. Strapi loads the compiled dist/ output.
Admin UI
The plugin adds a Component Manager section under Settings in the Strapi admin panel.
Global Defaults Tab
Manage default images for component variants.
- Click Add Mapping
- Select a Component from the dropdown (auto-populated from Strapi's component registry)
- Select a Variant (enum values from the component's
typefield) - Upload or select a Default Image from the Media Library
- Click Create
Each component + variant combination can have one global default image. The table shows all configured mappings with thumbnail previews.
Overrides Tab
Assign custom images to specific component instances, overriding the global default.
- Click Add Override
- Select a Collection (content types with component fields)
- Select an Entry from that collection
- Select a Component Instance (shows label like:
Banner — "Welcome" (text only)) - Upload or select an Override Image
- Click Create
Overrides are independent of global defaults — they can exist without a corresponding global mapping.
Permissions
The plugin registers two RBAC permissions:
| Permission | Description |
|-----------|-------------|
| plugin::strapi-rbac-component-manager.settings.read | View global defaults and overrides |
| plugin::strapi-rbac-component-manager.settings.update | Create, update, and delete mappings/overrides |
Super Admins have access by default. Grant these to other roles via Settings > Roles.
API Endpoints
Admin Routes (requires admin auth)
| Method | Path | Description |
|--------|------|-------------|
| GET | /strapi-rbac-component-manager/introspect/components | List components with type enum fields |
| GET | /strapi-rbac-component-manager/global-asset-mappings | List all global mappings |
| POST | /strapi-rbac-component-manager/global-asset-mappings | Create a mapping |
| PUT | /strapi-rbac-component-manager/global-asset-mappings/:id | Update a mapping |
| DELETE | /strapi-rbac-component-manager/global-asset-mappings/:id | Delete a mapping |
| GET | /strapi-rbac-component-manager/asset-overrides | List all overrides |
| POST | /strapi-rbac-component-manager/asset-overrides | Create an override |
| PUT | /strapi-rbac-component-manager/asset-overrides/:id | Update an override |
| DELETE | /strapi-rbac-component-manager/asset-overrides/:id | Delete an override |
| GET | /strapi-rbac-component-manager/collections | List content types with components |
| GET | /strapi-rbac-component-manager/collections/:uid/entries | List entries for a content type |
| GET | /strapi-rbac-component-manager/entries/:uid/:entryId/components | List component instances |
Content API Routes (for BFF consumption)
| Method | Path | Description |
|--------|------|-------------|
| GET | /api/strapi-rbac-component-manager/global-asset-mappings | Query global mappings |
| GET | /api/strapi-rbac-component-manager/asset-overrides | Query overrides |
These support Strapi's standard filters query parameter:
GET /api/strapi-rbac-component-manager/global-asset-mappings?filters[componentUid]=sections.banner&filters[variantValue]=text only
GET /api/strapi-rbac-component-manager/asset-overrides?filters[contentTypeUid]=api::page.page&filters[entryId]=abc123BFF Resolution Logic
The BFF should implement this resolution order:
1. Check asset-overrides for this specific component instance
→ If found, use override.image
2. Check global-asset-mappings for this component + variant
→ If found, use mapping.image
3. No image available (null)Example BFF query flow:
// 1. Try override first
const override = await fetchOverride({
contentTypeUid: 'api::page.page',
entryId: page.documentId,
componentInstanceId: banner.id,
});
if (override?.image) return override.image;
// 2. Fall back to global default
const globalDefault = await fetchGlobalMapping({
componentUid: 'sections.banner',
enumField: 'type',
variantValue: banner.type, // e.g. "text only"
});
if (globalDefault?.image) return globalDefault.image;
// 3. No image
return null;Data Model
Global Asset Mapping
| Field | Type | Description |
|-------|------|-------------|
| componentUid | string | Component identifier (e.g. sections.banner) |
| enumField | string | The enum attribute name (always type for now) |
| variantValue | string | The enum value (e.g. text only) |
| image | media | Single image from the Media Library |
Unique constraint: componentUid + enumField + variantValue
Asset Override
| Field | Type | Description |
|-------|------|-------------|
| contentTypeUid | string | Content type (e.g. api::page.page) |
| entryId | string | Document ID of the entry |
| componentInstanceId | integer | Strapi's internal component row ID |
| componentUid | string | Component identifier (e.g. sections.banner) |
| image | media | Single image from the Media Library |
Unique constraint: componentInstanceId
Multi-Domain Compatibility
This plugin is fully compatible with the @sensinum/strapi-plugin-multi-domain plugin:
- Records are domain-scoped via the
_domain_lnkjoin tables - Mappings created on domain A are not visible on domain B
- The plugin reads the current domain from the request context
- Domain links are automatically created when records are created through the admin UI
See PLUGIN-DEVELOPMENT-WITH-MULTI-DOMAIN.md in the project root for technical details on the integration pattern.
Lifecycle Hooks
- Entry deletion cascade: When a content entry is deleted, all asset-override records referencing that entry are automatically removed via a lifecycle hook registered in the plugin's bootstrap phase.
Architecture Notes
- Content type schemas are hidden from the Content Manager and Content-Type Builder (
visible: false) - Draft and publish is disabled on both content types (
draftAndPublish: false) - The introspection service reads
strapi.componentsat runtime — no configuration needed when adding new components - Only the
typeenumeration field is surfaced in the UI (extensible to other enum fields in the future via the storedenumFieldcolumn) - The plugin does not modify any existing component schemas
Extending
The architecture supports future extensions:
- Additional asset types: Add
video,icon, or other media fields to the mapping schema - Additional enum fields: The UI currently only shows
typebutenumFieldis stored, so supporting other discriminator enums requires only a UI change - Content-manager integration: A future iteration could inject indicators into the edit view showing which components use global defaults vs overrides
