Skip to content

Rules Index

Referenceable rules across this guideline. Each rule has a short, stable ID — DGT-<AREA>-<NUMBER> — assigned ascending per area and never reused: if a rule is removed, its ID is retired, not recycled, so references from project documentation stay unambiguous. See Rule Notation for the scheme.

Cite a rule by its ID (e.g. "deviates from DGT-SRV-060"); the links below jump straight to the rule where it is stated. Each row also has its own anchor (e.g. reference/rules.md#dgt-srv-060), so you can point a colleague at one specific rule directly in this list — they land on it and see the surrounding rules for context.

Foundation (FND)

Rule Statement Defined in
DGT-FND-010 If the customer has a defined standard, that standard takes precedence over this guideline. Scope & Principles
DGT-FND-020 Deviations from this guideline are permitted but must be documented and justified in the project's architectural documentation. Scope & Principles
DGT-FND-030 Every project maintains an ADR log in its main repository (docs/decisions/, one Markdown file per decision). Architecture Decision Records
DGT-FND-040 Fundamental decisions for or against a guideline rule require an ADR in MADR format. Architecture Decision Records
DGT-FND-050 A deviation ADR references the affected rule ID machine-readably; the ADR lifecycle is maintained. Architecture Decision Records
DGT-FND-060 ADRs pass through PR review and are part of the Definition of Done's documentation item. Architecture Decision Records

Architecture (ARC)

Rule Statement Defined in
DGT-ARC-010 Organize Dataverse solutions by component type (core/server/client/apps/flows), with a strict, documented dependency direction. Solution Architecture
DGT-ARC-020 A component lives in exactly one solution; tables are added segmented, never "Add all assets". Solution Architecture
DGT-ARC-030 Development environments hold the unmanaged solution; every other environment always receives it managed. Solution Architecture
DGT-ARC-040 Use the DIGITALL publisher/dgt_ prefix for productized components; a customer-specific publisher/prefix for customer projects. Publisher & Prefix
DGT-ARC-050 Once a prefix is chosen for a project, it does not change. Publisher & Prefix
DGT-ARC-060 Follow Microsoft's customization guidance by default; deviate only with a documented, concrete reason. Publisher & Prefix
DGT-ARC-070 Prefer an XrmToolBox plugin over installing a special-purpose third-party solution. Publisher & Prefix
DGT-ARC-080 Four target environments (dev → test → UAT → prod) is the common baseline; three is the minimum. Environment Strategy
DGT-ARC-090 Enable Managed Environments on every Power Platform Pipelines target environment from initial setup. Environment Strategy
DGT-ARC-100 One development environment per developer once the team is larger than one or two people. Environment Strategy
DGT-ARC-110 Decide the deployment approach (Pipelines / Azure DevOps / GitHub Actions / hybrid) once, early in the project. Deployment Approach

Customizing (CUS)

Rule Statement Defined in
DGT-CUS-010 All schema names are snake_case, lowercase, [publisher]_[name][_type-suffix]. Naming Conventions
DGT-CUS-020 Set IsCustomizable = false for security roles and rollup/calculated fields. Naming Conventions
DGT-CUS-030 Check whether a standard table already fits before adding a custom one. Tables, Columns & Relationships
DGT-CUS-040 Decide ownership, table type, and primary column deliberately — they are fixed at table creation. Tables, Columns & Relationships
DGT-CUS-050 High-volume telemetry-style data goes into an elastic table with a TTL column, never a standard table. Tables, Columns & Relationships
DGT-CUS-060 Pick the narrowest correct column data type. Tables, Columns & Relationships
DGT-CUS-070 Use global choices instead of local ones for any value list used on more than one column. Tables, Columns & Relationships
DGT-CUS-080 Don't store what you can derive — prefer rollup/calculated/formula columns over a plugin-written plain column. Tables, Columns & Relationships
DGT-CUS-090 Define an alternate key for any column an external system uses to address a record. Tables, Columns & Relationships
DGT-CUS-100 Default relationships to referential cascade; use parental only where the child has no meaning without the parent. Tables, Columns & Relationships
DGT-CUS-110 One main form per persona, not one form with everything hidden per role. Forms, Views & BPF
DGT-CUS-120 Logic belongs in code once non-trivial; register only OnLoad and wire the rest in TypeScript. Forms, Views & BPF
DGT-CUS-130 Keep view columns lean — every column is a query column. Forms, Views & BPF
DGT-CUS-140 A BPF models a cross-table process as few, meaningful ordered stages. Forms, Views & BPF
DGT-CUS-150 Build for the Unified Interface with the modern designers; classic-only features are off limits. Forms, Views & BPF
DGT-CUS-160 Build commands in the modern Command Bar Designer, not by hand-editing ribbon XML. Command Bar
DGT-CUS-170 Don't hide or override standard command-bar buttons globally without a specific, documented reason. Command Bar
DGT-CUS-180 Brand per app using the modern model-driven app theme, kept inside the solution. Themes & Icons
DGT-CUS-190 Use SVG web resources for table and command-bar icons. Themes & Icons
DGT-CUS-200 Assign unattended/production flow connections via an application user / service principal. Env Variables & Connection References
DGT-CUS-210 In development, create the environment variable definition only (no value) and deploy that. Env Variables & Connection References
DGT-CUS-220 Apply least privilege — grant only what a persona needs, at the smallest working ownership depth. Security Model
DGT-CUS-230 Don't edit out-of-the-box security roles — copy and adjust. Security Model
DGT-CUS-240 No standing System Administrator for application/service accounts. Security Model
DGT-CUS-250 Test with a real security role, not as System Administrator. Security Model
DGT-CUS-260 Never implement security through UI visibility — use column security and privileges. Security Model
DGT-CUS-270 Security roles are solution components and get deployed — never rebuilt manually in test/prod. Security Model

Server-side (SRV)

Rule Statement Defined in
DGT-SRV-010 Plugin and Custom API assemblies target net462. Project Setup
DGT-SRV-020 Use the SDK-style project format, not the legacy non-SDK .csproj. Project Setup
DGT-SRV-030 Reference Microsoft.CrmSdk.CoreAssemblies with PrivateAssets="all" — not Dataverse.Client. Project Setup
DGT-SRV-040 One plugin/Custom API/workflow group per assembly, versioned independently. Project Setup
DGT-SRV-050 Plugin packages are not signed (exceptions: classic single-assembly, managed identity). Project Setup
DGT-SRV-060 Plugin/Custom API projects use the plugin package (dependent-assembly .nupkg) format; ILMerge is not allowed. Plugin Packages
DGT-SRV-070 A plugin package/assembly belongs to exactly one solution. Plugin Packages
DGT-SRV-080 Inherit Executor and return a meaningful ExecutionResult (Ok/Failure/Skipped), not always Ok. DIGITALL Assembly
DGT-SRV-090 Prefer SecuredOrganizationService/ElevatedOrganizationService over calling OrganizationService(...) directly. DIGITALL Assembly
DGT-SRV-100 Register steps declaratively via [PluginRegistration] — code is the source of truth. Registration Attributes
DGT-SRV-110 Use generated early-bound models (dgtp codegeneration); generated code is not committed. Early-Bound Models
DGT-SRV-120 Prefer Custom APIs over classic (un)bound Actions for new server-side operations. Custom API & Data Providers
DGT-SRV-130 Keep plugins stateless — no mutable static state. Patterns & Pitfalls
DGT-SRV-140 No ExecuteMultipleRequest/ExecuteTransactionRequest inside plugins. Patterns & Pitfalls
DGT-SRV-150 No custom threading (Parallel.*, Task.Run) inside plugins. Patterns & Pitfalls
DGT-SRV-160 Synchronous steps on Retrieve/RetrieveMultiple only in justified exceptions. Patterns & Pitfalls
DGT-SRV-170 Don't use context.Depth as loop control — use filtering attributes and precise registration. Patterns & Pitfalls
DGT-SRV-180 Every query states an explicit ColumnSet — never AllColumns. Patterns & Pitfalls
DGT-SRV-190 Use InvalidPluginExecutionException (Status = Succeeded) only for user-facing validation messages. Patterns & Pitfalls
DGT-SRV-200 Use FilterAttributes on the registration rather than re-checking inside Execute(). Patterns & Pitfalls
DGT-SRV-210 Keep SuppressNullableSupport: true consistent across every project sharing a generated model. Patterns & Pitfalls

Client-side (CLI)

Rule Statement Defined in
DGT-CLI-010 Form and command-bar scripts are written in TypeScript and bundled with webpack (the webresources-template). TypeScript Web Resources
DGT-CLI-020 Only *.form.ts / *.ribbon.ts become bundles; shared code lives in plain imported modules. TypeScript Web Resources
DGT-CLI-030 Register only the form's OnLoad event in the designer; wire all other handlers in code. TypeScript Web Resources
DGT-CLI-040 Generate typed models with dgtp codegeneration and type the form context against them. TypeScript Web Resources
DGT-CLI-050 No deprecated client APIs: no Xrm.Page, no parent.Xrm, no platform scripts, no OData v2. TypeScript Web Resources
DGT-CLI-060 Biome owns formatting and linting for web resources; don't hand-tune style. TypeScript Web Resources
DGT-CLI-070 Use pac for PCF scaffolding rather than copying an older project's structure by hand. PCF Controls

Cloud & Integration (INT)

Rule Statement Defined in
DGT-INT-010 Don't do slow/external work synchronously in a plugin (2-minute sandbox limit) — slow or bursty work runs async. Cloud & Integration
DGT-INT-020 Use a single, lazily-created, shared HttpClient — never one per invocation. Cloud & Integration
DGT-INT-030 External calls from plugins set an explicit timeout and KeepAlive = false. Cloud & Integration
DGT-INT-040 Every integration handles HTTP 429 / Retry-After (service protection limits); use ServiceClient or equivalent backoff. Cloud & Integration
DGT-INT-050 Never use the Dataverse Search API for bulk queries. Cloud & Integration
DGT-INT-060 Push Dataverse events to Azure asynchronously via service-endpoint registration, not synchronous POSTs from plugins. Cloud & Integration

Power Automate Flows (FLW)

Rule Statement Defined in
DGT-FLW-010 Create flows solution-aware, never as standalone "My flows" artifacts. Power Automate Flows
DGT-FLW-020 No production flow without error handling (scope-based try/catch and failure notification). Power Automate Flows
DGT-FLW-030 Filter in the trigger (trigger conditions, column/row filters), not with a first-action condition. Power Automate Flows
DGT-FLW-040 Treat concurrency and pagination settings as code — variables aren't thread-safe under concurrency; raise pagination limits explicitly. Power Automate Flows

Testing & Quality (TST)

Rule Statement Defined in
DGT-TST-010 Use Digitall.Dataverse.Testing (in-memory) for plugin/Custom API unit tests, not a live environment. Server-side Unit Testing
DGT-TST-020 Run the Power Apps Solution Checker against every packed solution as a build-pipeline quality gate. Solution Checker
DGT-TST-030 Unit-test TypeScript web resource logic with Jest, mocking Xrm via xrm-mock. Client-side Testing
DGT-TST-040 A user story must meet the Definition of Ready before entering a sprint. Definition of Ready / Done
DGT-TST-050 A user story must meet the Definition of Done, including passing tests and updated documentation, to be closed. Definition of Ready / Done
DGT-TST-060 Activate each release wave's Early Access in a sandbox and run a regression before the wave reaches production. Performance & Release Waves

ALM & Deployment (ALM)

Rule Statement Defined in
DGT-ALM-010 Regularly commit the unpacked Dataverse solution to source control, regardless of deployment approach. Source Control
DGT-ALM-020 Enforce a single line-ending convention across the repository via .gitattributes. Source Control
DGT-ALM-030 No secrets, environment-specific values, or build artifacts in the repository. Source Control
DGT-ALM-040 Bump the solution version via dgtp maintenance solution-version, not by hand-editing solution.xml. Versioning
DGT-ALM-050 The plugin package/assembly version must increase on every build that gets pushed. Versioning
DGT-ALM-060 Follow the canonical build-pipeline step order, independent of the CI orchestrator. Build Pipeline
DGT-ALM-070 Use token-based (service principal) dgtp profiles for CI — never personal credentials. Build Pipeline
DGT-ALM-080 Import managed solutions as Upgrade (or stage for upgrade), not Update. Pre- & Post-Deployment Tasks
DGT-ALM-090 Provide connection references and environment-variable values via a deployment settings file per target. Pre- & Post-Deployment Tasks
DGT-ALM-100 Power Platform Pipelines production deployments run delegated (service principal) and require approval. Power Platform Pipelines
DGT-ALM-110 Use YAML pipelines checked into the repository, not classic editor-defined pipelines. Azure DevOps
DGT-ALM-120 Use the matching dgtp export/dgtp import command pair for non-solution-aware config objects. Config & Reference Data Migration

Operations (OPS)

Rule Statement Defined in
DGT-OPS-010 Enable Application Insights integration for every production environment. Monitoring & Telemetry
DGT-OPS-020 Every production environment has the monitoring baseline (plugin failures/time, flow failures, checker trend, deployment history). Monitoring & Telemetry
DGT-OPS-030 Define DLP policies at the environment-group or tenant level appropriate to the customer's risk posture. Governance & DLP
DGT-OPS-040 Don't customize outside development environments — rely on Managed Environments to enforce this. Governance & DLP
DGT-OPS-050 Scope production access to what's needed for support/troubleshooting, not standing System Administrator. Governance & DLP