Skip to main content
general-create-repository Create or extend a repository in the Umbraco backoffice. Covers detail (CRUD), item (batch lookup), collection (paginated list), and action-specific (publish, duplicate, move, etc.) repositories. Use when the user says "create a repository", "add a data source", or when a feature needs to fetch or post data. Each repository type has its own template — pick the right one based on the operation.
Ir para a instalação Skills Marketplace Descubra e explore skills de IA criadas pela comunidade.
Instalar com Codex ou Claude Copie este prompt, cole no Codex, Claude ou outro assistente e deixe que ele revise a página da skill e instale para você.
Copiar promptMostrar detalhes do prompt Um comando direto ignora o prompt de revisão. Verifique a origem antes de executá-lo.
npx skills add https://github.com/umbraco/Umbraco-CMS --skill general-create-repositoryO comando permanece em uma só linha. Role horizontalmente para revisá-lo antes de copiar.
Prefere uma cópia local? Baixe os arquivos disponíveis atualmente no SkillsMP.
Baixar Zip Baixando... Mais deste repositório Automated PR code review for Umbraco CMS. Analyzes changed files for intent, impact on consumers, breaking changes, architecture compliance, and code quality. Non-interactive — outputs a full structured review. Use this skill whenever the user asks to review a branch, review a PR, check their changes for issues, analyze a diff, or validate breaking change patterns — even if they don't say "review" explicitly. Does NOT apply to writing new code, fixing bugs, refactoring, explaining architecture, writing tests, or reviewing documentation content.
Regenerate the Management API OpenApi.json for Umbraco CMS from a running backend, and optionally regenerate the backoffice hey-api client so its generated types match. Proactively offer to run this at the end of any work that adds, removes, or changes Management API controllers, endpoints, routes, or their request/response/view models — OpenApi.json and the generated backend-api client go stale the moment the API surface changes, so suggest syncing rather than waiting to be asked. Also use it whenever the user asks to update/refresh/regenerate OpenApi.json or the openapi document, says the generated backend-api / hey-api client is stale or out of date, or has just added an endpoint and needs the client types — including phrasings like "sync the OpenAPI spec", "update the API client", "the openapi doc is out of date", or "regenerate the server API", even if OpenApi.json isn't named explicitly. Does NOT apply to Delivery API changes or to internal service/repository edits that don't alter the Management API su
general-add-value-summary Add a value summary extension so a feature's typed value can be displayed compactly in collection views (e.g., table columns). Use when a feature or property editor already has a value type and needs a renderer for collection table cells. Two variants — simple (element only, no API call) and resolver (batch API resolution needed). Prerequisite: a value type constant must already exist — use the general-add-value-type skill first if it doesn't.
Ocupações relacionadas SOC
Baseado na classificação ocupacional SOC
name general-create-repository description Create or extend a repository in the Umbraco backoffice. Covers detail (CRUD), item (batch lookup), collection (paginated list), and action-specific (publish, duplicate, move, etc.) repositories. Use when the user says "create a repository", "add a data source", or when a feature needs to fetch or post data. Each repository type has its own template — pick the right one based on the operation. allowed-tools Read, Write, Edit, Grep, Glob
Create Repository
Create or extend a repository and its data source for an entity feature in the Umbraco backoffice.
Foundational documentation
Read these before creating a repository — they define the conventions this skill builds on:
Repositories — Repository categories, file structure, naming, extension registration, when to use which type
Data Flow — Full data flow chain, tryExecute, model mapping, store direction
Package Development — Folder conventions, vertical slices, public API rules
What you need from the user
Entity name — singular, kebab-case (e.g., webhook, document, data-type)
Repository type — detail, item, collection, or action-specific
Package path — which package directory (e.g., src/packages/webhook/webhook/)
Additional for action-specific: 4. Action name — what the operation does (e.g., duplicate, move-to, publishing, culture-and-hostnames) 5. Methods — what operations the repository exposes
Choosing the right type
Option A: Detail Repository The most common repository type. Handles full CRUD lifecycle with store caching.
Prerequisites
Entity type constant in entity.ts
Detail model type in types.ts (must extend UmbEntityModel — needs entityType and unique fields)
Generated API client available for the entity
Files to create {package-path}/repository/detail/
├── {entity}-detail.repository.ts
├── {entity}-detail.server.data-source.ts
├── {entity}-detail.store.ts
├── {entity}-detail.store.context-token.ts
├── constants.ts
└── manifests.ts
Step 1: Create store context token File: {entity}-detail.store.context-token.ts
import type { UmbDetailStoreBase } from '@umbraco-cms/backoffice/store' ;
import type { Umb {EntityName }DetailModel } from '../../types.js' ;
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api' ;
export const UMB_ {ENTITY }_DETAIL_STORE_CONTEXT = new UmbContextToken <UmbDetailStoreBase <Umb {EntityName }DetailModel >>(
'Umb{EntityName}DetailStore' ,
);
Step 2: Create store File: {entity}-detail.store.ts
import type { Umb {EntityName }DetailModel } from '../../types.js' ;
import { UMB_ {ENTITY }_DETAIL_STORE_CONTEXT } from './{entity}-detail.store.context-token.js' ;
import { UmbDetailStoreBase } from '@umbraco-cms/backoffice/store' ;
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api' ;
export class Umb {EntityName }DetailStore extends UmbDetailStoreBase <Umb {EntityName }DetailModel > {
constructor (host : UmbControllerHost ) {
super (host, UMB_ {ENTITY }_DETAIL_STORE_CONTEXT);
}
}
export { Umb {EntityName }DetailStore as api };
Step 3: Create server data source File: {entity}-detail.server.data-source.ts
The data source maps between server API types and domain models. See Data Flow for context on how this fits in the chain.
import type { Umb {EntityName }DetailModel } from '../../types.js' ;
import { UMB_ {ENTITY }_ENTITY_TYPE } from '../../entity.js' ;
import { UmbId } from '@umbraco-cms/backoffice/id' ;
import type { UmbDetailDataSource } from '@umbraco-cms/backoffice/repository' ;
import { {EntityName }Service } from '@umbraco-cms/backoffice/external/backend-api' ;
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api' ;
import { tryExecute } from '@umbraco-cms/backoffice/resources' ;
export class Umb {EntityName }DetailServerDataSource implements UmbDetailDataSource <Umb {EntityName }DetailModel > {
#host : UmbControllerHost ;
constructor (host : UmbControllerHost ) {
this .#host = host;
}
async createScaffold (preset : Partial <Umb {EntityName}DetailModel > = {} ) {
const data : Umb {EntityName }DetailModel = {
entityType : UMB_ {ENTITY }_ENTITY_TYPE,
unique : UmbId .new (),
name : '' ,
...preset,
};
return { data };
}
async read (unique : string ) {
if (!unique) throw new Error ('Unique is missing' );
const { data, error } = await tryExecute (
this .#host,
{EntityName }Service .get {EntityName }ById ({ path : { id : unique } }),
);
if (error || !data) {
return { error };
}
const model : Umb {EntityName }DetailModel = {
entityType : UMB_ {ENTITY }_ENTITY_TYPE,
unique : data.id ,
name : data.name ?? '' ,
};
return { data : model };
}
async create (model : Umb {EntityName}DetailModel , parentUnique : string | null ) {
if (!model) throw new Error ('Model is missing' );
const body = {
id : model.unique ,
name : model.name ,
};
const { data, error } = await tryExecute (
this .#host,
{EntityName }Service .post {EntityName }({ body }),
);
if (data) {
return this .read (data as never );
}
return { error };
}
async update (model : Umb {EntityName}DetailModel ) {
if (!model.unique ) throw new Error ('Unique is missing' );
const body = {
name : model.name ,
};
const { error } = await tryExecute (
this .#host,
{EntityName }Service .put {EntityName }ById ({ path : { id : model.unique }, body }),
);
if (!error) {
return this .read (model.unique );
}
return { error };
}
async delete (unique : string ) {
if (!unique) throw new Error ('Unique is missing' );
return tryExecute (
this .#host,
{EntityName }Service .delete {EntityName }ById ({ path : { id : unique } }),
);
}
}
Important: Find the actual generated API service name and method names by checking @umbraco-cms/backoffice/external/backend-api. The names above are illustrative — the real generated service may differ.
Step 4: Create repository File: {entity}-detail.repository.ts
import type { Umb {EntityName }DetailModel } from '../../types.js' ;
import { Umb {EntityName }DetailServerDataSource } from './{entity}-detail.server.data-source.js' ;
import { UMB_ {ENTITY }_DETAIL_STORE_CONTEXT } from './{entity}-detail.store.context-token.js' ;
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api' ;
import { UmbDetailRepositoryBase } from '@umbraco-cms/backoffice/repository' ;
export class Umb {EntityName }DetailRepository extends UmbDetailRepositoryBase <Umb {EntityName }DetailModel > {
constructor (host : UmbControllerHost ) {
super (host, Umb {EntityName }DetailServerDataSource , UMB_ {ENTITY }_DETAIL_STORE_CONTEXT);
}
}
export { Umb {EntityName }DetailRepository as api };
Step 5: Create constants export const UMB_ {ENTITY }_DETAIL_REPOSITORY_ALIAS = 'Umb.Repository.{EntityName}.Detail' ;
export const UMB_ {ENTITY }_DETAIL_STORE_ALIAS = 'Umb.Store.{EntityName}.Detail' ;
Step 6: Create manifests import { UMB_ {ENTITY }_DETAIL_REPOSITORY_ALIAS, UMB_ {ENTITY }_DETAIL_STORE_ALIAS } from './constants.js' ;
import { Umb {EntityName }DetailStore } from './{entity}-detail.store.js' ;
export const manifests : Array <UmbExtensionManifest > = [
{
type : 'repository' ,
alias : UMB_ {ENTITY }_DETAIL_REPOSITORY_ALIAS,
name : '{EntityName} Detail Repository' ,
api : () => import ('./{entity}-detail.repository.js' ),
},
{
type : 'store' ,
alias : UMB_ {ENTITY }_DETAIL_STORE_ALIAS,
name : '{EntityName} Detail Store' ,
api : Umb {EntityName }DetailStore ,
},
];
Step 7: Wire manifests into parent Import and spread in the parent module's manifests.ts:
import { manifests as detailRepositoryManifests } from './repository/detail/manifests.js' ;
export const manifests : Array <UmbExtensionManifest > = [
...detailRepositoryManifests,
];
Detail repository checklist
Option B: Item Repository For batch-fetching lightweight display info (name, icon, entity type) by unique IDs. Used by pickers, reference lists, and breadcrumbs.
Prerequisites
Item model type in types.ts (needs unique field)
Generated API client with a batch/list endpoint
Files to create {package-path}/item/repository/
├── {entity}-item.repository.ts
├── {entity}-item.server.data-source.ts
├── {entity}-item.store.ts
├── {entity}-item.store.context-token.ts
├── constants.ts
└── manifests.ts
Step 1: Create item store context token File: {entity}-item.store.context-token.ts
import type { UmbItemStore } from '@umbraco-cms/backoffice/store' ;
import type { Umb {EntityName }ItemModel } from '../../types.js' ;
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api' ;
export const UMB_ {ENTITY }_ITEM_STORE_CONTEXT = new UmbContextToken <UmbItemStore <Umb {EntityName }ItemModel >>(
'Umb{EntityName}ItemStore' ,
);
Step 2: Create item store File: {entity}-item.store.ts
import type { Umb {EntityName }ItemModel } from '../../types.js' ;
import { UMB_ {ENTITY }_ITEM_STORE_CONTEXT } from './{entity}-item.store.context-token.js' ;
import { UmbItemStoreBase } from '@umbraco-cms/backoffice/store' ;
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api' ;
export class Umb {EntityName }ItemStore extends UmbItemStoreBase <Umb {EntityName }ItemModel > {
constructor (host : UmbControllerHost ) {
super (host, UMB_ {ENTITY }_ITEM_STORE_CONTEXT);
}
}
export { Umb {EntityName }ItemStore as api };
Step 3: Create item server data source File: {entity}-item.server.data-source.ts
import type { Umb {EntityName }ItemModel } from '../../types.js' ;
import { UMB_ {ENTITY }_ENTITY_TYPE } from '../../entity.js' ;
import { UmbItemServerDataSourceBase } from '@umbraco-cms/backoffice/repository' ;
import type { {EntityName }ItemResponseModel } from '@umbraco-cms/backoffice/external/backend-api' ;
import { {EntityName }Service } from '@umbraco-cms/backoffice/external/backend-api' ;
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api' ;
export class Umb {EntityName }ItemServerDataSource extends UmbItemServerDataSourceBase <
{EntityName }ItemResponseModel ,
Umb {EntityName }ItemModel
> {
constructor (host : UmbControllerHost ) {
super (host, {
getItems : (uniques ) => {EntityName }Service .getItem {EntityName }({ query : { id : uniques } }),
mapper : (item ) => ({
entityType : UMB_ {ENTITY }_ENTITY_TYPE,
unique : item.id ,
name : item.name ?? '' ,
}),
});
}
}
Step 4: Create item repository File: {entity}-item.repository.ts
import type { Umb {EntityName }ItemModel } from '../../types.js' ;
import { Umb {EntityName }ItemServerDataSource } from './{entity}-item.server.data-source.js' ;
import { UMB_ {ENTITY }_ITEM_STORE_CONTEXT } from './{entity}-item.store.context-token.js' ;
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api' ;
import { UmbItemRepositoryBase } from '@umbraco-cms/backoffice/repository' ;
export class Umb {EntityName }ItemRepository extends UmbItemRepositoryBase <Umb {EntityName }ItemModel > {
constructor (host : UmbControllerHost ) {
super (host, Umb {EntityName }ItemServerDataSource , UMB_ {ENTITY }_ITEM_STORE_CONTEXT);
}
}
export { Umb {EntityName }ItemRepository as api };
Step 5: Create constants and manifests Follow the same pattern as detail (Step 5–6), using Item instead of Detail in aliases.
Item repository checklist
Option C: Collection Repository For paginated/filtered listings. No base class — implement the UmbCollectionRepository interface on UmbRepositoryBase.
Files to create {package-path}/collection/repository/
├── {entity}-collection.repository.ts
├── {entity}-collection.server.data-source.ts
└── manifests.ts
Step 1: Create collection server data source File: {entity}-collection.server.data-source.ts
import type { Umb {EntityName }CollectionFilterModel } from '../types.js' ;
import { {EntityName }Service } from '@umbraco-cms/backoffice/external/backend-api' ;
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api' ;
import { tryExecute } from '@umbraco-cms/backoffice/resources' ;
export class Umb {EntityName }CollectionServerDataSource {
#host : UmbControllerHost ;
constructor (host : UmbControllerHost ) {
this .#host = host;
}
async getCollection (filter : Umb {EntityName}CollectionFilterModel ) {
const { data, error } = await tryExecute (
this .#host,
{EntityName }Service .get {EntityName }({ query : { skip : filter.skip , take : filter.take } }),
);
if (error || !data) {
return { error };
}
return {
data : {
items : data.items .map ((item ) => ({
})),
total : data.total ,
},
};
}
}
Step 2: Create collection repository File: {entity}-collection.repository.ts
import { Umb {EntityName }CollectionServerDataSource } from './{entity}-collection.server.data-source.js' ;
import type { Umb {EntityName }CollectionFilterModel } from '../types.js' ;
import { UmbRepositoryBase } from '@umbraco-cms/backoffice/repository' ;
import type { UmbCollectionRepository } from '@umbraco-cms/backoffice/collection' ;
export class Umb {EntityName }CollectionRepository
extends UmbRepositoryBase
implements UmbCollectionRepository
{
#collectionSource = new Umb {EntityName }CollectionServerDataSource (this );
async requestCollection (filter : Umb {EntityName}CollectionFilterModel ) {
return this .#collectionSource.getCollection (filter);
}
}
export { Umb {EntityName }CollectionRepository as api };
Collection repository checklist
Option D: Action-Specific Repository For domain operations that don't fit CRUD — publish, duplicate, move, sort, recycle bin, etc.
Prerequisites
Entity type constant
Generated API client with the relevant endpoint
Files to create {package-path}/{action-location}/repository/
├── {entity}-{action}.repository.ts
├── {entity}-{action}.server.data-source.ts
├── types.ts # Optional — args/response types
└── manifests.ts
Entity actions: entity-actions/{action-name}/repository/
Bulk actions: entity-bulk-actions/{action-name}/repository/
Domain sub-features: {feature-name}/repository/ (e.g., publishing/repository/)
Step 1: Create types (if needed) export interface Umb {Action }{EntityName }RequestArgs {
unique : string ;
}
Step 2: Create server data source File: {entity}-{action}.server.data-source.ts
import type { Umb {Action }{EntityName }RequestArgs } from './types.js' ;
import { {EntityName }Service } from '@umbraco-cms/backoffice/external/backend-api' ;
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api' ;
import { tryExecute } from '@umbraco-cms/backoffice/resources' ;
export class Umb {Action }{EntityName }ServerDataSource {
#host : UmbControllerHost ;
constructor (host : UmbControllerHost ) {
this .#host = host;
}
async {actionMethod}(args : Umb {Action }{EntityName }RequestArgs ) {
if (!args.unique ) throw new Error ('Unique is missing' );
return tryExecute (
this .#host,
{EntityName }Service .{apiMethod}({
path : { id : args.unique },
body : {
},
}),
);
}
}
Step 3: Create repository File: {entity}-{action}.repository.ts
import { Umb {Action }{EntityName }ServerDataSource } from './{entity}-{action}.server.data-source.js' ;
import type { Umb {Action }{EntityName }RequestArgs } from './types.js' ;
import { UMB_NOTIFICATION_CONTEXT } from '@umbraco-cms/backoffice/notification' ;
import { UmbRepositoryBase } from '@umbraco-cms/backoffice/repository' ;
export class Umb {Action }{EntityName }Repository extends UmbRepositoryBase {
#{action}Source = new Umb {Action }{EntityName }ServerDataSource (this );
async request{Action }(args : Umb {Action }{EntityName }RequestArgs ) {
const { data, error } = await this .#{action}Source .{actionMethod}(args);
if (!error) {
const notificationContext = await this .getContext (UMB_NOTIFICATION_CONTEXT );
const notification = { data : { message : `{Action} completed` } };
notificationContext.peek ('positive' , notification);
}
return { data, error };
}
}
export { Umb {Action }{EntityName }Repository as api };
Step 4: Create manifests export const manifests : Array <UmbExtensionManifest > = [
{
type : 'repository' ,
alias : 'Umb.Repository.{EntityName}.{Action}' ,
name : '{EntityName} {Action} Repository' ,
api : () => import ('./{entity}-{action}.repository.js' ),
},
];
Action-specific repository checklist
Reference examples