<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Aykan KÖMÜRCÜ</title>
    <description>The latest articles on DEV Community by Aykan KÖMÜRCÜ (@aykankomurcu).</description>
    <link>https://dev.to/aykankomurcu</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4051898%2Fc3e5b2d4-88b5-45e9-8753-dbd22a591544.jpg</url>
      <title>DEV Community: Aykan KÖMÜRCÜ</title>
      <link>https://dev.to/aykankomurcu</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/aykankomurcu"/>
    <language>en</language>
    <item>
      <title>Publishing an Electron AI App to the Microsoft Store: Everything I Got Wrong</title>
      <dc:creator>Aykan KÖMÜRCÜ</dc:creator>
      <pubDate>Thu, 06 Aug 2026 16:35:47 +0000</pubDate>
      <link>https://dev.to/aykankomurcu/publishing-an-electron-ai-app-to-the-microsoft-store-everything-i-got-wrong-3jbb</link>
      <guid>https://dev.to/aykankomurcu/publishing-an-electron-ai-app-to-the-microsoft-store-everything-i-got-wrong-3jbb</guid>
      <description>&lt;p&gt;I published a Windows desktop AI assistant to the Microsoft Store as a solo developer. It took two submissions, one rejection and a handful of undocumented surprises.&lt;/p&gt;

&lt;p&gt;This is the list I wish I had found before I started.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the Store at all
&lt;/h2&gt;

&lt;p&gt;I had a working NSIS installer and a payment flow running through an external provider. The Store was not obviously worth the trouble. Two things changed my mind.&lt;/p&gt;

&lt;p&gt;Microsoft signs the package for you. Without the Store, a Windows SmartScreen warning greets every single user on first launch, and the only way around it is a paid code signing certificate. For a solo developer shipping a privacy-focused product, telling users to click through a security warning is a bad first impression.&lt;/p&gt;

&lt;p&gt;The second reason is the 2026 policy allowing non-game apps to use their own payment systems. My entire purchase flow lives outside the Store and none of it had to change.&lt;/p&gt;

&lt;h2&gt;
  
  
  Surprise 1: electron-builder ignores your icon for appx
&lt;/h2&gt;

&lt;p&gt;My &lt;code&gt;package.json&lt;/code&gt; had a perfectly good &lt;code&gt;build/icon.ico&lt;/code&gt;. NSIS used it. The appx target did not.&lt;/p&gt;

&lt;p&gt;Appx packages need PNG assets at specific sizes, and electron-builder will not generate them from your ico. You need a &lt;code&gt;build/appx/&lt;/code&gt; folder containing at minimum:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Square44x44Logo.png&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Square150x150Logo.png&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;StoreLogo.png&lt;/code&gt; (50x50)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Wide310x150Logo.png&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Miss these and the build succeeds but your app shows up with a blank tile.&lt;/p&gt;

&lt;h2&gt;
  
  
  Surprise 2: the runFullTrust justification field silently truncates
&lt;/h2&gt;

&lt;p&gt;If your Electron app touches the filesystem, you declare &lt;code&gt;runFullTrust&lt;/code&gt; and Partner Center asks you to justify it in a text box.&lt;/p&gt;

&lt;p&gt;That box has a very low character limit and it does not tell you what it is. Long explanations get cut off without warning. Write two sentences, not two paragraphs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Surprise 3: package size
&lt;/h2&gt;

&lt;p&gt;My first appx came out at 526 MB. My second one, functionally identical, was 191 MB.&lt;/p&gt;

