Rock RMS Entity Model Scaffolder
You are scaffolding a new entity model in the Rock RMS codebase, or reviewing an existing one. Rock entities follow strict conventions — this skill enforces them.
The user's request: $ARGUMENTS
Reference Routing Table
Load reference files progressively — only when needed.
| Reference File | Load When |
|---|---|
references/entity-patterns.md |
Before writing any entity code (always in write mode) |
references/common-pitfalls.md |
Before finalizing — both write and review modes |
Do NOT read all files upfront. Read entity-patterns.md always for write mode; read common-pitfalls.md before finalizing.
Step 1 — Understand the Request and Determine Mode
Write mode — The user describes a new entity or says "create", "scaffold", "add". Proceed to Step 2 (Write Mode).
Review mode — The user says "review", "check", "audit", or names an existing entity file. Proceed to Step 2 (Review Mode).
For write mode, parse the user's intent:
- Entity name — PascalCase, singular (e.g.,
CampusSchedule, notCampusSchedules) - Domain — Which Rock domain it belongs to (Core, CRM, Communication, Connection, Event, Finance, Group, Engagement, LMS, etc.)
- Properties — What data fields does it need?
- Relationships — What other entities does it relate to? Required or optional FKs?
- Interfaces — Does it need ordering (
IOrdered), active flag (IHasActiveFlag), caching (ICacheable)? - Base class —
Model<T>(default — includes audit columns, security, attributes) orEntity<T>(simple entities without audit)
If the user doesn't specify all of these, make reasonable decisions based on the entity's purpose, but ask about the domain if unclear.
Write Mode
Step 2 — Research Existing Patterns
Before writing any code:
- Read
references/entity-patterns.mdfor the complete entity template and conventions - Check if the entity already exists:
Rock/Model/**/{EntityName}.cs - Read related entity models that this entity will reference (FK targets) — verify their exact property names, types, and table names
- Check
Rock/SystemGuid/EntityType.csfor naming conventions and to ensure no GUID conflicts - Check
Rock.Enums/if the entity needs new enum types — verify the domain folder exists
Step 3 — Generate SystemGuid
Every entity needs a unique GUID. There are two approaches used in the codebase:
Option A — SystemGuid constant (preferred for new entities):
- Generate a new GUID (uppercase, hyphenated format)
- Add a constant to
Rock/SystemGuid/EntityType.csin alphabetical order - Reference it in the entity class attribute
// In Rock/SystemGuid/EntityType.cs:
/// <summary>
/// The campus schedule entity type
/// </summary>
public const string CAMPUS_SCHEDULE = "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX";
// In the entity class:
[Rock.SystemGuid.EntityTypeGuid( Rock.SystemGuid.EntityType.CAMPUS_SCHEDULE )]
Option B — Inline GUID string: Many entities (especially newer ones) use an inline GUID string directly in the attribute instead of a SystemGuid constant. This is acceptable but less refactorable:
[Rock.SystemGuid.EntityTypeGuid( "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" )]
Use Option A when the entity type GUID will be referenced in migrations, seed data, or other code. Use Option B for entities that are only referenced by type name.
Step 4 — Write the Entity File
File path: Rock/Model/[Domain]/[EntityName]/[EntityName].cs
Namespace: Rock.Model
The entity file contains both the entity class and its EntityTypeConfiguration in the same file. Read references/entity-patterns.md for the complete template and all annotation requirements.
Key structural requirements:
- Copyright header (exact format from reference)
- Class-level attributes:
[RockDomain],[Table],[DataContract],[CodeGenerateRest],[Rock.SystemGuid.EntityTypeGuid] - Inherit from
Model<T>(orEntity<T>for non-audited entities) - Properties organized in
#region Entity Properties/#region Navigation Properties/#region Public Methods EntityTypeConfigurationclass in#region Entity Configurationat the bottom of the file- Every FK relationship configured in the EntityTypeConfiguration constructor
Step 5 — Write Supporting Files (if needed)
Enum definitions
If the entity has enum-typed properties, create the enum file:
- File:
Rock.Enums/[Domain]/[EnumName].cs - Namespace:
Rock.Enums.[Domain](match the folder). Do NOT useRock.Model— that is a legacy holdover. - No
[Enums.EnumDomain]attribute — that attribute is only for legacy enums still in theRock.Modelnamespace. TheRock.Enums.[Domain]namespace already conveys the domain. - XML doc comment on every enum value
Custom service methods
Only create Rock/Model/[Domain]/[EntityName]/[EntityName]Service.cs if the entity needs custom query methods beyond standard CRUD. The base Service<T> class (auto-generated via CodeGeneration) provides standard operations.
If created:
- It's a
partial classextending the auto-generated service - Constructor takes
RockContext - Contains domain-specific query methods (e.g.,
GetByParentId())
Options POCOs
If a service method needs multiple behavior-modifying parameters, create an Options POCO:
- File:
Rock/Model/[Domain]/[EntityName]/Options/[PocoName].cs - Namespace:
Rock.Model.[Domain].[EntityName].Options
Step 6 — Validate
Read references/common-pitfalls.md and run through the checklist before presenting.
Output: Write the files and show their contents in conversation. Remind the user of next steps:
- Run
Rock.CodeGeneration(WPF app) to generate the[Entity]Service.CodeGenerated.csfile - Use
/migrationto scaffold and write the EF migration that creates the table - Use
/bag-generator(if available) to create ViewModels/Bags for Obsidian blocks
Review Mode
Step 2 (Review Mode) — Find and Read the Entity
- If
$ARGUMENTSnames a specific entity, find it:Rock/Model/**/{EntityName}.cs - Read the full entity file — class, properties, navigation, configuration
- If a custom service file exists, read that too
Step 3 (Review Mode) — Research for Comparison
- Read
references/entity-patterns.mdfor expected patterns - Read related entity models referenced by FKs — verify relationship correctness
- Check
Rock/SystemGuid/EntityType.cs— verify the GUID exists and matches - If enums are used, verify they exist in
Rock.Enums/[Domain]/with correct attributes
Step 4 (Review Mode) — Audit
Read references/common-pitfalls.md and run through the checklist, plus:
Structural checks
- Inherits
Model<T>orEntity<T>(not rawDbContextentity) - Copyright header present
- All five class-level attributes present
partial classkeyword used- EntityTypeConfiguration class present in
#region Entity Configuration
Property checks
- All properties have XML doc comments (at minimum
<summary>tags; older entities also have<value>tags) [DataMember]on entity properties (navigation properties may omit it — check if entity follows newer or older conventions)[DataMember( IsRequired = true )]on required properties[Required]on non-nullable value-type properties and required string properties[MaxLength]on string properties that need length constraints- FK properties are nullable
int?for optional relationships, non-nullableintfor required
Relationship checks
- Every FK property has a matching navigation property
- Every FK has a configuration entry in EntityTypeConfiguration
- Cascade delete rules are appropriate (PersonAlias FKs: always
false; parent-child: depends)
Step 5 (Review Mode) — Report Findings
Present findings using severity levels:
| Severity | Meaning | Examples |
|---|---|---|
| CRITICAL | Must fix — will cause build errors, runtime failures, or data issues | Missing EntityTypeConfiguration, wrong base class, missing SystemGuid |
| WARNING | Should fix — violates conventions or could cause subtle bugs | Missing [DataMember], wrong cascade rule, missing XML docs |
| NOTE | Consider — minor improvement | Could implement IOrdered, property naming suggestion |
End with a summary: total findings by severity and a go/no-go recommendation.
If the entity is clean: Say so. Don't invent issues to fill a report.
Examples
Example 1: Simple entity with FK
User says: "Create a CampusSchedule entity in Core that links a Campus to a Schedule with an IsActive flag"
Actions:
- Generate GUID, add to
Rock/SystemGuid/EntityType.cs - Create
Rock/Model/Core/CampusSchedule/CampusSchedule.cswith:CampusId(required FK),ScheduleId(required FK),IsActive(bool)- Navigation properties for Campus and Schedule
- EntityTypeConfiguration with
HasRequiredfor both FKs, cascade delete false
- No enum or custom service needed
Result: Two files written — SystemGuid entry and entity file. User reminded to run CodeGeneration and /migration.
Example 2: Entity with enum and ordering
User says: "Create a NotificationPreference entity in Communication with a PreferenceType enum (Email, SMS, Push) and an Order property"
Actions:
- Create enum file:
Rock.Enums/Communication/NotificationPreferenceType.cs - Generate GUID, add to
Rock/SystemGuid/EntityType.cs - Create entity implementing
IOrderedwithPreferenceTypeenum property andOrderint property
Result: Three files written — enum definition, SystemGuid entry, and entity file with IOrdered interface.
Example 3: Entity with custom service methods
User says: "Create a MembershipCard entity in Group with a PersonAliasId, GroupId, ExpirationDate, and a service method to get active cards for a person"
Actions:
- Generate GUID, add to SystemGuid
- Create entity with FK properties and ExpirationDate
- Create
MembershipCardService.cspartial class withGetActiveCardsForPerson(int personAliasId)method
Result: Three files written — SystemGuid entry, entity file, and custom service file.
Example 4: Review an existing entity
User says: "review the AIAgent entity"
Actions:
- Find and read
Rock/Model/AI/AIAgent/AIAgent.cs - Check against entity patterns checklist
- Verify SystemGuid exists, FK configurations are correct, properties are properly annotated
Result: Severity-based findings report with go/no-go recommendation.
Troubleshooting
"Entity not discovered by EF": Rock uses reflection to auto-discover IEntity implementations. Ensure the class inherits from Model<T> or Entity<T>, is public, is not abstract, and doesn't have [NotMapped]. No DbSet registration is needed.
"CodeGeneration didn't produce a service file": The CodeGeneration WPF app (Rock.CodeGeneration/) generates [Entity]Service.CodeGenerated.cs files. It must be run manually after creating a new entity. The generated file goes in Rock/Model/CodeGenerated/.
"Table name conflicts": The [Table] attribute value should match the entity name (singular, no prefix). Rock removes the pluralizing convention, so [Table("CampusSchedule")] maps to table [CampusSchedule].
"FK cascade delete causing issues": Default to WillCascadeOnDelete( false ) for most relationships. Only use true for true parent-child ownership where deleting the parent should delete all children. PersonAlias audit FKs must always be false.
"Enum not recognized in entity": Ensure the enum is in Rock.Enums/[Domain]/ with namespace Rock.Enums.[Domain] (no [Enums.EnumDomain] attribute — that is only for legacy Rock.Model enums), and add the matching using Rock.Enums.[Domain]; to the entity file. The enum project must be referenced by the Rock project.
"Build error: 'EntityTypeConfiguration' not found": Add using System.Data.Entity.ModelConfiguration; to the entity file's using statements.