PA

party-tph-catalog

Simplifies small lookup table management by using a shared polymorphic database structure.

Install

mkdir -p .claude/skills/party-tph-catalog && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/17378" && unzip -o skill.zip -d .claude/skills/party-tph-catalog && rm skill.zip

Installs to .claude/skills/party-tph-catalog

Activation

This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.

Use when adding a small polymorphic catalog dimension (Gender, BlogTag, BlogPostStatus, statuses, types, categories-as-lookup) instead of scaffolding a full entity. Covers the Party base (TPH, int key, PartyType discriminator), PartyRelation for party-to-party links, DTO inheritance from Info/Create/UpdatePartyDto, BasePartyService with SetPolicies and SearchByCriteriaByPartyTypeAsync, and discriminator registration. Domain: Persistence, Domain Modeling. Level: Intermediate. Tags: party, tph, discriminator, catalog, lookup.
529 chars✓ has a “when” triggerlonger than Claude Code's old 250-char listing cap (fine on current versions)
Intermediate

Key capabilities

  • Add small polymorphic catalog dimensions
  • Implement Type-Per-Hierarchy (TPH) pattern for entities
  • Manage DTO inheritance for Info, Create, and Update operations
  • Register discriminators for derived types
  • Handle party-to-party links using `PartyRelation` table

How it works

The skill provides a pattern for small catalog dimensions to share a single table via TPH with a string discriminator, managing inheritance for entities, DTOs, and services.

Inputs & outputs

You give it
A small catalog dimension like Gender or BlogTag
You get back
A new catalog dimension implemented using the Party TPH pattern, including inherited DTOs and service

When to use party-tph-catalog

  • Add new lookup status
  • Create shared catalog entity
  • Implement polymorphic party pattern

About this skill

Activation

ACTIVATION:
  triggers:
    - "party pattern"
    - "catalog dimension"
    - "lookup table"
    - "TPH"
    - "new tag/status/type entity"
  context: decision-point | implementation
  anti-triggers:
    - "Entities with their own rich schema — use scaffold-template-entity"
    - "Anything needing its own table or non-int key"

Detail

Party (TPH) Catalog Pattern

Problem

Small catalog dimensions (Gender, BlogTag, BlogPostStatus, BlogPostVisibility…) each need audit fields, state, soft delete, permissions and CRUD — but giving each its own table + migration + full scaffold is overkill for rows that are basically (id, description).

Solution

All catalog dimensions share one table (Parties) via TPH with a PartyType string discriminator.

  1. Inherit Party (which already implements IEntity<int>, IAuditableEntity, IStateEntity; Description serves as the display name). New properties must be nullable/defaulted so they don't interfere with sibling types:
public class BlogTag : Party
{
    public string Slug { get; set; } = string.Empty;
    public string TagName => Description ?? string.Empty;   // computed alias for clarity
}
public class Gender : Party { }
  1. Register the discriminator in PartyConfiguration (.HasValue<Gender>(ResourceIdentifiers.Gender)), add DbSet<Gender> Genders to AppDbSetter, and the ResourceIdentifiers constant. No new table/migration for the type itself (only if you added columns).
  2. DTOs inherit the Party DTOs in one file: InfoGenderDto : InfoPartyDto, CreateGenderDto : CreatePartyDto, UpdateGenderDto : UpdatePartyDto (reuse DeletePartyDto).
  3. Service inherits BasePartyService<TParty, TInfo, TCreate, TUpdate, TDelete> (int key, extends PayloadService<>): call SetPolicies(_cachePolicies) in the constructor; CreateAsync stamps createDto.PartyType = typeof(TParty).Name automatically; type-scoped reads via SearchByCriteriaByPartyTypeAsync<TDerived>(model) / ExportByPartyTypeAsync<TDerived>(...) which filter by discriminator through _repository.AsQueryableOfType<TDerived>(false).
  4. Party-to-party links use the PartyRelation table (PartyId, RelatedPartyId, RelationshipType, StartDate/EndDate, notes; auditable) — don't invent join tables between dimensions.
  5. Endpoints/permissions follow the standard recipe (GenderEndpoints : IEndpointDefinition, attribute triad).

Applicability

ConditionApply?
Small lookup shared-shape dimension (id + description + state)✅ Yes
Dimension with 1-3 extra nullable columns✅ Yes
Entity with rich schema, relations, own lifecycle❌ No — full scaffold
Read-only projection❌ No — QueryPayloadService<>

Gotchas

  1. Key is int (Party owns it) — not the Guid default of full entities.
  2. New properties on a derived type live on the shared table — keep them nullable or defaulted, or sibling inserts break.
  3. Forgetting the discriminator registration makes EF treat rows as base Party — type-scoped queries return empty.
  4. SearchByCriteriaByPartyTypeAsync caches under the first policy (falls back to CacheRoutes.Parties) — call SetPolicies or you share the generic Parties cache.
  5. Root SKILL.md declares this pattern as its anti-trigger — one entry point per flow: full entity → root skill, catalog dimension → this one.

Related Skills

  • scaffold-template-entity, permission-model, cache-policy-eviction

When not to use it

  • When entities have their own rich schema and require a full scaffold
  • When an entity needs its own table or a non-integer key
  • When a read-only projection is needed

Limitations

  • The key for entities implemented with this pattern is always `int`
  • New properties on derived types must be nullable or defaulted
  • Forgetting discriminator registration makes EF treat rows as base `Party`

How it compares

This skill offers a specialized pattern for small catalog entities, reusing a single table and inheritance, which is more efficient than scaffolding a full entity for each.

Compared to similar skills

party-tph-catalog side by side with the closest alternatives in the catalog.

SkillInstallsUpdatedSafetyDifficulty
party-tph-catalog (this skill)025dNo flagsIntermediate
drizzle-orm321moNo flagsIntermediate
django-pro203moNo flagsIntermediate
event-store-design52moNo flagsAdvanced

Try saying

Example prompts that trigger this skill in your AI assistant.

Search skills

Search the agent skills registry