&lt;p&gt;The culprit was the &lt;code&gt;files&lt;/code&gt; array in my electron-builder config. &lt;code&gt;**/*&lt;/code&gt; means everything, including development dependencies you never ship. Audit that array before you upload half a gigabyte.&lt;/p&gt;

&lt;h2&gt;
  
  
  The rejection: policy 11.16
&lt;/h2&gt;

&lt;p&gt;My first submission was rejected. One reason, nothing else.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Policy 11.16, Live Generative AI Content.&lt;/strong&gt; If your app produces generative AI output, you must give users a way to report inappropriate content, in the app, visible, one click away.&lt;/p&gt;

&lt;p&gt;I had spent months on the privacy architecture. Zero data retention, no file uploads, local processing, provider-side data collection disabled. I had thought carefully about where data goes and not at all about what happens when the model says something wrong.&lt;/p&gt;

&lt;p&gt;The fix took half a day:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A flag button under every assistant message, next to copy and read aloud&lt;/li&gt;
&lt;li&gt;A modal where the user writes what went wrong&lt;/li&gt;
&lt;li&gt;An endpoint that writes the report to the database and sends a notification email&lt;/li&gt;
&lt;li&gt;No credit cost, because reporting a problem should never cost the user anything&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Resubmitted. Approved in 24 hours.&lt;/p&gt;

&lt;h2&gt;
  
  
  Surprise 4: your app will pass certification and still be broken
&lt;/h2&gt;

&lt;p&gt;This is the one that actually hurt.&lt;/p&gt;

&lt;p&gt;My server spawned a child process like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;node&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dist/index.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That works on my machine. Node.js is installed on my machine. It is not installed on my users' machines.&lt;/p&gt;

&lt;p&gt;The app launched fine. The UI rendered. Nothing crashed. Certification passed. And every single user who typed a message got a sixty second wait followed by a generic error, because the child process never started.&lt;/p&gt;

&lt;p&gt;The fix is one line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;execPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dist/index.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;ELECTRON_RUN_AS_NODE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Electron ships its own Node runtime. Use it instead of hoping the user has one.&lt;/p&gt;

&lt;p&gt;To verify the fix I renamed my Node installation folder, which makes the machine behave like a clean user machine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Rename-Item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"C:\Program Files\nodejs"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"C:\Program Files\nodejs_off"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run your packaged app in that state before every single submission. Five minutes of testing against two days of certification turnaround.&lt;/p&gt;

&lt;h2&gt;
  
  
  What certification actually checks
&lt;/h2&gt;

&lt;p&gt;Store certification is a compliance review, not a functional one. It verifies signing, manifest validity, declared capabilities, policy compliance and that the app does not crash on launch.&lt;/p&gt;

&lt;p&gt;It does not verify that your app works. That is entirely on you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus: IARC ratings transfer
&lt;/h2&gt;

&lt;p&gt;Filling out the age rating questionnaire produces an IARC Global Rating ID. That ID works across other IARC-licensed stores without redoing the survey. If you add a feature that would change your answers, you redo it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The short version
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Generate appx PNG assets manually&lt;/li&gt;
&lt;li&gt;Keep the runFullTrust justification short&lt;/li&gt;
&lt;li&gt;Audit your &lt;code&gt;files&lt;/code&gt; array&lt;/li&gt;
&lt;li&gt;If your app generates AI content, ship a reporting mechanism before you submit&lt;/li&gt;
&lt;li&gt;Never assume the user has your development dependencies installed&lt;/li&gt;
&lt;li&gt;Test the packaged build in a clean environment every time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The product is &lt;a href="https://neondijital.com/urunler/neoncore" rel="noopener noreferrer"&gt;NeonCore&lt;/a&gt;, a Windows AI assistant that processes documents without uploading them anywhere. Built solo.&lt;/p&gt;

</description>
      <category>electron</category>
      <category>microsoftstore</category>
      <category>ai</category>
      <category>windows</category>
    </item>
    <item>
      <title>I built FHIR R4 support into a local-first desktop AI assistant. Here is what I learned.</title>
      <dc:creator>Aykan KÖMÜRCÜ</dc:creator>
      <pubDate>Tue, 28 Jul 2026 19:06:04 +0000</pubDate>
      <link>https://dev.to/aykankomurcu/i-built-fhir-r4-support-into-a-local-first-desktop-ai-assistant-here-is-what-i-learned-31k4</link>
      <guid>https://dev.to/aykankomurcu/i-built-fhir-r4-support-into-a-local-first-desktop-ai-assistant-here-is-what-i-learned-31k4</guid>
      <description>&lt;p&gt;Healthcare software has a problem that most AI tooling ignores completely. The data cannot leave the building.&lt;/p&gt;

&lt;p&gt;Not "should not." Cannot. A hospital that ships patient records to a third party API is not making a tradeoff between convenience and privacy. It is breaking the law in most jurisdictions, and it is breaking the trust of every person whose record is in that system.&lt;/p&gt;

&lt;p&gt;I build NeonCore, a Windows desktop AI assistant that parses documents entirely on the machine it runs on. No cloud upload, no data retention. A few months ago I started getting the same question from people in the health sector: can it read our patient records?&lt;/p&gt;

&lt;p&gt;The honest answer was no. So I built it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why FHIR and not something simpler
&lt;/h2&gt;

&lt;p&gt;FHIR R4 is the standard most modern hospital systems already speak. If you want to read patient data without asking an institution to change anything about their infrastructure, FHIR is the door that is already open.&lt;/p&gt;

&lt;p&gt;The alternative would have been asking hospitals to export data into some format my app understands. That is a non-starter. Every export step is a copy of sensitive data sitting somewhere it should not be, and no IT department will approve it.&lt;/p&gt;

&lt;p&gt;So the design constraint was simple: talk to the FHIR server the institution already runs, on their own network, and never write anything back out.&lt;/p&gt;

&lt;h2&gt;
  
  
  The architecture
&lt;/h2&gt;

&lt;p&gt;Three pieces:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. A local FHIR client.&lt;/strong&gt; NeonCore connects to the institution's FHIR R4 endpoint over the local network. The endpoint address is configured by the institution, not by me. I never see it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Query tools exposed to the model.&lt;/strong&gt; Two functions, &lt;code&gt;fhir_sorgula&lt;/code&gt; for searching resources and &lt;code&gt;fhir_kayit_oku&lt;/code&gt; for reading a specific record by ID. The model calls these the same way it would call any other tool.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. On-device reasoning.&lt;/strong&gt; The record comes back, gets reasoned over locally, and the answer appears on screen. Nothing is written to disk unless the user explicitly saves it. Nothing goes to a cloud endpoint.&lt;/p&gt;

&lt;p&gt;The important part is what is missing from that list. There is no sync layer. No telemetry on query contents. No caching of patient data between sessions.&lt;/p&gt;

&lt;h2&gt;
  
  
  What was harder than expected
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;FHIR is a large standard.&lt;/strong&gt; R4 defines well over a hundred resource types. I did not implement all of them and I do not intend to. Patient, Observation, Condition, MedicationRequest and DocumentReference cover the overwhelming majority of what a clinician actually asks about. Scope discipline mattered more than completeness.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Authentication varies wildly.&lt;/strong&gt; Some institutions use SMART on FHIR, some use plain bearer tokens, some sit behind a network boundary and use nothing at all. I ended up supporting a configurable auth layer rather than assuming any one flow.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Search parameters are inconsistent in practice.&lt;/strong&gt; The spec says one thing. Individual server implementations do their own interpretation. Defensive parsing was not optional.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Explaining it is harder than building it.&lt;/strong&gt; I spent months describing "on-device processing with zero data retention" and watching people nod politely. The moment I changed the sentence to "patient records never leave the institution," people understood immediately. Same architecture, different words.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I would tell someone building in this space
&lt;/h2&gt;

&lt;p&gt;Do not treat privacy as a feature you add. Treat it as a constraint that removes options. Once you accept that data cannot leave the machine, a lot of architectural decisions make themselves. You stop reaching for the cloud service that would have been easier, because it is simply not available to you.&lt;/p&gt;

&lt;p&gt;That constraint is also the entire product. There are plenty of AI assistants that can read a document. There are very few that a hospital's compliance officer will approve.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this is going
&lt;/h2&gt;

&lt;p&gt;FHIR support is live in NeonCore now. Next on the list is expanding resource coverage based on what people actually ask for rather than what the spec suggests, and better handling for institutions running older FHIR versions.&lt;/p&gt;

&lt;p&gt;If you work in health IT and want to poke holes in this, I would genuinely like to hear it. The failure modes I have not thought of are worth more to me than the ones I have.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://neondijital.com/blog/fhir-r4-local-first-ai" rel="noopener noreferrer"&gt;https://neondijital.com/blog/fhir-r4-local-first-ai&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;NeonCore is at &lt;a href="https://neondijital.com" rel="noopener noreferrer"&gt;neondijital.com&lt;/a&gt;. Built and maintained solo, self funded, from Izmir.&lt;/p&gt;

</description>
      <category>healthcare</category>
      <category>ai</category>
      <category>electron</category>
      <category>privacy</category>
    </item>
  </channel>
</rss>
