Introduction
While Canvas Apps excel at mobile-first experiences, Model-Driven Apps shine when building complex, data-centric enterprise applications. Built on Microsoft Dataverse (formerly Common Data Service), model-driven apps provide automatic UI generation, sophisticated business logic, and enterprise-grade securityβperfect for CRM systems, ERP solutions, and line-of-business applications.
In this comprehensive guide, you'll master model-driven app development from table design through advanced customization. You'll build a complete Project Management System with projects, tasks, time tracking, resource allocation, and reportingβdemonstrating real-world enterprise patterns and best practices.
What You'll Learn:
- Dataverse table design and relationships
- Creating model-driven apps with sitemap navigation
- Custom forms with business rules and JavaScript
- Views, charts, and dashboards for data visualization
- Security roles and field-level permissions
- Business Process Flows for guided workflows
- Power Automate integration for automation
- Custom pages with Canvas Apps components
- ALM strategies for model-driven apps
- Performance optimization techniques
Time to Complete: 120-180 minutes
Skill Level: Intermediate to Advanced
Model-Driven Apps Architecture
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Model-Driven Apps & Dataverse Architecture β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β User Interface Layer β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Model-Driven App (Unified Interface) β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€ β
β β β β
β β Navigation: β β
β β ββββββββββββ ββββββββββββ ββββββββββββ ββββββββββββ β β
β β β Projects β β Tasks β βResources β β Reports β β β
β β ββββββββββββ ββββββββββββ ββββββββββββ ββββββββββββ β β
β β β β
β β Main Content Area: β β
β β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β
β β β Form / View β β β
β β β β β β
β β β Forms: Views: β β β
β β β β’ Main Form β’ Active Projects (Grid) β β β
β β β β’ Quick Create Form β’ My Tasks (Kanban) β β β
β β β β’ Quick View Form β’ Overdue Items (Calendar) β β β
β β β β’ Mobile Form β’ Resource Utilization (Chart) β β β
β β β β β β
β β β Business Rules: Dashboards: β β β
β β β β’ Field Validation β’ Project Health β β β
β β β β’ Conditional Visibility β’ Time Tracking β β β
β β β β’ Auto-calculation β’ Resource Allocation β β β
β β β β β β
β β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β
β β β β
β β Command Bar: β β
β β [New] [Save] [Delete] [Deactivate] [Assign] [Custom Actions] β β
β β β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β β
β β Metadata-Driven β
β βΌ β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Business Logic Layer β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€ β
β β β β
β β Business Rules: JavaScript: β β
β β ββββββββββββββββββββββββ βββββββββββββββββββββββββββ β β
β β β β’ Scope: Form/Entity β β β’ OnLoad Event β β β
β β β β’ Conditions β β β’ OnSave Event β β β
β β β β’ Actions β β β’ OnChange Event β β β
β β β - Set Field Value β β β’ Custom Functions β β β
β β β - Set Required β β β’ Web API Calls β β β
β β β - Show/Hide Field β β β’ Complex Calculations β β β
β β β - Lock/Unlock β β β β β
β β β - Show Message β β β β β
β β ββββββββββββββββββββββββ βββββββββββββββββββββββββββ β β
β β β β
β β Business Process Flows: Power Automate: β β
β β ββββββββββββββββββββββββ βββββββββββββββββββββββββββ β β
β β β β’ Linear Workflow β β β’ Automated Flows β β β
β β β β’ Stage Gates β β β’ Approval Workflows β β β
β β β β’ Required Fields β β β’ Notifications β β β
β β β β’ Cross-Entity β β β’ External Integrations β β β
β β ββββββββββββββββββββββββ βββββββββββββββββββββββββββ β β
β β β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β β
β β Data Access β
β βΌ β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Microsoft Dataverse β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€ β
β β β β
β β Tables (Entities): β β
β β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β
β β β β β β
β β β Project (Custom Table) β β β
β β β ββ Name (Primary Field) β β β
β β β ββ Status (OptionSet: Active, On Hold, Completed, Cancelled) β β β
β β β ββ Start Date (Date) β β β
β β β ββ End Date (Date) β β β
β β β ββ Budget (Currency) β β β
β β β ββ Project Manager (Lookup to User) β β β
β β β ββ Client (Lookup to Account) β β β
β β β ββ Description (Multi-line Text) β β β
β β β β β β
β β β Task (Custom Table) β β β
β β β ββ Title (Primary Field) β β β
β β β ββ Project (Lookup to Project) [1:N Relationship] β β β
β β β ββ Assigned To (Lookup to User) β β β
β β β ββ Status (OptionSet: Not Started, In Progress, Complete) β β β
β β β ββ Priority (OptionSet: Low, Medium, High, Critical) β β β
β β β ββ Due Date (Date) β β β
β β β ββ Estimated Hours (Decimal) β β β
β β β ββ Actual Hours (Rollup from Time Entries) β β β
β β β ββ Completion % (Calculated Field) β β β
β β β β β β
β β β Time Entry (Custom Table) β β β
β β β ββ Description (Primary Field) β β β
β β β ββ Task (Lookup to Task) [1:N Relationship] β β β
β β β ββ User (Lookup to User) β β β
β β β ββ Date (Date) β β β
β β β ββ Hours (Decimal) β β β
β β β ββ Billable (Yes/No) β β β
β β β ββ Notes (Multi-line Text) β β β
β β β β β β
β β β Resource Allocation (Custom Table) β β β
β β β ββ Name (Primary Field - Auto-numbered) β β β
β β β ββ Project (Lookup to Project) [N:N via intersection] β β β
β β β ββ Resource (Lookup to User) β β β
β β β ββ Role (OptionSet: Developer, Designer, PM, Tester) β β β
β β β ββ Allocation % (Whole Number) β β β
β β β ββ Start Date (Date) β β β
β β β ββ End Date (Date) β β β
β β β β β β
β β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β
β β β β
β β Relationships: β β
β β β’ Project β Task (1:N) β β
β β β’ Task β Time Entry (1:N) β β
β β β’ Project β Resource Allocation (1:N) β β
β β β’ User β Task (1:N - Assigned To) β β
β β β’ Account β Project (1:N - Client) β β
β β β β
β β Security: β β
β β β’ Security Roles (CRUD permissions per table) β β
β β β’ Field-Level Security (sensitive data) β β
β β β’ Column-Level Security (encryption) β β
β β β’ Business Units (organizational hierarchy) β β
β β β’ Teams (shared access) β β
β β β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β Integration Layer: β
β β’ Dataverse Web API (REST/OData) β
β β’ Power Automate (automated workflows) β
β β’ Power BI (analytics and reporting) β
β β’ Azure Logic Apps (external integrations) β
β β’ Custom Connectors (third-party systems) β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Prerequisites
Required Licenses
- Power Apps per user/per app license (or included in Microsoft 365 E3/E5)
- Dataverse database (automatic with Power Apps environment)
- Power Automate premium (optional, for advanced flows)
Required Permissions
- Environment Maker role (minimum)
- System Administrator (for full solution management)
- System Customizer (for app and entity creation)
Development Tools
- Power Apps Studio (web-based)
- Visual Studio Code (for JavaScript development)
- XrmToolBox (optional, for advanced administration)
- Power Platform CLI (for ALM and CI/CD)
Verify Prerequisites
# Install Power Platform CLI
winget install Microsoft.PowerPlatformCLI
# Verify installation
pac --version
# Authenticate to Power Platform
pac auth create --url https://contoso.crm.dynamics.com
# List environments
pac env list
# Select environment
pac env select --environment <Environment-ID>
# List solutions in environment
pac solution list
Step 1: Create Dataverse Tables
Create Project Table
# Using Power Platform CLI to create table
pac solution init --publisher-name Contoso --publisher-prefix con
# Create Project table definition (JSON)
$projectTable = @{
"@odata.type" = "Microsoft.Dynamics.CRM.EntityDefinition"
LogicalName = "con_project"
DisplayName = @{
"@odata.type" = "Microsoft.Dynamics.CRM.Label"
LocalizedLabels = @(
@{
"@odata.type" = "Microsoft.Dynamics.CRM.LocalizedLabel"
Label = "Project"
LanguageCode = 1033
}
)
}
DisplayCollectionName = @{
"@odata.type" = "Microsoft.Dynamics.CRM.Label"
LocalizedLabels = @(
@{
"@odata.type" = "Microsoft.Dynamics.CRM.LocalizedLabel"
Label = "Projects"
LanguageCode = 1033
}
)
}
Description = @{
"@odata.type" = "Microsoft.Dynamics.CRM.Label"
LocalizedLabels = @(
@{
"@odata.type" = "Microsoft.Dynamics.CRM.LocalizedLabel"
Label = "Project management table"
LanguageCode = 1033
}
)
}
OwnershipType = "UserOwned"
IsActivity = $false
HasActivities = $true
HasNotes = $true
} | ConvertTo-Json -Depth 10
# Note: In practice, create tables via Power Apps UI for simplicity
Write-Host "β Recommended: Create tables via Power Apps maker portal" -ForegroundColor Yellow
Write-Host " Navigate to: https://make.powerapps.com β Dataverse β Tables" -ForegroundColor Cyan
Create Tables via Power Apps Portal
Step-by-Step Table Creation:
- Navigate to https://make.powerapps.com
- Select your environment
- Go to Dataverse β Tables
- Click + New table β Add columns and data
Project Table:
| Column Name | Data Type | Required | Settings |
|---|---|---|---|
| Name | Single line of text | Yes | Primary field, max 100 chars |
| Status | Choice | Yes | Active, On Hold, Completed, Cancelled |
| Start Date | Date only | Yes | |
| End Date | Date only | No | |
| Budget | Currency | No | Precision 2, min 0 |
| Actual Cost | Currency | No | Calculated rollup |
| Project Manager | Lookup | Yes | References: User table |
| Client | Lookup | No | References: Account table |
| Description | Multiple lines of text | No | Max 2000 chars |
| Priority | Choice | Yes | Low, Medium, High, Critical |
| Health Status | Choice | Yes | Green, Yellow, Red |
| Completion % | Whole number | No | Min 0, Max 100 |
PowerShell Script to Create Columns:
# Connect to Dataverse
Install-Module Microsoft.Xrm.Data.PowerShell -Force
$conn = Get-CrmConnection -InteractiveMode
# Create Status column (Choice)
$statusChoices = @(
@{Value=1; Label="Active"; Color="#0078D4"},
@{Value=2; Label="On Hold"; Color="#FFB900"},
@{Value=3; Label="Completed"; Color="#107C10"},
@{Value=4; Label="Cancelled"; Color="#D13438"}
)
# Note: Use Power Apps UI for easier column creation
# Below is conceptual API approach
# Create lookup column (Project Manager)
$lookupAttribute = @{
SchemaName = "con_ProjectManager"
DisplayName = "Project Manager"
Description = "User responsible for project"
RequiredLevel = "ApplicationRequired"
Type = "Lookup"
Targets = @("systemuser")
}
Write-Host "β Table schema defined" -ForegroundColor Green
Write-Host " Continue in Power Apps portal for visual creation" -ForegroundColor Cyan
Create Task Table
Task Table Schema:
| Column Name | Data Type | Required | Settings |
|---|---|---|---|
| Title | Single line of text | Yes | Primary field |
| Project | Lookup | Yes | References: Project (1:N) |
| Assigned To | Lookup | No | References: User |
| Status | Choice | Yes | Not Started, In Progress, Complete |
| Priority | Choice | Yes | Low, Medium, High, Critical |
| Due Date | Date only | No | |
| Estimated Hours | Decimal number | No | Precision 2 |
| Actual Hours | Decimal number | No | Rollup from Time Entries |
| Completion % | Whole number | No | 0-100 |
| Dependencies | Lookup | No | References: Task (self-referential) |
| Notes | Multiple lines of text | No |
Create Time Entry Table
Time Entry Table Schema:
| Column Name | Data Type | Required | Settings |
|---|---|---|---|
| Description | Single line of text | Yes | Primary field |
| Task | Lookup | Yes | References: Task |
| User | Lookup | Yes | References: User |
| Date | Date only | Yes | Default: Today |
| Hours | Decimal number | Yes | Precision 2, min 0.25 |
| Billable | Yes/No | Yes | Default: Yes |
| Notes | Multiple lines of text | No |
Create Resource Allocation Table
Resource Allocation Schema:
| Column Name | Data Type | Required | Settings |
|---|---|---|---|
| Name | Auto number | Yes | Format: RA-{SEQNUM:5} |
| Project | Lookup | Yes | References: Project |
| Resource | Lookup | Yes | References: User |
| Role | Choice | Yes | Developer, Designer, PM, Tester, BA |
| Allocation % | Whole number | Yes | Min 0, Max 100 |
| Start Date | Date only | Yes | |
| End Date | Date only | No | |
| Hourly Rate | Currency | No | For cost calculation |
Step 2: Configure Table Relationships
Create 1:N Relationships
# Conceptual relationship definitions
# Project β Task (1:N)
$projectTaskRelationship = @{
SchemaName = "con_project_task"
ReferencedEntity = "con_project"
ReferencedAttribute = "con_projectid"
ReferencingEntity = "con_task"
ReferencingAttribute = "con_projectid"
RelationshipBehavior = "Parental" # Cascade delete
CascadeConfiguration = @{
Assign = "Cascade"
Delete = "Cascade"
Merge = "Cascade"
Reparent = "Cascade"
Share = "Cascade"
Unshare = "Cascade"
}
}
# Task β Time Entry (1:N)
$taskTimeEntryRelationship = @{
SchemaName = "con_task_timeentry"
ReferencedEntity = "con_task"
ReferencingEntity = "con_timeentry"
RelationshipBehavior = "Parental"
}
# Project β Resource Allocation (1:N)
$projectResourceRelationship = @{
SchemaName = "con_project_resourceallocation"
ReferencedEntity = "con_project"
ReferencingEntity = "con_resourceallocation"
RelationshipBehavior = "Referential" # Don't cascade delete
}
Write-Host "β Relationship schema defined" -ForegroundColor Green
Create Relationships via Power Apps UI:
- Navigate to Dataverse β Tables β Project
- Click Relationships tab
- Click + Add relationship β One-to-many
- Configure:
- Related table: Task
- Lookup column: Project
- Relationship behavior: Parental (cascade delete)
- Click Done β Save table
Step 3: Create Model-Driven App
Create New Model-Driven App
# Using Power Platform CLI
pac canvas create --msapp-name "Project Management System"
# Note: Model-driven apps are better created via UI
Write-Host "Creating model-driven app via Power Apps portal..." -ForegroundColor Cyan
Create App via Power Apps Portal:
- Go to https://make.powerapps.com
- Click + Create β Model-driven app
- Name: "Project Management System"
- Click Create
Configure Sitemap (Navigation)
Sitemap Structure:
<!-- Sitemap definition -->
<SiteMap>
<Area Id="ProjectsArea" Title="Projects" Icon="/_imgs/area_1.png">
<Group Id="ProjectsGroup" Title="Project Management">
<SubArea Id="ProjectsSubArea" Title="Projects" Entity="con_project" />
<SubArea Id="TasksSubArea" Title="Tasks" Entity="con_task" />
<SubArea Id="TimeEntriesSubArea" Title="Time Tracking" Entity="con_timeentry" />
<SubArea Id="ResourcesSubArea" Title="Resources" Entity="con_resourceallocation" />
</Group>
<Group Id="ReportsGroup" Title="Analytics">
<SubArea Id="DashboardsSubArea" Title="Dashboards" Url="/main.aspx?pagetype=dashboard" />
<SubArea Id="ChartsSubArea" Title="Charts" Url="/main.aspx?pagetype=chartlist" />
</Group>
</Area>
<Area Id="SettingsArea" Title="Settings" Icon="/_imgs/area_2.png">
<Group Id="AdminGroup" Title="Administration">
<SubArea Id="SecuritySubArea" Title="Security Roles" Url="/main.aspx?page=settingssecurity" />
<SubArea Id="CustomizationsSubArea" Title="Customizations" Url="/main.aspx?page=settingscustomization" />
</Group>
</Area>
</SiteMap>
Configure via App Designer:
- In App Designer, click Site Map (navigation icon)
- Add Area: "Projects"
- Add Group: "Project Management"
- Add Subarea:
- Title: "Projects"
- Entity: Project
- Icon: Select from gallery
- Repeat for Tasks, Time Entries, Resources
- Click Save β Publish
Step 4: Design Forms
Create Main Form for Project
Form Layout:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Project: Web Application Redesign β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β [General Tab] [Team Tab] [Tasks Tab] [Timeline] β
β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β General Information β β
β β β β
β β Name*: [Web Application Redesign ] β β
β β Client: [Contoso Corporation βΌ] β β
β β Project Manager*: [John Doe βΌ] β β
β β β β
β β Start Date*: [01/15/2025] End Date: [06/30/2025]β β
β β Status*: [Active βΌ] Priority: [High βΌ] β β
β β Health Status: [Green βΌ] Completion: [45%] β β
β β β β
β β Budget: [$150,000.00] Actual Cost: [$67,500.00] β β
β β β β
β β Description: β β
β β [Complete redesign of customer portal with ] β β
β β [modern UI/UX, mobile responsiveness, and ] β β
β β [integration with new backend APIs. ] β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Quick Stats β β
β β β β
β β Total Tasks: 45 Resources: 8 β β
β β Completed: 20 Open Tasks: 25 β β
β β Overdue: 3 Hours Logged: 450 β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β [Save] [Save & Close] [Deactivate] [Assign] [...] β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Form Configuration Steps:
- In App Designer, select Project table
- Click Forms β Main Form β Edit
- Add sections:
- General Information (2 columns)
- Financial (2 columns)
- Quick Stats (read-only, 3 columns)
- Add fields by dragging from field explorer
- Configure field properties:
- Required fields: Red asterisk
- Read-only: Lock icon
- Business rules: Will add next
Add Business Rules to Form
Business Rule 1: Auto-calculate Budget Status
// When Budget or Actual Cost changes
// IF Actual Cost > Budget THEN
// Set Health Status = Red
// Show Warning Message
// ELSE IF Actual Cost > (Budget * 0.8) THEN
// Set Health Status = Yellow
// ELSE
// Set Health Status = Green
Create via Business Rules Designer:
- In Form Designer, click Business Rules β + New business rule
- Name: "Budget Health Check"
- Scope: Entity (applies to all forms)
- Condition:
- IF Actual Cost > Budget
- THEN Set Health Status = "Red"
- AND Show Error: "Project is over budget!"
- Add second condition:
- ELSE IF Actual Cost > (Budget Γ 0.8)
- THEN Set Health Status = "Yellow"
- AND Show Warning: "Approaching budget limit"
- Add default action:
- ELSE Set Health Status = "Green"
- Click Activate β Save
Business Rule 2: Validate Dates
- Name: "Date Validation"
- Condition:
- IF End Date < Start Date
- THEN Show Error: "End date must be after start date"
- AND Set Required: End Date = true
- Activate and save
Add JavaScript for Complex Logic
Create Web Resource (JavaScript):
// ProjectForm.js
var ProjectForm = ProjectForm || {};
ProjectForm.OnLoad = function(executionContext) {
var formContext = executionContext.getFormContext();
// Calculate and display project duration
ProjectForm.calculateDuration(formContext);
// Load team members count
ProjectForm.loadTeamStats(formContext);
// Set up event handlers
formContext.getAttribute("con_startdate").addOnChange(ProjectForm.calculateDuration);
formContext.getAttribute("con_enddate").addOnChange(ProjectForm.calculateDuration);
};
ProjectForm.calculateDuration = function(executionContext) {
var formContext = executionContext.getFormContext();
var startDate = formContext.getAttribute("con_startdate").getValue();
var endDate = formContext.getAttribute("con_enddate").getValue();
if (startDate && endDate) {
var duration = Math.floor((endDate - startDate) / (1000 * 60 * 60 * 24));
// Display duration (requires custom field: con_duration)
formContext.getAttribute("con_duration").setValue(duration);
// Update notification
formContext.ui.setFormNotification(
"Project duration: " + duration + " days",
"INFO",
"duration"
);
}
};
ProjectForm.loadTeamStats = function(formContext) {
var projectId = formContext.data.entity.getId().replace(/[{}]/g, "");
// Query related resource allocations
var fetchXml = [
"<fetch aggregate='true'>",
" <entity name='con_resourceallocation'>",
" <attribute name='con_resourceallocationid' aggregate='count' alias='count'/>",
" <filter>",
" <condition attribute='con_projectid' operator='eq' value='" + projectId + "'/>",
" </filter>",
" </entity>",
"</fetch>"
].join("");
Xrm.WebApi.retrieveMultipleRecords(
"con_resourceallocation",
"?fetchXml=" + encodeURIComponent(fetchXml)
).then(
function success(result) {
if (result.entities.length > 0) {
var count = result.entities[0].count;
formContext.ui.setFormNotification(
"Team Members: " + count,
"INFO",
"teamcount"
);
}
},
function error(error) {
console.error("Error loading team stats:", error.message);
}
);
};
ProjectForm.OnSave = function(executionContext) {
var formContext = executionContext.getFormContext();
// Validate budget before saving
var budget = formContext.getAttribute("con_budget").getValue();
var actualCost = formContext.getAttribute("con_actualcost").getValue();
if (actualCost > budget * 1.2) {
executionContext.getEventArgs().preventDefault();
Xrm.Navigation.openAlertDialog({
text: "Project is significantly over budget. Please review before saving.",
confirmButtonLabel: "OK"
});
}
};
Upload JavaScript as Web Resource:
- Go to Solutions β Your solution
- Click + New β More β Web resource
- Upload ProjectForm.js
- Name: "con_/scripts/ProjectForm.js"
- Display Name: "Project Form Scripts"
- Click Save β Publish
Attach to Form:
- Open Project Main Form
- Click Form Properties
- Form Libraries β Add Library
- Select "con_/scripts/ProjectForm.js"
- Event Handlers:
- OnLoad: ProjectForm.OnLoad
- OnSave: ProjectForm.OnSave
- Save β Publish
Step 5: Create Views
Create Active Projects View
View Configuration:
- Go to Project table β Views
- Click + New view
- Name: "Active Projects"
- Filter: Status = Active
- Add columns:
- Name
- Client
- Project Manager
- Start Date
- End Date
- Health Status
- Completion %
- Budget
- Sort by: Start Date (Descending)
- Save and publish
FetchXML for Advanced View:
<fetch version="1.0" output-format="xml-platform" mapping="logical">
<entity name="con_project">
<attribute name="con_name" />
<attribute name="con_status" />
<attribute name="con_startdate" />
<attribute name="con_enddate" />
<attribute name="con_budget" />
<attribute name="con_completion" />
<attribute name="con_healthstatus" />
<order attribute="con_startdate" descending="true" />
<filter type="and">
<condition attribute="con_status" operator="eq" value="1" />
<condition attribute="statecode" operator="eq" value="0" />
</filter>
<link-entity name="account" from="accountid" to="con_clientid" link-type="outer" alias="client">
<attribute name="name" />
</link-entity>
<link-entity name="systemuser" from="systemuserid" to="con_projectmanagerid" alias="pm">
<attribute name="fullname" />
</link-entity>
</entity>
</fetch>
Create My Tasks View (for Task table)
<fetch version="1.0" output-format="xml-platform" mapping="logical">
<entity name="con_task">
<attribute name="con_title" />
<attribute name="con_priority" />
<attribute name="con_status" />
<attribute name="con_duedate" />
<attribute name="con_estimatedhours" />
<attribute name="con_completion" />
<order attribute="con_duedate" descending="false" />
<filter type="and">
<condition attribute="con_assignedtoid" operator="eq-userid" />
<condition attribute="con_status" operator="ne" value="3" />
<condition attribute="statecode" operator="eq" value="0" />
</filter>
<link-entity name="con_project" from="con_projectid" to="con_projectid" alias="project">
<attribute name="con_name" />
</link-entity>
</entity>
</fetch>
Step 6: Create Dashboards and Charts
Create Project Health Dashboard
Dashboard Layout:
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Project Management Dashboard β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β ββββββββββββββββββββββββ ββββββββββββββββββββββββββββββββ β
β β Projects by Status β β Projects by Health Status β β
β β β β β β
β β [Pie Chart] β β [Donut Chart] β β
β β Active: 15 β β Green: 10 β β
β β On Hold: 3 β β Yellow: 4 β β
β β Completed: 25 β β Red: 4 β β
β ββββββββββββββββββββββββ ββββββββββββββββββββββββββββββββ β
β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Active Projects (Grid) β β
β β β β
β β Name PM Budget Completion% β β
β β Web Redesign John Doe $150K 45% β β
β β Mobile App Jane Smith $200K 30% β β
β β CRM Integration Bob Johnson $100K 75% β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β ββββββββββββββββββββββββ ββββββββββββββββββββββββββββββββ β
β β Budget vs Actual β β Tasks by Priority β β
β β (Column Chart) β β (Bar Chart) β β
β ββββββββββββββββββββββββ ββββββββββββββββββββββββββββββββ β
β β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Create Chart: Projects by Status
- Go to Project table β Charts
- Click + New chart
- Name: "Projects by Status"
- View: Active Projects
- Chart type: Pie
- Legend: Status
- Series: Count of Projects
- Save and close
Create Chart: Budget vs Actual
<!-- Chart data descriptor -->
<datadescription>
<fetch aggregate="true">
<entity name="con_project">
<attribute name="con_name" alias="name" groupby="true" />
<attribute name="con_budget" alias="budget" aggregate="sum" />
<attribute name="con_actualcost" alias="actual" aggregate="sum" />
<filter>
<condition attribute="con_status" operator="eq" value="1" />
</filter>
<order alias="name" descending="false" />
</entity>
</fetch>
</datadescription>
Step 7: Implement Business Process Flow
Create Project Initiation Process Flow
BPF Stages:
[Stage 1: Planning] β [Stage 2: Approval] β [Stage 3: Execution] β [Stage 4: Closure]
Stage 1: Planning
- Required Fields:
- Project Name
- Project Manager
- Start Date
- Budget
- Steps:
- Define scope
- Identify stakeholders
- Create initial schedule
Stage 2: Approval
- Required Fields:
- Client
- Budget (confirmed)
- Resource Allocation
- Steps:
- Submit for manager approval
- Get client sign-off
- Allocate resources
Stage 3: Execution
- Required Fields:
- Team assigned
- Tasks created
- Steps:
- Kick-off meeting
- Begin task execution
- Track progress
Stage 4: Closure
- Required Fields:
- Completion % = 100
- Status = Completed
- Steps:
- Final deliverables review
- Client acceptance
- Lessons learned documentation
Create BPF:
- Go to Flows (Power Automate)
- Click + New flow β Business process flow
- Name: "Project Lifecycle"
- Entity: Project
- Add stages and steps as defined
- Configure branching:
- IF Budget > $100K THEN require executive approval
- Save and activate
Step 8: Configure Security Roles
Create Custom Security Roles
Project Manager Role:
Privileges:
- Project: Create, Read, Write, Delete (Own), Append, Append To
- Task: Create, Read, Write, Delete (Team), Append, Append To
- Time Entry: Read (Organization), Create/Write/Delete (Own)
- Resource Allocation: Create, Read, Write (Team)
Team Member Role:
Privileges:
- Project: Read (Team)
- Task: Read (Team), Create/Write/Delete (Assigned To Me)
- Time Entry: Create, Read, Write, Delete (Own)
- Resource Allocation: Read (Team)
Executive Role:
Privileges:
- Project: Read (Organization), Write (Business Unit)
- Task: Read (Organization)
- Time Entry: Read (Organization)
- Resource Allocation: Read (Organization)
- Dashboards: Read (Organization)
Create Security Role:
- Go to Settings β Security β Security Roles
- Click + New role
- Name: "Project Manager"
- Configure privileges for each table
- Save and assign to users
Step 9: Advanced Customization
Add Calculated and Rollup Fields
Calculated Field: Days Remaining
// Field type: Calculated
// Data type: Whole Number
// Formula:
DIFFINDAYS(TODAY(), con_enddate)
Rollup Field: Total Hours Logged
// Field type: Rollup
// Source Entity: Time Entry
// Aggregation: SUM
// Field to Aggregate: Hours
// Filter: Task = Current Project's Tasks
Create via Power Apps:
- Edit Project table
- Add column β Calculated or Rollup
- Configure formula/aggregation
- Save and publish
Create Power Automate Integration
Flow: Notify PM on Overdue Tasks
Trigger: Recurrence (Daily at 8 AM)
Actions:
1. List overdue tasks:
- Filter: Due Date < Today AND Status != Complete
2. For each overdue task:
a. Get project details
b. Get project manager email
c. Send email notification:
To: Project Manager
Subject: "Overdue Task Alert: [Task Title]"
Body: |
Task: [Title]
Project: [Project Name]
Assigned To: [User]
Due Date: [Due Date]
Days Overdue: [Calculated]
Real-World Enterprise Example
Scenario: Contoso Consulting Firm
Challenge: Managing 50+ concurrent client projects with 200+ employees
- No centralized project tracking
- Time entry done in spreadsheets
- Resource allocation conflicts
- Budget overruns not caught early
- Client reporting manual and time-consuming
Solution Implementation:
Dataverse Schema:
- 5 custom tables (Project, Task, Time Entry, Resource, Client)
- 20+ custom fields with business logic
- Automated rollups for financial tracking
Model-Driven App:
- 4 custom forms with JavaScript validation
- 12 views for different stakeholder needs
- 6 dashboards (Executive, PM, Team Member)
- Business Process Flow for standardized project lifecycle
Integration:
- Power BI for executive reporting
- Power Automate for 15+ workflows
- Outlook integration for time entry
- Teams integration for collaboration
Results After 6 Months:
| Metric | Before | After | Improvement |
|---|---|---|---|
| Time to create project | 2 hours | 15 minutes | 87% faster |
| Budget overruns | 25% of projects | 8% of projects | 68% reduction |
| Resource utilization | 65% | 85% | 31% increase |
| Time entry compliance | 60% | 95% | 58% increase |
| Client reporting time | 4 hours/project | 30 minutes | 87% faster |
| PM productivity | Baseline | +40% | Significant gain |
Best Practices Summary
DO:
- β Design schema before building UI
- β Use business rules for simple logic (no code)
- β Implement rollup fields for aggregations
- β Create separate security roles for each persona
- β Use Business Process Flows for standardization
- β Enable auditing for compliance requirements
- β Use solutions for ALM (export/import)
- β Test in dev environment before production
- β Document customizations for maintenance
- β Use FetchXML for complex queries
DON'T:
- β Over-customize with JavaScript (use platform features first)
- β Create too many tables (normalize appropriately)
- β Skip relationship configuration
- β Grant excessive permissions
- β Forget to publish customizations
- β Ignore performance (limit form fields < 100)
- β Hard-code GUIDs in JavaScript
- β Skip field-level security for sensitive data
- β Create forms without business rules
- β Deploy without backup/rollback plan
Key Takeaways
- Dataverse is powerful - Relational database with built-in features
- Metadata-driven UI - Forms/views generated from schema
- Business rules > Code - Use no-code when possible
- Security is granular - Field-level, row-level, table-level
- BPF standardizes workflows - Guided user experiences
- Rollups aggregate data - No manual calculations needed
- JavaScript extends capabilities - Complex logic when needed
- Integration is seamless - Power Automate, Power BI, Teams
- ALM with solutions - Export/import entire apps
- Enterprise-ready - Scalable, secure, compliant
Additional Resources
- Model-Driven Apps Documentation
- Dataverse Developer Guide
- Business Rules
- FetchXML Reference
- Web API Reference
Next Steps
- Add mobile optimization: Configure mobile forms and views
- Implement AI Builder: Prediction models for project risk
- Create custom connectors: Integrate with external systems
- Build Power BI reports: Advanced analytics and forecasting
- Deploy to production: Using solutions and pipelines
- Train end users: Create documentation and training videos
- Set up monitoring: Application Insights and usage analytics
- Implement CI/CD: Azure DevOps pipelines for solutions
Ready to build enterprise data management solutions? Model-driven apps with Dataverse provide the foundation for scalable, secure, and maintainable business applications!