A plugin that resolves IOrganizationService with InitiatingUserId instead of UserId silently bypasses the calling user's security context. A solution XML with an invalid version format fails to import. A PCF manifest with a mismatched property type doesn't deploy. These aren't edge cases — they're the failures that eat the first day of every Dynamics engagement.
Archiet generates the full Dynamics 365 customisation scaffold correctly. The output follows the patterns that Power Platform architects approve, and the ADR explains the architectural decisions so your team understands why each choice was made.
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.