Avanade

coreex-contract

"Create or modify a hand-authored contract (DTO/entity) in a CoreEx domain. USE FOR: new root entity contract, new subordinate/request contract, modifying an existing contract (add property, add interface, wire ref-data), extracting a shared base class. DO NOT USE FOR: reference-data contracts (generated via coreex-refdata / *.CodeGen), Infrastructure persistence models (generated by *.Database CodeGen)."

Avanade 28 8 Updated 1w ago

Resources

1
GitHub

Install

npx skillscat add avanade/coreex/coreex-contract

Install via the SkillsCat registry.

SKILL.md

CoreEx: Contract

Guides you through creating or modifying a hand-authored contract (DTO/entity) in *.Contracts. Covers root entities, subordinate types, request/response objects, and base class extraction.

When to Use

  • New root entity contract — independently identifiable, persisted, has its own API endpoint
  • New subordinate, line-item, or request/response contract (accessed via a parent — may still carry its own identifier)
  • Adding or changing properties on an existing contract
  • Wiring a ref-data navigation property ([ReferenceData<T>]) on an existing contract
  • Extracting a shared base class when ≥2 contracts repeat the same fields and every shared field is meaningful on each (genuine superset) — not for patch/subset request contracts

When Not to Use

  • Reference data contracts (generated by *.CodeGen from ref-data.yaml) — use coreex-refdata
  • Infrastructure persistence models (generated by *.Database CodeGen from dbex.yaml)
  • Domain aggregates, entities, value objects — see coreex-domain.instructions.md and the coreex-aggregate skill (DDD domains only)

Quick Reference

Clarifying questions to ask before emitting any code:
0. Resolve from state first. Read the solution-root AGENTS.md Feature Configuration for refdata-enabled (whether [ReferenceData<T>] wiring applies) and check whether a *.Domain project exists (aggregate-mapping context). Only ask for what is unresolved; re-state resolved values for confirmation.

  1. Root or subordinate? (if not explicit)
  2. Identifier type? (default string? — confirm before using any other type)
  3. IETag needed? (default yes for root contracts — omit only on explicit request)
  4. IChangeLog needed? (ask for root contracts — add when created/updated audit trail is required)
  5. Sub-folder within *.Contracts? (default: flat root — only create one if requested)
  6. [Schema] override? (only if user explicitly requests a custom event schema name/version)

Key rules at a glance:

  • [Contract] + partial on all contract classes by default
  • Only [ReferenceData<T>] properties are partial — never make plain properties partial (CS9248)
  • [ReadOnly(true)] on all server-assigned fields (Id, ETag, ChangeLog, computed/derived)
  • [NonNullable] on any property that is mandatory/required (ultimately not nullable) but declared nullable (string?, int?) for DTO flexibility — drives nullable: false in OpenAPI; not the same as System.Diagnostics.CodeAnalysis.NotNull. Never on Id/ETag/ChangeLog; on other [ReadOnly] properties only when the type is never a request body
  • Every property needs a <summary> XML doc comment
  • Same contract type for both API response and event payload — never split them
  • Patch/subset contracts (merge-patch, partial-update requests): standalone class with only the needed fields (+ IETag) — never inherit a sibling and suppress the rest; inheritance is for genuine supersets only

For full workflow, decision trees, and code examples see `references/workflow.md`.

Key References