Field Technician
Reporting App
A technician opens the app, selects their work site and the equipment they’re inspecting, works through an automatically generated checklist, and submits. Power Automate picks up the submission, calls AI Builder to generate a plain-language summary, and emails it to the right manager — all without any manual steps.
The data model
Dataverse was chosen over SharePoint for three reasons: proper relational relationships between tables, column-level security so technicians only see data relevant to their assigned sites, and a clean API surface for the Power Automate flow.
The dynamic checklist problem
Different equipment types need different inspection steps. An HVAC unit and a generator don’t share the same checklist. Hardcoding a checklist per equipment type doesn’t scale — add a new type and you’d need to update the app itself.
The solution is a lookup chain the app follows at runtime: Equipment selected → What type is it? → Which checklist template belongs to that type? → Load the checklist items for that template. Add a new equipment type and checklist in Dataverse and the app shows it automatically, with zero app changes.
- Adding a new site: one Location record
- Adding a new piece of equipment: one Equipment record with the correct type lookup
- Adding a new equipment type with its own checklist: one EquipmentType, one ChecklistTemplate, and however many ChecklistItem records the checklist needs
- App changes required in all three cases: zero
The 7 tables
The full relationship chain
Left side defines what can be inspected. Right side captures what happened. Report Item connects the two halves — linking a specific checklist question to a specific inspection event with a specific result.
The canvas app
Screen structure and data source connections were set up through Power Apps Studio. Formula editing was handled through Claude Code in VS Code — downloading the .msapp file, unpacking it to readable YAML, editing Power Fx formulas as plain text, repacking, and importing back. This approach was significantly more reliable than writing complex formulas in the Studio formula bar, particularly for filtering through Dataverse lookup relationships.
- Dataverse lookup fields in canvas apps must be compared using the underlying GUID, not by comparing whole records or display name strings
- The correct pattern: Location.saeid_locationid = varSelectedLocation.saeid_locationid
- This is delegation-safe and avoids type mismatch errors that occur with direct record comparison
Screen by screen
Screen 1 — Select Location. Gallery of all sites. Tapping a row stores the full record in varSelectedLocation and navigates forward. Storing the full record means Manager Email is available later without a second database query.
Screen 2 — Select Equipment. Gallery filtered to show only equipment at the chosen location:
Screen 3 — Checklist. The most complex screen. The gallery follows the full lookup chain to load the right checklist automatically:
Each checklist row has a button cycling through Pass, Fail, and N/A. Every tap updates an in-memory collection for immediate UI feedback and writes directly to Dataverse simultaneously — so partial inspections are never lost if the app closes mid-session.
Screen 4 — Review and Submit. Shows location, equipment, date, and all results color-coded. Submit patches the Job Report status to Submitted, triggers Power Automate, and resets the app for the next inspection.
Power Automate + AI Builder
Once a technician submits, the flow “Field Report AI Summary” fires automatically. It fetches the results, formats them, calls an AI Builder prompt, and writes the generated summary back to Dataverse — then emails it to the location manager. No custom code, no external API calls, everything runs inside the Microsoft stack.
The 7 steps
- The Dataverse trigger body does not include FormattedValue annotations for lookup columns — only the raw GUID under the _columnname_value path
- To get a human-readable display name for a lookup field, you need a separate Get row action or the FormattedValue annotation path
- This is why the Get Equipment Row step exists as a dedicated action rather than reading the location name directly from the trigger
From tap to manager inbox
A technician selects their site, picks the equipment they’re inspecting, works through the auto-generated checklist, taps Pass or Fail on each item, adds notes where needed, and submits. Within seconds the manager receives:
Why it scales
This is the difference between a form and a system. A form captures data. A system applies logic to that data, routes it to the right people, and generates value from it automatically.