{"id":1549,"date":"2025-07-28T08:10:00","date_gmt":"2025-07-28T13:10:00","guid":{"rendered":"https:\/\/automatethemundane.com\/index.php\/2025\/07\/28\/copilot-studio-and-ai-builder-better-together-post-2-building-the-core-dataverse-table-relationship-design-and-model-driven-app\/"},"modified":"2025-07-28T08:10:00","modified_gmt":"2025-07-28T13:10:00","slug":"copilot-studio-and-ai-builder-better-together-post-2-building-the-core-dataverse-table-relationship-design-and-model-driven-app","status":"publish","type":"post","link":"https:\/\/automatethemundane.com\/index.php\/2025\/07\/28\/copilot-studio-and-ai-builder-better-together-post-2-building-the-core-dataverse-table-relationship-design-and-model-driven-app\/","title":{"rendered":"Copilot Studio and AI builder &#8211; Better together. Post 2 \u2013 Building the Core: Dataverse Table Relationship Design, and Model Driven App"},"content":{"rendered":"\n<h1 class=\"wp-block-heading\">Introduction<\/h1>\n\n\n<p class=\"has-text-color\" style=\"color: rgb(0, 0, 0)\">Before automating anything or designing a user interface, I needed to make sure the data model was solid. Since the Talent Intake System relies on capturing and relating candidates, resumes, and job applications, I started by designing a structure in Dataverse that could support flexible workflows, easy querying, and clean integration with forms and flows.<\/p>\n\n\n<p class=\"has-text-color\" style=\"color: rgb(0, 0, 0)\">In this post, I\u2019ll walk through the four key tables that make up the foundation of the solution, how they relate to one another, and some of the decisions I made to keep the model lean but extensible.<\/p>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity is-style-wide\"\/>\n\n\n<h1 class=\"wp-block-heading\"><strong>Core Tables and Relationship Design<\/strong><\/h1>\n\n\n<p class=\"has-text-color\" style=\"color: rgb(0, 0, 0)\">The solution uses four main Dataverse tables:<\/p>\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th><strong>Table<\/strong><\/th><th><strong>Purpose<\/strong><\/th><\/tr><\/thead><tbody><tr><td><strong>Candidate<\/strong><\/td><td>Stores applicant information like name, email, and contact details.<\/td><\/tr><tr><td><strong>Resume<\/strong><\/td><td>Manages uploaded resume files and links back to the candidate.<\/td><\/tr><tr><td><strong>Application<\/strong><\/td><td>Represents a submitted application tied to a specific job posting.<\/td><\/tr><tr><td><strong>Job Posting<\/strong><\/td><td>Contains open positions visible on the public Power Pages form.<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n<h3 class=\"wp-block-heading\">&#x1f9d1;&#x200d;&#x1f4bc; Candidate<\/h3>\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th><strong>Field Name<\/strong><\/th><th><strong>Type<\/strong><\/th><th><strong>Purpose<\/strong><\/th><\/tr><\/thead><tbody><tr><td>Full Name<\/td><td>String<\/td><td>Candidate\u2019s full name.<\/td><\/tr><tr><td>Email<\/td><td>String<\/td><td>Candidate\u2019s email address (for contact or login).<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity is-style-wide\"\/>\n\n\n<h3 class=\"wp-block-heading\">&#x1f4c4; Resume<\/h3>\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th><strong>Field Name<\/strong><\/th><th><strong>Type<\/strong><\/th><th><strong>Purpose<\/strong><\/th><\/tr><\/thead><tbody><tr><td>Candidate Name<\/td><td>Lookup (Candidate)<\/td><td>Links this resume to a candidate.<\/td><\/tr><tr><td>Resume Title<\/td><td>String<\/td><td>Descriptive title for the resume.<\/td><\/tr><tr><td>Resume<\/td><td>File (Virtual)<\/td><td>The uploaded resume document.<\/td><\/tr><tr><td>Resume_Name<\/td><td>String<\/td><td>Internal or uploaded file name.<\/td><\/tr><tr><td>Submission Date<\/td><td>DateTime<\/td><td>When the resume was submitted (e.g., via portal or form).<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity is-style-wide\"\/>\n\n\n<h3 class=\"wp-block-heading\">&#x1f4dd; Application<\/h3>\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th><strong>Field Name<\/strong><\/th><th><strong>Type<\/strong><\/th><th><strong>Purpose<\/strong><\/th><\/tr><\/thead><tbody><tr><td>Job Title<\/td><td>Lookup (Job Posting)<\/td><td>The job that this application is associated with.<\/td><\/tr><tr><td>Resume<\/td><td>Lookup (Resume)<\/td><td>The resume being submitted for this application.<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity is-style-wide\"\/>\n\n\n<h3 class=\"wp-block-heading\">&#x1f4e2; Job Posting<\/h3>\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th><strong>Field Name<\/strong><\/th><th><strong>Type<\/strong><\/th><th><strong>Purpose<\/strong><\/th><\/tr><\/thead><tbody><tr><td>Job Title<\/td><td>String<\/td><td>Name\/title of the open position.<\/td><\/tr><tr><td>Department<\/td><td>String<\/td><td>Department within the organization.<\/td><\/tr><tr><td>Location<\/td><td>String<\/td><td>Where the job is based (or remote).<\/td><\/tr><tr><td>Security Clearance Requirement<\/td><td>String<\/td><td>Any security clearance required for the job.<\/td><\/tr><tr><td>Job Listing<\/td><td>Memo<\/td><td>Rich text job description body.<\/td><\/tr><tr><td>Skills<\/td><td>Memo<\/td><td>List of skills required or desired.<\/td><\/tr><tr><td>Work Experience<\/td><td>String<\/td><td>Required prior work experience.<\/td><\/tr><tr><td>Hiring Manager<\/td><td>Lookup (User)<\/td><td>Person overseeing the hiring process.<\/td><\/tr><tr><td>HR Coordinator<\/td><td>Lookup (User)<\/td><td>Person supporting the application process.<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n<pre class=\"wp-block-code\"><code>erDiagram\n    Candidate ||--o{ Resume : &quot;submits&quot;\n    Resume ||--o{ Application : &quot;is used in&quot;\n    JobPosting ||--o{ Application : &quot;is for&quot;\n    JobPosting }o--|| User : &quot;Hiring Manager&quot;\n    JobPosting }o--|| User : &quot;HR Coordinator&quot;\n\n    Candidate {\n        string FullName\n        string Email\n    }\n\n    Resume {\n        string ResumeTitle\n        file ResumeFile\n        string ResumeFileName\n        datetime SubmissionDate\n    }\n\n    JobPosting {\n        string JobTitle\n        string Department\n        string Location\n        string SecurityClearanceRequirement\n        string Skills\n        string WorkExperience\n    }\n\n    Application {\n        string PlaceholderField\n    }\n\n    User {\n        string Name\n    }\n<\/code><\/pre>\n\n\n<p>&nbsp;<\/p>\n\n\n<p class=\"has-text-color\" style=\"color: rgb(0, 0, 0)\">&nbsp;<\/p>\n\n\n<p class=\"has-text-color\" style=\"color: rgb(0, 0, 0)\">This setup reflects the natural flow of a typical applicant experience: the candidate enters their details, uploads a resume, and then applies for a specific position.<\/p>\n\n\n<h2 class=\"wp-block-heading\"><strong>Relationship Design<\/strong><\/h2>\n\n\n<p class=\"has-text-color\" style=\"color: rgb(0, 0, 0)\">Here\u2019s how the tables are connected in the Talent Intake System:<\/p>\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Candidate (1) \u2192 (N) Resume<\/strong>\n<p class=\"has-text-color\" style=\"color: rgb(0, 0, 0)\">Each candidate can have multiple resumes over time. This allows for versioning or updates without altering the original candidate record.<\/p>\n<\/li>\n\n\n\n<li><strong>Resume (1) \u2192 (N) Application<\/strong>\n<p class=\"has-text-color\" style=\"color: rgb(0, 0, 0)\">A single resume can be used for multiple applications. This supports scenarios where a candidate submits the same resume to different job postings, or where applications are versioned without re-uploading files.<\/p>\n<\/li>\n\n\n\n<li><strong>Application (N) \u2192 (1) Job Posting<\/strong>\n<p class=\"has-text-color\" style=\"color: rgb(0, 0, 0)\">Multiple applications can be submitted to the same job posting. This supports both single and recurring job openings.<\/p>\n<\/li>\n<\/ul>\n\n\n<h3 class=\"wp-block-heading\">Why Resume and Application Are Separated<\/h3>\n\n\n<p class=\"has-text-color\" style=\"color: rgb(0, 0, 0)\">The separation between <strong>Resume<\/strong> and <strong>Application<\/strong> is intentional and strategic:<\/p>\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Resumability<\/strong>: A candidate might begin an application, revise their resume, or use the same resume across multiple applications.<\/li>\n\n\n\n<li><strong>Auditability<\/strong>: It preserves submission history and allows tracking how many times a resume was submitted and to which postings.<\/li>\n\n\n\n<li><strong>Flexibility<\/strong>: Future enhancements like tagging resumes or attaching multiple documents (e.g., cover letters) can be isolated at the resume level without cluttering application logic.<\/li>\n<\/ul>\n\n\n<p class=\"has-text-color\" style=\"color: rgb(0, 0, 0)\">This design keeps the data model normalized and scalable\u2014ideal for a job portal or recruiting process.<\/p>\n\n\n<h3 class=\"wp-block-heading\"><strong>Design Considerations<\/strong><\/h3>\n\n\n<p class=\"has-text-color\" style=\"color: rgb(0, 0, 0)\">While keeping the schema straightforward, I added a few thoughtful touches to support future enhancements:<\/p>\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Optional Fields<\/strong> \u2013 Fields like \u201cResume Status\u201d and \u201cApplication Source\u201d provide hooks for future automation or reporting without overcomplicating the initial build.<\/li>\n\n\n\n<li><strong>Custom File Handling<\/strong> \u2013 Resumes are stored as attachments in the Resume table, not embedded in the Candidate table. This keeps the file logic isolated and easier to manage in flows.<\/li>\n\n\n\n<li><strong>Lean First, Expand Later<\/strong> \u2013 I avoided overengineering at this stage. The goal was to create a flexible, functional structure that could support the initial workflow but grow with future needs like approvals, interview tracking, or feedback.<\/li>\n<\/ul>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity is-style-wide\"\/>\n\n\n<h1 class=\"wp-block-heading\">Model Driven App<\/h1>\n\n\n<p class=\"has-text-color\" style=\"color: rgb(0, 0, 0)\">The Model-Driven App serves as the primary interface for HR professionals to manage job postings and oversee candidate applications. While the app provides full access to create and update postings, most day-to-day interactions\u2014such as conducting interviews or reviewing applicant data\u2014are streamlined through integrated Teams Adaptive Cards and Power BI dashboards. This approach keeps the app focused on administrative setup while shifting operational tasks to more natural, role-specific tools.<\/p>\n\n\n<h2 class=\"wp-block-heading\">App and Form Design<\/h2>\n\n\n<p class=\"has-text-color\" style=\"color: rgb(0, 0, 0)\">The MDA is a simple app with the four tables added. \n<\/p>\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/automatethemundane.com\/wp-content\/uploads\/2025\/07\/image-1024x494.png\" alt=\"\"\/><\/figure>\n\n\n<h3 class=\"wp-block-heading\">Job Posting<\/h3>\n\n\n<p class=\"has-text-color\" style=\"color: rgb(0, 0, 0)\">The job posting form consists of two tabs. The first is what allows HR professionals to enter in the job details. The second are the prompt outputs of three AI builder prompts, breaking down the job posting for future use. <\/p>\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/automatethemundane.com\/wp-content\/uploads\/2025\/07\/image-1-1024x510.png\" alt=\"\"\/><\/figure>\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/automatethemundane.com\/wp-content\/uploads\/2025\/07\/image-2-1024x511.png\" alt=\"\"\/><\/figure>\n\n\n<h3 class=\"wp-block-heading\">Candidates<\/h3>\n\n\n<p class=\"has-text-color\" style=\"color: rgb(0, 0, 0)\"> The <strong>Candidate<\/strong> table uses a straightforward, single-tab form. Since the candidate\u2019s <strong>Name<\/strong> and <strong>Email<\/strong> are captured at the time of record creation\u2014typically from the public Power Pages form\u2014these fields are set to <strong>read-only<\/strong> to preserve data integrity. The only editable field on the form is <strong>Phone Number<\/strong>, which allows internal users to add or update contact information if needed.<\/p>\n\n\n<p class=\"has-text-color\" style=\"color: rgb(0, 0, 0)\">This approach ensures that once a candidate is created, their core identity remains unchanged, while still allowing HR staff the flexibility to complete missing details or make necessary updates.<\/p>\n\n\n<p class=\"has-text-color\" style=\"color: rgb(0, 0, 0)\">&nbsp;<\/p>\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/automatethemundane.com\/wp-content\/uploads\/2025\/07\/image-3-1024x491.png\" alt=\"\"\/><\/figure>\n\n\n<p class=\"has-text-color\" style=\"color: rgb(0, 0, 0)\">&nbsp;<\/p>\n\n\n<h3 class=\"wp-block-heading\">Resumes<\/h3>\n\n\n<p class=\"has-text-color\" style=\"color: rgb(0, 0, 0)\">This table and its form are used to connect the Candidate to a Resume. <\/p>\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/automatethemundane.com\/wp-content\/uploads\/2025\/07\/image-4-1024x293.png\" alt=\"\"\/><\/figure>\n\n\n<h3 class=\"wp-block-heading\">Application<\/h3>\n\n\n<p class=\"has-text-color\" style=\"color: rgb(0, 0, 0)\">The Application table and its main form are the core of the MDA. It has four tabs and a Business Process Flow (BPF) to manage the process.<\/p>\n\n\n<p class=\"has-text-color\" style=\"color: rgb(0, 0, 0)\">The first tab has all the information about the Resume being submitted, when it was submitted, the resume, and the overall assessment of the applicants resume. <\/p>\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/automatethemundane.com\/wp-content\/uploads\/2025\/07\/image-5-1024x506.png\" alt=\"\"\/><\/figure>\n\n\n<p class=\"has-text-color\" style=\"color: rgb(0, 0, 0)\"> \nThe <strong>Resume<\/strong> tab captures all evaluations tied to the submitted resume. These fields are automatically populated by Copilot Studio agents as part of the application submission workflow. This approach ensures consistency in how resumes are assessed and minimizes the need for manual data entry by HR staff.<\/p>\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/automatethemundane.com\/wp-content\/uploads\/2025\/07\/image-6-1024x407.png\" alt=\"\"\/><\/figure>\n\n\n<p class=\"has-text-color\" style=\"color: rgb(0, 0, 0)\"> The <strong>Job Posting<\/strong> tab on the form serves as a snapshot of the job details at the time of submission. This design choice ensures that if the original job posting is later updated or modified, the application retains a historical record of what the position looked like when the candidate applied. This is especially useful for audit scenarios or when reviewing application context after a job has evolved.\n<\/p>\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/automatethemundane.com\/wp-content\/uploads\/2025\/07\/image-7-1024x282.png\" alt=\"\"\/><\/figure>\n\n\n<p class=\"has-text-color\" style=\"color: rgb(0, 0, 0)\">\nThe <strong>Assessment<\/strong> tab is where Copilot Studio agents evaluate the resume against the job posting criteria. As part of this automated process, the agent assigns a score from 1 to 5 based on the alignment between the applicant\u2019s qualifications and the job requirements.<\/p>\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/automatethemundane.com\/wp-content\/uploads\/2025\/07\/image-8-1024x405.png\" alt=\"\"\/><\/figure>\n\n\n<p class=\"has-text-color\" style=\"color: rgb(0, 0, 0)\">\nThe <strong>Interview<\/strong> tab captures feedback from all stages of the human interview process. It\u2019s organized into three sections\u2014<strong>HR<\/strong>, <strong>Hiring Manager<\/strong>, and <strong>Overall Assessment<\/strong>. The HR and Hiring Manager sections are filled out during their respective interviews, while the <strong>Overall Assessment<\/strong> is automatically generated by an agent based on those inputs. This ensures the process remains efficient without losing the value of human insight.\n<\/p>\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/automatethemundane.com\/wp-content\/uploads\/2025\/07\/image-9-1024x512.png\" alt=\"\"\/><\/figure>\n\n\n<p class=\"has-text-color\" style=\"color: rgb(0, 0, 0)\">&nbsp;<\/p>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity is-style-wide\"\/>\n\n\n<h2 class=\"wp-block-heading\"><strong>Lessons Learned<\/strong><\/h2>\n\n\n<p class=\"has-text-color\" style=\"color: rgb(0, 0, 0)\">One early lesson was the importance of modeling around the <em>user experience<\/em>, not just the data. For example, separating Resume from Candidate helped reduce complexity when handling file uploads and made it easier to validate submissions on the front end. It also improved flow performance by minimizing the size of the Candidate record payload.<\/p>\n\n\n<p class=\"has-text-color\" style=\"color: rgb(0, 0, 0)\">Additionally, designing with Power Pages in mind meant I had to pay close attention to relationships and permissions\u2014especially since the site is anonymous and needed to map submissions without requiring sign-in.<\/p>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity is-style-wide\"\/>\n\n\n<h2 class=\"wp-block-heading\"><strong>Up Next: Power Pages<\/strong><\/h2>\n\n\n<p class=\"has-text-color\" style=\"color: rgb(0, 0, 0)\">With the data model in place, the next step was making it accessible to applicants. In the next post, I\u2019ll walk through how I used Power Pages to build a multi-step, user-friendly application form\u2014complete with anonymous access, file upload handling, and clean navigation between stages.<\/p>\n\n","protected":false},"excerpt":{"rendered":"<p>Introduction Before automating anything or designing a user interface, I needed to make sure the data model was solid. Since the Talent Intake System relies on capturing and relating candidates, resumes, and job applications, I started by designing a structure in Dataverse that could support flexible workflows, easy querying, and clean integration with forms and [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":1550,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[22,38,6],"tags":[],"class_list":["post-1549","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-dataverse","category-design","category-model-driven-app","entry","has-media"],"jetpack_featured_media_url":"https:\/\/automatethemundane.com\/wp-content\/uploads\/2025\/07\/photo-1545987796-200677ee1011-scaled.jpg","_links":{"self":[{"href":"https:\/\/automatethemundane.com\/index.php\/wp-json\/wp\/v2\/posts\/1549","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/automatethemundane.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/automatethemundane.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/automatethemundane.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/automatethemundane.com\/index.php\/wp-json\/wp\/v2\/comments?post=1549"}],"version-history":[{"count":0,"href":"https:\/\/automatethemundane.com\/index.php\/wp-json\/wp\/v2\/posts\/1549\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/automatethemundane.com\/index.php\/wp-json\/wp\/v2\/media\/1550"}],"wp:attachment":[{"href":"https:\/\/automatethemundane.com\/index.php\/wp-json\/wp\/v2\/media?parent=1549"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/automatethemundane.com\/index.php\/wp-json\/wp\/v2\/categories?post=1549"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/automatethemundane.com\/index.php\/wp-json\/wp\/v2\/tags?post=1549"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}