What you get in the generated ZIP
dynamics-365/
├── Solution/
│ ├── solution.xml # Dataverse solution: publisher, version, components
│ └── customizations.xml # Entity attribute metadata
├── Plugins/
│ ├── {Entity}Plugin.cs # IPlugin: service resolution, message/stage check,
│ │ # UserId (not InitiatingUserId), tracing
│ ├── {Entity}Plugin.csproj # Microsoft.CrmSdk.CoreAssemblies target
│ ├── {Entity}StateMachinePlugin.cs # Pre-operation stage guard for state transitions
│ │ # (present when state machine declared)
│ └── AuditPlugin.cs # Present when audit_trail capability selected
├── PCFControls/
│ └── {Entity}Control/
│ ├── {entity}Control.tsx # React + Fluent UI component
│ ├── ControlManifest.Input.xml # type-group, property, resources — valid format
│ └── index.ts # init(), updateView(), getOutputs(), destroy()
├── PowerAutomate/
│ └── {Entity}Approval.json # Cloud flow: Dataverse trigger → approval → update
├── SecurityRoles/
│ └── {AppName}_User.xml # Entity + field privileges: Read/Write/Create/Delete
├── WebResources/
│ └── {AppName}.webapi.ts # TypeScript Web API service for client JS calls
└── docs/
├── decisions/
│ └── ADR-dynamics-plugin-vs-flow.md # When plugin, when flow, when Business Rule
├── compliance/
│ └── dynamics-security-model.md # Role hierarchy, BU model, FLS
└── runbooks/
└── dynamics-solution-import.md # Managed vs unmanaged, import order, deps
What's already wired
Plugin service resolution — UserId, not InitiatingUserId:
The generated plugin always resolves IOrganizationService via serviceFactory.CreateOrganizationService(context.UserId). Using context.InitiatingUserId instead runs the service as the impersonated caller's security context — which bypasses the plugin's intended security model. This is the most common Dynamics plugin mistake and it's absent from the generated output.
Message and stage guard — first line of Execute():
Every plugin checks context.MessageName and context.Stage before acting. A plugin that runs on every message/stage because someone forgot the guard wastes one synchronous RPC per record operation in the org.
State machine plugin — pre-operation guard:
When your genome declares state transitions, the state machine plugin runs in pre-operation (stage 20), validates the from-state, and throws InvalidPluginExecutionException with a message surfaced to the user before the record saves. Attempting an invalid transition is blocked at the platform level, not silently written.
PCF manifest — property types match the component:
The generated ControlManifest.Input.xml has correct type and of-type values for each declared property. A mismatch (type="SingleLine.Text" on a property that receives a DateTime) causes a silent render failure with a generic error in the browser console.
Solution version format:
<Version>1.0.0.0</Version> — four-part format required. The common mistake of writing 1.0.0 (three parts) causes an import failure with a non-obvious error message.
Security role — all required privilege entries present:
The generated security role XML includes Read, Write, Create, and Append privileges for every entity in the solution. A role missing Append on a related entity produces cryptic "access denied" errors when creating relationships.
ADR — plugin vs flow decision documented:
docs/decisions/ADR-dynamics-plugin-vs-flow.md captures the decision made for each process in your genome: synchronous business logic (e.g. validation) → plugin, long-running approvals → Power Automate, simple field defaults → Business Rule. The reasoning persists so the next developer doesn't re-debate it.
What ships in docs/
docs/decisions/ADR-dynamics-plugin-vs-flow.md— synchronous plugin vs Power Automate flow vs Business Rule decision matrix for each processdocs/compliance/dynamics-security-model.md— role hierarchy, business unit structure, field-level security, auditingdocs/runbooks/dynamics-solution-import.md— managed vs unmanaged, import order, dependency resolution, rollback
Internal links
- Dynamics 365 integration for the full generated file reference
- Salesforce custom development use case for the Salesforce equivalent
CTA
Try it — free plan, no credit card. archiet.com.
Generate a Dynamics 365 project from your entity model. Open the plugin and the solution manifest. Check whether it's the shape your Power Platform team would deploy.