<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Data Bear</title>
	<atom:link href="https://databear.com/feed/" rel="self" type="application/rss+xml" />
	<link>https://databear.com/</link>
	<description>Be Data Savvy</description>
	<lastBuildDate>Tue, 21 Jul 2026 09:29:46 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.1</generator>

<image>
	<url>https://databear.com/wp-content/uploads/2022/10/cropped-databear-favicon-32x32.png</url>
	<title>Data Bear</title>
	<link>https://databear.com/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Lessons from a Fabric App demo build</title>
		<link>https://databear.com/lessons-from-a-fabric-app-demo-build/</link>
		
		<dc:creator><![CDATA[Johann Joubert]]></dc:creator>
		<pubDate>Tue, 21 Jul 2026 09:29:46 +0000</pubDate>
				<category><![CDATA[Fabric]]></category>
		<guid isPermaLink="false">https://databear.com/?p=51018</guid>

					<description><![CDATA[<p>We built a Fabric App demo. Here&#8217;s what it would take to make it production-grade, and why a demo isn&#8217;t there yet A Fabric App demo can be built fast, especially with AI assistance. A working page that reads a semantic model, renders like a polished web app and does something a report cannot, that [&#8230;]</p>
<p>The post <a href="https://databear.com/lessons-from-a-fabric-app-demo-build/">Lessons from a Fabric App demo build</a> appeared first on <a href="https://databear.com">Data Bear</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h1 class="text-text-100 mt-3 -mb-1 text-[1.375rem] font-bold" data-sourcepos="1:1-1:116;0-115">We built a Fabric App demo. Here&#8217;s what it would take to make it production-grade, and why a demo isn&#8217;t there yet</h1>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="3:1-3:264;117-380">A Fabric App demo can be built fast, especially with AI assistance. A working page that reads a semantic model, renders like a polished web app and does something a report cannot, that can exist in days. The speed is real and it is genuinely useful for discovery.</p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="5:1-5:519;382-900">It is also the trap. Because the thing that makes a demo fast to build is precisely the set of questions it lets you skip: who owns this, who reviews changes to it, what happens when the model underneath it shifts, who gets the call when a user says a number looks wrong. A Power BI report answers most of those questions by convention, because the platform and your organisation already have a shape for it. A Fabric App is a custom web application on top of your data, and it answers none of them by default. You do.</p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="7:1-7:459;902-1360">We built a finance Fabric App demo (a dashboard plus forecast writeback) and, because we build these for clients, we were deliberate about the line between &#8220;demo-grade&#8221; and &#8220;production-grade&#8221; from the start. This post is about that line: the governance and maintainability work a Fabric App needs before it is more than a demo, drawn from the actual guardrails we put around ours and the specific reasons a demo is not production even when it looks finished.</p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="9:1-9:131;1362-1492">The short version: the demo is the easy 90% of the effort and the last 10% is most of the risk. Everything below is that last 10%.</p>
<h2 class="text-text-100 mt-3 -mb-1 text-[1.125rem] font-bold" data-sourcepos="11:1-11:46;1494-1539">The visible part is not the quality signal</h2>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="13:1-13:291;1541-1831">The first thing anyone notices about a Fabric App is the interface: custom visuals, app-style navigation, a guided experience instead of a report canvas full of slicers. That is the part that gets attention in a demo, and it is the part that matters least to whether the app can be trusted.</p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="15:1-15:547;1833-2379">The quality signal sits underneath, and it is mostly invisible in a demo: can the semantic model reliably answer the questions the app asks, are the queries against it validated, is there a clear owner for the app code and a separate clear owner for the model, and is there a defined path for a change to reach users without breaking them. A demo can score perfectly on look and zero on every one of those, and from the outside the two are indistinguishable. That gap between what a demo shows and what production needs is the whole subject here.</p>
<p><img fetchpriority="high" decoding="async" class="alignnone size-full wp-image-51019" src="https://databear.com/wp-content/uploads/2026/07/Creating-a-Fabric-App-scaled.png" alt="fabric app" width="1920" height="518" srcset="https://databear.com/wp-content/uploads/2026/07/Creating-a-Fabric-App-scaled.png 1920w, https://databear.com/wp-content/uploads/2026/07/Creating-a-Fabric-App-300x81.png 300w, https://databear.com/wp-content/uploads/2026/07/Creating-a-Fabric-App-1024x276.png 1024w, https://databear.com/wp-content/uploads/2026/07/Creating-a-Fabric-App-150x40.png 150w, https://databear.com/wp-content/uploads/2026/07/Creating-a-Fabric-App-1536x415.png 1536w, https://databear.com/wp-content/uploads/2026/07/Creating-a-Fabric-App-2048x553.png 2048w" sizes="(max-width: 1920px) 100vw, 1920px" /></p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="17:1-17:178;2381-2558"><em>At the time of writing this, July 2026, Fabric Apps are still in preview.</em></p>
<p><img decoding="async" class="alignnone size-full wp-image-50981" src="https://databear.com/wp-content/uploads/2026/07/Fabric-Apps-Finance-Overview-scaled.png" alt="Fabric Apps Dashboard" width="1920" height="880" srcset="https://databear.com/wp-content/uploads/2026/07/Fabric-Apps-Finance-Overview-scaled.png 1920w, https://databear.com/wp-content/uploads/2026/07/Fabric-Apps-Finance-Overview-300x137.png 300w, https://databear.com/wp-content/uploads/2026/07/Fabric-Apps-Finance-Overview-1024x469.png 1024w, https://databear.com/wp-content/uploads/2026/07/Fabric-Apps-Finance-Overview-150x69.png 150w, https://databear.com/wp-content/uploads/2026/07/Fabric-Apps-Finance-Overview-1536x704.png 1536w, https://databear.com/wp-content/uploads/2026/07/Fabric-Apps-Finance-Overview-2048x938.png 2048w" sizes="(max-width: 1920px) 100vw, 1920px" /></p>
<p>The Fabric App landing page. The interface is the visible layer. Whether the app is production-grade is decided by things this screenshot cannot show.</p>
<h2 class="text-text-100 mt-3 -mb-1 text-[1.125rem] font-bold" data-sourcepos="19:1-19:39;2560-2598">Ownership is two questions, not one</h2>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="21:1-21:180;2600-2779">The instinct is to ask &#8220;who owns the app?&#8221; In a Fabric App there are two owners and they are usually not the same person, which is exactly the complication a report does not have.</p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="23:1-23:570;2781-3350">There is the app code: the React, the TypeScript, the queries, the layout, the deployment. And there is the semantic model: the tables, the relationships, the DAX measures, the security rules. In our build these are cleanly separate concerns, and the separation is not incidental, it is structural. The model&#8217;s fact and dimension tables are read-only to the app. The app reads them through the data service and cannot write to them. Anything the app needs to persist (in our case a forecast adjustment) goes to a separate writeable store, never into the model&#8217;s tables.</p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="25:1-25:713;3352-4064">That read-only boundary is the single most clarifying fact for ownership. It means the model team can own the model and the app team can own the app without stepping on each other, because the app physically cannot alter the model&#8217;s data. But it also means a change on either side of the boundary can break the other, and nobody owns the boundary itself unless you deliberately assign it. The question production forces that a demo lets you dodge is: when a measure definition changes in the model, who is responsible for checking that the app still reads it correctly? In a demo, the answer is &#8220;the same person built both, so nobody had to ask.&#8221; In production, that person has moved on and the question is live.</p>
<h2 class="text-text-100 mt-3 -mb-1 text-[1.125rem] font-bold" data-sourcepos="27:1-27:57;4066-4122">Deployment is where a demo quietly becomes production</h2>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="29:1-29:324;4124-4447">The most dangerous moment in a Fabric App&#8217;s life is the one nobody notices: the deploy where a prototype starts being used for real. Nothing technical marks it. The app that was a demo yesterday is load-bearing today, and if you have not built the discipline in advance, you build it after something has already gone wrong.</p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="31:1-31:590;4449-5038">We put the controls in before the app was worth protecting, which is the only time it is cheap to do. Concretely, deployment runs through a single choke point: exactly one script is permitted to deploy, and it refuses to run unless several preconditions hold. It checks it is on the working branch and not the protected one. It checks the git tree is clean. It checks the deploy target is the one specific workspace and item it is allowed to touch, and refuses any other target outright. It logs every deploy. No deploy can happen any other way, and that is enforced, not merely requested.</p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="33:1-33:424;5040-5463">The reason for a single guarded path is that ad hoc deploys are how demos rot into production without anyone deciding they should. If any developer can push the live app from their machine on a whim, there is no moment where a change is reviewed, and &#8220;it worked on my screen&#8221; becomes the release process. Funnelling every deploy through one gate creates the checkpoint that a report gets for free from its publishing model.</p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="35:1-35:584;5465-6048">Alongside that, the main branch is protected: changes reach it only through review, never by a direct push, and several categories of action are blocked outright by automated guards rather than left to good intentions. Destructive operations against the data, edits to secret and credential files, and any write while on the protected branch are all refused at the tooling level. The principle we followed throughout: a rule that depends on everyone remembering it is not a control, it is a hope. If it matters, it should be impossible to violate by accident, not merely discouraged.</p>
<p><img decoding="async" class="alignnone wp-image-51020" src="https://databear.com/wp-content/uploads/2026/07/app-explorer1.png" alt="fabric workspace" width="639" height="809" srcset="https://databear.com/wp-content/uploads/2026/07/app-explorer1.png 825w, https://databear.com/wp-content/uploads/2026/07/app-explorer1-237x300.png 237w, https://databear.com/wp-content/uploads/2026/07/app-explorer1-809x1024.png 809w, https://databear.com/wp-content/uploads/2026/07/app-explorer1-119x150.png 119w" sizes="(max-width: 639px) 100vw, 639px" /></p>
<p><img loading="lazy" decoding="async" class="alignnone wp-image-51022" src="https://databear.com/wp-content/uploads/2026/07/Fabric-Workspace.png" alt="fabric workspace" width="615" height="440" srcset="https://databear.com/wp-content/uploads/2026/07/Fabric-Workspace.png 1410w, https://databear.com/wp-content/uploads/2026/07/Fabric-Workspace-300x215.png 300w, https://databear.com/wp-content/uploads/2026/07/Fabric-Workspace-1024x734.png 1024w, https://databear.com/wp-content/uploads/2026/07/Fabric-Workspace-150x107.png 150w" sizes="(max-width: 615px) 100vw, 615px" /></p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="37:1-37:208;6050-6257"><em>One guarded deployment path, a protected main branch, review before release. The controls a report inherits by convention, an app has to be given.</em></p>
<h2 class="text-text-100 mt-3 -mb-1 text-[1.125rem] font-bold" data-sourcepos="39:1-39:56;6259-6314">Secrets and auth: the boundary a script cannot cross</h2>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="41:1-41:166;6316-6481">Here is a concrete production consideration that a demo surfaces in an awkward way, and it is worth stating plainly because it caught us out before we understood it.</p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="43:1-43:591;6483-7073">The credentials the app needs to reach its data live in environment and configuration files that must never enter version control and must never be edited by an automated process. We enforced that with a hard guard: the build tooling is blocked from touching those files at all, with no exception path. Any change to them is a deliberate human edit in a separate session, and the files themselves are kept out of the repository and backed up separately. That is ordinary secure practice, but a Fabric App makes it your responsibility explicitly, where a report keeps it inside the platform.</p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="45:1-45:476;7075-7550">The sharper, less obvious one: the app&#8217;s writes to its data store run under Fabric&#8217;s embedded authentication, which is tied to the signed-in user session inside the running app. A command-line or automated process cannot complete that authentication. It is not awkward, it is structurally impossible. For us that meant certain operations, seeding data, verifying what was written, can only happen as actions a signed-in human takes inside the deployed app, never as a script.</p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="47:1-47:478;7552-8029">This matters for production planning far beyond the demo, because it dictates what can and cannot be automated in the app&#8217;s operations. If your maintenance plan assumes you can script the app&#8217;s data setup or run automated checks that write to its store, embedded auth says otherwise, and you need to know that at design time, not when you are trying to build a nightly job that cannot authenticate. Classify the operations that are structurally human-in-the-app from the start.</p>
<h2 class="text-text-100 mt-3 -mb-1 text-[1.125rem] font-bold" data-sourcepos="49:1-49:70;8031-8100">The demo will lie to you about maintainability in one specific way</h2>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="51:1-51:263;8102-8364">A demo runs on a machine where the person who built it is present, the model has not changed since, and every dependency is exactly as it was. Production is defined by the absence of all three. The maintainability questions are the ones the demo conditions hide:</p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="53:1-53:486;8366-8851">What happens when the model schema changes? A renamed column or a redefined measure that the app reads will not announce itself, the app will keep rendering, possibly with wrong numbers, exactly the way our own headline figure once read plausibly while being wrong. In production you need a way to catch that a model change has desynchronised the app, which means tests over the app&#8217;s important data journeys that run against the real deployed app, not just the developer&#8217;s confidence.</p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="55:1-55:347;8853-9199">What happens when a user reports a number that looks wrong? In a demo, the builder investigates. In production, someone has to be able to trace a displayed number back through the query, to the measure, to the model, and that someone needs to exist and know the path. If ownership is unclear (the two-owner problem above), this is where it bites.</p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="57:1-57:269;9201-9469">What is the rollback plan? A demo has none because it does not need one. A production app needs a defined way back to the last good state when a deploy goes wrong, and for an app that writes data, that plan has to account for the data written since, not just the code.</p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="59:1-59:201;9471-9671">None of these are exotic. They are the standard concerns of running software, and that is the point: a Fabric App is software, and the demo is the one phase where you are allowed to pretend it is not.</p>
<h2 class="text-text-100 mt-3 -mb-1 text-[1.125rem] font-bold" data-sourcepos="61:1-61:82;9673-9754">Match the governance to the risk, and sometimes that means not building an app</h2>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="63:1-63:387;9756-10142">The weight of everything above should scale with what the app is for. A throwaway internal demo needs almost none of it. An app that finance or operations leaders rely on needs most of it, and that starts to look like software delivery: version control, clear ownership on both sides of the model boundary, validated queries, tested user journeys, reviewed permissions, a rollback plan.</p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="65:1-65:583;10144-10726">Which leads to the honest conclusion, the same one we reach on every one of these builds. Not every report should become a Fabric App. If the deliverable is something people read and explore, a Power BI report is faster to build, cheaper to maintain, and comes with an ownership and governance model your organisation already understands. The app earns its governance cost only when it does something a report fundamentally cannot, and even then the cost is real and should be counted before you start, not discovered after the demo has quietly become the thing everyone depends on.</p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="67:1-67:430;10728-11157">We built the controls into our demo not because a demo needs them, but because the distance between a demo that has them and one that does not is exactly the distance between something you can put in front of a client and something you can hand to a client. That distance is the work. It is mostly invisible, it is almost all in the last stretch, and it is the part worth asking about before anyone is impressed by the interface.</p>
<p>To learn more about Microsoft Fabric and how we can help with Fabric Apps, see our <a href="https://databear.com/microsoft-fabric/">Microsoft Fabric page.</a></p>
<p>The post <a href="https://databear.com/lessons-from-a-fabric-app-demo-build/">Lessons from a Fabric App demo build</a> appeared first on <a href="https://databear.com">Data Bear</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Power BI finance writeback translytical task flow</title>
		<link>https://databear.com/power-bi-finance-writeback-translytical-task-flow/</link>
		
		<dc:creator><![CDATA[Johann Joubert]]></dc:creator>
		<pubDate>Tue, 21 Jul 2026 09:29:30 +0000</pubDate>
				<category><![CDATA[Microsoft Power BI]]></category>
		<category><![CDATA[Power BI]]></category>
		<guid isPermaLink="false">https://databear.com/?p=51024</guid>

					<description><![CDATA[<p>The hard part of Power BI finance writeback wasn&#8217;t the writeback We set out to build a finance commentary writeback report in Power BI using Fabric translytical task flows. The interaction sounds trivial: select a finance row, type an explanation, click a button, write the comment to a Fabric SQL Database, and show it back [&#8230;]</p>
<p>The post <a href="https://databear.com/power-bi-finance-writeback-translytical-task-flow/">Power BI finance writeback translytical task flow</a> appeared first on <a href="https://databear.com">Data Bear</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h1 class="text-text-100 mt-3 -mb-1 text-[1.375rem] font-bold" data-sourcepos="1:1-1:67;0-66">The hard part of Power BI finance writeback wasn&#8217;t the writeback</h1>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="3:1-3:380;68-447">We set out to build a finance commentary writeback report in Power BI using Fabric translytical task flows. The interaction sounds trivial: select a finance row, type an explanation, click a button, write the comment to a Fabric SQL Database, and show it back against the same row. The Python that does the insert is a dozen lines. It was the easy part, and it was working early.</p>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-51027" src="https://databear.com/wp-content/uploads/2026/07/Fianance-Writeback-scaled.png" alt="Power BI TTF writeback report" width="1920" height="1069" srcset="https://databear.com/wp-content/uploads/2026/07/Fianance-Writeback-scaled.png 1920w, https://databear.com/wp-content/uploads/2026/07/Fianance-Writeback-300x167.png 300w, https://databear.com/wp-content/uploads/2026/07/Fianance-Writeback-1024x570.png 1024w, https://databear.com/wp-content/uploads/2026/07/Fianance-Writeback-150x84.png 150w, https://databear.com/wp-content/uploads/2026/07/Fianance-Writeback-1536x855.png 1536w, https://databear.com/wp-content/uploads/2026/07/Fianance-Writeback-2048x1141.png 2048w" sizes="(max-width: 1920px) 100vw, 1920px" /></p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="5:1-5:545;449-993">Everything that actually took the time lived in the seams between the pieces: deciding what a single comment is really attached to, keeping the finance facts immutable, getting one selected key out of a Power BI table, fixing service-side authentication that looked like a wrong server name, mapping button parameters that a published-and-tested function still would not accept, and telling a correctly-filtered empty visual apart from a broken one. Two of the most alarming &#8220;the data is gone&#8221; moments turned out not to be data failures at all.</p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="7:1-7:259;995-1253">This is the build diary we would have wanted before we started: the route that worked, the false leads, the specific platform behaviours, and the point where a translytical task flow stops being the right tool and you should reach for an application instead.</p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="9:1-9:442;1255-1696">One clarification up front, because we have written separately about building forecast <a href="https://databear.com/fabric-apps-finance-forecast-writeback/">writeback inside a full Fabric App</a>. This is a different pattern. Here the writeback lives inside an ordinary Power BI report, driven by a data-function button against Fabric User Data Functions. It is the lighter-weight option, and a large part of what we learned is exactly where its natural ceiling sits relative to a full app. More on that at the end.</p>
<h2 class="text-text-100 mt-3 -mb-1 text-[1.125rem] font-bold" data-sourcepos="11:1-11:69;1698-1766">Two apparent data failures that were really report-state failures</h2>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="13:1-13:252;1768-2019">The most useful lesson of the build came from two bugs that both looked like the data had vanished and were both nothing of the kind. We are putting them first because they are the heart of what makes translytical reports different from ordinary ones.</p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="15:1-15:89;2021-2109">The report has a one-to-many relationship from the finance view to the commentary table:</p>
<div class="relative group/copy bg-bg-000/50 border-0.5 border-border-400 rounded-lg focus:outline-none focus-visible:ring-2 focus-visible:ring-accent-100" tabindex="0" role="group" aria-label="text code" data-sourcepos="17:1-19:4;2111-2188">
<div class="sticky opacity-0 group-hover/copy:opacity-100 group-focus-within/copy:opacity-100 top-2 py-2 h-12 w-0 float-right">
<div class="absolute right-0 h-8 px-2 items-center inline-flex z-10"></div>
</div>
<div class="text-text-500 font-small p-3.5 pb-0">text</div>
<div class="overflow-x-auto">
<pre class="code-block__code !my-0 !rounded-lg !text-sm !leading-relaxed p-3.5"><code class="language-text">vw_FinanceDemo[FinanceKey] 1 → many FinanceCommentary[FinanceKey]</code></pre>
</div>
</div>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="21:1-21:81;2190-2270">The first bug appeared the moment we added a comment count to the finance table:</p>
<div class="relative group/copy bg-bg-000/50 border-0.5 border-border-400 rounded-lg focus:outline-none focus-visible:ring-2 focus-visible:ring-accent-100" tabindex="0" role="group" aria-label="dax code" data-sourcepos="23:1-25:4;2272-2327">
<div class="sticky opacity-0 group-hover/copy:opacity-100 group-focus-within/copy:opacity-100 top-2 py-2 h-12 w-0 float-right">
<div class="absolute right-0 h-8 px-2 items-center inline-flex z-10"></div>
</div>
<div class="text-text-500 font-small p-3.5 pb-0">DAX</div>
<div class="overflow-x-auto">
<pre class="code-block__code !my-0 !rounded-lg !text-sm !leading-relaxed p-3.5"><code class="language-DAX">Comment Count = COUNTROWS(FinanceCommentary)</code></pre>
</div>
</div>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="27:1-27:367;2329-2695">Almost every finance row disappeared, leaving only the single row that had our one manually inserted test comment. It looked exactly as though the relationship had filtered the finance data down to nothing. It had not. The measure returned blank for every row with no commentary, and the visual dropped the blank rows. Converting blank to zero brought them all back:</p>
<div class="relative group/copy bg-bg-000/50 border-0.5 border-border-400 rounded-lg focus:outline-none focus-visible:ring-2 focus-visible:ring-accent-100" tabindex="0" role="group" aria-label="dax code" data-sourcepos="29:1-31:4;2697-2765">
<div class="sticky opacity-0 group-hover/copy:opacity-100 group-focus-within/copy:opacity-100 top-2 py-2 h-12 w-0 float-right">
<div class="absolute right-0 h-8 px-2 items-center inline-flex z-10"></div>
</div>
<div class="text-text-500 font-small p-3.5 pb-0">DAX</div>
<div class="overflow-x-auto">
<pre class="code-block__code !my-0 !rounded-lg !text-sm !leading-relaxed p-3.5"><code class="language-DAX">Comment Count = COALESCE(COUNTROWS(FinanceCommentary), 0)</code></pre>
</div>
</div>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="33:1-33:418;2767-3184">The second bug was subtler and more instructive. The commentary history visual showed a comment even when no finance row was selected, because nothing was restricting it. We added a <code class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]">Show Selected Commentary</code> measure as a visual-level filter and set the finance table&#8217;s interaction to Filter, so commentary appears only when exactly one row is selected. That fixed the behaviour but created an ambiguity that matters:</p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="35:1-35:491;3186-3676">A blank commentary table can mean two completely different things. Either the visual is not receiving the selected-row context (broken), or the visual is correctly filtered and that row simply has no comments yet (working). We hit this exact ambiguity during final testing: the selected-row card was populated, the commentary table was blank, and for a moment it looked like a filter failure. It was the opposite, a correctly selected row with no commentary. The blank was the right answer.</p>
<p data-sourcepos="35:1-35:491;3186-3676"><img loading="lazy" decoding="async" class="alignnone size-full wp-image-51028" src="https://databear.com/wp-content/uploads/2026/07/sinlge-row-no-comment-scaled.png" alt="Power BI TTF writeback report" width="1920" height="723" srcset="https://databear.com/wp-content/uploads/2026/07/sinlge-row-no-comment-scaled.png 1920w, https://databear.com/wp-content/uploads/2026/07/sinlge-row-no-comment-300x113.png 300w, https://databear.com/wp-content/uploads/2026/07/sinlge-row-no-comment-1024x386.png 1024w, https://databear.com/wp-content/uploads/2026/07/sinlge-row-no-comment-150x57.png 150w, https://databear.com/wp-content/uploads/2026/07/sinlge-row-no-comment-1536x579.png 1536w, https://databear.com/wp-content/uploads/2026/07/sinlge-row-no-comment-2048x771.png 2048w" sizes="(max-width: 1920px) 100vw, 1920px" /></p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="37:1-37:139;3678-3816"><em>Single finance row selected, selected-row card populated, commentary history correctly blank because no comments exist yet</em></p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="39:1-39:486;3818-4303">That is the whole character of this kind of report in one example. A translytical report is a stateful interface, and the model has to account for every state: no selection, one selection, several selections, blank input, a successful write, a failed write, and a successful write that is not yet visible. In a production version we would make the empty state explicit (&#8220;No commentary recorded for this finance row&#8221;) so that zero records can never be mistaken for a broken interaction.</p>
<h2 class="text-text-100 mt-3 -mb-1 text-[1.125rem] font-bold" data-sourcepos="41:1-41:63;4305-4367">What the comment is attached to is the real design question</h2>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="43:1-43:491;4369-4859">Microsoft&#8217;s standard tutorial uses the small AdventureWorksLT sample and writes back a product description. That is fine for showing the mechanics, but it hides the decision that actually matters in finance, because in a product-description example the target row is obvious. In a finance report the visible row might be a fact row, an aggregate, a subtotal, or a measure evaluated under several filters. Before you can write a comment, you have to define precisely what it is a comment on.</p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="45:1-45:542;4861-5402">So we used the larger <code class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]">AdventureWorksDW2022</code>, whose <code class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]">FactFinance</code> gives real amounts by date, account, scenario, organisation and department, and we made the central modelling decision early: <code class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]">FactFinance</code> stays immutable. A finance amount and a user&#8217;s explanation are different kinds of record. The amount is analytical data; the explanation is an auditable action with its own author, timestamp and lifecycle. They belong in different tables, so commentary went into a separate <code class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]">dbo.FinanceCommentary</code> and the fact table was never touched.</p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="47:1-47:463;5404-5866">Our first commentary design stored all the dimensional keys explicitly, date, account, organisation, department, scenario. It was descriptive but it made the button contract far too wide: a single click would have had to pass several key values reliably, with a real chance of a partial or inconsistent combination. So we collapsed the contract to a single surrogate <code class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]">FinanceKey</code>. Power BI passes one integer; the function resolves everything else from that row.</p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="49:1-49:191;5868-6058">The key stays hidden from the user. The report shows a friendly <code class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]">Selected Finance Row</code> card with recognisable business context, while the <code class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]">FinanceKey</code> exists only to carry the function call.</p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="51:1-51:97;6060-6156"><em>[Screenshot: selected finance row card showing business context while FinanceKey stays hidden]</em></p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="53:1-53:547;6158-6704">This works because the demo comments against one physical finance row. It would be the wrong key for a comment like &#8220;total operating expenses for Q3 across all organisations.&#8221; An aggregate comment needs a stable aggregate grain, account plus fiscal period plus organisation scope, or a dedicated review entity. Reusing an arbitrary underlying fact key would make an aggregate comment look precise while quietly attaching it to the wrong business object. That boundary is the single most important thing to get right before extending this pattern.</p>
<h2 class="text-text-100 mt-3 -mb-1 text-[1.125rem] font-bold" data-sourcepos="55:1-55:61;6706-6766">The function was short; proving its boundary was the work</h2>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="57:1-57:103;6768-6870">The user data function, <code class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]">addFinanceCommentary</code>, takes the three values the report can supply reliably:</p>
<div class="relative group/copy bg-bg-000/50 border-0.5 border-border-400 rounded-lg focus:outline-none focus-visible:ring-2 focus-visible:ring-accent-100" tabindex="0" role="group" aria-label="python code" data-sourcepos="59:1-65:4;6872-6978">
<div class="sticky opacity-0 group-hover/copy:opacity-100 group-focus-within/copy:opacity-100 top-2 py-2 h-12 w-0 float-right">
<div class="absolute right-0 h-8 px-2 items-center inline-flex z-10"></div>
</div>
<div class="text-text-500 font-small p-3.5 pb-0">python</div>
<div class="overflow-x-auto">
<pre class="code-block__code !my-0 !rounded-lg !text-sm !leading-relaxed p-3.5"><code class="language-python">addFinanceCommentary<span class="token token">(</span>
    financeKey<span class="token token">:</span> <span class="token token">int</span><span class="token token">,</span>
    commentText<span class="token token">:</span> <span class="token token">str</span><span class="token token">,</span>
    createdBy<span class="token token">:</span> <span class="token token">str</span>
<span class="token token">)</span> <span class="token token">-</span><span class="token token">&gt;</span> <span class="token token">str</span></code></pre>
</div>
</div>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="67:1-67:206;6980-7185">The <code class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]">-&gt; str</code> return type is not incidental: Power BI data-function buttons require a string-returning function. In production that string should be a designed, user-facing result, not a raw exception dump.</p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="69:1-69:445;7187-7631">We tested the function in isolation in the Fabric portal before wiring it to anything, passing a known key, a test comment and a test user. It returned <code class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]">Commentary saved.</code> and a SQL query confirmed the row. That single isolation step paid for itself repeatedly later: once the insert was proven independently of Power BI, every subsequent failure could be attributed to selection, mapping, publication, permissions or refresh, never to the SQL.</p>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-51030" src="https://databear.com/wp-content/uploads/2026/07/comment-being-saved-scaled.png" alt="Power BI TTF writeback report" width="1920" height="683" srcset="https://databear.com/wp-content/uploads/2026/07/comment-being-saved-scaled.png 1920w, https://databear.com/wp-content/uploads/2026/07/comment-being-saved-300x107.png 300w, https://databear.com/wp-content/uploads/2026/07/comment-being-saved-1024x364.png 1024w, https://databear.com/wp-content/uploads/2026/07/comment-being-saved-150x53.png 150w, https://databear.com/wp-content/uploads/2026/07/comment-being-saved-1536x546.png 1536w, https://databear.com/wp-content/uploads/2026/07/comment-being-saved-2048x728.png 2048w" sizes="(max-width: 1920px) 100vw, 1920px" /></p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="71:1-71:84;7633-7716"><em>Fabric User Data Function portal test returning &#8220;Commentary saved.&#8221;<br />
<img loading="lazy" decoding="async" class="alignnone size-full wp-image-51029" src="https://databear.com/wp-content/uploads/2026/07/comment-saved-scaled.png" alt="Power BI TTF writeback report" width="1920" height="470" srcset="https://databear.com/wp-content/uploads/2026/07/comment-saved-scaled.png 1920w, https://databear.com/wp-content/uploads/2026/07/comment-saved-300x73.png 300w, https://databear.com/wp-content/uploads/2026/07/comment-saved-1024x250.png 1024w, https://databear.com/wp-content/uploads/2026/07/comment-saved-150x37.png 150w, https://databear.com/wp-content/uploads/2026/07/comment-saved-1536x376.png 1536w, https://databear.com/wp-content/uploads/2026/07/comment-saved-2048x501.png 2048w" sizes="(max-width: 1920px) 100vw, 1920px" /><br />
</em></p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="73:1-73:513;7718-8230">Two small platform snags cost real time here. The connection alias rejected an underscore: <code class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]">finance_sql</code> was refused and <code class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]">FinanceSql</code> accepted, the field only takes alphanumerics in this experience. And the Fabric interface caused a genuine terminology hunt, we were looking for a way into &#8220;Develop mode&#8221; when the item was already in Develop, shown by the mode selector at the top right. Neither is conceptually hard; both are exactly the kind of undocumented friction a diary like this exists to warn you about.</p>
<h2 class="text-text-100 mt-3 -mb-1 text-[1.125rem] font-bold" data-sourcepos="75:1-75:55;8232-8286">Selecting the function did not configure the button</h2>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="77:1-77:203;8288-8490">This was the most misleading interface state in the whole build. We chose the Data-function action, connected the published function, and the selection completed cleanly, yet hovering the button warned:</p>
<div class="relative group/copy bg-bg-000/50 border-0.5 border-border-400 rounded-lg focus:outline-none focus-visible:ring-2 focus-visible:ring-accent-100" tabindex="0" role="group" aria-label="text code" data-sourcepos="79:1-81:4;8492-8549">
<div class="sticky opacity-0 group-hover/copy:opacity-100 group-focus-within/copy:opacity-100 top-2 py-2 h-12 w-0 float-right">
<div class="absolute right-0 h-8 px-2 items-center inline-flex z-10"></div>
</div>
<div class="text-text-500 font-small p-3.5 pb-0">text</div>
<div class="overflow-x-auto">
<pre class="code-block__code !my-0 !rounded-lg !text-sm !leading-relaxed p-3.5"><code class="language-text">The data function is not properly configured.</code></pre>
</div>
</div>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="83:1-83:292;8551-8842">Because the function was already published and had passed its portal test, this looked like the connection had failed. It had not. Selecting a function and supplying its inputs are two separate steps, and nothing on screen made that obvious. We added and mapped the three parameters by hand:</p>
<div class="relative group/copy bg-bg-000/50 border-0.5 border-border-400 rounded-lg focus:outline-none focus-visible:ring-2 focus-visible:ring-accent-100" tabindex="0" role="group" aria-label="text code" data-sourcepos="85:1-89:4;8844-8951">
<div class="sticky opacity-0 group-hover/copy:opacity-100 group-focus-within/copy:opacity-100 top-2 py-2 h-12 w-0 float-right">
<div class="absolute right-0 h-8 px-2 items-center inline-flex z-10"></div>
</div>
<div class="text-text-500 font-small p-3.5 pb-0">text</div>
<div class="overflow-x-auto">
<pre class="code-block__code !my-0 !rounded-lg !text-sm !leading-relaxed p-3.5"><code class="language-text">financeKey  → Selected FinanceKey
commentText → input slicer value
createdBy   → Writeback User</code></pre>
</div>
</div>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="91:1-91:267;8953-9219"><code class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]">Selected FinanceKey</code> uses <code class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]">SELECTEDVALUE</code>, deliberately returning blank unless exactly one row is in context. The input slicer supplies the free text. <code class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]">Writeback User</code> uses the signed-in Power BI identity. The moment all three mappings existed, the warning cleared.</p>
<p data-sourcepos="91:1-91:267;8953-9219"><img loading="lazy" decoding="async" class="alignnone size-full wp-image-51031" src="https://databear.com/wp-content/uploads/2026/07/action-button.png" alt="PBI writeback button" width="1566" height="891" srcset="https://databear.com/wp-content/uploads/2026/07/action-button.png 1566w, https://databear.com/wp-content/uploads/2026/07/action-button-300x171.png 300w, https://databear.com/wp-content/uploads/2026/07/action-button-1024x583.png 1024w, https://databear.com/wp-content/uploads/2026/07/action-button-150x85.png 150w, https://databear.com/wp-content/uploads/2026/07/action-button-1536x874.png 1536w" sizes="(max-width: 1566px) 100vw, 1566px" /></p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="93:1-93:98;9221-9318"><em>Power BI button action settings with financeKey, commentText and createdBy mapped]</em></p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="95:1-95:408;9320-9727">We then saved, republished over the existing report and semantic model, opened the report in the service, selected one finance row, typed a comment, and clicked the button. It completed, the row was written, and after the visuals refreshed the new comment appeared against the same selected <code class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]">FinanceKey</code>. The full loop, report selection to database insert to refreshed DirectQuery visual, worked end to end.<br />
<img loading="lazy" decoding="async" class="alignnone size-full wp-image-51032" src="https://databear.com/wp-content/uploads/2026/07/comment-history.png" alt="Writeback comment" width="985" height="243" srcset="https://databear.com/wp-content/uploads/2026/07/comment-history.png 985w, https://databear.com/wp-content/uploads/2026/07/comment-history-300x74.png 300w, https://databear.com/wp-content/uploads/2026/07/comment-history-150x37.png 150w" sizes="(max-width: 985px) 100vw, 985px" /></p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="97:1-97:104;9729-9832"><em>The new comment appearing in the commentary history after clicking the writeback button</em></p>
<h2 class="text-text-100 mt-3 -mb-1 text-[1.125rem] font-bold" data-sourcepos="99:1-99:67;9834-9900">DirectQuery was a choice, and it exposed an authentication trap</h2>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="101:1-101:540;9902-10441">We chose DirectQuery deliberately, not by default. The point of the demo is a visible writeback loop: the user clicks and expects the comment to appear. An Import model would insert the row but not surface it until a semantic-model refresh, which breaks that expectation. DirectQuery shows the new row immediately. The trade-off is that it pushes performance pressure to query time, our simple view was fine for a sample but should not be assumed to scale to a large finance model without query, indexing, concurrency and capacity testing.</p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="103:1-103:329;10443-10771">One earlier snag on the way in: we started in Power Query Online and could not find a DirectQuery option. The source was fine; the surface was wrong. The model and report interaction have to be built in Power BI Desktop, using the SQL Server connector against the Fabric SQL server and database, with DirectQuery selected there.</p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="105:1-105:416;10773-11188">Publishing then exposed the trap worth remembering. Desktop connected perfectly, but the semantic-model credentials in the service were set to Basic authentication, and the resulting error complained about being unable to open server <code class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]">databear.com</code>, which made it look like a wrong server name rather than an auth-mode problem. Switching the service-side credentials to Organisational/OAuth resolved it immediately.</p>
<p data-sourcepos="105:1-105:416;10773-11188"><img loading="lazy" decoding="async" class="alignnone wp-image-51033" src="https://databear.com/wp-content/uploads/2026/07/auth.png" alt="model auth" width="453" height="601" srcset="https://databear.com/wp-content/uploads/2026/07/auth.png 882w, https://databear.com/wp-content/uploads/2026/07/auth-226x300.png 226w, https://databear.com/wp-content/uploads/2026/07/auth-772x1024.png 772w, https://databear.com/wp-content/uploads/2026/07/auth-113x150.png 113w" sizes="(max-width: 453px) 100vw, 453px" /></p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="107:1-107:117;11190-11306"><em>Semantic model data source settings after changing authentication from Basic to Organisational/OAuth<br />
<img loading="lazy" decoding="async" class="alignnone wp-image-51034" src="https://databear.com/wp-content/uploads/2026/07/auth-approved.png" alt="auth approved" width="643" height="285" srcset="https://databear.com/wp-content/uploads/2026/07/auth-approved.png 954w, https://databear.com/wp-content/uploads/2026/07/auth-approved-300x133.png 300w, https://databear.com/wp-content/uploads/2026/07/auth-approved-150x67.png 150w" sizes="(max-width: 643px) 100vw, 643px" /><br />
</em></p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="109:1-109:421;11308-11728">The lesson generalises: a successful Desktop connection only proves the Desktop connection. It says nothing about whether the published semantic model, the Fabric SQL Database, the user data function and the report viewer are all using the intended identity. We would not call this production-ready until it had been tested with a non-owner account and the Execute, data and row-level permissions verified independently.</p>
<h2 class="text-text-100 mt-3 -mb-1 text-[1.125rem] font-bold" data-sourcepos="111:1-111:64;11730-11793">Getting the finance database into Fabric took a local detour</h2>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="113:1-113:167;11795-11961">The demo data path was more involved than the tutorials suggest, because we wanted the richer warehouse sample rather than the lightweight one. The route that worked:</p>
<div class="relative group/copy bg-bg-000/50 border-0.5 border-border-400 rounded-lg focus:outline-none focus-visible:ring-2 focus-visible:ring-accent-100" tabindex="0" role="group" aria-label="text code" data-sourcepos="115:1-117:4;11963-12063">
<div class="sticky opacity-0 group-hover/copy:opacity-100 group-focus-within/copy:opacity-100 top-2 py-2 h-12 w-0 float-right">
<div class="absolute right-0 h-8 px-2 items-center inline-flex z-10"></div>
</div>
<div class="text-text-500 font-small p-3.5 pb-0">text</div>
<div class="overflow-x-auto">
<pre class="code-block__code !my-0 !rounded-lg !text-sm !leading-relaxed p-3.5"><code class="language-text">AdventureWorksDW2022.bak → local SQL Server restore → .bacpac export → Fabric SQL import</code></pre>
</div>
</div>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="119:1-119:222;12065-12286">The machine had neither a local SQL Server nor SSMS to begin with, so those went on first. During the restore we lost track of whether &#8220;relocate all files&#8221; had been ticked; rather than restart, we just asked the database:</p>
<div class="relative group/copy bg-bg-000/50 border-0.5 border-border-400 rounded-lg focus:outline-none focus-visible:ring-2 focus-visible:ring-accent-100" tabindex="0" role="group" aria-label="sql code" data-sourcepos="121:1-123:4;12288-12378">
<div class="sticky opacity-0 group-hover/copy:opacity-100 group-focus-within/copy:opacity-100 top-2 py-2 h-12 w-0 float-right">
<div class="absolute right-0 h-8 px-2 items-center inline-flex z-10"></div>
</div>
<div class="text-text-500 font-small p-3.5 pb-0">sql</div>
<div class="overflow-x-auto">
<pre class="code-block__code !my-0 !rounded-lg !text-sm !leading-relaxed p-3.5"><code class="language-sql"><span class="token token">SELECT</span> name<span class="token token">,</span> state_desc <span class="token token">FROM</span> sys<span class="token token">.</span><span class="token token">databases</span> <span class="token token">WHERE</span> name <span class="token token">=</span> <span class="token token">'AdventureWorksDW2022'</span><span class="token token">;</span></code></pre>
</div>
</div>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="125:1-125:442;12380-12821">It returned <code class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]">ONLINE</code>, which settled it without redoing the step. <code class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]">SqlPackage</code> was the next gap, and its first install route wanted a whole .NET SDK we did not otherwise need, so we used the standalone Windows package instead and exported a roughly 16 MB <code class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]">.bacpac</code>, then imported it into an empty Fabric SQL Database with Entra interactive auth and confirmed the finance fact and dimension tables were present before building anything on top.</p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="127:1-127:105;12823-12927"><em>Fabric SQL Database explorer showing FactFinance and the finance dimensions after import<br />
<img loading="lazy" decoding="async" class="alignnone wp-image-51035" src="https://databear.com/wp-content/uploads/2026/07/Database.png" alt="database" width="482" height="696" srcset="https://databear.com/wp-content/uploads/2026/07/Database.png 1012w, https://databear.com/wp-content/uploads/2026/07/Database-208x300.png 208w, https://databear.com/wp-content/uploads/2026/07/Database-709x1024.png 709w, https://databear.com/wp-content/uploads/2026/07/Database-104x150.png 104w" sizes="(max-width: 482px) 100vw, 482px" /><br />
</em></p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="129:1-129:290;12929-13218">This is fine for standing up a demonstration database. It is explicitly not a deployment lifecycle. For anything ongoing, the schema, views, writeback tables and permissions belong in scripts under source control; a <code class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]">.bacpac</code> moves a starting dataset, it is not database change management.</p>
<h2 class="text-text-100 mt-3 -mb-1 text-[1.125rem] font-bold" data-sourcepos="131:1-131:33;13220-13252">Debugging by proven contracts</h2>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="133:1-133:244;13254-13497">The reason the build stayed manageable is that we proved each layer before the next depended on it, which turned a vague &#8220;why doesn&#8217;t writeback work&#8221; into a precise &#8220;which contract is proven, and which is the next unproven one.&#8221; The chain was:</p>
<div class="relative group/copy bg-bg-000/50 border-0.5 border-border-400 rounded-lg focus:outline-none focus-visible:ring-2 focus-visible:ring-accent-100" tabindex="0" role="group" aria-label="text code" data-sourcepos="135:1-144:4;13499-13746">
<div class="sticky opacity-0 group-hover/copy:opacity-100 group-focus-within/copy:opacity-100 top-2 py-2 h-12 w-0 float-right">
<div class="absolute right-0 h-8 px-2 items-center inline-flex z-10"></div>
</div>
<div class="text-text-500 font-small p-3.5 pb-0">text</div>
<div class="overflow-x-auto">
<pre class="code-block__code !my-0 !rounded-lg !text-sm !leading-relaxed p-3.5"><code class="language-text">backup → local database
local database → bacpac
bacpac → Fabric SQL
finance tables → reporting view
report selection → one FinanceKey
Power BI inputs → function parameters
function → SQL insert
SQL insert → refreshed DirectQuery visual</code></pre>
</div>
</div>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="146:1-146:492;13748-14239">That framing is what stopped us fixing the wrong thing. When the function worked in the portal but the button warned about configuration, there was no reason to touch the SQL. When finance rows vanished after adding the count measure, there was no reason to reimport the warehouse. When the commentary table was blank for a row with no comments, there was no reason to change the relationship. Each failure could be isolated to one contract because every earlier contract was already proven.</p>
<h2 class="text-text-100 mt-3 -mb-1 text-[1.125rem] font-bold" data-sourcepos="148:1-148:41;14241-14281">When this pattern is the right choice</h2>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="150:1-150:520;14283-14802">This architecture is at its best when the user is already making a bounded decision inside Power BI and the action ties cleanly to a stable reporting object. Commentary fits perfectly: the input is small, the volume is low, the user&#8217;s context is already on screen, and the write can be stored separately with a timestamp and identity. The same shape supports a variance-review status, an owner assignment, an approval flag, an exception note, or a controlled planning adjustment held outside the system-of-record facts.</p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="152:1-152:437;14804-15240">The real test is not whether Power BI can call a function. It is whether the action has a clear grain and a small, auditable contract. In our build that contract was one <code class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]">FinanceKey</code>, one comment, one identity. It also demands a report designer willing to treat report state as application state: selection cardinality, blank inputs, error feedback, refresh latency and permissions are not edge cases here, they are the user experience.</p>
<h2 class="text-text-100 mt-3 -mb-1 text-[1.125rem] font-bold" data-sourcepos="154:1-154:31;15242-15272">When it is the wrong choice</h2>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="156:1-156:249;15274-15522">We would not use this to edit accounting actuals, post journals, or change governed ledger facts. Appending commentary or workflow metadata to a separate table is safe; mutating system-of-record transactions is a different control problem entirely.</p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="158:1-158:553;15524-16076">We would also avoid it for high-volume or spreadsheet-style multi-row entry, offline work, attachment-heavy processes, long-running approvals, complex cross-field validation, or records several users edit at once. Those needs point to a Power App, a model-driven app, or a full Fabric App, with Power BI kept as the analytical surface. This is exactly the line between this pattern and the Fabric App forecast-writeback build we have written about separately: when the interaction outgrows a single bounded action, you have left translytical territory.</p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="160:1-160:350;16078-16427">There are also current service limits worth knowing before you plan a team around this. During our build, only the item owner could edit and publish the function, and service-principal access to Fabric items and data sources was not supported. Those constraints shape ownership, deployment and identity design even when the report itself works fine.</p>
<h2 class="text-text-100 mt-3 -mb-1 text-[1.125rem] font-bold" data-sourcepos="162:1-162:42;16429-16470">What we would change before production</h2>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="164:1-164:668;16472-17139">The demo works end to end, but &#8220;works in a demo&#8221; and &#8220;ready for users&#8221; are different bars. We would guard the button so it is disabled when no single row is selected or the input is empty, and make the empty commentary state an explicit message rather than a blank table. We would move the schema and function code into source control with a repeatable deployment, separate commentary permissions from finance-read permissions, and have the function enforce authorisation itself rather than trusting the report interface, then test the whole thing with a non-owner account and verify row-level security, SQL permissions and function Execute permissions independently.</p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="166:1-166:449;17141-17589">We would also settle the commentary lifecycle, which is currently append-only. A production owner has to decide whether comments can be edited, whether edits create versions, whether a comment can be superseded, and how deletions show up in the audit history. And we would test query performance and concurrency at realistic volumes, since DirectQuery&#8217;s responsiveness comes at the cost of depending on source-query performance at interaction time.</p>
<h2 class="text-text-100 mt-3 -mb-1 text-[1.125rem] font-bold" data-sourcepos="168:1-168:28;17591-17618">The practical conclusion</h2>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="170:1-170:471;17620-18090">The working part of this writeback demo was never the Python. It was a chain of explicit contracts across SQL, Fabric User Data Functions and Power BI, and the decisive choices were all modelling and interaction ones: keep commentary out of <code class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]">FactFinance</code>, reduce the report-to-function contract to a single <code class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]">FinanceKey</code>, expose context through a friendly card while hiding the key, choose DirectQuery so the write is visible, and treat report state as application state.</p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="172:1-172:362;18092-18453">The most misleading failures were never backend failures. A blank count hid the finance rows. A correctly filtered empty table looked broken. A published, tested function still threw a configuration warning until its parameters were mapped. A perfect Desktop connection masked a wrong service identity. Each one tempted us to fix a layer that was already sound.</p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="174:1-174:487;18455-18941">That is the decision frame we would give any finance team considering this. When the action is narrow, contextual, low-volume and auditable, a translytical task flow removes the friction of leaving Power BI and hunting down the same business context somewhere else. When the workflow starts to need a real application&#8217;s data-entry, concurrency, approval and lifecycle capabilities, build the application. Knowing which side of that line you are on, before you start, is most of the job.</p>
<p>Learn more about how we can help you with your <a href="https://databear.com/power-bi-consulting/">Power BI writeback requirements.</a></p>
<p>The post <a href="https://databear.com/power-bi-finance-writeback-translytical-task-flow/">Power BI finance writeback translytical task flow</a> appeared first on <a href="https://databear.com">Data Bear</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Fabric Apps &#8211; Finance Forecast Writeback</title>
		<link>https://databear.com/fabric-apps-finance-forecast-writeback/</link>
		
		<dc:creator><![CDATA[Johann Joubert]]></dc:creator>
		<pubDate>Mon, 13 Jul 2026 12:10:02 +0000</pubDate>
				<category><![CDATA[Fabric]]></category>
		<category><![CDATA[Microsoft Fabric]]></category>
		<guid isPermaLink="false">https://databear.com/?p=50979</guid>

					<description><![CDATA[<p>We built a Fabric App that lets finance edit the forecast, and the hard part was not the UI Most write-ups about Microsoft Fabric Apps stop at the same place: here is a data app, here is a chart, look how it resembles a web application instead of a report. That is the easy 80%. [&#8230;]</p>
<p>The post <a href="https://databear.com/fabric-apps-finance-forecast-writeback/">Fabric Apps &#8211; Finance Forecast Writeback</a> appeared first on <a href="https://databear.com">Data Bear</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h2>We built a Fabric App that lets finance edit the forecast, and the hard part was not the UI</h2>
<p>Most write-ups about Microsoft Fabric Apps stop at the same place: here is a data app, here is a chart, look how it resembles a web application instead of a report. That is the easy 80%. The interesting question is what happens when you ask a Fabric App to do the one thing a Power BI report structurally cannot: let a user change a number and have that change survive as governed, audited data.</p>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-51015" src="https://databear.com/wp-content/uploads/2026/07/Fabric-Apps-reveiw-page-scaled.png" alt="fabric apps review page" width="1920" height="763" srcset="https://databear.com/wp-content/uploads/2026/07/Fabric-Apps-reveiw-page-scaled.png 1920w, https://databear.com/wp-content/uploads/2026/07/Fabric-Apps-reveiw-page-300x119.png 300w, https://databear.com/wp-content/uploads/2026/07/Fabric-Apps-reveiw-page-1024x407.png 1024w, https://databear.com/wp-content/uploads/2026/07/Fabric-Apps-reveiw-page-150x60.png 150w, https://databear.com/wp-content/uploads/2026/07/Fabric-Apps-reveiw-page-1536x611.png 1536w, https://databear.com/wp-content/uploads/2026/07/Fabric-Apps-reveiw-page-2048x814.png 2048w" sizes="(max-width: 1920px) 100vw, 1920px" /></p>
<p>We built exactly that. Our Finance Writeback demo is a Fabric App that reproduces a Power BI financial dashboard and then adds forecast writeback on top: a finance user opens the Plan page, increases a marketing forecast by £60,000, watches the affected totals recalculate on screen, then saves it as a draft, submits it for review, and commits it. Every one of those actions lands in an append-only audit log. No semantic model refresh, no export to Excel, no email thread. The number changes in the report because the user changed it in the app.</p>
<p>This post is the build log for the parts that actually bit us, because those are the parts you cannot get from the documentation.</p>
<h2>Why writeback is the real test, not &#8220;does it look like an app&#8221;</h2>
<p>A store or finance manager rarely needs a prettier dashboard. They need to answer a question and then act on it. The reporting half of  the Fabric Apps demo (the Financial Overview) is genuinely just table stakes: Power BI already renders an income statement with actuals, budget, prior year and variance perfectly well, and if that is all you need, a report is cheaper to build and easier to maintain. We say that plainly in our own scope: pixel-replicating read-only report pages is disproportionately expensive relative to the demo value.</p>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-50996" src="https://databear.com/wp-content/uploads/2026/07/Fabric-Apps-Charts-scaled.png" alt="Fabric Apps charts" width="1920" height="680" srcset="https://databear.com/wp-content/uploads/2026/07/Fabric-Apps-Charts-scaled.png 1920w, https://databear.com/wp-content/uploads/2026/07/Fabric-Apps-Charts-300x106.png 300w, https://databear.com/wp-content/uploads/2026/07/Fabric-Apps-Charts-1024x363.png 1024w, https://databear.com/wp-content/uploads/2026/07/Fabric-Apps-Charts-150x53.png 150w, https://databear.com/wp-content/uploads/2026/07/Fabric-Apps-Charts-1536x544.png 1536w" sizes="(max-width: 1920px) 100vw, 1920px" /></p>
<p>The differentiator is the write path. When a forecast adjustment can be entered, recalculated, saved, submitted, committed and audited inside the same surface the user is already looking at, the app stops being a report and becomes a small piece of finance software. That is the boundary where a Fabric App earns its place, and it is the boundary this post lives on.</p>
<p><img loading="lazy" decoding="async" class="alignnone wp-image-50981 size-large" src="https://databear.com/wp-content/uploads/2026/07/Fabric-Apps-Finance-Overview-1024x469.png" alt="Fabric Apps Dashboard" width="1024" height="469" srcset="https://databear.com/wp-content/uploads/2026/07/Fabric-Apps-Finance-Overview-1024x469.png 1024w, https://databear.com/wp-content/uploads/2026/07/Fabric-Apps-Finance-Overview-300x137.png 300w, https://databear.com/wp-content/uploads/2026/07/Fabric-Apps-Finance-Overview-150x69.png 150w, https://databear.com/wp-content/uploads/2026/07/Fabric-Apps-Finance-Overview-1536x704.png 1536w, https://databear.com/wp-content/uploads/2026/07/Fabric-Apps-Finance-Overview-2048x938.png 2048w, https://databear.com/wp-content/uploads/2026/07/Fabric-Apps-Finance-Overview-scaled.png 1920w" sizes="(max-width: 1024px) 100vw, 1024px" /></p>
<h3>The sign convention that makes a correct demo look broken</h3>
<p>Here is the first thing nobody warns you about, and it cost us a genuine bug twice before we pinned it.</p>
<p>In the finance dataset, expenses are stored as negative values. October&#8217;s Digital Marketing budget for the UK entity is not `80,892`, it is `-80,892`. That is correct and normal at the data layer. The problem is what &#8220;increase spend by 60,000&#8221; means once you are in negative space: increasing spend makes the stored number *more* negative. `-80,892` becomes `-140,892`, and the delta the audit log records is `-60,000`.</p>
<p>If you render those raw signed values to a finance user, the demo looks broken. They asked to spend more and the number went down. So the app has to store signed and display friendly: the screen shows &#8220;Forecast 140,892&#8221; and &#8220;Spend +60,000&#8221; while the database holds `-140,892` and `-60,000`. Get this backwards in even one place and either the maths is wrong or the screen is confusing, and the two failure modes look identical from the outside.</p>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-50998" src="https://databear.com/wp-content/uploads/2026/07/Fabric-apps-charts1-scaled.png" alt="Fabric apps charts" width="1920" height="501" srcset="https://databear.com/wp-content/uploads/2026/07/Fabric-apps-charts1-scaled.png 1920w, https://databear.com/wp-content/uploads/2026/07/Fabric-apps-charts1-300x78.png 300w, https://databear.com/wp-content/uploads/2026/07/Fabric-apps-charts1-1024x267.png 1024w, https://databear.com/wp-content/uploads/2026/07/Fabric-apps-charts1-150x39.png 150w, https://databear.com/wp-content/uploads/2026/07/Fabric-apps-charts1-1536x401.png 1536w, https://databear.com/wp-content/uploads/2026/07/Fabric-apps-charts1-2048x535.png 2048w" sizes="(max-width: 1920px) 100vw, 1920px" /></p>
<p>The fix that actually held was to stop treating sign as a formatting afterthought. We centralised the whole convention, the magnitude flip, the stored-from-display conversion, the delta maths and the formatters, into a single module and reused it everywhere. The lesson generalises well beyond finance: when a domain has a storage convention that inverts the user&#8217;s mental model, that conversion is not display polish, it is a load-bearing part of the data contract, and it belongs in exactly one place.</p>
<p>A related trap on the same theme: there were two amount columns in the model, a raw local-currency `Amount` and a converted `AmountUSD`. Computing on the wrong one was the single root cause of our original KPI miss, and it tried to come back a second time when we built the writeback recalculation. If you take one portable thing from this post, let it be: find out which column is authoritative before you write a single measure, and write it down where the next person will see it.</p>
<p><img loading="lazy" decoding="async" class="alignnone wp-image-50982 size-full" src="https://databear.com/wp-content/uploads/2026/07/Adding-coments-to-change-a-variance-scaled.png" alt="Fabric Apps Writeback" width="1920" height="894" srcset="https://databear.com/wp-content/uploads/2026/07/Adding-coments-to-change-a-variance-scaled.png 1920w, https://databear.com/wp-content/uploads/2026/07/Adding-coments-to-change-a-variance-300x140.png 300w, https://databear.com/wp-content/uploads/2026/07/Adding-coments-to-change-a-variance-1024x477.png 1024w, https://databear.com/wp-content/uploads/2026/07/Adding-coments-to-change-a-variance-150x70.png 150w, https://databear.com/wp-content/uploads/2026/07/Adding-coments-to-change-a-variance-1536x715.png 1536w, https://databear.com/wp-content/uploads/2026/07/Adding-coments-to-change-a-variance-2048x954.png 2048w" sizes="(max-width: 1920px) 100vw, 1920px" /><br />
The edit updates the affected line and its full-year total on screen, before anything is saved.</p>
<h3>The constraint that quietly reshapes the whole architecture: embedded auth</h3>
<p>This is the one we most wish someone had told us at the start, and it is now the first thing we classify on any new Fabric App.</p>
<p>The writeback runs against Rayfin SQL under Fabric&#8217;s embedded authentication. That auth is tied to the signed-in session inside the deployed, running app. A command-line or headless process cannot complete it. Not &#8220;it is awkward from the CLI&#8221;, it genuinely cannot obtain the credential.</p>
<p>That single fact reshapes everything downstream. It means you cannot seed your working forecast from a script. You cannot verify the persisted rows from a terminal. You cannot drive the writes from any automated Node process at all. Every operation that touches the writeback tables, seeding the baseline, saving a draft, reading back what was stored, has to happen as a click inside the app, by a signed-in human.</p>
<p>We spent real time discovering this the hard way before we understood it was structural rather than a bug in our setup. The takeaway we now carry: identify the operations that are structurally un-automatable, embedded-auth writes, in-app-only steps, at intake, and plan them as expected human-in-the-app steps from day one. If you assume you can script your test data and you cannot, you find out at the worst possible moment, mid-build, with a demo date approaching.</p>
<h3>Writes and reads are not symmetric, and treating them the same is a bug</h3>
<p>Once you accept the app is doing real writes, retry policy stops being boilerplate.</p>
<p>Reads are safe to retry. If a read fails on a transient cold-mount error, firing it again just gets you the same rows. We gave reads a single one-shot retry for exactly that transient 5xx case, plus a manual retry button, and moved on.</p>
<p>Writes are a different animal. A forecast &#8220;save&#8221; that silently retries can create the row twice. There is no safe transparent retry for a create, because you cannot tell from the outside whether the first attempt failed before or after it wrote. So writes get *no* transparent retry. When a write fails, the app surfaces an explicit Retry control and hands the decision to the user, who can check whether the row is already there.</p>
<p>This is a small design decision that only shows up once you are writing rather than reading, and it is invisible in any demo that never persists anything. It is also the kind of thing a generic &#8220;how to build a data app&#8221; article will never mention, because that article never had to worry about a duplicate committed forecast.</p>
<h3>The state machine, and why &#8220;committed&#8221; is the only status that counts</h3>
<p>The lifecycle is Draft to Submitted to Committed, and each transition does specific work:</p>
<p>A **Draft** is editable by its owner and is deliberately *excluded* from the adjusted forecast total. **Submitted** locks the row to its owner and marks it pending review. **Committed** locks it permanently and is the only status whose delta actually merges into the adjusted forecast. Draft, Submitted and Rejected are all filtered out of the total. This matters because it means a half-finished &#8220;what if&#8221; a user is still typing never contaminates the headline number. Only a deliberate commit moves the forecast.</p>
<p>Every transition appends exactly one audit row: old value, new value, signed delta, timestamp, user email. And the original baseline is never overwritten. The adjusted forecast is always baseline plus committed deltas, computed, never a destructive edit to the source figures.</p>
<p><img loading="lazy" decoding="async" class="alignnone wp-image-50983 size-full" src="https://databear.com/wp-content/uploads/2026/07/Writeback-scaled.png" alt="fabric app writeback demo" width="1920" height="390" srcset="https://databear.com/wp-content/uploads/2026/07/Writeback-scaled.png 1920w, https://databear.com/wp-content/uploads/2026/07/Writeback-300x61.png 300w, https://databear.com/wp-content/uploads/2026/07/Writeback-1024x208.png 1024w, https://databear.com/wp-content/uploads/2026/07/Writeback-150x30.png 150w, https://databear.com/wp-content/uploads/2026/07/Writeback-1536x312.png 1536w, https://databear.com/wp-content/uploads/2026/07/Writeback-2048x416.png 2048w" sizes="(max-width: 1920px) 100vw, 1920px" /><br />
Submit and commit are one-way locks, and only a commit moves the forecast total.</p>
<h3>The append-only audit trap: a clean demo is a data-layer job, not a UI feature</h3>
<p>Here is the lesson that surprised us most, and it is a genuinely portable one.</p>
<p>The audit page is append-only by design. No delete control in the UI, no &#8220;undo&#8221;, no casual reset button, because a finance audit trail that a user can quietly edit is not an audit trail. That is obviously the right call for governance.</p>
<p>But it collides head-on with a demo requirement: you need to rehearse the full Draft-to-Save-to-Submit-to-Commit story repeatedly, from a clean slate, in front of different audiences. And you have just deliberately built a system with no way to get back to a clean slate from inside the app.</p>
<p>The naive instinct is to add a reset feature. That instinct is wrong, and recognising why is the lesson. If you add an in-app reset, you have compromised the append-only guarantee you just spent effort building; the feature that makes the demo convenient is the exact feature that makes the audit trail untrustworthy. The correct answer is that a repeatable-clean-state requirement, when combined with an append-only data model, forces an out-of-band reset at the data layer. Not a UI feature. In our case that is a direct, scoped, preview-gated SQL delete against the Fabric endpoint, run deliberately by a human between rehearsals, never something the app itself can do.</p>
<p>The generalisable version: when you design any append-only or no-delete model, ask at that moment how clean state will be re-established, and commit to answering it at the data layer. If you defer that question, you will eventually be tempted to answer it with a UI feature that quietly undermines the whole point.</p>
<p><img loading="lazy" decoding="async" class="alignnone wp-image-50984 size-full" src="https://databear.com/wp-content/uploads/2026/07/Fabric-Apps-Audit-scaled.png" alt="audit page fabric app" width="1920" height="316" srcset="https://databear.com/wp-content/uploads/2026/07/Fabric-Apps-Audit-scaled.png 1920w, https://databear.com/wp-content/uploads/2026/07/Fabric-Apps-Audit-300x49.png 300w, https://databear.com/wp-content/uploads/2026/07/Fabric-Apps-Audit-1024x168.png 1024w, https://databear.com/wp-content/uploads/2026/07/Fabric-Apps-Audit-150x25.png 150w, https://databear.com/wp-content/uploads/2026/07/Fabric-Apps-Audit-1536x253.png 1536w, https://databear.com/wp-content/uploads/2026/07/Fabric-Apps-Audit-2048x337.png 2048w" sizes="(max-width: 1920px) 100vw, 1920px" /><br />
Clean state for the next demo happens at the data layer, out of band, by a human.</p>
<h3>When you should not build this at all</h3>
<p>A Fabric App is not automatically the right answer because it is newer. If your users need flexible, exploratory analysis and never need to write anything back, a Power BI report is cheaper to build, easier to maintain, and better suited to weekly visual iteration. If your team has no appetite to own custom code, an app is a liability, not an asset. The writeback demo earns its place precisely because writeback is something the report genuinely cannot do. If your requirement does not include that write path, use the report.</p>
<h3>What this actually proves</h3>
<p>The reporting layer of a Fabric App is the part everyone shows you and the part that matters least, because Power BI already does it. The writeback layer, edit, recalculate, save, submit, commit, audit, with the baseline never overwritten and only committed changes moving the number, is where a Fabric App becomes something a report is not.</p>
<p>And the work that makes it trustworthy is almost entirely underneath the surface: getting the sign convention right so a correct demo does not look broken, planning around embedded auth that no script can cross, treating writes and reads as the different risks they are, and resolving the append-only-versus-clean-state tension at the data layer instead of papering over it with a button. That is the part worth writing down, because it is the part you cannot look up.</p>
<p>To learn more about Microsoft Fabric and how we can help with Fabric Apps, see our <a href="https://databear.com/microsoft-fabric/">Microsoft Fabric page.</a></p>
<p>The post <a href="https://databear.com/fabric-apps-finance-forecast-writeback/">Fabric Apps &#8211; Finance Forecast Writeback</a> appeared first on <a href="https://databear.com">Data Bear</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Replicating a Power BI report in a Microsoft Fabric App</title>
		<link>https://databear.com/replicating-a-power-bi-report-in-a-microsoft-fabric-app/</link>
		
		<dc:creator><![CDATA[Johann Joubert]]></dc:creator>
		<pubDate>Mon, 13 Jul 2026 12:07:35 +0000</pubDate>
				<category><![CDATA[Fabric]]></category>
		<category><![CDATA[Power BI]]></category>
		<guid isPermaLink="false">https://databear.com/?p=50987</guid>

					<description><![CDATA[<p>Replicating a Power BI report in a Fabric App: a practical guide to the parts that fight back Microsoft Fabric Apps let you build a data-driven application on top of the same semantic model that feeds your Power BI reports. One of the first things people want to try is the obvious one: take a [&#8230;]</p>
<p>The post <a href="https://databear.com/replicating-a-power-bi-report-in-a-microsoft-fabric-app/">Replicating a Power BI report in a Microsoft Fabric App</a> appeared first on <a href="https://databear.com">Data Bear</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h2 class="text-text-100 mt-3 -mb-1 text-[1.375rem] font-bold" data-sourcepos="1:1-1:96;0-95">Replicating a Power BI report in a Fabric App: a practical guide to the parts that fight back</h2>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="3:1-3:396;97-492">Microsoft Fabric Apps let you build a data-driven application on top of the same semantic model that feeds your Power BI reports. One of the first things people want to try is the obvious one: take a report they already have in Power BI and rebuild it as a Fabric App page. We did exactly that, reproducing a financial overview dashboard, and this guide is the honest account of what that takes.</p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="5:1-5:608;494-1101">The short version up front, because it is the most useful thing we can tell you: in a Fabric App you are hand-building, in code, every visual that Power BI gives you out of the box. A sparkline, a formatted number, a chart with its months in the right order, these are configuration clicks in Power BI and lines of code in a Fabric App. That difference is the whole story, and everything below is a worked example of it. If your goal is simply a report, Power BI is faster. A Fabric App earns its keep when you need to do something a report cannot, and the reporting layer is the price of admission to that.</p>
<p data-sourcepos="5:1-5:608;494-1101"><img loading="lazy" decoding="async" class="alignnone wp-image-50981 size-full" src="https://databear.com/wp-content/uploads/2026/07/Fabric-Apps-Finance-Overview-scaled.png" alt="Fabric Apps Dashboard" width="1920" height="880" srcset="https://databear.com/wp-content/uploads/2026/07/Fabric-Apps-Finance-Overview-scaled.png 1920w, https://databear.com/wp-content/uploads/2026/07/Fabric-Apps-Finance-Overview-300x137.png 300w, https://databear.com/wp-content/uploads/2026/07/Fabric-Apps-Finance-Overview-1024x469.png 1024w, https://databear.com/wp-content/uploads/2026/07/Fabric-Apps-Finance-Overview-150x69.png 150w, https://databear.com/wp-content/uploads/2026/07/Fabric-Apps-Finance-Overview-1536x704.png 1536w, https://databear.com/wp-content/uploads/2026/07/Fabric-Apps-Finance-Overview-2048x938.png 2048w" sizes="(max-width: 1920px) 100vw, 1920px" /></p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="7:1-7:170;1103-1272"><em>This is the Fabric App. Below is the Power BI version</em></p>
<p><img loading="lazy" decoding="async" class="alignnone wp-image-50990 size-full" src="https://databear.com/wp-content/uploads/2026/07/Power-BI-finance-scaled.png" alt="Power BI finance" width="1920" height="992" srcset="https://databear.com/wp-content/uploads/2026/07/Power-BI-finance-scaled.png 1920w, https://databear.com/wp-content/uploads/2026/07/Power-BI-finance-300x155.png 300w, https://databear.com/wp-content/uploads/2026/07/Power-BI-finance-1024x529.png 1024w, https://databear.com/wp-content/uploads/2026/07/Power-BI-finance-150x77.png 150w, https://databear.com/wp-content/uploads/2026/07/Power-BI-finance-1536x793.png 1536w, https://databear.com/wp-content/uploads/2026/07/Power-BI-finance-2048x1058.png 2048w" sizes="(max-width: 1920px) 100vw, 1920px" /><br />
To a viewer they are the same page. The effort is entirely in how each got built</p>
<h2 class="text-text-100 mt-3 -mb-1 text-[1.125rem] font-bold" data-sourcepos="9:1-9:40;1274-1313">What you are actually signing up for</h2>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="11:1-11:378;1315-1692">Before the setup checklist, it helps to be clear about the mental shift. Power BI is a report authoring tool: you bind fields to a visual and the tool handles rendering, sorting, formatting, number abbreviation, tooltips and responsive resizing for you. A Fabric App is a web application: you have a blank canvas and a component library, and anything the page shows, you build.</p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="13:1-13:579;1694-2272">Concretely, our stack split the work like this:</p>
<ul>
<li class="font-claude-response-body break-words whitespace-normal" data-sourcepos="13:1-13:579;1694-2272"><strong>React</strong> handles everything structural: the page layout, the left-hand navigation, the KPI cards, the tables, the toggles and selectors.</li>
<li class="font-claude-response-body break-words whitespace-normal" data-sourcepos="13:1-13:579;1694-2272"><strong>TypeScript</strong> handles the data loading and the finance calculations.</li>
<li class="font-claude-response-body break-words whitespace-normal" data-sourcepos="13:1-13:579;1694-2272"><strong>Vega-Lite</strong> handles the charts, and only the charts, the trend lines, the bar chart, the donut. That division matters: Vega-Lite is excellent for plotting a series but is the wrong tool for laying out a card or a grid, and trying to make it do layout is a common early mistake. Charts in Vega-Lite, everything else in React and CSS.</li>
</ul>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="15:1-15:233;2274-2506">The data comes from the semantic model, the same one behind the Power BI report, read through the Fabric data service. You do not get Power BI&#8217;s visual layer along with that data. You get the numbers, and the job is to present them.</p>
<p>Below is Fabric Apps charts<br />
<img loading="lazy" decoding="async" class="alignnone wp-image-50996 size-full" src="https://databear.com/wp-content/uploads/2026/07/Fabric-Apps-Charts-scaled.png" alt="Fabric Apps charts" width="1920" height="680" srcset="https://databear.com/wp-content/uploads/2026/07/Fabric-Apps-Charts-scaled.png 1920w, https://databear.com/wp-content/uploads/2026/07/Fabric-Apps-Charts-300x106.png 300w, https://databear.com/wp-content/uploads/2026/07/Fabric-Apps-Charts-1024x363.png 1024w, https://databear.com/wp-content/uploads/2026/07/Fabric-Apps-Charts-150x53.png 150w, https://databear.com/wp-content/uploads/2026/07/Fabric-Apps-Charts-1536x544.png 1536w" sizes="(max-width: 1920px) 100vw, 1920px" /></p>
<p>Below is the Power BI version<br />
<img loading="lazy" decoding="async" class="alignnone size-full wp-image-50997" src="https://databear.com/wp-content/uploads/2026/07/PBI-charts-scaled.png" alt="power bi charts" width="1920" height="746" srcset="https://databear.com/wp-content/uploads/2026/07/PBI-charts-scaled.png 1920w, https://databear.com/wp-content/uploads/2026/07/PBI-charts-300x117.png 300w, https://databear.com/wp-content/uploads/2026/07/PBI-charts-1024x398.png 1024w, https://databear.com/wp-content/uploads/2026/07/PBI-charts-150x58.png 150w, https://databear.com/wp-content/uploads/2026/07/PBI-charts-1536x597.png 1536w" sizes="(max-width: 1920px) 100vw, 1920px" /></p>
<h2 class="text-text-100 mt-3 -mb-1 text-[1.125rem] font-bold" data-sourcepos="17:1-17:27;2508-2534">Setup and prerequisites</h2>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="19:1-19:208;2536-2743">Fabric Apps are a preview capability, so the setup has real prerequisites that will stop you dead if any one is missing. In our experience these are the ones worth confirming before you write a line of code:</p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="21:1-21:406;2745-3150">A Fabric workspace where you have contributor or admin rights. The Fabric Apps workload enabled at the tenant level, which is an admin action, not something you can self-serve. A semantic model hosted on Fabric or Power BI capacity, with Build and Read permissions granted to you on that model. And the tooling to create and deploy the app itself, in our case the Rayfin SDK and its command-line workflow.</p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="23:1-23:258;3152-3409">None of these are difficult individually, but they cross permission and tenant-admin boundaries, so if you are not the tenant admin, line those approvals up first. Discovering mid-build that the workload was never enabled is a frustrating way to lose a day.</p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="25:1-25:415;3411-3825">One practical note that shaped our whole workflow: the app running locally on your machine has the layout but no live data. The only surface that renders the true figures from the model is the deployed app. So your loop is edit, deploy, look, not edit, refresh, look. Deploys cost real minutes, which quietly changes how you work, you batch changes and check them together rather than tweaking one pixel at a time.</p>
<h2 class="text-text-100 mt-3 -mb-1 text-[1.125rem] font-bold" data-sourcepos="27:1-27:45;3827-3871">The rendering fights, and how we won them</h2>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="29:1-29:229;3873-4101">This is the part you came for. Every item below is something Power BI does silently and a Fabric App makes you build. None of them is conceptually hard. All of them cost time, and a few cost more time than they had any right to.</p>
<h3 class="text-text-100 mt-2 -mb-1 text-base font-bold" data-sourcepos="31:1-31:32;4103-4134">Sparklines in the KPI cards</h3>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="33:1-33:279;4136-4414">Power BI puts a little trend line inside a KPI card with a checkbox. In a Fabric App there is no such checkbox. A KPI-card sparkline is a chart you build yourself: take the monthly series, draw it as a thin line in a small fixed drawing area, and place it beside the big number.</p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="35:1-35:687;4416-5102">The subtlety is that a sparkline is not a shrunk-down chart. It has no axes, no gridlines, no labels, no markers, just the bare line. We built ours as a simple polyline in a hand-sized drawing area sitting next to the value, and the discipline was resisting the urge to add the things a normal chart has. Our first attempts crept in an end-of-line marker and a shaded fill under the line, neither of which was in the Power BI reference, and we had to strip them back out. The lesson that generalises: check the reference for exactly what the element does and does not have before building it, because it is easy to spend an afternoon perfecting a detail that should not be there at all.</p>
<h3 class="text-text-100 mt-2 -mb-1 text-base font-bold" data-sourcepos="37:1-37:29;5104-5132">Getting the sizing right</h3>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="39:1-39:347;5134-5480">This one is deceptively fiddly. A KPI card holds a label, a large value, a comparison line and the sparkline, and getting them to share the horizontal space cleanly is a CSS layout problem you own entirely. Our sparklines initially rendered cramped and mis-proportioned because the text block and the chart were fighting over the available width.</p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="41:1-41:548;5482-6029">The fix was in how the flex layout distributed space: letting the text block take its natural width without stretching, and giving the sparkline a flexible share of what remained, then sizing the chart&#8217;s internal drawing area to match its actual rendered box rather than a guessed nominal size. If the drawing area&#8217;s dimensions and the on-screen box disagree, the line renders distorted. Matching them is what makes a sparkline look intentional rather than squeezed. This is ordinary web layout work, but it is work Power BI never asked you to do.</p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="43:1-43:174;6031-6204"><em><img loading="lazy" decoding="async" class="alignnone wp-image-50992 size-full" src="https://databear.com/wp-content/uploads/2026/07/Fabric-Apps-KPI-cards-scaled.png" alt="fabric app kpi cards" width="1920" height="221" srcset="https://databear.com/wp-content/uploads/2026/07/Fabric-Apps-KPI-cards-scaled.png 1920w, https://databear.com/wp-content/uploads/2026/07/Fabric-Apps-KPI-cards-300x35.png 300w, https://databear.com/wp-content/uploads/2026/07/Fabric-Apps-KPI-cards-1024x118.png 1024w, https://databear.com/wp-content/uploads/2026/07/Fabric-Apps-KPI-cards-150x17.png 150w, https://databear.com/wp-content/uploads/2026/07/Fabric-Apps-KPI-cards-1536x177.png 1536w, https://databear.com/wp-content/uploads/2026/07/Fabric-Apps-KPI-cards-2048x236.png 2048w" sizes="(max-width: 1920px) 100vw, 1920px" /><br />
Above is the Fabric Apps KPI cards, below is the Power BI KPI cards<br />
<img loading="lazy" decoding="async" class="alignnone wp-image-50993 size-full" src="https://databear.com/wp-content/uploads/2026/07/Power-BI-KPI-cards-scaled.png" alt="power bi kpi cards" width="1920" height="177" srcset="https://databear.com/wp-content/uploads/2026/07/Power-BI-KPI-cards-scaled.png 1920w, https://databear.com/wp-content/uploads/2026/07/Power-BI-KPI-cards-300x28.png 300w, https://databear.com/wp-content/uploads/2026/07/Power-BI-KPI-cards-1024x94.png 1024w, https://databear.com/wp-content/uploads/2026/07/Power-BI-KPI-cards-150x14.png 150w, https://databear.com/wp-content/uploads/2026/07/Power-BI-KPI-cards-1536x141.png 1536w, https://databear.com/wp-content/uploads/2026/07/Power-BI-KPI-cards-2048x188.png 2048w" sizes="(max-width: 1920px) 100vw, 1920px" />The sparkline sharing card width cleanly with the value and comparison line. All hand-tuned CSS.</em></p>
<h3 class="text-text-100 mt-2 -mb-1 text-base font-bold" data-sourcepos="45:1-45:65;6206-6270">Months in alphabetical order (the one that cost us the most)</h3>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="47:1-47:92;6272-6363">This is the standout gotcha, and it is worth telling in full because you cannot look it up.</p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="49:1-49:347;6365-6711">Our trend charts came out with the months along the x-axis in alphabetical order, April, August, December, January, rather than chronological. This is a classic charting problem with a classic fix: tell the chart to sort the axis by the month&#8217;s actual order. So we set the sort property. Nothing changed. We set it a different way. Still nothing.</p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="51:1-51:297;6713-7009">The cause turned out to be that the Fabric visual component silently ignores Vega-Lite&#8217;s <code class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]">sort</code> property. It does not throw an error, it does not warn, it simply does nothing with that instruction. Every hour we spent adjusting the sort was spent on a control the platform was quietly discarding.</p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="53:1-53:538;7011-7548">The fix, once we understood the cause, was to stop trying to sort at all. Instead we encoded the x-axis on a numeric month index, one through twelve, so the chart orders points by a real number, and then generated the visible month labels separately from that index. Order by numeric encoding, never by the sort property. That single sentence is now a permanent note in our build guide, and if you take one concrete thing from this article, let it be that: on this platform, do not trust <code class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]">sort</code> on a chart axis, encode order as a number.</p>
<h3 class="text-text-100 mt-2 -mb-1 text-base font-bold" data-sourcepos="57:1-57:38;7753-7790">Abbreviating and rounding numbers</h3>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="59:1-59:258;7792-8049">Power BI shows 55.56M and $800K and 51.27% because its formatting engine abbreviates and rounds for you, per visual, from a dropdown. A Fabric App renders exactly the number you hand it. If you pass a raw revenue figure into a KPI card, you get every digit.</p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="61:1-61:793;8051-8843">So number presentation becomes your code. You decide where to abbreviate to millions or thousands, how many decimal places each context carries, where the currency symbol and percent sign go, and how the axis ticks read ($5.0M, $10.0M rather than 5000000). The trap here is inconsistency: it is easy to abbreviate one card to two decimals and another to one, or to round a KPI differently from the axis it sits above, and the page then looks subtly untidy in a way that is hard to pin down. The cure is to centralise formatting, decide the rules once, in one place, and route every displayed number through them, rather than formatting each value where it happens to be rendered. That way &#8220;millions to two decimal places with a leading currency symbol&#8221; is defined once and applied everywhere.</p>
<p>Below is an Fabric Apps Revenue trend:<br />
<img loading="lazy" decoding="async" class="alignnone wp-image-50994 size-large" src="https://databear.com/wp-content/uploads/2026/07/Fabric-App-Revenue-Trend-1024x572.png" alt="fabric apps rev trend" width="1024" height="572" srcset="https://databear.com/wp-content/uploads/2026/07/Fabric-App-Revenue-Trend-1024x572.png 1024w, https://databear.com/wp-content/uploads/2026/07/Fabric-App-Revenue-Trend-300x168.png 300w, https://databear.com/wp-content/uploads/2026/07/Fabric-App-Revenue-Trend-150x84.png 150w, https://databear.com/wp-content/uploads/2026/07/Fabric-App-Revenue-Trend.png 1251w" sizes="(max-width: 1024px) 100vw, 1024px" /></p>
<p>Below is the Power BI revenue trend.<br />
<img loading="lazy" decoding="async" class="alignnone wp-image-50995 size-large" src="https://databear.com/wp-content/uploads/2026/07/Power-BI-revenue-trend-1024x561.png" alt="power bi rev trend" width="1024" height="561" srcset="https://databear.com/wp-content/uploads/2026/07/Power-BI-revenue-trend-1024x561.png 1024w, https://databear.com/wp-content/uploads/2026/07/Power-BI-revenue-trend-300x164.png 300w, https://databear.com/wp-content/uploads/2026/07/Power-BI-revenue-trend-150x82.png 150w, https://databear.com/wp-content/uploads/2026/07/Power-BI-revenue-trend.png 1413w" sizes="(max-width: 1024px) 100vw, 1024px" /></p>
<h3 class="text-text-100 mt-2 -mb-1 text-base font-bold" data-sourcepos="63:1-63:36;8845-8880">Formatting the rest of the look</h3>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="65:1-65:734;8882-9615">Beyond numbers, a pile of smaller visual details each needed a deliberate decision that Power BI would have defaulted for you. The prior-year line being dashed rather than solid to distinguish it from actuals. The trend y-axes starting at zero on the revenue and cost charts, but deliberately staying zoomed on the net-margin chart so a one-percent movement is visible. Removing the vertical gridlines while keeping the horizontals. The area fill, or absence of it, under each trend line. None of these is hard. Collectively they are the difference between a page that looks like a finance report and one that looks like a developer&#8217;s first draft, and every one is a line of configuration you write rather than a property you toggle.</p>
<p>Below is the Fabric Apps charts<br />
<img loading="lazy" decoding="async" class="alignnone size-full wp-image-50998" src="https://databear.com/wp-content/uploads/2026/07/Fabric-apps-charts1-scaled.png" alt="Fabric apps charts" width="1920" height="501" srcset="https://databear.com/wp-content/uploads/2026/07/Fabric-apps-charts1-scaled.png 1920w, https://databear.com/wp-content/uploads/2026/07/Fabric-apps-charts1-300x78.png 300w, https://databear.com/wp-content/uploads/2026/07/Fabric-apps-charts1-1024x267.png 1024w, https://databear.com/wp-content/uploads/2026/07/Fabric-apps-charts1-150x39.png 150w, https://databear.com/wp-content/uploads/2026/07/Fabric-apps-charts1-1536x401.png 1536w, https://databear.com/wp-content/uploads/2026/07/Fabric-apps-charts1-2048x535.png 2048w" sizes="(max-width: 1920px) 100vw, 1920px" /></p>
<p>Below is the Power BI version<br />
<img loading="lazy" decoding="async" class="alignnone size-full wp-image-50999" src="https://databear.com/wp-content/uploads/2026/07/PBI-charts1-scaled.png" alt="PBI charts" width="1920" height="433" srcset="https://databear.com/wp-content/uploads/2026/07/PBI-charts1-scaled.png 1920w, https://databear.com/wp-content/uploads/2026/07/PBI-charts1-300x68.png 300w, https://databear.com/wp-content/uploads/2026/07/PBI-charts1-1024x231.png 1024w, https://databear.com/wp-content/uploads/2026/07/PBI-charts1-150x34.png 150w, https://databear.com/wp-content/uploads/2026/07/PBI-charts1-1536x347.png 1536w, https://databear.com/wp-content/uploads/2026/07/PBI-charts1-2048x462.png 2048w" sizes="(max-width: 1920px) 100vw, 1920px" /></p>
<h2 class="text-text-100 mt-3 -mb-1 text-[1.125rem] font-bold" data-sourcepos="67:1-67:56;9617-9672">The honest verdict: Power BI is quicker for a report</h2>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="69:1-69:115;9674-9788">Here is the conclusion we reached, stated plainly because it is the most useful thing for anyone weighing this up.</p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="71:1-71:443;9790-10232">Building a report is faster in Power BI. It is not close. Every visual we have described, the sparkline, the formatted numbers, the correctly ordered months, the dashed comparison line, is something Power BI delivers with a few clicks and a Fabric App makes you construct by hand. If the deliverable is a report that people read, rebuilding it as a Fabric App is spending a lot of engineering effort to arrive back where Power BI already was.</p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="73:1-73:544;10234-10777">That is not a criticism of Fabric Apps. It is a statement about what they are for. A Fabric App is a web application that happens to sit on your semantic model, and its value is that it can do the things a report fundamentally cannot: guide a user through a specific decision path, or, most powerfully, let a user write data back and have it recalculate and persist. The reporting layer is not the point of a Fabric App. It is the familiar surface you rebuild so that the unfamiliar, genuinely differentiating capability has somewhere to live.</p>
<p class="font-claude-response-body break-words whitespace-normal" data-sourcepos="75:1-75:573;10779-11351">So the decision rule we would offer is simple. If you need a report, build it in Power BI. If you need an application that includes reporting as one part of something larger, a Fabric App is the right tool, and this guide is your map to the reporting-replication tax you will pay to get there. Go in knowing that the tax is real, that most of it is paid in small rendering details rather than big architectural problems, and that at least one of those details, the silently ignored sort, will cost you an afternoon unless someone warns you first. Consider yourself warned.</p>
<p>To learn more about Microsoft Fabric and how we can help with Fabric Apps, see our <a href="https://databear.com/microsoft-fabric/">Microsoft Fabric page.</a></p>
<p>The post <a href="https://databear.com/replicating-a-power-bi-report-in-a-microsoft-fabric-app/">Replicating a Power BI report in a Microsoft Fabric App</a> appeared first on <a href="https://databear.com">Data Bear</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>The three issues that fail nearly every Power BI Health Check we run</title>
		<link>https://databear.com/the-three-issues-that-fail-nearly-every-power-bi-health-check-we-run/</link>
		
		<dc:creator><![CDATA[Boniface Muchendu]]></dc:creator>
		<pubDate>Sun, 21 Jun 2026 12:04:38 +0000</pubDate>
				<category><![CDATA[Power BI]]></category>
		<guid isPermaLink="false">https://databear.com/?p=50921</guid>

					<description><![CDATA[<p>A UK manufacturer rang us in February asking for a Power BI Health Check. Their executive dashboard had stopped refreshing inside its scheduled window. An in-house team had built the model two years earlier, everyone who needed to had signed it off, and it ran cleanly until the dataset crossed some invisible threshold and something [&#8230;]</p>
<p>The post <a href="https://databear.com/the-three-issues-that-fail-nearly-every-power-bi-health-check-we-run/">The three issues that fail nearly every Power BI Health Check we run</a> appeared first on <a href="https://databear.com">Data Bear</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p class="code-line" dir="auto" data-line="6">A UK manufacturer rang us in February asking for a Power BI Health Check. Their executive dashboard had stopped refreshing inside its scheduled window. An in-house team had built the model two years earlier, everyone who needed to had signed it off, and it ran cleanly until the dataset crossed some invisible threshold and something began to slip. By the time we arrived, the morning briefing was running on yesterday&#8217;s numbers.</p>
<p class="code-line" dir="auto" data-line="8">Six hours into the Health Check we had found three issues. None of them new. None of them visible from the report itself. All three of them already sitting on the internal list we keep of the patterns we see almost every time.</p>
<p class="code-line" dir="auto" data-line="10">We have run more than 200 Power BI Health Checks since 2018, across financial services, retail, public sector, manufacturing, and healthcare. Different industries, different team sizes, different model complexities. The same three issues come up almost every time. This piece walks through what they are, why they recur, and what we recommend.</p>
<h3 id="1-auto-datetime-hierarchies-left-on" class="code-line" dir="auto" data-line="14">1. Auto date/time hierarchies left on</h3>
<h4 id="what-it-looks-like" class="code-line" dir="auto" data-line="16">What it looks like</h4>
<p class="code-line" dir="auto" data-line="18">Open File &gt; Options &gt; Current File &gt; Data Load in Power BI Desktop and find the Time intelligence section. If &#8220;Auto date/time&#8221; is ticked, Power BI silently generates a hidden date table behind every date column in the model. We have audited models that contain fourteen date columns. The model is carrying fourteen hidden date hierarchies, each one indexing every day from the start of the data to the end of next year.</p>
<p class="code-line" dir="auto" data-line="20"><img loading="lazy" decoding="async" class="alignnone size-full wp-image-50926" src="https://databear.com/wp-content/uploads/2026/05/01-auto-date-time-options.png" alt="Power BI Desktop Options dialog showing the Auto date/time toggle in the Time Intelligence section" width="643" height="653" srcset="https://databear.com/wp-content/uploads/2026/05/01-auto-date-time-options.png 643w, https://databear.com/wp-content/uploads/2026/05/01-auto-date-time-options-295x300.png 295w, https://databear.com/wp-content/uploads/2026/05/01-auto-date-time-options-148x150.png 148w" sizes="(max-width: 643px) 100vw, 643px" /></p>
<p class="code-line" dir="auto" data-line="20"> <em>Power BI Desktop &gt; File &gt; Options &gt; Current File &gt; Data Load &gt; Time intelligence. The toggle is on by default.</em></p>
<p class="code-line" dir="auto" data-line="23">You will not see these tables in the model view. You will see them if you open the model in DAX Studio or Tabular Editor, or if you look at the .pbix file size and wonder why a model with twelve million rows of fact data weighs four gigabytes.</p>
<h4 id="why-it-matters" class="code-line" dir="auto" data-line="25">Why it matters</h4>
<p class="code-line" dir="auto" data-line="27">On the manufacturer&#8217;s model, switching auto date/time off and substituting a single date dimension cut the .pbix from 1.8 GB to 640 MB. Refresh time fell from forty-one minutes to twelve. The dashboard met its SLA again the following Monday.</p>
<p class="code-line" dir="auto" data-line="29">The cost is rarely about disk space, though. It is about the VertiPaq engine doing more work than it needs to during refresh, and about the model carrying compression overhead that buys it nothing. On a Premium capacity, that overhead costs money. On a Pro tenant, it costs you users who close the dashboard and open Excel.</p>
<h4 id="what-we-recommend" class="code-line" dir="auto" data-line="31">What we recommend</h4>
<p class="code-line" dir="auto" data-line="33">Auto date/time is on by default in every new Power BI Desktop install, and that default has not changed. So the first move is to turn it off at the file level (File &gt; Options &gt; Current File &gt; Data Load &gt; Time intelligence) for every new model. For existing models, turn it off in the same place and replace it with a single, marked date dimension. If you need to keep auto date/time on for one specific dataset, which is occasionally the right call for a sandbox or experimentation model, make that an explicit decision rather than an inherited default.</p>
<h3 id="2-bidirectional-relationships-used-as-a-workaround" class="code-line" dir="auto" data-line="37">2. Bidirectional relationships used as a workaround</h3>
<h4 id="what-it-looks-like-1" class="code-line" dir="auto" data-line="39">What it looks like</h4>
<p class="code-line" dir="auto" data-line="41">In the model view, any double-headed arrow between two tables. Sometimes one. Sometimes seven. Each one is a sign that someone, at some point, found a filter that would not propagate the direction they needed, switched the relationship to bidirectional, watched the visual update correctly, and moved on.</p>
<p class="code-line" dir="auto" data-line="43"><img loading="lazy" decoding="async" class="alignnone wp-image-50927 size-large" src="https://databear.com/wp-content/uploads/2026/05/02-bidirectional-model-view-1024x720.png" alt="Power BI model view showing multiple bidirectional relationships, anonymised" width="1024" height="720" srcset="https://databear.com/wp-content/uploads/2026/05/02-bidirectional-model-view-1024x720.png 1024w, https://databear.com/wp-content/uploads/2026/05/02-bidirectional-model-view-300x211.png 300w, https://databear.com/wp-content/uploads/2026/05/02-bidirectional-model-view-150x105.png 150w, https://databear.com/wp-content/uploads/2026/05/02-bidirectional-model-view-1536x1080.png 1536w, https://databear.com/wp-content/uploads/2026/05/02-bidirectional-model-view.png 1616w" sizes="(max-width: 1024px) 100vw, 1024px" /></p>
<p class="code-line" dir="auto" data-line="43"><em>An anonymised model from a recent Health Check. The double-headed arrows are bidirectional relationships. Seven of them, in this case.</em></p>
<p class="code-line" dir="auto" data-line="46">The visual updated correctly because bidirectional cross-filtering brute-forces the engine into propagating filters in directions it would not otherwise go. It also creates relationships that mask missing bridge tables, ambiguous join paths, and assumptions that fall apart the moment someone adds a new measure.</p>
<h4 id="why-it-matters-1" class="code-line" dir="auto" data-line="48">Why it matters</h4>
<p class="code-line" dir="auto" data-line="50">Bidirectional relationships are the single most common cause of the &#8220;this visual is taking too long to load&#8221; warning we see in Performance Analyzer. On a retail client&#8217;s sales model, removing four bidirectional relationships and replacing two of them with bridge tables took a slicer-driven page from nine seconds to under two. The page had not changed; the user could not tell us what we had done, only that it now responded the moment they clicked. That is the kind of fix that earns a Health Check its fee, because it is invisible until someone measures it.</p>
<p class="code-line" dir="auto" data-line="52"><img loading="lazy" decoding="async" class="alignnone size-full wp-image-50922" src="https://databear.com/wp-content/uploads/2026/05/03-performance-analyzer-before-after.png" alt="" width="287" height="653" srcset="https://databear.com/wp-content/uploads/2026/05/03-performance-analyzer-before-after.png 287w, https://databear.com/wp-content/uploads/2026/05/03-performance-analyzer-before-after-132x300.png 132w, https://databear.com/wp-content/uploads/2026/05/03-performance-analyzer-before-after-66x150.png 66w" sizes="(max-width: 287px) 100vw, 287px" /></p>
<p class="code-line" dir="auto" data-line="52"> <em>Performance Analyzer on the same page before and after the fix. Total query duration on the right.</em></p>
<p class="code-line" dir="auto" data-line="55">Performance is only the visible half of the cost. Bidirectional relationships are also the most common cause of ambiguity errors that surface months after a model goes live, when someone adds a measure that crosses the wrong filter path and Power BI flags the calculation as ambiguous. The error is technically correct. The model has been wrong for months, and the new measure is simply the first thing to ask a question the broken filter path could not answer.</p>
<h5 id="why-it-keeps-happening" class="code-line" dir="auto" data-line="57">Why it keeps happening</h5>
<p class="code-line" dir="auto" data-line="59">Bidirectional cross-filtering is a one-click change in the modelling pane, and it usually fixes the immediate symptom on the spot. The underlying cause, which is almost always a missing bridge table or a many-to-many that the data layer should have resolved, requires more thought and does not show its payoff on the screen in front of you.</p>
<p class="code-line" dir="auto" data-line="61">Microsoft&#8217;s documentation now warns against the pattern in several places, but those warnings live deep inside longer modelling articles. The user never sees them at the moment of the click, which is the only moment that would change the decision.</p>
<h4 id="what-we-recommend-1" class="code-line" dir="auto" data-line="63">What we recommend</h4>
<p class="code-line" dir="auto" data-line="65">Treat every bidirectional relationship as a flag, not a fix. If your model has more than one, write down what each one is doing and what would break if it were single-directional. In almost every case, the right answer is a bridge table, a measure that uses CROSSFILTER inside its calculation, or a remodel of the underlying schema.</p>
<h3 id="3-calculated-columns-doing-the-work-of-measures" class="code-line" dir="auto" data-line="69">3. Calculated columns doing the work of measures</h3>
<h4 id="what-it-looks-like-2" class="code-line" dir="auto" data-line="71">What it looks like</h4>
<p class="code-line" dir="auto" data-line="73">A model with thirty, forty, sometimes more than a hundred calculated columns. Sales margin as a column. Year-on-year change as a column. Customer lifetime value as a column. The engine computes each one row by row during refresh, stores it uncompressed (or close to it) in the model, and gains nothing at query time because every source refresh recomputes the column anyway.</p>
<p class="code-line" dir="auto" data-line="75"><img loading="lazy" decoding="async" class="alignnone size-full wp-image-50929" src="https://databear.com/wp-content/uploads/2026/05/column-metrics-587ed69e98c88f425d365a9625875e1a.png" alt="DAX Studio VertiPaq Analyzer Columns view sorted by Col Size, showing calculated columns in the top entries" width="900" height="268" srcset="https://databear.com/wp-content/uploads/2026/05/column-metrics-587ed69e98c88f425d365a9625875e1a.png 900w, https://databear.com/wp-content/uploads/2026/05/column-metrics-587ed69e98c88f425d365a9625875e1a-300x89.png 300w, https://databear.com/wp-content/uploads/2026/05/column-metrics-587ed69e98c88f425d365a9625875e1a-150x45.png 150w" sizes="(max-width: 900px) 100vw, 900px" /></p>
<p class="code-line" dir="auto" data-line="75"> <em>VertiPaq Analyzer in DAX Studio, sorted by column size. Calculated columns in the top ten are the ones we focus on first.</em></p>
<p class="code-line" dir="auto" data-line="78">The giveaway is the calculation icon next to the column name in the field list. The cost stays hidden until you look at the storage tab in DAX Studio and find that a third of the model size has gone to columns that should have been measures.</p>
<h4 id="why-it-matters-2" class="code-line" dir="auto" data-line="80">Why it matters</h4>
<p class="code-line" dir="auto" data-line="82">Calculated columns sit at the wrong end of every Power BI performance trade-off. They bloat the model. Their values are often unique or near-unique per row, so compression is poor. Visuals cannot reuse them the way measures can. Refresh time grows with every column added, because the engine recomputes each one whenever the source refreshes. And the work happens at refresh, when the VertiPaq engine could do it faster at query time through a measure.</p>
<p class="code-line" dir="auto" data-line="84">On a financial services client&#8217;s general ledger model, converting twenty-three calculated columns into measures reduced model size by 38% and brought refresh time down by nine minutes. The measures themselves added negligible query time, because the engine aggregates at speed.</p>
<h4 id="why-it-keeps-happening-1" class="code-line" dir="auto" data-line="86">Why it keeps happening</h4>
<p class="code-line" dir="auto" data-line="88">Calculated columns feel intuitive to anyone who has spent time in Excel. They look like spreadsheet formulas. They produce a column you can see, drag, and filter. Measures, by contrast, only exist when something asks for them. So new Power BI developers learn calculated columns first, build their first three or four models around them, and never revisit the choice.</p>
<h4 id="where-you-actually-want-a-calculated-column" class="code-line" dir="auto" data-line="90">Where you actually want a calculated column</h4>
<p class="code-line" dir="auto" data-line="92">There are cases where a calculated column is the right tool, and they are worth naming so the rule does not harden into dogma. You want one when the value participates in a relationship, when users will filter or group on it directly, or when it feeds a slicer a measure cannot. Everything else should default to a measure. To find the columns that broke that rule, sort your model&#8217;s columns in DAX Studio by storage size and walk down the list, asking of each whether it could be a measure instead. Most of them can be.</p>
<h4 id="what-to-do-before-you-bring-anyone-in" class="code-line" dir="auto" data-line="96">What to do before you bring anyone in</h4>
<p class="code-line" dir="auto" data-line="98">Three checks you can run against your own model this afternoon:</p>
<ol class="code-line" dir="auto" data-line="100">
<li class="code-line" dir="auto" data-line="100">Open File &gt; Options &gt; Current File &gt; Data Load. If &#8220;Auto date/time&#8221; is on, turn it off, then check each existing model in the tenant.</li>
<li class="code-line" dir="auto" data-line="101">Open the model view. Count the bidirectional relationships. For each one, write down what would break if it were single-directional. Any one you cannot answer is a flag.</li>
<li class="code-line" dir="auto" data-line="102">Open DAX Studio against your largest model. Run VertiPaq Analyzer. Sort columns by size. If calculated columns appear in your top ten, you have at least one conversation worth having.</li>
</ol>
<p class="code-line" dir="auto" data-line="104">If any of these return more than you expected, you have somewhere to start.</p>
<h3 id="why-the-power-bi-health-check-still-finds-these-three" class="code-line" dir="auto" data-line="108">Why the Power BI Health Check still finds these three</h3>
<p class="code-line" dir="auto" data-line="110">These three issues have been in our top three for six years. Power BI has changed in that time, the licences have changed, and Microsoft has rebranded the products more than once. The underlying patterns have not changed.</p>
<p class="code-line" dir="auto" data-line="112">Part of the reason is that Microsoft ships defaults that are friendly to a first-time user and costly to a mature one, and Power BI&#8217;s user base has matured faster than the defaults have. Part of it is that the path from &#8220;I built a working dashboard&#8221; to &#8220;I built a healthy dashboard&#8221; is not a path most teams know they need to walk. The dashboard works. The questions get answered. The cost shows up later, usually as a refresh that started missing its window.</p>
<p class="code-line" dir="auto" data-line="114">Some of the harder decisions sit upstream of the model itself, in where data preparation lives and what the pipeline architecture should look like. We have written separately about <a href="https://databear.com/silver-layer-power-bi/" data-href="https://databear.com/silver-layer-power-bi/">whether you need a silver layer in Power BI</a>, which is often the next conversation after a Health Check, when the answer to &#8220;fix the model&#8221; turns out to be &#8220;the model is the wrong place to fix it.&#8221;</p>
<p class="code-line" dir="auto" data-line="116">A <a href="https://databear.com/%5BURL%5D" data-href="https://databear.com/%5BURL%5D">Power BI Health Check</a> is one way to catch the cost early, particularly where these three patterns sit underneath thirty more that an afternoon&#8217;s self-check will not surface. Running the three checks above against your own model, honestly, is the cheaper place to start.</p>
<p>The post <a href="https://databear.com/the-three-issues-that-fail-nearly-every-power-bi-health-check-we-run/">The three issues that fail nearly every Power BI Health Check we run</a> appeared first on <a href="https://databear.com">Data Bear</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>The two kinds of Power BI debt and how to tell which you have</title>
		<link>https://databear.com/the-two-kinds-of-power-bi-debt-and-how-to-tell-which-you-have/</link>
		
		<dc:creator><![CDATA[Boniface Muchendu]]></dc:creator>
		<pubDate>Sun, 21 Jun 2026 12:04:35 +0000</pubDate>
				<category><![CDATA[Power BI]]></category>
		<guid isPermaLink="false">https://databear.com/?p=50934</guid>

					<description><![CDATA[<p>A finance director called us last autumn. They had eight Power BI developers across two teams, a Premium capacity, and 247 published reports. Refresh failures were a weekly conversation. The company had officially deprecated two reports, but more than eighty users still opened them each month. The CFO had asked, reasonably, why the BI investment [&#8230;]</p>
<p>The post <a href="https://databear.com/the-two-kinds-of-power-bi-debt-and-how-to-tell-which-you-have/">The two kinds of Power BI debt and how to tell which you have</a> appeared first on <a href="https://databear.com">Data Bear</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p class="code-line" dir="auto" data-line="6">A finance director called us last autumn. They had eight Power BI developers across two teams, a Premium capacity, and 247 published reports. Refresh failures were a weekly conversation. The company had officially deprecated two reports, but more than eighty users still opened them each month. The CFO had asked, reasonably, why the BI investment was producing more confusion than clarity. The answer was Power BI debt, and not the kind they assumed.</p>
<p class="code-line" dir="auto" data-line="8">We started with the technical side. The semantic models were workmanlike. Properly modelled, sensible naming, reasonable size. Refreshes were failing not because of design issues but because nobody could agree which reports were still in use, so every developer was protecting every dataset.</p>
<p class="code-line" dir="auto" data-line="10">That client had almost no model debt. They had a vast amount of adoption debt. They had also spent eighteen months hiring developers to fix it, which had not worked, which was why they had called us.</p>
<p class="code-line" dir="auto" data-line="12">Most Power BI estates carry both kinds of debt. Almost none carry them in equal measure. Knowing which one you have more of is the difference between hiring a developer and hiring a programme manager, and the wrong choice will not work no matter how good the person is.</p>
<p class="code-line" dir="auto" data-line="14">We have audited Power BI estates at more than 150 organisations over the last decade. This piece sets out what each kind of debt looks like, how to tell which one you have, and what we recommend doing about each.</p>
<h3 id="type-1-power-bi-model-debt" class="code-line" dir="auto" data-line="18">Type 1: Power BI model debt</h3>
<h4 id="what-model-debt-is" class="code-line" dir="auto" data-line="20">What model debt is</h4>
<p class="code-line" dir="auto" data-line="22">Debt in the technical foundations of your semantic models. Bidirectional relationships used as quick fixes. Calculated columns doing the work of measures. Auto date/time left on. Business logic that should live in the data layer, hardcoded in DAX instead. Manual data preparation steps that exist only in one developer&#8217;s head. Models that different people built grain by grain, without any shared design.</p>
<p class="code-line" dir="auto" data-line="24"><img loading="lazy" decoding="async" class="alignnone size-full wp-image-50924" src="https://databear.com/wp-content/uploads/2026/05/debt-01-model-debt-example.png" alt="Model view of a Power BI semantic model showing tangled relationships, anonymised" width="645" height="355" srcset="https://databear.com/wp-content/uploads/2026/05/debt-01-model-debt-example.png 645w, https://databear.com/wp-content/uploads/2026/05/debt-01-model-debt-example-300x165.png 300w, https://databear.com/wp-content/uploads/2026/05/debt-01-model-debt-example-150x83.png 150w" sizes="(max-width: 645px) 100vw, 645px" /></p>
<p class="code-line" dir="auto" data-line="24"> <em>A semantic model carrying significant model debt. Eleven tables, six bidirectional relationships, no obvious fact-and-dimension split.</em></p>
<h4 id="what-it-costs-you" class="code-line" dir="auto" data-line="27">What it costs you</h4>
<p class="code-line" dir="auto" data-line="29">Refresh times grow. New measures break old ones in non-obvious ways. Every change becomes a careful threading exercise through assumptions nobody has written down. Developers spend more time on operations than on building. The cost shows up as a slow drain on the team&#8217;s velocity, and as the unease that settles over any model that has lasted longer than its design intended.</p>
<h4 id="a-worked-example" class="code-line" dir="auto" data-line="31">A worked example</h4>
<p class="code-line" dir="auto" data-line="33">One engagement last year shows the shape of it. A logistics business came to us with a single semantic model that had grown over four years to forty-one tables. Refresh ran for fifty-three minutes and failed roughly one morning in five. Nobody on the team could say what most of the model did, because the two developers who had built it had both since moved on.</p>
<p class="code-line" dir="auto" data-line="35">When we opened it in DAX Studio, the picture was familiar. Nine bidirectional relationships. A central fact table carrying thirty-one calculated columns, several of them recomputing values that already existed as measures elsewhere in the same model. Auto date/time had quietly generated hidden hierarchies behind nineteen separate date columns. None of this was visible from the reports, which looked fine, which was exactly why it had survived four years.</p>
<p class="code-line" dir="auto" data-line="37">The fix was not glamorous. We marked a single date dimension and switched auto date/time off, which on its own took the model from 2.3 GB to 900 MB. We converted twenty-six of the calculated columns to measures and removed seven of the nine bidirectional relationships, replacing two of them with bridge tables. Refresh dropped to fourteen minutes and stopped failing.</p>
<p class="code-line" dir="auto" data-line="39">The work took six weeks. Most of that was not the refactor itself but reconstructing what the undocumented logic was supposed to do, because you cannot safely change code when nobody can tell you what it was for. That recovery, not the rebuild, is where model debt charges most of its interest.</p>
<h4 id="five-questions-for-your-lead-developer" class="code-line" dir="auto" data-line="41">Five questions for your lead developer</h4>
<p class="code-line" dir="auto" data-line="43">Put them to whoever owns your largest model:</p>
<ol class="code-line" dir="auto" data-line="45">
<li class="code-line" dir="auto" data-line="45">Could you onboard a new developer to that model in a week?</li>
<li class="code-line" dir="auto" data-line="46">If your most experienced developer left tomorrow, would the model still be maintainable?</li>
<li class="code-line" dir="auto" data-line="47">When someone adds a new measure, do you know with confidence which existing measures it touches?</li>
<li class="code-line" dir="auto" data-line="48">If a stakeholder asks for a new calculation, is the answer &#8220;two days&#8221; or &#8220;two weeks&#8221;?</li>
<li class="code-line" dir="auto" data-line="49">When you open the model in DAX Studio and look at VertiPaq Analyzer, is the top of the column-size list mostly tables you expected to see there?</li>
</ol>
<p class="code-line" dir="auto" data-line="51">If you hesitated on two or more, the model is carrying more debt than its surface suggests.</p>
<h4 id="how-you-pay-it-down" class="code-line" dir="auto" data-line="53">How you pay it down</h4>
<p class="code-line" dir="auto" data-line="55">Model debt is fixable with technical skill. You pay it down through audit, refactoring, and discipline going forward. Some of the work also sits upstream of the model itself, in where data preparation lives. We have written separately about <a href="https://databear.com/silver-layer-power-bi/" data-href="https://databear.com/silver-layer-power-bi/">whether you need a silver layer in Power BI</a>, which is often the right starting point when the model is the wrong place to fix the problem. We will also publish a companion piece on the three issues that fail nearly every Power BI Health Check we run (link to be added once that post is live), covering the model patterns that account for most of the Power BI debt we see in practice.</p>
<h3 id="type-2-power-bi-adoption-debt" class="code-line" dir="auto" data-line="59">Type 2: Power BI adoption debt</h3>
<h4 id="what-adoption-debt-looks-like" class="code-line" dir="auto" data-line="61">What adoption debt looks like</h4>
<p class="code-line" dir="auto" data-line="63">Debt in the people, processes, and governance around your Power BI estate. No clear ownership for each model or workspace. Reports that someone built once and then quietly abandoned. No retirement process. Training delivered as a one-off event and never refreshed. Workspaces with names nobody can explain and contents nobody has audited. Different departments answering the same question with different numbers, all defended.</p>
<p class="code-line" dir="auto" data-line="65"><img loading="lazy" decoding="async" class="alignnone size-full wp-image-50925" src="https://databear.com/wp-content/uploads/2026/05/debt-02-adoption-debt-usage.png" alt="Power BI admin centre usage list showing long tail of low-view reports" width="722" height="411" srcset="https://databear.com/wp-content/uploads/2026/05/debt-02-adoption-debt-usage.png 722w, https://databear.com/wp-content/uploads/2026/05/debt-02-adoption-debt-usage-300x171.png 300w, https://databear.com/wp-content/uploads/2026/05/debt-02-adoption-debt-usage-150x85.png 150w" sizes="(max-width: 722px) 100vw, 722px" /></p>
<p class="code-line" dir="auto" data-line="65"> <em>Report usage from a recent client audit, anonymised. The top ten reports account for 71% of views. Of the remaining 240, more than half had not been opened in the last quarter.</em></p>
<h4 id="why-it-costs-more-than-it-looks" class="code-line" dir="auto" data-line="68">Why it costs more than it looks</h4>
<p class="code-line" dir="auto" data-line="70">High tool spend with low business outcome. Time spent reconciling versions of the same number instead of acting on what the number says. Decisions that rested on whichever data was easiest to find, rather than whichever data was most accurate. Senior stakeholders who lose confidence in BI and revert to Excel. Most expensively, the slow erosion of the assumption that anyone can trust the BI estate at all.</p>
<h4 id="how-to-tell" class="code-line" dir="auto" data-line="72">How to tell</h4>
<p class="code-line" dir="auto" data-line="74">Three questions for whoever runs the Power BI tenant:</p>
<ol class="code-line" dir="auto" data-line="76">
<li class="code-line" dir="auto" data-line="76">Do you know which reports are actively used this quarter, and which are not?</li>
<li class="code-line" dir="auto" data-line="77">If a senior stakeholder asks &#8220;what is our [headline KPI]?&#8221;, does everyone come back with the same number?</li>
<li class="code-line" dir="auto" data-line="78">Is there a named owner for each production dataset?</li>
</ol>
<p class="code-line" dir="auto" data-line="80">A single uncomfortable answer here is enough. This is not a problem a better dashboard solves.</p>
<h4 id="why-a-developer-cant-fix-it" class="code-line" dir="auto" data-line="82">Why a developer can&#8217;t fix it</h4>
<p class="code-line" dir="auto" data-line="84">Adoption debt is harder than model debt because it is not technical. You pay it down through governance, ownership, and culture, none of which a developer can fix on their own. The fix requires sponsorship at a level above the BI team. Without it, the debt grows back faster than any individual can pay it down.</p>
<h3 id="why-the-two-kinds-of-power-bi-debt-matter-separately" class="code-line" dir="auto" data-line="88">Why the two kinds of Power BI debt matter separately</h3>
<p class="code-line" dir="auto" data-line="90">Hiring a Power BI developer to fix adoption debt does not work. They will produce excellent dashboards that nobody owns, and the problem will simply move.</p>
<p class="code-line" dir="auto" data-line="92">Hiring a programme manager to fix model debt does not work either. They will run useful governance forums about a model that fundamentally cannot bear the weight of the questions being asked of it.</p>
<p class="code-line" dir="auto" data-line="94">The two kinds of Power BI debt also feed each other. Model debt produces adoption debt because users stop trusting numbers that arrive late or behave inconsistently. The reverse runs more quietly: where ownership is unclear, developers build defensively, and defensive modelling is how a clean model slowly takes on the complexity nobody chose.</p>
<p class="code-line" dir="auto" data-line="96">The diagnostic question we put to clients on the first day of an audit is deliberately blunt: when you sit with your most expensive current Power BI problem, is the painful work mostly technical or mostly organisational? The honest answer tells you where to start.</p>
<h3 id="what-to-do-before-you-bring-anyone-in" class="code-line" dir="auto" data-line="100">What to do before you bring anyone in</h3>
<p class="code-line" dir="auto" data-line="102">Three checks you can run in an afternoon, one for each debt and one to compare them.</p>
<ol class="code-line" dir="auto" data-line="104">
<li class="code-line" dir="auto" data-line="104">Pull a report usage list for the last 90 days from the Power BI admin centre. Sort by views. If your top ten reports account for less than 30% of total views, you almost certainly have adoption debt. If they account for more than 80%, the long tail is probably already self-correcting and your problem sits elsewhere.</li>
<li class="code-line" dir="auto" data-line="105">Run VertiPaq Analyzer (in DAX Studio) on your largest model. Look at total model size, refresh time, and the number of calculated columns in the top ten by storage. If any of those raise a flag, you almost certainly have model debt.</li>
<li class="code-line" dir="auto" data-line="106">Ask your three most senior Power BI users which report they trust the most. If they give different answers, you have a clue about both debts, and a useful place to begin the conversation that follows.</li>
</ol>
<p class="code-line" dir="auto" data-line="108">If you run all three and your answers are healthy on every count, congratulations. You are an outlier.</p>
<h3 id="one-reflection-on-power-bi-debt-after-150-audits" class="code-line" dir="auto" data-line="112">One reflection on Power BI debt after 150 audits</h3>
<p class="code-line" dir="auto" data-line="114">Clients who arrive convinced they have a model problem almost always have an adoption problem sitting behind it, and the reverse holds just as often. The harder question is which one to fix first.</p>
<p class="code-line" dir="auto" data-line="116">In the <a href="https://databear.com/power-bi-training/" data-href="https://databear.com/%5BURL%5D">consulting engagements where we lead this work</a>, we start with whichever debt is currently blocking value. Sometimes that means a structural intervention to the semantic model and a six-week refactor. In other engagements, it is a governance conversation the organisation has postponed for three years. Occasionally it is a frank discussion with the sponsor about whether the BI team has the mandate it needs to do either.</p>
<p class="code-line code-active-line" dir="auto" data-line="118">The mistake we see most often is the same one in either direction: an organisation pours money into the kind of debt they are comfortable thinking about, because the other kind is harder to face. Model debt has the comfort of being technical and therefore fixable. Adoption debt has the comfort of being someone else&#8217;s job. Neither comfort survives the audit.</p>
<p>The post <a href="https://databear.com/the-two-kinds-of-power-bi-debt-and-how-to-tell-which-you-have/">The two kinds of Power BI debt and how to tell which you have</a> appeared first on <a href="https://databear.com">Data Bear</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Power Apps Layout Containers for Responsive Design</title>
		<link>https://databear.com/power-apps-layout-containers/</link>
		
		<dc:creator><![CDATA[Boniface Muchendu]]></dc:creator>
		<pubDate>Wed, 13 May 2026 19:14:32 +0000</pubDate>
				<category><![CDATA[Power BI]]></category>
		<guid isPermaLink="false">https://databear.com/?p=45392</guid>

					<description><![CDATA[<p>Designing responsive apps in Power Apps can be frustrating  especially when resizing, reordering, and aligning elements on different devices becomes a never-ending formula chase. But what if there was a simpler way? Power Apps layout containers offer a clean, efficient way to create responsive designs without writing a single formula. Enter layout containers  the secret [&#8230;]</p>
<p>The post <a href="https://databear.com/power-apps-layout-containers/">Power Apps Layout Containers for Responsive Design</a> appeared first on <a href="https://databear.com">Data Bear</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Designing responsive apps in Power Apps can be frustrating  especially when resizing, reordering, and aligning elements on different devices becomes a never-ending formula chase. But what if there was a simpler way? <strong data-start="491" data-end="523">Power Apps layout containers</strong> offer a clean, efficient way to create responsive designs without writing a single formula.</p>
<p>Enter <strong>layout containers</strong>  the secret to building modern, responsive Power Apps <strong>without writing formulas</strong>.</p>
<p>In this blog post, we&#8217;ll walk through:</p>
<ul>
<li>The difference between <strong>bad vs. good responsive app layouts</strong></li>
<li>How to <strong>use container templates effectively</strong></li>
<li>Aligning elements using <strong>horizontal and vertical containers</strong></li>
<li>A real-world layout replication using <strong>nested containers</strong></li>
<li>Pro tips for <strong>alignment, spacing, and responsiveness</strong></li>
</ul>
<p>Let’s demystify layout containers in Power Apps  and save you hours of work.</p>
<h5>The Problem with Manual Layouts<img loading="lazy" decoding="async" class="aligncenter wp-image-50822 size-full" src="https://databear.com/wp-content/uploads/2026/05/Screenshot-2026-05-13-221231.png" alt="Power Apps Layout Containers for Responsive Design" width="1035" height="516" srcset="https://databear.com/wp-content/uploads/2026/05/Screenshot-2026-05-13-221231.png 1035w, https://databear.com/wp-content/uploads/2026/05/Screenshot-2026-05-13-221231-300x150.png 300w, https://databear.com/wp-content/uploads/2026/05/Screenshot-2026-05-13-221231-1024x511.png 1024w, https://databear.com/wp-content/uploads/2026/05/Screenshot-2026-05-13-221231-150x75.png 150w" sizes="(max-width: 1035px) 100vw, 1035px" /></h5>
<p>Before discovering containers, many app builders (including experienced ones) tried to manage layout using complex formulas:</p>
<pre><code class="language-plaintext">Width = App.Width * 0.66
X = SomeControl.X + SomeControl.Width + 10
</code></pre>
<p>This approach becomes fragile and unsustainable as your app scales.</p>
<p>For example, a “bad” home screen might look fine initially  until you rotate the device or view it on another screen size. Suddenly:</p>
<ul>
<li>Buttons disappear</li>
<li>Images shift</li>
<li>Navigation is misaligned</li>
</ul>
<p>Responsive design breaks down fast.</p>
<h5>What a “Good” Layout Looks Like  Without Formulas</h5>
<p>By using <strong>layout containers</strong>, you can build a responsive design that adjusts automatically across screen sizes. With proper setup:</p>
<ul>
<li>Buttons stay centered</li>
<li>Images scale properly</li>
<li>Navigation remains intuitive</li>
<li>No layout formulas are needed</li>
</ul>
<p>This is possible thanks to <strong>container-based screen templates</strong> now built directly into Power Apps.</p>
<h5>Getting Started with Container Templates in Power Apps</h5>
<p>When creating a new screen, Power Apps offers <strong>containerized templates</strong> such as:</p>
<ul>
<li>Sidebar</li>
<li>Header/Main</li>
<li>Dashboard layouts</li>
</ul>
<p>For a layout with a header, sidebar, image, and navigation buttons, the <strong>&#8220;Sidebar&#8221; template</strong> works perfectly.</p>
<p>Once added, inspect the <strong>Tree View</strong> to see the structure:</p>
<pre><code>Screen
├── Screen Container
    ├── Header Container (Top)
    └── Bottom Container
        ├── Sidebar Container (Left)
        └── Main Container (Right)
</code></pre>
<h5>Key Tip:</h5>
<p>Don’t give up on containers because you can’t drag-and-drop like other controls. Instead:</p>
<ul>
<li>Use the <strong>Tree View</strong> to reorder</li>
<li>Or use the <strong>right-click &gt; Reorder &gt; Move to start/end</strong> options</li>
</ul>
<h5>Horizontal vs. Vertical Containers Explained</h5>
<p>Understanding <strong>directionality</strong> is crucial:</p>
<ul>
<li><strong>Horizontal containers</strong> lay out items left to right</li>
<li><strong>Vertical containers</strong> stack items top to bottom</li>
</ul>
<p>Use the <strong>properties panel</strong> to confirm the direction. Icons in the Tree View also help identify layout flow.</p>
<h5>Aligning Images and Buttons Without Formulas</h5>
<p>To resize and align images or buttons <strong>within containers</strong>, use:</p>
<ul>
<li><strong>Align in container</strong>: Set to <em>Stretch</em> for full width</li>
<li><strong>Flexible height/width</strong>: Enable to auto-resize within available space</li>
<li><strong>Justify/Align</strong>: Vertically and horizontally center buttons</li>
<li><strong>Gap</strong>: Control spacing between items (e.g., 10px between buttons)</li>
</ul>
<p>You can now center multiple buttons, align images perfectly, and ensure responsiveness  without touching a single formula.</p>
<h5>Real-World Layout Replication: Building a Booking App UI</h5>
<p>Let’s recreate a professional layout inspired by a hotel booking web app, using nested containers.</p>
<h5>Step 1: Set Up a Vertical Screen Container</h5>
<ul>
<li>Add a <strong>vertical container</strong> to fill the entire screen</li>
<li>Set a <strong>background color</strong> (e.g., pale blue)</li>
<li>Rename logically: <code>ScreenContainer</code></li>
</ul>
<h5>Step 2: Add a Main White Container Inside</h5>
<ul>
<li>Insert another <strong>vertical container</strong></li>
<li>Set <strong>background: white</strong></li>
<li>Add <strong>padding</strong>: 15px top/bottom, 30px sides</li>
<li>Rename: <code>MainContainer</code></li>
</ul>
<h5>Designing a Responsive Three-Part Header</h5>
<p>To create a header with:</p>
<ul>
<li>A <strong>logo (left)</strong></li>
<li><strong>Action buttons (center)</strong></li>
<li><strong>User info (right)</strong></li>
</ul>
<p>Nest three horizontal containers inside your main header container:</p>
<pre><code>MainHeaderContainer
├── LeftHeaderContainer (Logo)
├── MidHeaderContainer (Buttons)
└── RightHeaderContainer (User Info)
</code></pre>
<p>Use <strong>alignment and padding</strong> settings to:</p>
<ul>
<li>Center items vertically and horizontally</li>
<li>Add <strong>gap spacing</strong> between buttons</li>
<li>Adjust container <strong>height</strong> manually if needed</li>
</ul>
<h5>Creating the Working Area: Filters, Data, and Details</h5>
<p>Below the header, add a <strong>horizontal container</strong>:</p>
<ul>
<li>Left: Filtering and gallery</li>
<li>Right: Image and additional info</li>
</ul>
<p>Nest containers as follows:</p>
<pre><code>WorkingAreaContainer (Horizontal)
├── LeftWorkingContainer (Vertical)
│   ├── FiltersContainer (Gray background, horizontal)
│   └── GalleryContainer (White, with data)
└── RightWorkingContainer (Vertical)
    ├── SelectedItemDetails
    └── Image or Actions
</code></pre>
<p>Use <strong>minimum height</strong>, <strong>padding</strong>, <strong>flexible width</strong>, and <strong>drop shadows</strong> to polish the layout and improve visual hierarchy.</p>
<h5>Final Touches: Fully Responsive and Formula-Free</h5>
<p>Once completed, your app will:</p>
<ul>
<li>Adjust to device orientation</li>
<li>Auto-center buttons and images</li>
<li>Handle resizing with grace</li>
<li>Require <strong>zero formulas</strong> for responsiveness</li>
</ul>
<p>You&#8217;re left with a <strong>professional, modern UI</strong>  without the layout headaches.</p>
<h5>Best Practices for Using Layout Containers</h5>
<p>Here are some tips to streamline your development:</p>
<p><strong>Use container templates</strong> when possible<br />
<strong>Rename containers logically</strong> for better readability<br />
<strong>Understand directionality</strong> (horizontal vs. vertical)<br />
<strong>Leverage flexible sizing and alignment settings</strong><br />
<strong>Use Tree View for reordering</strong> controls<br />
<strong>Minimize formulas</strong> use container properties instead</p>
<h5>Want to Level Up Your Power Platform Skills?</h5>
<p>If you&#8217;re serious about designing better Power Apps, improving data visuals in Power BI, or mastering the Microsoft Power Platform  structured training can make all the difference.</p>
<p><strong>Check out <a href="https://databear.com/power-bi-training/">Data Bear&#8217;s Power BI Training</a></strong> for hands-on, real-world courses designed to elevate your Power BI and reporting skills.</p>
<h5>Conclusion: Layout Containers Save Time &amp; Sanity</h5>
<p>Power Apps containers aren&#8217;t just a nice-to-have  they&#8217;re essential for building responsive, user-friendly Canvas Apps. Once you understand how to structure, align, and nest containers effectively, you&#8217;ll:</p>
<ul>
<li>Stop writing redundant formulas</li>
<li>Design apps that work on all devices</li>
<li>Save <strong>hours</strong> of development and debugging</li>
</ul>
<p>The post <a href="https://databear.com/power-apps-layout-containers/">Power Apps Layout Containers for Responsive Design</a> appeared first on <a href="https://databear.com">Data Bear</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Power BI Theming and External Sharing Tools in Microsoft Fabric</title>
		<link>https://databear.com/power-bi-theming-tools/</link>
		
		<dc:creator><![CDATA[Boniface Muchendu]]></dc:creator>
		<pubDate>Wed, 13 May 2026 19:03:06 +0000</pubDate>
				<category><![CDATA[Power BI]]></category>
		<guid isPermaLink="false">https://databear.com/?p=43776</guid>

					<description><![CDATA[<p>In today’s fast-moving data landscape, Power BI theming and secure external sharing are becoming more important than ever. As businesses scale their analytics efforts, they also need reports that look professional, stay consistent, and remain easy to share securely. Because of this, Microsoft Fabric now introduces two major innovations: an improved Power BI theme designer [&#8230;]</p>
<p>The post <a href="https://databear.com/power-bi-theming-tools/">Power BI Theming and External Sharing Tools in Microsoft Fabric</a> appeared first on <a href="https://databear.com">Data Bear</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>In today’s fast-moving data landscape, Power BI theming and secure external sharing are becoming more important than ever. As businesses scale their analytics efforts, they also need reports that look professional, stay consistent, and remain easy to share securely. Because of this, Microsoft Fabric now introduces two major innovations: an improved Power BI theme designer and a powerful external sharing accelerator.</p>
<h5>Streamline Power BI Report Design with a Visual Theme Generator<img loading="lazy" decoding="async" class="aligncenter wp-image-50820 size-full" src="https://databear.com/wp-content/uploads/2026/05/Screenshot-2026-05-13-220020.png" alt="Streamline Power BI Report Design with a Visual Theme Generator" width="1030" height="383" srcset="https://databear.com/wp-content/uploads/2026/05/Screenshot-2026-05-13-220020.png 1030w, https://databear.com/wp-content/uploads/2026/05/Screenshot-2026-05-13-220020-300x112.png 300w, https://databear.com/wp-content/uploads/2026/05/Screenshot-2026-05-13-220020-1024x381.png 1024w, https://databear.com/wp-content/uploads/2026/05/Screenshot-2026-05-13-220020-150x56.png 150w" sizes="(max-width: 1030px) 100vw, 1030px" /></h5>
<p>Creating a consistent design across many Power BI reports can be difficult. In the past, theme customization often required manual JSON editing, which made the process slow and technical. However, this updated tool simplifies Power BI theming for both beginners and advanced users.</p>
<h5>Key Features</h5>
<h5>Live Visual Editor</h5>
<p>Users can instantly see theme changes applied to visuals in real time. As a result, report design becomes faster and more interactive.</p>
<h5>Ready-to-Use Templates</h5>
<p>Prebuilt layouts and backgrounds help users start quickly. In addition, these templates improve consistency across reports.</p>
<h5>Organized Property Management</h5>
<p>An alphabetical search makes styling options easier to find. Therefore, users spend less time searching through settings.</p>
<h5>PBIP Compatibility</h5>
<p>The tool fully supports Power BI Project (PBIP) files, making it easier to manage enterprise reporting projects.</p>
<h5>Built-in Code Editor and Validator</h5>
<p>Advanced users can still fine-tune JSON manually. At the same time, built-in validation helps reduce errors before deployment.</p>
<h5>Preview Mode</h5>
<p>Users can test themes on existing reports before saving changes. Consequently, teams can avoid design mistakes and maintain quality standards.</p>
<p>Overall, this tool greatly improves the report design process. Not only does it save time, but it also helps organizations maintain a clean and professional reporting experience.</p>
<h5>Secure External Sharing for Power BI</h5>
<p>Sharing Power BI reports with clients, vendors, or external users has traditionally been difficult. Furthermore, many organizations struggle to balance accessibility with security. To solve this challenge, a new embedded analytics solution now provides a secure and polished way to distribute Power BI content externally.</p>
<h5>Core Capabilities</h5>
<h5>In-App Report Rendering</h5>
<p>Users can view both standard and paginated Power BI reports inside one centralized interface. As a result, navigation becomes simpler and more user-friendly.</p>
<h5>Personalized User Experience</h5>
<p>End users can save bookmarks, customize layouts, and organize dashboards based on their preferences. Therefore, reports become more interactive and useful.</p>
<h5>Editable Reports</h5>
<p>Reports can also be edited directly within the application. This feature is especially valuable for collaborative client environments.</p>
<h5>Paginated Table Builder</h5>
<p>Users can create filterable and exportable reports directly from semantic models. In addition, this allows teams to generate custom tables without extra development work.</p>
<h5>Brand Customization</h5>
<p>Organizations can create white-labeled, multi-tenant experiences that match their branding. Consequently, businesses can deliver a more professional client experience.</p>
<p>By combining secure sharing with flexible analytics, this solution supports modern reporting needs while improving collaboration and usability.</p>
<h5>Why These Updates Matter</h5>
<p>Together, these Power BI and Microsoft Fabric innovations help organizations improve both report design and external collaboration. On one hand, the visual theme generator simplifies branding and consistency. On the other hand, the external sharing accelerator improves security and user experience.</p>
<p>As analytics environments continue to grow, tools like these become essential for scalable and professional reporting solutions.</p>
<h5>Elevate Your Power BI Skills</h5>
<p>If you want to improve your Power BI expertise and learn how to use these tools effectively, explore the training resources below:</p>
<p><a href="https://databear.com/power-bi-training/?utm_source=chatgpt.com">Power BI Training from Data Bear</a></p>
<p>Whether you are just getting started or expanding an enterprise analytics environment, expert-led training can help you build cleaner, more effective, and more impactful Power BI solutions.</p>
<p>The post <a href="https://databear.com/power-bi-theming-tools/">Power BI Theming and External Sharing Tools in Microsoft Fabric</a> appeared first on <a href="https://databear.com">Data Bear</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Power Pages Data Model Step-by-Step Guide</title>
		<link>https://databear.com/power-pages-data-model-guide/</link>
		
		<dc:creator><![CDATA[Boniface Muchendu]]></dc:creator>
		<pubDate>Wed, 13 May 2026 18:49:40 +0000</pubDate>
				<category><![CDATA[Power BI]]></category>
		<guid isPermaLink="false">https://databear.com/?p=50735</guid>

					<description><![CDATA[<p>Building a robust data model is a critical step when developing cloud-based applications in Microsoft Power Pages. While a visually appealing website is important, the real power lies in how your data is structured, stored, and connected. In this guide, we’ll walk through how to: Create a data model for Power Pages Automatically generate tables [&#8230;]</p>
<p>The post <a href="https://databear.com/power-pages-data-model-guide/">Power Pages Data Model Step-by-Step Guide</a> appeared first on <a href="https://databear.com">Data Bear</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Building a robust data model is a critical step when developing cloud-based applications in Microsoft Power Pages. While a visually appealing website is important, the real power lies in how your data is structured, stored, and connected.</p>
<p>In this guide, we’ll walk through how to:</p>
<ul>
<li>Create a data model for Power Pages</li>
<li>Automatically generate tables and relationships</li>
<li>Customize your schema</li>
<li>Add sample data for testing</li>
<li>Prepare your application for real data integration</li>
</ul>
<blockquote><p><strong><a href="https://databear.com/power-bi-training/">Power BI Training Resource</a></strong></p></blockquote>
<h5>Prerequisites<img loading="lazy" decoding="async" class="aligncenter wp-image-50818 size-full" src="https://databear.com/wp-content/uploads/2026/05/Screenshot-2026-05-13-214752.png" alt="Prerequisites" width="680" height="492" srcset="https://databear.com/wp-content/uploads/2026/05/Screenshot-2026-05-13-214752.png 680w, https://databear.com/wp-content/uploads/2026/05/Screenshot-2026-05-13-214752-300x217.png 300w, https://databear.com/wp-content/uploads/2026/05/Screenshot-2026-05-13-214752-150x109.png 150w" sizes="(max-width: 680px) 100vw, 680px" /></h5>
<p>Before diving in, ensure you have:</p>
<ul>
<li>A Power Pages site already created and deployed</li>
<li>Access to Microsoft Dataverse</li>
<li>Visual Studio Code installed</li>
<li>Necessary Power Platform permissions</li>
</ul>
<p>This tutorial builds on previous steps where the website has already been set up and deployed.</p>
<h5>Why Data Modeling Matters in Power Pages</h5>
<p>At this stage, your Power Pages site may still rely on placeholder or mock data. A proper data model enables:</p>
<ul>
<li>Structured data storage</li>
<li>Scalable application architecture</li>
<li>Seamless integration with APIs and external systems</li>
<li>Better reporting and analytics (including Power BI integration)</li>
</ul>
<h5>Step 1: Generate a Data Model Using VS Code</h5>
<p>Power Pages allows you to quickly scaffold a data model using built-in commands.</p>
<h5>Run the Data Model Setup Command</h5>
<p>In Visual Studio Code, execute:</p>
<pre><code>/setup data model
</code></pre>
<p>This command will:</p>
<ul>
<li>Analyze your existing application</li>
<li>Recommend a set of tables</li>
<li>Generate an <strong>Entity Relationship Diagram (ERD)</strong></li>
<li>Create relationships between tables</li>
<li>Prepare the schema for deployment</li>
</ul>
<p>You’ll be prompted to confirm permissions and answer a few configuration questions.</p>
<h5>Step 2: Review and Customize the Generated Tables</h5>
<p>Once the process runs, an HTML preview will display the proposed data model.</p>
<h5>Example Tables Created</h5>
<p>The system typically generates tables such as:</p>
<ul>
<li>Service Categories</li>
<li>Service Requests</li>
<li>Service Request Notes</li>
<li>Attachments</li>
<li>Contact (existing table)</li>
</ul>
<h5>Key Customizations</h5>
<p>Before finalizing, review and adjust:</p>
<h5>1. Prefix Naming Convention</h5>
<p>Instead of default prefixes, define your own (e.g., <code>PW</code> for your organization).</p>
<h5>2. Column Data Types</h5>
<p>For example:</p>
<ul>
<li>Change <strong>Request Number</strong> from text → Auto Number</li>
<li>Add meaningful prefixes (e.g., <code>SR-0001</code>)</li>
</ul>
<h5>3. Field Validation</h5>
<p>Ensure fields like:</p>
<ul>
<li>Titles</li>
<li>Descriptions</li>
<li>Relationships</li>
</ul>
<p>…match your business logic.</p>
<h5>Step 3: Approve and Deploy the Data Model</h5>
<p>Once satisfied:</p>
<ul>
<li>Approve the schema</li>
<li>Allow the system to create tables</li>
<li>Wait for validation and deployment (this may take several minutes)</li>
</ul>
<p>During deployment, the system:</p>
<ul>
<li>Runs pre-checks</li>
<li>Creates tables in Dataverse</li>
<li>Establishes relationships</li>
<li>Publishes the schema</li>
</ul>
<h5>Step 4: Create a Solution in Power Apps</h5>
<p>To manage and deploy your components efficiently:</p>
<ol>
<li>Go to Power Apps</li>
<li>Navigate to <strong>Solutions</strong></li>
<li>Create a new solution</li>
<li>Define:
<ul>
<li>Publisher</li>
<li>Prefix (e.g., <code>PW</code>)</li>
</ul>
</li>
</ol>
<h5>Why Use Solutions?</h5>
<p>Solutions help you:</p>
<ul>
<li>Move assets from Dev → QA → Production</li>
<li>Package tables, apps, and components</li>
<li>Maintain version control</li>
</ul>
<h5>Step 5: Add Tables to Your Solution</h5>
<p>After deployment:</p>
<ul>
<li>Add existing tables using your prefix (e.g., <code>PW</code>)</li>
<li>Include all related objects</li>
</ul>
<p>This ensures everything is centrally managed.</p>
<h5>Step 6: Build a Model-Driven App</h5>
<p>To visualize and interact with your data:</p>
<ol>
<li>Create a <strong>Model-Driven App</strong></li>
<li>Add pages using Dataverse tables</li>
<li>Include:
<ul>
<li>Newly created tables</li>
<li>Contact table</li>
</ul>
</li>
</ol>
<p>This app acts as a quick interface to validate your data model.</p>
<h5>Step 7: Populate Sample Data</h5>
<p>To test your model, generate mock data using:</p>
<pre><code>/add sample data
</code></pre>
<h5>Configuration Options:</h5>
<ul>
<li>Select tables (or all tables)</li>
<li>Define number of records (e.g., 5 per table)</li>
</ul>
<h5>What Happens Next:</h5>
<ul>
<li>The system validates prerequisites</li>
<li>Inserts sample records</li>
<li>Links related data automatically</li>
</ul>
<p>You’ll start seeing:</p>
<ul>
<li>Service categories populated</li>
<li>Service requests generated</li>
<li>Relationships reflected in real time</li>
</ul>
<h5>Step 8: Validate Data in Your App</h5>
<p>Open your model-driven app and:</p>
<ul>
<li>Refresh tables</li>
<li>Verify records are being populated</li>
<li>Check relationships between entities</li>
</ul>
<p>This confirms your data model is functioning correctly.</p>
<h5>Important Best Practices</h5>
<h5>1. Backup Regularly</h5>
<p>At each stage:</p>
<ul>
<li>Export your solution</li>
<li>Save a ZIP backup</li>
<li>Use source control if possible</li>
</ul>
<h5>2. Validate Data Types Early</h5>
<p>Incorrect data types can cause issues later when integrating APIs or Power BI.</p>
<h5>3. Use Meaningful Naming Conventions</h5>
<p>Consistent prefixes and naming improve maintainability.</p>
<h5>4. Monitor Automated Processes</h5>
<p>The system may retry failed steps automatically review logs when needed.</p>
<h5>What’s Next?</h5>
<p>At this point:</p>
<ul>
<li>Your data model is complete</li>
<li>Tables and relationships are deployed</li>
<li>Sample data is available</li>
</ul>
<p>However, your Power Pages site is still not connected to this data.</p>
<h5>Upcoming Step:</h5>
<p>In the next phase, you will:</p>
<ul>
<li>Bind your data model to your website</li>
<li>Use APIs (such as Web API)</li>
<li>Replace mock UI with real, dynamic data</li>
</ul>
<h5>Conclusion</h5>
<p>Creating a data model in Power Pages using Dataverse is a powerful way to accelerate development while maintaining flexibility and scalability. By leveraging automated tools and customizing where needed, you can quickly move from a static website to a fully data-driven application.</p>
<p>This foundational step sets you up for:</p>
<ul>
<li>Real-time data interaction</li>
<li>Integration with Power BI</li>
<li>Enterprise-grade application development</li>
</ul>
<p>The post <a href="https://databear.com/power-pages-data-model-guide/">Power Pages Data Model Step-by-Step Guide</a> appeared first on <a href="https://databear.com">Data Bear</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Power BI Organizational Themes Guide</title>
		<link>https://databear.com/power-bi-organizational-themes/</link>
		
		<dc:creator><![CDATA[Boniface Muchendu]]></dc:creator>
		<pubDate>Tue, 12 May 2026 16:33:01 +0000</pubDate>
				<category><![CDATA[Power BI]]></category>
		<guid isPermaLink="false">https://databear.com/?p=50772</guid>

					<description><![CDATA[<p>Power BI Organizational Themes make it easier to standardize report branding across your organization. Instead of manually sharing JSON theme files through email or SharePoint, administrators can centrally manage themes in Microsoft Fabric and Power BI, ensuring every report follows the same visual style and branding guidelines. Fortunately, Microsoft introduced a powerful new preview feature [&#8230;]</p>
<p>The post <a href="https://databear.com/power-bi-organizational-themes/">Power BI Organizational Themes Guide</a> appeared first on <a href="https://databear.com">Data Bear</a>.</p>
]]></description>
										<content:encoded><![CDATA[<div class="" data-turn-id-container="request-WEB:4c99d8cc-08fe-485a-9a32-586c1e39016c-39" data-is-intersecting="true">
<div class="relative w-full overflow-visible">
<section class="text-token-text-primary w-full focus:outline-none [--shadow-height:45px] has-data-writing-block:pointer-events-none has-data-writing-block:-mt-(--shadow-height) has-data-writing-block:pt-(--shadow-height) [&amp;:has([data-writing-block])&gt;*]:pointer-events-auto R6Vx5W_threadScrollVars scroll-mb-[calc(var(--scroll-root-safe-area-inset-bottom,0px)+var(--thread-response-height))] scroll-mt-[calc(var(--header-height)+min(200px,max(70px,20svh)))]" dir="auto" data-turn-id="request-WEB:4c99d8cc-08fe-485a-9a32-586c1e39016c-39" data-turn-id-container="request-WEB:4c99d8cc-08fe-485a-9a32-586c1e39016c-39" data-testid="conversation-turn-8" data-scroll-anchor="false" data-turn="assistant">
<div class="text-base my-auto mx-auto pb-10 [--thread-content-margin:var(--thread-content-margin-xs,calc(var(--spacing)*4))] @w-sm/main:[--thread-content-margin:var(--thread-content-margin-sm,calc(var(--spacing)*6))] @w-lg/main:[--thread-content-margin:var(--thread-content-margin-lg,calc(var(--spacing)*16))] px-(--thread-content-margin)">
<div class="[--thread-content-max-width:40rem] @w-lg/main:[--thread-content-max-width:48rem] mx-auto max-w-(--thread-content-max-width) flex-1 group/turn-messages focus-visible:outline-hidden relative flex w-full min-w-0 flex-col agent-turn">
<div class="flex max-w-full flex-col gap-4 grow">
<div class="min-h-8 text-message relative flex w-full flex-col items-end gap-2 text-start break-words whitespace-normal outline-none keyboard-focused:focus-ring [.text-message+&amp;]:mt-1" dir="auto" tabindex="0" data-message-author-role="assistant" data-message-id="ad5ac820-86e3-4cbc-ba81-10b8031764c1" data-message-model-slug="gpt-5-5" data-turn-start-message="true">
<div class="flex w-full flex-col gap-1 empty:hidden">
<div class="markdown prose dark:prose-invert wrap-break-word w-full dark markdown-new-styling">
<p data-start="330" data-end="660" data-is-last-node="" data-is-only-node="">Power BI Organizational Themes make it easier to standardize report branding across your organization. Instead of manually sharing JSON theme files through email or SharePoint, administrators can centrally manage themes in Microsoft Fabric and Power BI, ensuring every report follows the same visual style and branding guidelines.</p>
</div>
</div>
</div>
</div>
<div class="z-0 flex min-h-[46px] justify-start"><span style="font-size: 16px;">Fortunately, Microsoft introduced a powerful new preview feature in Power BI and Microsoft Fabric called </span><strong style="font-size: 16px;">Organizational Themes</strong><span style="font-size: 16px;">.</span></div>
</div>
</div>
</section>
</div>
</div>
<p>This feature allows Power BI administrators to centrally manage report themes and make them available to every report developer in the organization. Even better, these themes can now be applied to <strong>Copilot-generated reports</strong>, ensuring consistent branding across manually created and AI-generated reports alike.</p>
<p>In this article, we’ll walk through:</p>
<ul>
<li>What Organizational Themes are</li>
<li>Why they matter</li>
<li>How to configure them</li>
<li>How to use them in Power BI Desktop and Power BI Service</li>
<li>How they integrate with Copilot</li>
<li>Best practices for enterprise branding</li>
</ul>
<p>If you want to improve your Power BI skills even further, check out this Power BI training resource from <a href="https://databear.com/power-bi-training/?utm_source=chatgpt.com">DataBear Power BI Training</a>.</p>
<h5>What Are Organizational Themes in Power BI?<img loading="lazy" decoding="async" class="aligncenter wp-image-50781 size-full" src="https://databear.com/wp-content/uploads/2026/05/Screenshot-2026-05-12-193118.png" alt="What Are Organizational Themes in Power BI?" width="727" height="564" srcset="https://databear.com/wp-content/uploads/2026/05/Screenshot-2026-05-12-193118.png 727w, https://databear.com/wp-content/uploads/2026/05/Screenshot-2026-05-12-193118-300x233.png 300w, https://databear.com/wp-content/uploads/2026/05/Screenshot-2026-05-12-193118-150x116.png 150w" sizes="(max-width: 727px) 100vw, 727px" /></h5>
<p>Organizational Themes are centrally managed Power BI theme files that administrators can publish through the Power BI Admin Portal.</p>
<p>Instead of sending JSON files manually between developers, organizations can now:</p>
<ul>
<li>Store approved themes centrally</li>
<li>Make themes available across the organization</li>
<li>Standardize report branding</li>
<li>Ensure visual consistency</li>
<li>Apply themes to Copilot-generated reports</li>
</ul>
<p>This feature significantly improves governance and branding consistency in enterprise Power BI environments.</p>
<h5>Why Organizational Themes Matter</h5>
<p>Before this feature existed, many organizations relied on:</p>
<ul>
<li>Email attachments</li>
<li>Shared folders</li>
<li>SharePoint repositories</li>
<li>Teams chats</li>
<li>Manual imports</li>
</ul>
<p>This created several common problems:</p>
<ul>
<li>Developers used outdated theme files</li>
<li>Reports lacked visual consistency</li>
<li>Branding standards were difficult to enforce</li>
<li>New team members struggled to find the correct theme</li>
</ul>
<p>Organizational Themes solve these issues by creating a <strong>single source of truth</strong> for report styling.</p>
<h5>How to Add an Organizational Theme in Power BI</h5>
<p>To configure Organizational Themes, you need access to the Power BI or Microsoft Fabric Admin Portal.</p>
<h5>Step 1: Open the Admin Portal</h5>
<p>Inside Microsoft Fabric or Power BI Service:</p>
<ol>
<li>Navigate to the <strong>Admin Portal</strong></li>
<li>Locate <strong>Organizational Themes</strong></li>
</ol>
<p>This section allows administrators to upload and manage theme files centrally.</p>
<h5>Step 2: Upload Your Theme JSON File</h5>
<p>Once inside the Organizational Themes section:</p>
<ol>
<li>Click <strong>Add Organizational Theme</strong></li>
<li>Browse for your Power BI JSON theme file</li>
<li>Upload the file</li>
</ol>
<p>The uploaded JSON file becomes available for organizational use.</p>
<h5>Step 3: Add a Description</h5>
<p>Provide a clear description for the theme.</p>
<p>For example:</p>
<ul>
<li>Corporate Branding Theme</li>
<li>Executive Dashboard Theme</li>
<li>Finance Department Theme</li>
<li>Dark Mode Reporting Theme</li>
</ul>
<p>This helps developers identify the correct theme quickly.</p>
<h5>Enabling Organizational Themes for Copilot</h5>
<p>One of the most exciting additions is the ability to use Organizational Themes with Power BI Copilot.</p>
<p>When uploading the theme, administrators can enable a toggle that allows:</p>
<ul>
<li>Copilot-generated reports</li>
<li>AI-created report pages</li>
<li>Automated visual layouts</li>
</ul>
<p>to automatically inherit the organization&#8217;s branding.</p>
<p>This ensures AI-generated reports align with:</p>
<ul>
<li>Corporate color palettes</li>
<li>Typography standards</li>
<li>Visual formatting guidelines</li>
</ul>
<p>Without this feature, Copilot-generated reports may look inconsistent with the rest of the organization’s reporting ecosystem.</p>
<h5>Important: Enable the Theme Gallery</h5>
<p>After uploading the theme, there is one critical step many users miss.</p>
<p>By default, the uploaded theme is initially disabled.</p>
<p>To activate it:</p>
<ol>
<li>Click the ellipsis (<strong>&#8230;</strong>) next to the theme</li>
<li>Select <strong>Enable for Theme Gallery</strong></li>
</ol>
<p>Once enabled, the theme becomes visible to report developers throughout the organization.</p>
<h5>Using Organizational Themes in Power BI Desktop</h5>
<p>After enabling the theme, developers can immediately access it inside Power BI Desktop.</p>
<h5>How to Apply the Theme</h5>
<p>Inside Power BI Desktop:</p>
<ol>
<li>Open your report</li>
<li>Navigate to <strong>View</strong></li>
<li>Select <strong>Themes</strong></li>
<li>Locate <strong>Organizational Themes</strong></li>
<li>Choose the uploaded theme</li>
</ol>
<p>The report instantly adopts the organization’s branding.</p>
<p>This includes:</p>
<ul>
<li>Colors</li>
<li>Fonts</li>
<li>Visual styles</li>
<li>Background settings</li>
<li>Formatting standards</li>
</ul>
<p>One impressive aspect of this feature is that Power BI Desktop updates dynamically without needing to restart the application.</p>
<h5>Using Organizational Themes in Power BI Service</h5>
<p>Organizational Themes also work directly inside Power BI Service.</p>
<h5>Applying Themes in Existing Dashboards</h5>
<p>To apply a theme in the Service:</p>
<ol>
<li>Open your dashboard or report</li>
<li>Click <strong>Edit</strong></li>
<li>Navigate to <strong>View &gt; Theme</strong></li>
<li>Select your Organizational Theme</li>
</ol>
<p>The report updates instantly with the centralized branding.</p>
<p>This is particularly useful for:</p>
<ul>
<li>Executive dashboards</li>
<li>Shared workspaces</li>
<li>Departmental reporting</li>
<li>Enterprise analytics portals</li>
</ul>
<h5>Using Organizational Themes with Copilot</h5>
<p>The integration with Copilot is where this feature becomes especially powerful.</p>
<h5>Creating a Copilot-Generated Report</h5>
<p>Here’s how it works:</p>
<ol>
<li>Open a semantic model</li>
<li>Click <strong>Create Report</strong></li>
<li>Launch Copilot</li>
<li>Enter a prompt such as:
<ul>
<li>“Create a sales performance versus targets report”</li>
</ul>
</li>
</ol>
<p>Copilot generates:</p>
<ul>
<li>Visuals</li>
<li>Layouts</li>
<li>KPIs</li>
<li>Charts</li>
<li>Report pages</li>
</ul>
<p>And now, thanks to Organizational Themes, those generated reports automatically follow your organization’s branding guidelines.</p>
<p>This dramatically reduces cleanup work after Copilot generates a report.</p>
<h5>Common Issue: Transparency Settings</h5>
<p>One issue highlighted during testing involved transparency settings not behaving as expected.</p>
<p>In some cases:</p>
<ul>
<li>Visual backgrounds appeared partially transparent</li>
<li>Formatting differed slightly from the original theme</li>
</ul>
<p>Fortunately, this can usually be corrected by:</p>
<ul>
<li>Resetting the theme to default</li>
<li>Reapplying the organizational theme</li>
<li>Adjusting transparency manually</li>
</ul>
<p>Since Organizational Themes are still in preview, occasional inconsistencies are expected.</p>
<h5>Benefits of Organizational Themes</h5>
<h5>1. Centralized Governance</h5>
<p>Administrators maintain full control over approved themes.</p>
<h5>2. Consistent Branding</h5>
<p>Every report follows the same visual standards.</p>
<h5>3. Faster Report Development</h5>
<p>Developers no longer waste time searching for theme files.</p>
<h5>4. Improved Copilot Integration</h5>
<p>AI-generated reports automatically match company branding.</p>
<h5>5. Better User Experience</h5>
<p>Executives and stakeholders see a consistent reporting environment.</p>
<h5>Best Practices for Organizational Themes</h5>
<p>To maximize the value of this feature:</p>
<h5>Standardize Naming Conventions</h5>
<p>Use clear names such as:</p>
<ul>
<li>Corporate Theme v1</li>
<li>Executive Reporting Theme</li>
<li>Sales Analytics Theme</li>
</ul>
<h5>Maintain Version Control</h5>
<p>Keep backup copies of your JSON files in source control systems like:</p>
<ul>
<li>GitHub</li>
<li>Azure DevOps</li>
<li>SharePoint</li>
</ul>
<h5>Test Themes Thoroughly</h5>
<p>Validate themes across:</p>
<ul>
<li>Desktop</li>
<li>Service</li>
<li>Mobile layouts</li>
<li>Copilot-generated reports</li>
</ul>
<h5>Document Branding Standards</h5>
<p>Create internal documentation covering:</p>
<ul>
<li>Color palettes</li>
<li>Typography</li>
<li>Approved visuals</li>
<li>Accessibility requirements</li>
</ul>
<h5>Organizational Themes and Enterprise BI Strategy</h5>
<p>This feature may seem small initially, but it represents a major advancement in enterprise Power BI governance.</p>
<p>As organizations scale their BI environments:</p>
<ul>
<li>Branding consistency becomes critical</li>
<li>Self-service BI expands rapidly</li>
<li>AI-generated reports become more common</li>
</ul>
<p>Organizational Themes help bridge the gap between:</p>
<ul>
<li>Flexibility for developers</li>
<li>Governance for administrators</li>
<li>Consistency for stakeholders</li>
</ul>
<h5>Final Thoughts</h5>
<p>Power BI Organizational Themes provide a smarter and more scalable way to manage branding across reports and dashboards.</p>
<p>Instead of manually distributing JSON files, organizations can now:</p>
<ul>
<li>Centralize theme management</li>
<li>Standardize report design</li>
<li>Streamline developer workflows</li>
<li>Enhance Copilot-generated reports</li>
</ul>
<p>For teams heavily invested in Power BI and Microsoft Fabric, this feature can significantly improve governance, efficiency, and visual consistency.</p>
<p>As Microsoft continues enhancing Copilot and AI-assisted analytics, Organizational Themes will likely become an essential part of modern Power BI development workflows.</p>
<h5>Learn More About Power BI</h5>
<p>If you&#8217;re looking to improve your Power BI development skills, dashboard design techniques, and reporting strategies, explore this excellent training resource from <a href="https://databear.com/power-bi-training/?utm_source=chatgpt.com">DataBear Power BI Training</a>.</p>
<p>The post <a href="https://databear.com/power-bi-organizational-themes/">Power BI Organizational Themes Guide</a> appeared first on <a href="https://databear.com">Data Bear</a>.</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
