<?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>Development Archives - Mobile USTP MKL</title>
	<atom:link href="https://mobile.fhstp.ac.at/category/development/feed/" rel="self" type="application/rss+xml" />
	<link>https://mobile.fhstp.ac.at/category/development/</link>
	<description>Die &#34;Mobile Forschungsgruppe&#34; der USTP, sie  sammelt hier alles zu den Themen Design, UX und Entwicklung mobiler Applikationen</description>
	<lastBuildDate>Thu, 17 Sep 2026 09:37:10 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	

<image>
	<url>https://mobile.fhstp.ac.at/wp-content/uploads/2025/03/icon-120x120.webp</url>
	<title>Development Archives - Mobile USTP MKL</title>
	<link>https://mobile.fhstp.ac.at/category/development/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>OnTime V2</title>
		<link>https://mobile.fhstp.ac.at/allgemein/ontime-v2/</link>
					<comments>https://mobile.fhstp.ac.at/allgemein/ontime-v2/#respond</comments>
		
		<dc:creator><![CDATA[Sander Hahn]]></dc:creator>
		<pubDate>Thu, 17 Sep 2026 09:37:09 +0000</pubDate>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[Cross Plattform]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[Projekte]]></category>
		<category><![CDATA[Webdevelopment]]></category>
		<category><![CDATA[database]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[React]]></category>
		<category><![CDATA[Rust]]></category>
		<category><![CDATA[supabase]]></category>
		<category><![CDATA[Typescript]]></category>
		<guid isPermaLink="false">https://mobile.fhstp.ac.at/?p=15971</guid>

					<description><![CDATA[<p>OnTime started because I didn&#8217;t want to pay for a time tracker. Version one only had that traccker and one Tauri 2 codebase that shipped to the web, Windows and Android. V2 lives in a new repository, but it is of course built on Version one. The tracker is still at its core and around <a class="read-more" href="https://mobile.fhstp.ac.at/allgemein/ontime-v2/">[...]</a></p>
<p>The post <a href="https://mobile.fhstp.ac.at/allgemein/ontime-v2/">OnTime V2</a> appeared first on <a href="https://mobile.fhstp.ac.at">Mobile USTP MKL</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">OnTime started because I didn&#8217;t want to pay for a time tracker. Version one only had that traccker and one Tauri 2 codebase that shipped to the web, Windows and Android.</p>



<p class="wp-block-paragraph">V2 lives in a new repository, but it is of course built on Version one. The tracker is still at its core and around it, OnTime now handles teams, invoices and payments.</p>



<h2 class="wp-block-heading">What changed</h2>



<p class="wp-block-paragraph">In V1, one person tracked their own time but in V2, everything happens inside <strong>workspaces</strong>. A workspace can consist of just you or a whole team and every member has one of four roles: owner, admin, manager or member.</p>



<figure class="wp-block-image size-large"><img fetchpriority="high" decoding="async" width="1540" height="800" src="https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/OnTimeV2-Calendar-Dark-1540x800.png" alt="" class="wp-image-15973" srcset="https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/OnTimeV2-Calendar-Dark-1540x800.png 1540w, https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/OnTimeV2-Calendar-Dark-770x400.png 770w" sizes="(max-width: 1540px) 100vw, 1540px" /></figure>



<p class="wp-block-paragraph">But the basics are of course still there: a timer, manual entries and clients, projects and tasks with their own detail pages. The calendar is now shared and even updates live across devices. Projects can have budgets that send a notification when they cross a threshold. The whole app is in English and German and on mobile it works offline thanks to a persisted query cache.</p>



<figure class="wp-block-image size-large"><img decoding="async" width="1540" height="800" src="https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/OnTimeV2-Overview-Dark-1540x800.png" alt="" class="wp-image-15974" srcset="https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/OnTimeV2-Overview-Dark-1540x800.png 1540w, https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/OnTimeV2-Overview-Dark-770x400.png 770w" sizes="(max-width: 1540px) 100vw, 1540px" /></figure>



<h2 class="wp-block-heading">Invoices and payments<br></h2>



<p class="wp-block-paragraph">This is where V2 changes the most from its previous version. Billable time becomes an invoice and when you send it, an Edge Function renders it as a PDF and <strong>freezes</strong> it. If you edit the underlying time entries later, the document the client already received doesn&#8217;t change.</p>



<p class="wp-block-paragraph">Additionally, OnTime connects to your bank through <strong>Enable Banking</strong>. The connection is read-only by design and you bring your own credentials, which are stored encrypted in Supabase Vault. A scheduled pg_cron job pulls in transactions and matches them against open invoices. When a match is confident, the invoice is marked paid automatically. Everything else waits in a queue for one-click review.<br></p>



<h2 class="wp-block-heading">Database changes</h2>



<p class="wp-block-paragraph">V1&#8217;s database only had to serve one person tracking their own hours. V2 needed a real data model, so I didn&#8217;t patch the old schema and started from the start.</p>



<p class="wp-block-paragraph">As said before, <strong>Everything belongs to a workspace</strong>: Clients, projects, tasks, time entries and invoices all hang off a workspace and every row knows which workspace it belongs to. That one change is what makes teams possible. It&#8217;s also what the security model is built on.</p>



<p class="wp-block-paragraph">Also, every table has row-level security policies that check the caller&#8217;s workspace and role before returning a single row. Views run with <code>security_invoker</code>, so they apply the permissions of the person querying them instead of quietly bypassing them. Owners, admins, managers and members all hit the same tables and get different answers. Since the frontend isn&#8217;t trusted to enforce any of this, pgTAP suites test the rules against a real database.</p>



<p class="wp-block-paragraph">Another security measure was to add a timestamp to entries when they get deleted. Now they are moved to a trash view, where they can be restored. A pg_cron job purges them for good once they&#8217;ve been in the trash long enough, so nobody has to clean up by hand.</p>



<p class="wp-block-paragraph">An invoice can&#8217;t point at time entries and hourly rates, because those can change or be edited. When an invoice is sent, it stores a JSONB snapshot of everything it was built from and the PDF is frozen alongside it. Rates also keep a history, so billing a project in March uses March&#8217;s rate even if it went up in June. Invoice numbers are generated per workspace and restart each year.</p>



<p class="wp-block-paragraph">pg_cron also triggers the bank sync so that transactions come in on a schedule, get matched against open invoices and confident matches mark the invoice as paid. The bank credentials never sit in a plain column and are encrypted in Supabase Vault.</p>



<p class="wp-block-paragraph">The shared calendar and the notifications subscribe to database changes through Supabase Realtime. When someone stops a timer on their phone, the entry shows up on everyone else&#8217;s desktop without a refresh.</p>



<h2 class="wp-block-heading">Testing</h2>



<p class="wp-block-paragraph">Tests run in three layers:</p>



<ul class="wp-block-list">
<li><strong>Vitest</strong> for units and components</li>



<li><strong>Playwright</strong> end-to-end tests against a preview build</li>



<li><strong>pgTAP</strong> for the security rules</li>
</ul>



<p class="wp-block-paragraph">Unit and end-to-end coverage are combined into one number and uploaded to Codecov on every CI run. Right now I have about 40% coverage but that will still be improved in later versions.</p>



<figure class="wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-1 is-layout-flex wp-block-gallery-is-layout-flex">
<figure class="wp-block-image size-large"><img decoding="async" width="1540" height="800" data-id="15980" src="https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/OnTimeV2-Calendar-Dark-1-1540x800.png" alt="" class="wp-image-15980" srcset="https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/OnTimeV2-Calendar-Dark-1-1540x800.png 1540w, https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/OnTimeV2-Calendar-Dark-1-770x400.png 770w" sizes="(max-width: 1540px) 100vw, 1540px" /></figure>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1540" height="800" data-id="15978" src="https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/OnTimeV2-Calendar-Light-1540x800.png" alt="" class="wp-image-15978" srcset="https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/OnTimeV2-Calendar-Light-1540x800.png 1540w, https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/OnTimeV2-Calendar-Light-770x400.png 770w" sizes="auto, (max-width: 1540px) 100vw, 1540px" /></figure>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1540" height="800" data-id="15983" src="https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/OnTimeV2-Invoice-Detail-Dark-1540x800.png" alt="" class="wp-image-15983" srcset="https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/OnTimeV2-Invoice-Detail-Dark-1540x800.png 1540w, https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/OnTimeV2-Invoice-Detail-Dark-770x400.png 770w" sizes="auto, (max-width: 1540px) 100vw, 1540px" /></figure>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1540" height="800" data-id="15985" src="https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/OnTimeV2-Invoice-Detail-Light-1540x800.png" alt="" class="wp-image-15985" srcset="https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/OnTimeV2-Invoice-Detail-Light-1540x800.png 1540w, https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/OnTimeV2-Invoice-Detail-Light-770x400.png 770w" sizes="auto, (max-width: 1540px) 100vw, 1540px" /></figure>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1540" height="800" data-id="15984" src="https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/OnTimeV2-Invoices-Dark-1540x800.png" alt="" class="wp-image-15984" srcset="https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/OnTimeV2-Invoices-Dark-1540x800.png 1540w, https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/OnTimeV2-Invoices-Dark-770x400.png 770w" sizes="auto, (max-width: 1540px) 100vw, 1540px" /></figure>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1540" height="800" data-id="15982" src="https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/OnTimeV2-Invoices-Light-1540x800.png" alt="" class="wp-image-15982" srcset="https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/OnTimeV2-Invoices-Light-1540x800.png 1540w, https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/OnTimeV2-Invoices-Light-770x400.png 770w" sizes="auto, (max-width: 1540px) 100vw, 1540px" /></figure>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1540" height="800" data-id="15981" src="https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/OnTimeV2-Overview-Light-1540x800.png" alt="" class="wp-image-15981" srcset="https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/OnTimeV2-Overview-Light-1540x800.png 1540w, https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/OnTimeV2-Overview-Light-770x400.png 770w" sizes="auto, (max-width: 1540px) 100vw, 1540px" /></figure>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1540" height="680" data-id="15977" src="https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/OnTimeV2-Payment-Review-Dark-1-1540x680.png" alt="" class="wp-image-15977"/></figure>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1540" height="680" data-id="15979" src="https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/OnTimeV2-Payment-Review-Light-1540x680.png" alt="" class="wp-image-15979"/></figure>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1540" height="800" data-id="15987" src="https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/OnTimeV2-Projects-Dark-1540x800.png" alt="" class="wp-image-15987" srcset="https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/OnTimeV2-Projects-Dark-1540x800.png 1540w, https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/OnTimeV2-Projects-Dark-770x400.png 770w" sizes="auto, (max-width: 1540px) 100vw, 1540px" /></figure>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1540" height="800" data-id="15988" src="https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/OnTimeV2-Projects-Light-1540x800.png" alt="" class="wp-image-15988" srcset="https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/OnTimeV2-Projects-Light-1540x800.png 1540w, https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/OnTimeV2-Projects-Light-770x400.png 770w" sizes="auto, (max-width: 1540px) 100vw, 1540px" /></figure>
</figure>
<p>The post <a href="https://mobile.fhstp.ac.at/allgemein/ontime-v2/">OnTime V2</a> appeared first on <a href="https://mobile.fhstp.ac.at">Mobile USTP MKL</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://mobile.fhstp.ac.at/allgemein/ontime-v2/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Creating your own custom Agent Harness like Claude Code and why it matters</title>
		<link>https://mobile.fhstp.ac.at/development/ai-agent-harness-claude-code/</link>
					<comments>https://mobile.fhstp.ac.at/development/ai-agent-harness-claude-code/#respond</comments>
		
		<dc:creator><![CDATA[Jakob Laschober]]></dc:creator>
		<pubDate>Thu, 17 Sep 2026 06:50:00 +0000</pubDate>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[Agent Harness]]></category>
		<category><![CDATA[AI Agents]]></category>
		<category><![CDATA[AI Automation]]></category>
		<category><![CDATA[AI Development]]></category>
		<category><![CDATA[AI Memory Management]]></category>
		<category><![CDATA[Anthropic]]></category>
		<category><![CDATA[Claude Code]]></category>
		<category><![CDATA[Generative AI]]></category>
		<category><![CDATA[Large Language Models]]></category>
		<category><![CDATA[LLM Architecture]]></category>
		<category><![CDATA[Model Context Protocol]]></category>
		<category><![CDATA[Open Source AI]]></category>
		<category><![CDATA[Software Engineering]]></category>
		<category><![CDATA[Softwareentwicklung]]></category>
		<guid isPermaLink="false">https://mobile.fhstp.ac.at/?p=15914</guid>

					<description><![CDATA[<p>Have you ever typed something into Claude Code and wondered how it actually works? It’s not too hard to find out, after all, Anthropic accidentally released the Claude Code codebase back in March (The Verge). But what exactly is going on under the hood? How does the architecture function? And how can you build your <a class="read-more" href="https://mobile.fhstp.ac.at/development/ai-agent-harness-claude-code/">[...]</a></p>
<p>The post <a href="https://mobile.fhstp.ac.at/development/ai-agent-harness-claude-code/">Creating your own custom Agent Harness like Claude Code and why it matters</a> appeared first on <a href="https://mobile.fhstp.ac.at">Mobile USTP MKL</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Have you ever typed something into Claude Code and wondered how it actually works? It’s not too hard to find out, after all, Anthropic accidentally released the Claude Code codebase back in March (<a href="https://www.theverge.com/ai-artificial-intelligence/904776/anthropic-claude-source-code-leak">The Verge</a>). But what exactly is going on under the hood? How does the architecture function? And how can you build your own bespoke version of such a system? And do you even want to?</p>



<h2 class="wp-block-heading">What Is an Agent Harness?</h2>



<p class="wp-block-paragraph">Finding a clear-cut definition of an &#8220;agent harness&#8221; isn&#8217;t easy. This is largely because many AI companies are reluctant to give away the exact approach of how their agents work, often disguising the technical definition in marketing jargon that sounds cool or magical (definitions e.g.: <a href="https://cloud.google.com/discover/what-are-ai-agents">Google</a>, <a href="https://developers.openai.com/api/docs/guides/agents/define-agents">OpenAi</a>, <a href="https://www.anthropic.com/engineering/building-effective-agents">Anthropic</a>).</p>



<p class="wp-block-paragraph">The best difinition I could find was one I stumbled over reading a Github repo about &#8220;<a href="https://github.com/RyanAlberts/best-of-Agent-Harnesses">Best of Agent Harnesses and Harness Techniques</a>&#8221; which quoted a Blog entry from <a href="https://simonwillison.net/2025/Sep/18/agents/">Simon Willison’s Weblog</a>: &#8220;An LLM agent runs tools in a loop to achieve a goal.&#8221; (6)</p>



<p class="wp-block-paragraph">Technically speaking, an agent harness is the infrastructure and control layer built around a Large Language Model (LLM). A base model (like Claude 3.7 or GPT-4o) cannot natively search your local files, execute terminal commands, or iteratively fix code—it only generates text. The harness is what grants the LLM autonomy. It provides the model with tools, enforces permissions, manages state, and orchestrates the overarching loop of an agentic session. (1)</p>



<h2 class="wp-block-heading">Inside Claude Code: Architecture Overview</h2>



<p class="wp-block-paragraph">When we examine the architecture of a sophisticated harness like Claude Code, it reveals a highly structured system that goes far beyond a simple chat interface.</p>



<p class="wp-block-paragraph">At its core, the architecture relies on a continuous evaluation loop. The model isn&#8217;t just generating an answer; it&#8217;s navigating a Gather-Act-Verify cycle. (2)</p>



<pre class="wp-block-code"><code>graph TD
    A&#91;User Input / Prompt] --> B(Agent Harness Control Loop)
    B --> C{LLM Decision Engine}
    
    C -- Needs Context --> D&#91;Gather]
    D --> D1(Search Files, Read Memory)
    D1 --> B
    
    C -- Ready to Execute --> E&#91;Act]
    E --> E1(Write Code, Run Terminal)
    E1 --> B
    
    C -- Needs Validation --> F&#91;Verify]
    F --> F1(Run Tests, Check Linting)
    F1 -- Error Found --> B
    F1 -- Success --> G&#91;Final Response to User]</code></pre>



<p class="wp-block-paragraph">Another crucial component of this architecture is Memory Management. Developer Simon Willison highlighted a fascinating architectural detail in a recent blog post comparing the memory implementations of Claude and ChatGPT. (2)<br><br>Claude’s harness philosophy prioritizes extreme transparency. Unlike OpenAI, which often injects user profiles or past context into the background automatically, Claude Code starts every conversation as a blank slate. Memory is implemented as explicit tools (specifically conversation_search and recent_chats).</p>



<pre class="wp-block-code"><code>sequenceDiagram
    participant User
    participant Harness
    participant LLM
    participant MemoryDB
    
    User->>Harness: "Continue where we left off yesterday"
    Harness->>LLM: Pass user prompt
    LLM->>Harness: Tool Call: conversation_search()
    Harness->>MemoryDB: Query past logs
    MemoryDB-->>Harness: Return relevant context
    Harness-->>LLM: Inject context into prompt
    LLM->>User: "Ah yes, we were fixing the routing bug..."</code></pre>



<p class="wp-block-paragraph">Because the model decides when to pull from memory via a visible tool call, you avoid the issue of old &#8220;bug loops&#8221; silently poisoning a fresh workspace.</p>



<h2 class="wp-block-heading">Building Your Own Agent Harness and the benefits</h2>



<p class="wp-block-paragraph">But why should you build your own agent harness when they already exist and work fine? I think its just the same reason why open source software exists. Closed-source systems like Claude Code are incredibly powerful, but they are highly opinionated and tailored to specific workflows (like general software development). By building your own, you gain maximum flexibility.</p>



<p class="wp-block-paragraph">You can customize the exact tools the agent has access to, perhaps integrating it directly with your company&#8217;s proprietary databases, Jira ticketing systems, or internal APIs. Or you can just adjust it for your needs for software developement or general purpose use. Fortunately, you don&#8217;t have to start from scratch. An excellent starting point is the GitHub repository <code>RyanAlberts/best-of-Agent-Harnesses</code>. (4) This curated, weekly-updated list ranks over 100 open-source agent harnesses. Notably, it even includes an MCP (Model Context Protocol) server, <code>llms.txt</code>, and JSON data, allowing agents themselves to read the repository and recommend the best harness framework for your specific needs.</p>



<h2 class="wp-block-heading">For what would i use a &#8220;Harness&#8221; for?</h2>



<p class="wp-block-paragraph">To understand the practical value, let’s look at a real-world project I am doing at work: a system designed to fully automate the production of AI-generated videos.<br>To be honest, the architecture diagram below represents a highly structured pipeline rather than a full-blown autonomous harness, because I have to make it highly predictable. However, it perfectly illustrates the foundational steps. By giving the central &#8220;Orchestrator&#8221; more flexibility and decision-making power, this pipeline could easily evolve into a true agentic harness.</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="6194" height="5176" src="https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/Diagram-1.png" alt="" class="wp-image-15943" style="aspect-ratio:1.1966900063653725;width:487px;height:auto" srcset="https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/Diagram-1.png 6194w, https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/Diagram-1-1536x1284.png 1536w, https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/Diagram-1-2048x1711.png 2048w" sizes="auto, (max-width: 6194px) 100vw, 6194px" /></figure>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">How would this be agentic then if we give it more freedom to be &#8220;creative&#8221;. If we apply the <strong>Gather-Act-Verify</strong> principles discussed earlier to this exact diagram, the system becomes truly autonomous:</p>



<ul class="wp-block-list">
<li><strong>Gather (Data &amp; Script Prep):</strong> Instead of just following a static script, the agent uses tools to autonomously query the <em>AWS Database</em> for the latest product stats and fetches the correct <em>Presentation Assets</em> (potentially using the Model Context Protocol, MCP, to search through company directories).</li>



<li><strong>Verify (Validation &amp; Creation):</strong> This is where a harness shines. In a rigid pipeline, if the <em>Small compliance/Legal check</em> fails, the system just throws an error and stops. In an agent harness, the LLM catches this error, analyzes <em>why</em> the script failed compliance, and autonomously rewrites it until it passes the check.</li>



<li><strong>Act (Audio, Sync &amp; Rendering):</strong> Once the agent verifies the script is perfect, it triggers the text-to-speech tools, gathers the exact audio timestamps, and hands everything over to the rendering engine before finally publishing it.</li>
</ul>



<h2 class="wp-block-heading">Challenges and Best Practices</h2>



<p class="wp-block-paragraph">If you decide to build a custom harness, keep these best practices in mind:</p>



<ol start="1" class="wp-block-list">
<li><strong>Cost and Latency Control:</strong> Because the agent runs in continuous loops (sending accumulating context back to the model), API costs can skyrocket. Implementing effective <strong>Prompt Caching</strong> is mandatory. (5)</li>



<li><strong>Robust Error Handling:</strong> If a tool (e.g., a terminal command) fails, the harness must not crash. It needs to gracefully catch the error (like a stack trace) and feed it back to the LLM during the <em>Verify</em> phase so the agent can self-correct. (5)</li>



<li><strong>Transparency:</strong> Follow Claude’s example. Don&#8217;t hide memory injections in the system prompt. Implement memory and context retrieval as visible tool calls so users can audit what the agent is doing. (6)</li>



<li><strong>Sandboxing:</strong> Because the <em>Act</em> phase allows the execution of commands, your harness must enforce strict security boundaries (e.g., running actions inside Docker containers) to prevent an autonomous agent from accidentally deleting critical system files. (5)</li>
</ol>



<h2 class="wp-block-heading">Conclusion</h2>



<p class="wp-block-paragraph">An agent harness is much more than an API wrapper, it is the vital infrastructure that gives a language model the tools it needs. While leaks and teardowns of commercial tools like Claude Code give us a glimpse into high-end, proprietary architectures, the vast open-source community proves that custom, bespoke solutions are more accessible than ever. By mastering the <em>Gather-Act-Verify</em> loop and maintaining clean, transparent tool management, you can transform a simple text generator into an autonomous, specialized digital colleague. </p>



<p class="wp-block-paragraph">Btw: There is also a very good video if you want to know more about harnesses from Langchain: <a href="https://www.youtube.com/watch?v=HI2q3ci3Iuc&amp;t=409s">https://www.youtube.com/watch?v=HI2q3ci3Iuc&amp;t=409s</a></p>



<h3 class="wp-block-heading">Sources</h3>



<ol class="wp-block-list">
<li><a href="https://vrungta.substack.com/p/claude-code-architecture-reverse">https://vrungta.substack.com/p/claude-code-architecture-reverse</a></li>



<li><a href="https://michaellivs.com/blog/architecture-behind-claude-code">https://michaellivs.com/blog/architecture-behind-claude-code</a></li>



<li><a href="https://www.mindstudio.ai/blog/claude-code-source-leak-memory-architecture">https://www.mindstudio.ai/blog/claude-code-source-leak-memory-architecture</a></li>



<li><a href="https://github.com/RyanAlberts/best-of-Agent-Harnesses">https://github.com/RyanAlberts/best-of-Agent-Harnesses</a></li>



<li><a href="https://resources.anthropic.com/building-effective-ai-agents">https://resources.anthropic.com/building-effective-ai-agents</a></li>



<li><a href="https://simonwillison.net/2025/Sep/18/agents/">https://simonwillison.net/2025/Sep/18/agents/</a></li>
</ol>
<p>The post <a href="https://mobile.fhstp.ac.at/development/ai-agent-harness-claude-code/">Creating your own custom Agent Harness like Claude Code and why it matters</a> appeared first on <a href="https://mobile.fhstp.ac.at">Mobile USTP MKL</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://mobile.fhstp.ac.at/development/ai-agent-harness-claude-code/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Gymetrics: A Self-Hostable Fitness App with Kotlin Multiplatform, NestJS, and Dockerization</title>
		<link>https://mobile.fhstp.ac.at/allgemein/gymetrics-a-self-hostable-fitness-app/</link>
					<comments>https://mobile.fhstp.ac.at/allgemein/gymetrics-a-self-hostable-fitness-app/#respond</comments>
		
		<dc:creator><![CDATA[Jakob Laschober]]></dc:creator>
		<pubDate>Thu, 17 Sep 2026 06:49:00 +0000</pubDate>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[Native Development]]></category>
		<category><![CDATA[AI Coding Agents]]></category>
		<category><![CDATA[Claude Code]]></category>
		<category><![CDATA[Compose Multiplatform]]></category>
		<category><![CDATA[Docker]]></category>
		<category><![CDATA[Fitness App]]></category>
		<category><![CDATA[KMP]]></category>
		<category><![CDATA[Koin Dependency Injection]]></category>
		<category><![CDATA[Kotlin Multiplatform]]></category>
		<category><![CDATA[MCP Server]]></category>
		<category><![CDATA[Mobile Architecture]]></category>
		<category><![CDATA[Model Context Protocol]]></category>
		<category><![CDATA[NestJs]]></category>
		<category><![CDATA[offline-first]]></category>
		<category><![CDATA[Self-Hosted App]]></category>
		<category><![CDATA[Software Engineering]]></category>
		<guid isPermaLink="false">https://mobile.fhstp.ac.at/?p=15928</guid>

					<description><![CDATA[<p>I set out to build this app in my first semester as a simple replacement for the Excel spreadsheet I used for workout tracking. But in the process of making it, it became so much more. And if you want to check it out you can on gymetrics.at (yeah I&#8217;ve already bought a Domain &#8230;). <a class="read-more" href="https://mobile.fhstp.ac.at/allgemein/gymetrics-a-self-hostable-fitness-app/">[...]</a></p>
<p>The post <a href="https://mobile.fhstp.ac.at/allgemein/gymetrics-a-self-hostable-fitness-app/">Gymetrics: A Self-Hostable Fitness App with Kotlin Multiplatform, NestJS, and Dockerization</a> appeared first on <a href="https://mobile.fhstp.ac.at">Mobile USTP MKL</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">I set out to build this app in my first semester as a simple replacement for the Excel spreadsheet I used for workout tracking. But in the process of making it, it became so much more. And if you want to check it out you can on <a href="https://gymetrics.at/">gymetrics.at</a> (yeah I&#8217;ve already bought a Domain &#8230;).</p>



<p class="wp-block-paragraph">When I started out, I decided to make an application that was really worth trying. I designed a database structure and a system architecture that I meant to be perfect. But for my first frontend (tbh not only the frontend), I was struggling. I am no designer myself and couldn&#8217;t really create a smooth user flow, so I used AI to help me with that. After I was done, I wasn&#8217;t very happy with either the scalability or the look and feel. I had used Ionic, a web framework that ran in a WebView on the device. The touch inputs didn&#8217;t feel instant or responsive enough, and for what was basically a simple CRUD app, it felt a little bit sluggish (or maybe that’s just me).</p>



<p class="wp-block-paragraph">So, in my second semester, I focused on refining that whole experience and making it better in every way.</p>



<h3 class="wp-block-heading">The Rewrite: Embracing Kotlin Multiplatform</h3>



<p class="wp-block-paragraph">I decided on a new frontend framework: Kotlin Multiplatform (KMP), which allows you to build apps for nearly any platform using a shared codebase. I also added new features, like self-hosted AI solutions to generate content and a posibility to choose your  current Gym.</p>



<p class="wp-block-paragraph">Implementing my app with Kotlin was challenging because it was a completely new programming language to me. After learning the fundamentals and coding on my own for the first week, I brought in some AI coding agents to help speed up the process. At first, I used a local model called <code>qwen3-coder:30b</code>, which I quantized to run on constrained hardware. My setup was a Mac Book Air M1 from the USTP rental service running <a href="https://omlx.ai/" data-type="link" data-id="https://omlx.ai/">OMLX</a> (which was especially built for Macs to take advantage of their unified memory). Running in my IDE was the open-source AI code agent <a href="https://marketplace.visualstudio.com/items?itemName=Continue.continue">Continue</a>, which allowed me to implement MCP servers and feed code context from my project to the model. Later I learned that this extention or IDE whatever you wanna call it, is no longer being developed and was acquired by Cursor.</p>



<p class="wp-block-paragraph">After I sadly had to return the rental Mac (originally i wanted to use it for building the App for IOS as well but just failed to finish the App in time <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f641.png" alt="🙁" class="wp-smiley" style="height: 1em; max-height: 1em;" /> ) , I switched to Claude Code. For me, it was essential to double-check Claude’s work and architectural decisions. Honestly, I was a little bit shocked by some of the choices it made, like trying to store API keys or passwords in plain text just somewhere in the Code! To be fair, I wasn&#8217;t using their frontier model to avoid spending too many tokens (as I argued a lot with it during the development process), but still. However, it was particularly handy for creating the frontend layer with Jetpack Compose, thanks to the vast documentation available for Android&#8217;s UI framework.</p>



<p class="wp-block-paragraph">To avoid hallucinations and provide the model with up-to-date documentation, I added an MCP Server called <a href="https://context7.com/">Context7</a>. It allowed me to filter exactly what documentation the model received and what it had access to &#8230; a really handy tool.</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="960" height="2142" src="https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/Screenshot_20260916-220509.png" alt="" class="wp-image-16013" style="aspect-ratio:0.4481865284974093;width:289px;height:auto" srcset="https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/Screenshot_20260916-220509.png 960w, https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/Screenshot_20260916-220509-688x1536.png 688w, https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/Screenshot_20260916-220509-918x2048.png 918w" sizes="auto, (max-width: 960px) 100vw, 960px" /></figure>



<h3 class="wp-block-heading">Frontend Challenges: Caching, Offline Sync, and Navigation</h3>



<p class="wp-block-paragraph"><br>The hardest part of my frontend implementation was the caching logic. I wanted the app to always instantly display the relevant information you need in the moment. To achieve this, I decided to cache the first 10 items of every category (e.g., Templates, Trainings, UserData).</p>



<p class="wp-block-paragraph">All of this is stored in a Key-Value database called <a href="https://github.com/xxfast/KStore">KStore</a>, a small library that works great for simple data storage on Android and iOS devices. The absolute hardest part was defining the behavior for when I saved something offline, ensuring that the moment I got back online, it would post to the backend so the two storages would &#8220;sync&#8221; up again. We now have a (mostly) robust network-first cache strategy with offline fallbacks.</p>



<p class="wp-block-paragraph">I also completely revamped the app&#8217;s navigation and UI architecture using Compose Multiplatform: </p>



<ul class="wp-block-list">
<li><strong>Two-Level Navigation:</strong> We have an outer navigation graph for the Auth-Flow (Login/Register) and an inner graph wrapped in a <code>Scaffold</code> for the main tabs. This allows for a persistent BottomBar that stays visible while you switch tabs.</li>
</ul>



<ul class="wp-block-list">
<li><strong>Profile Dialog:</strong> Instead of routing to a new screen, the user profile opens as a clean Dialog Card over the current screen, making it feel much faster.</li>
</ul>



<ul class="wp-block-list">
<li><strong>Security:</strong> Tokens are stored securely using <code>KVault</code> (Keychain for iOS, EncryptedSharedPreferences for Android).</li>
</ul>



<ul class="wp-block-list">
<li><strong>Dependency Injection:</strong> I used Koin to keep the architecture clean (MVVM), allowing the UI to remain logic-free.</li>
</ul>



<h3 class="wp-block-heading">The Backend: Keeping it Clean &amp; Adding a Scraping Service</h3>



<p class="wp-block-paragraph">For my backend (a self-hosted NestJS API), I tried to make major improvements to security and code cleanliness. Most of my backend wasn&#8217;t even touched by AI &#8230; I mean aside from a few MongoDB queries &#8230; they&#8217;re just really weird to write ok? &#8230; so I could assure everything was up to my expectations.</p>



<p class="wp-block-paragraph">For extended features, I added a custom scraping service using a separate Python server. It scrapes all the fitness studios listed on my gym&#8217;s website and writes everything about their equipment directly into my database. It&#8217;s scheduled to run on startup and then one time per Month (don&#8217;t want to get accused of creating to much net traffic for them). I deployed this service in a separate Docker container within the same Docker network to ensure minimal downtime in case the scraper ever crashes.</p>



<h3 class="wp-block-heading">Building a Local AI Agent for Training Templates</h3>



<p class="wp-block-paragraph">Having the exact context of my gym&#8217;s equipment in the database was especially helpful for my next big feature: Local AI Training Template generation.</p>



<p class="wp-block-paragraph">To be honest, I initially wanted to use the MCP server I had programmed earlier for this task. But by the time I got to implementing the AI feature, I realized that Ollama doesn&#8217;t actually support MCP natively because it lacks an MCP client.</p>



<p class="wp-block-paragraph">So, I built an Agentic loop directly in my NestJS backend to act as a middleman between Ollama and my server. I <em>could</em> have gone the route of calling my MCP server through my backend and called it a day. But after a short &#8220;question battle&#8221; with Claude Code, I decided that wasn&#8217;t feasible due to the unnecessary network requests I could save by just implementing the agent loop directly in the backend.</p>



<p class="wp-block-paragraph">My custom MCP Server now exists on its own and isn&#8217;t connected to anything just yet. But building it was a fantastic learning experience regarding how these systems work. It lays the groundwork for future implementations, as I eventually plan to integrate external MCP-capable AI tools like Claude or ChatGPT.</p>



<h3 class="wp-block-heading">Technical Deep Dive: Gymetrics Feature List</h3>



<p class="wp-block-paragraph">For those interested in the exact tech stack and architectural decisions, here is a breakdown of what’s running under the hood:</p>



<p class="wp-block-paragraph"><strong>The Stack</strong></p>



<ul class="wp-block-list">
<li><strong>Frontend:</strong> Kotlin Multiplatform, Compose Multiplatform (Shared UI), targeting Android (first priority) and iOS.</li>



<li><strong>Backend:</strong> Self-hosted NestJS API with Dockerized microservices.</li>



<li><strong>Auth:</strong> Short-lived Bearer tokens + Refresh tokens.</li>
</ul>



<p class="wp-block-paragraph"><strong>Core Implementations</strong></p>



<ul class="wp-block-list">
<li><strong>Ktor Client &amp; Auto-Refresh:</strong> Centralized HTTP client handling JSON serialization, timeouts, and dynamic base URLs. Used the Ktor <code>Auth</code> plugin to automatically attach tokens and trigger a silent refresh route (<code>POST /auth/refresh</code>) on 401 errors.</li>



<li><strong>Offline-First Capabilities:</strong> Built a custom <code>ConnectivityObserver</code> that tracks network state app-wide. The app displays an offline badge in the TopBar and handles offline Auth checks by optimistically trusting the securely stored token.</li>



<li><strong>App-Wide Theming:</strong> Implemented a custom <code>GymetricsTheme</code> wrapper around MaterialTheme, featuring a sleek, app-wide dark mode and adaptive Android icons.</li>



<li><strong>State Management &amp; DI:</strong> Strict MVVM architecture. State is handled via <code>sealed interfaces</code> and exhaustive <code>when</code> statements (Idle/Loading/Success/Error). Dependency Injection is handled entirely by <strong>Koin</strong> (using <code>appModule</code>, <code>single</code>, and <code>viewModelOf</code>).</li>
</ul>



<p class="wp-block-paragraph">It’s been a massive journey from a simple Ionic prototype to a fully-fledged, offline-capable KMP application with agentic AI workflows. It started as a way to replace a spreadsheet, but it taught me modern mobile architecture, backend, and how to effectively wrangle AI coding assistants.</p>



<p class="wp-block-paragraph"></p>
<p>The post <a href="https://mobile.fhstp.ac.at/allgemein/gymetrics-a-self-hostable-fitness-app/">Gymetrics: A Self-Hostable Fitness App with Kotlin Multiplatform, NestJS, and Dockerization</a> appeared first on <a href="https://mobile.fhstp.ac.at">Mobile USTP MKL</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://mobile.fhstp.ac.at/allgemein/gymetrics-a-self-hostable-fitness-app/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>RevMatchMarket Phase 2 – From Swipe-Based Browsing to Buyer-Seller Communication</title>
		<link>https://mobile.fhstp.ac.at/allgemein/revmatchmarket-phase-2-from-swipe-based-browsing-to-buyer-seller-communication/</link>
					<comments>https://mobile.fhstp.ac.at/allgemein/revmatchmarket-phase-2-from-swipe-based-browsing-to-buyer-seller-communication/#respond</comments>
		
		<dc:creator><![CDATA[Csongor]]></dc:creator>
		<pubDate>Wed, 16 Sep 2026 21:40:10 +0000</pubDate>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[Webdevelopment]]></category>
		<category><![CDATA[mobile]]></category>
		<category><![CDATA[Web Development]]></category>
		<category><![CDATA[Web-App]]></category>
		<guid isPermaLink="false">https://mobile.fhstp.ac.at/?p=15917</guid>

					<description><![CDATA[<p>1. Introduction Rev Match Market is a used car marketplace lead by the left right swiping mechanism for marking interest in used car postings and connecting buyers with sellers. This blog post describes the second phase of development that took place on this project. Initially a MVP was made in the 1st phase that already <a class="read-more" href="https://mobile.fhstp.ac.at/allgemein/revmatchmarket-phase-2-from-swipe-based-browsing-to-buyer-seller-communication/">[...]</a></p>
<p>The post <a href="https://mobile.fhstp.ac.at/allgemein/revmatchmarket-phase-2-from-swipe-based-browsing-to-buyer-seller-communication/">RevMatchMarket Phase 2 – From Swipe-Based Browsing to Buyer-Seller Communication</a> appeared first on <a href="https://mobile.fhstp.ac.at">Mobile USTP MKL</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading">1. Introduction</h2>



<p class="wp-block-paragraph">Rev Match Market is a used car marketplace lead by the left right swiping mechanism for marking interest in used car postings and connecting buyers with sellers. This blog post describes the second phase of development that took place on this project. Initially a MVP was made in the 1st phase that already contained the following features: authenticated sessions, swipe-based discovery, favorites, and seller listing management. For further reading about the 1st phase find the previous blog post <a href="https://mobile.fhstp.ac.at/allgemein/rev-match-market-a-swipe-based-used-car-marketplace/">here</a>.</p>



<p class="wp-block-paragraph">As a continuation to the initial MVP, the 2nd phase&#8217;s main goal was to introduce buyer-seller communication within the application aided with a notification system informing buyers and sellers about new interactions from each other. Another goal was to significantly improve the mobile experience and expand the capability of the UI from a single mobile view to a responsively transitioning UI that supports desktop, tablet, and mobile. Additional goals were the implementation of a concrete sold state that could later be the starting point of KPI tracking. Finally, to be able to later experiment with the app as a real business the application structure and code quality was to be made more production-ready.</p>



<h2 class="wp-block-heading">2. From Phase 1 MVP to Phase 2 &#8211; The Plan</h2>



<p class="wp-block-paragraph">The starting point of the 2nd phase was directly from where phase 1 and the last blog post left off.</p>



<ul class="wp-block-list">
<li>Authenticated marketplace.</li>



<li>Seller listing creation, editing and soft deletion.</li>



<li>Swipe-based discovery with LIKE and PASS.</li>



<li>Favorites and basic make/model/price filtering.</li>



<li>Nuxt, NestJS, PostgreSQL and Prisma foundation.</li>
</ul>



<p class="wp-block-paragraph">The features implemented by phase 2 in order of priority.</p>



<ul class="wp-block-list">
<li>Mobile-first redesign before implementing major new screens.</li>



<li>Chat and in-app notifications as the main new product features.</li>



<li>Improved marketplace filtering and incremental feed loading.</li>



<li>Cleaner domain boundaries, response contracts and privacy handling.</li>
</ul>



<p class="wp-block-paragraph">The result speak for them self, even if at this point of the blog only visually.</p>



<figure class="wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-2 is-layout-flex wp-block-gallery-is-layout-flex">
<figure class="wp-block-image size-large size-full"><img loading="lazy" decoding="async" width="1699" height="944" data-id="16003" src="https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/Screenshot-2026-09-16-131945-3.png" alt="" class="wp-image-16003" srcset="https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/Screenshot-2026-09-16-131945-3.png 1699w, https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/Screenshot-2026-09-16-131945-3-1536x853.png 1536w" sizes="auto, (max-width: 1699px) 100vw, 1699px" /></figure>
</figure>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-8f761849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:100%"></div>
</div>



<h2 class="wp-block-heading">3. The Mobile-First Interface</h2>



<p class="wp-block-paragraph"><strong>Shared Application Shell</strong><br>The shell places the screens in a wrapping element which provides consistent navigation throughout the navigation between pages and also provides a responsive layout. The components and visual primitives used in the application are also standardized across the different pages including spacing, typography and interaction states. This meant that many components from phase 1 have been completely replaced with special care so no parallel or redundant designs would have to be maintained.</p>



<p class="wp-block-paragraph"><strong>Screen Changes and Account Identity</strong><br>To start off at the beginning of users journey the login and registration pages have been completely redesigned and made responsive, along with the swipe, car-detail, favorites and seller-listing screens. A visible addition to the users was also made by displaying a name for user facing identity. The user identity also gained increased protection, since emails and user IDs of other users are no longer reaching the frontend other than public contact information on car-detail pages. </p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="545" height="1189" src="https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/Screenshot-2026-09-16-132131.png" alt="" class="wp-image-15934" style="aspect-ratio:0.45837641540362645;width:192px;height:auto"/><figcaption class="wp-element-caption">Swipe page of the application with demo data where users brows listings.</figcaption></figure>



<h2 class="wp-block-heading"><strong>4. Improving Marketplace Discovery</strong></h2>



<p class="wp-block-paragraph">A task originally coming from phase 1 has been implemented and improved, which is pagination and filtering of the queue of cars on the swipe page. First of all Filtering did already exist but it is now moved from the frontend to the backend. The number of filters remains small though now its way easier to expand. The front end now only holds a limited number of cars that come next and before the queue is exhausted the prefetching of new cars occurs. Pass decisions still expire and listings return to the queue later.</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="3760" height="3160" src="https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/image-1.png" alt="" class="wp-image-16005" srcset="https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/image-1.png 3760w, https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/image-1-1536x1291.png 1536w, https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/image-1-2048x1721.png 2048w" sizes="auto, (max-width: 3760px) 100vw, 3760px" /></figure>



<h2 class="wp-block-heading">5. Communication (Chat), Notifications and Sale Lifecycle</h2>



<p class="wp-block-paragraph">This section is arguably the most important for phase 2. This encapsulates Likes creating conversations, the chat experience between buyer and seller, in-app notifications, and a new state for listings &#8220;SOLD&#8221;.</p>



<p class="wp-block-paragraph"><strong>LIKEs and conversations</strong><br>As one can know from phase 1 when a user likes a listing, the listing appears in the users favorites tab. Now following that the seller also receives a notification of a potential buyer who liked their listing. To avoid the creation of empty conversations a like in it self doesn&#8217;t create a new conversation. Following the like both parties get the chance to initiate a conversation. The seller can initiate from the notification they receive and the buyer can start a chat from the favorites tab or the car-detail page. Either way a new conversation is created when the first message is sent. There can only be one conversation per car and interested buyer.</p>



<p class="wp-block-paragraph"><strong>Chat experience</strong><br>Chats appear in a list like page which provides basic information to the user about all the chats like total number of unread messages and about individual list items representing a single chat like the last message, the time it was sent and the car that is the subject of the conversation. Chats can still be reached following a successful sale or if a buyer decided to withdraw interest. When a listing is deleted the chat is still readable but new messages are blocked.</p>



<p class="wp-block-paragraph"><strong>In-app Notifications</strong><br>The two sources of notifications are the Likes and messages. When the application is open and the user receives a notification an in-app popup appears temporarily. In case the user misses the popup, they might still access the notifications in their inbox with a list view. The notification inbox list view similarly to the chat shows notification contents, read or unread states and a counter for all unread notifications. The user can mark only one notification or all at the same time as read.</p>



<p class="wp-block-paragraph"><strong>Sold Listing</strong><br>The listings can be marked as sold only by the seller. They can do this either from the listing itself or the conversation which will associate the conversation with the successful sale. Sold listings can’t be found on the swipe page anymore and buyers may no longer start new conversations about the sold listings. Within favorites or existing conversations, the listing shows up as sold.</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="3760" height="3560" src="https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/image.png" alt="" class="wp-image-16004" srcset="https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/image.png 3760w, https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/image-1536x1454.png 1536w, https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/image-2048x1939.png 2048w" sizes="auto, (max-width: 3760px) 100vw, 3760px" /></figure>



<h2 class="wp-block-heading"><strong>6. Technical Foundation and Data Model</strong></h2>



<ul class="wp-block-list">
<li>RevMatchMarket still uses Nuxt 4 for the frontend, NestJS for the backend, and PostgreSQL with Prisma ORM for the database.</li>



<li>New persistence models that were added in phase 2 are conversations, messages, notifications, and sold state.</li>



<li>A major change is the increased privacy meaning that response DTOs no longer expose account email and userID.</li>



<li>The development process was also improved between phases 1 and 2 by using dedicated git feature branches merged into develop and later charry picking from develop to main (production).</li>
</ul>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="10460" height="3960" src="https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/image-3.png" alt="" class="wp-image-16007" srcset="https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/image-3.png 10460w, https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/image-3-1536x582.png 1536w, https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/image-3-2048x775.png 2048w" sizes="auto, (max-width: 10460px) 100vw, 10460px" /></figure>



<h2 class="wp-block-heading"><strong>7. Challenges and Lessons Learned</strong></h2>



<p class="wp-block-paragraph">The first challenge was to plan the chat and notification system before implementation, what I learned is that it is significantly easier if the process is visualized beforehand using one of many flow chat methods. I also learned about the effort required to produce production grade code, where edge cases have to be treated with special care. I have learnt about several new techniques listed below.</p>



<p class="wp-block-paragraph"><strong>Cursor Pagination</strong><br>Pagination is used when requesting batches of a long list of data from the API. Cursor pagination loads the next group of records relative to the last record already received. This differs from the more simple offset pagination which requests by skipping x amount of records from the start. A cursor marks the last record loaded by a deterministic value in most cases a timestamp and the record&#8217;s id. This is used on RevMatchMarket&#8217;s swipe feed, and notification and chat inbox for example to avoid duplicate or skipped records.</p>



<p class="wp-block-paragraph"><strong>Client-side Reconciliation</strong><br>Reconciliation is to be understood as checking back with the API new data based on the data the browser already had. This process merges new server data with the existing state of the browser. This technique is important mainly because the application uses polling to fetch new messages or notifications. In case a notification is deleted and at the same time the polling occurs the deleted notification may appear again because the polling happened before the delete went through. When new server data arrives it is merged with the browser data by comparing IDs and the newer updatedAt wins over the older one.</p>



<p class="wp-block-paragraph"><strong>Prefetching</strong><br>The swipe page uses prefetching to achieve a continues feed. When only 3 cars remain from the previous batch of 20 a newer batch is fetched. To have a fluid swipe feed additional steps are also taken to filter out duplicates, potentially successful swipes can&#8217;t be re-introduced again, and account and filter changes are watched.</p>



<h2 class="wp-block-heading">8. Results</h2>



<p class="wp-block-paragraph">The development in the 2nd phase yielded the following results: a completely reworked design and application structure, the ability for buyers and sellers to connect within the application after a potential buyer liked a listing, a notification system to keep buyers and sellers up to date with liked and owned listings, and finally a revised discovery logic that is more reliable and scalable.</p>
<p>The post <a href="https://mobile.fhstp.ac.at/allgemein/revmatchmarket-phase-2-from-swipe-based-browsing-to-buyer-seller-communication/">RevMatchMarket Phase 2 – From Swipe-Based Browsing to Buyer-Seller Communication</a> appeared first on <a href="https://mobile.fhstp.ac.at">Mobile USTP MKL</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://mobile.fhstp.ac.at/allgemein/revmatchmarket-phase-2-from-swipe-based-browsing-to-buyer-seller-communication/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Designing Offline-First iOS Apps: Local State, Persistence, and Sync Without Losing User Trust</title>
		<link>https://mobile.fhstp.ac.at/allgemein/designing-offline-first-ios-apps-local-state-persistence-and-sync-without-losing-user-trust/</link>
					<comments>https://mobile.fhstp.ac.at/allgemein/designing-offline-first-ios-apps-local-state-persistence-and-sync-without-losing-user-trust/#respond</comments>
		
		<dc:creator><![CDATA[Melanie Maier]]></dc:creator>
		<pubDate>Wed, 16 Sep 2026 08:37:26 +0000</pubDate>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[Native Development]]></category>
		<category><![CDATA[Studium]]></category>
		<category><![CDATA[iOS]]></category>
		<category><![CDATA[mobile]]></category>
		<category><![CDATA[offline-first]]></category>
		<category><![CDATA[persistence]]></category>
		<category><![CDATA[Sync]]></category>
		<guid isPermaLink="false">https://mobile.fhstp.ac.at/?p=15926</guid>

					<description><![CDATA[<p>Abstract Many mobile apps look simple until they must preserve an unfinished edit, work offline, survive a crash, and reconcile changes from two devices. Then “save and sync” becomes an architecture, and a promise to the user. An offline-first iOS app treats its local store as the immediate source of truth. User actions update it <a class="read-more" href="https://mobile.fhstp.ac.at/allgemein/designing-offline-first-ios-apps-local-state-persistence-and-sync-without-losing-user-trust/">[...]</a></p>
<p>The post <a href="https://mobile.fhstp.ac.at/allgemein/designing-offline-first-ios-apps-local-state-persistence-and-sync-without-losing-user-trust/">Designing Offline-First iOS Apps: Local State, Persistence, and Sync Without Losing User Trust</a> appeared first on <a href="https://mobile.fhstp.ac.at">Mobile USTP MKL</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading">Abstract</h2>



<p class="wp-block-paragraph">Many mobile apps look simple until they must preserve an unfinished edit, work offline, survive a crash, and reconcile changes from two devices. Then “save and sync” becomes an architecture, and a promise to the user.</p>



<p class="wp-block-paragraph">An offline-first iOS app treats its local store as the immediate source of truth. User actions update it first; synchronization is separate and retryable. State boundaries must be explicit, writes safe, conflicts explainable, and the interface honest about data stored only locally.</p>



<p class="wp-block-paragraph">This article follows that model from SwiftUI state through persistence, autosave, change tracking, conflicts, and failure UX.</p>



<h2 class="wp-block-heading">1. Why Offline-First Still Matters</h2>



<p class="wp-block-paragraph">In 2026, fast networks are common, reliable connectivity is not. A phone can enter a tunnel, encounter a captive portal, or lose authentication. A request may reach the server even when its response never reaches the client.</p>



<p class="wp-block-paragraph">Offline-first begins with a rule: the user performs the app’s core work against local data. The app records the intent durably and synchronizes later. A task app should not discard a completed task because the server timed out.</p>



<p class="wp-block-paragraph">This is different from caching. A cache is usually disposable and can be reconstructed from an authoritative source. Offline-created user data cannot. If deleting the local copy would destroy information that exists nowhere else, it is not “just a cache.”</p>



<p class="wp-block-paragraph">Reachability is not permission to write. Network status can help decide when to attempt synchronization, but it cannot prove that the next request will succeed. Foundation can wait through <code>URLSessionConfiguration.waitsForConnectivity</code>, but the durable queue, not a green icon, is what makes a write reliable (<a href="https://developer.apple.com/documentation/foundation/urlsessionconfiguration/waitsforconnectivity">Apple: </a><code><a href="https://developer.apple.com/documentation/foundation/urlsessionconfiguration/waitsforconnectivity">waitsForConnectivity</a></code>).</p>



<p class="wp-block-paragraph">The useful mental model is:</p>



<ol start="1" class="wp-block-list">
<li>accept the user’s action</li>



<li>validate it locally</li>



<li>commit it locally</li>



<li>render the committed result</li>



<li>enqueue synchronization</li>



<li>retry safely until the server acknowledges it</li>
</ol>



<p class="wp-block-paragraph">The network path affects step five, not the validity of steps one through four.</p>



<h2 class="wp-block-heading">2. Local State Is Not Temporary State</h2>



<p class="wp-block-paragraph">SwiftUI makes state easy to declare, which can make unlike kinds of state look deceptively similar. A robust app distinguishes at least three layers.</p>



<p class="wp-block-paragraph"><strong>View state</strong>&nbsp;exists only to present or control the current interface: whether a sheet is open, which tab is selected, a search field’s draft text, or the expansion state of a disclosure group.&nbsp;<code>@State</code>&nbsp;is often appropriate because SwiftUI owns that value for the lifetime of the view identity.</p>



<p class="wp-block-paragraph"><strong>Domain state</strong>&nbsp;represents meaningful work: a document title, completed task, or pending deletion. It must not depend on whether a view exists. Observation and&nbsp;<code>@Observable</code>&nbsp;help present domain objects, but observability is not persistence.</p>



<p class="wp-block-paragraph"><strong>Persistent application state</strong>&nbsp;has crossed a durability boundary. It has been written to a file or store that can be reconstructed after relaunch. SwiftData’s&nbsp;<code>ModelContainer</code>&nbsp;and&nbsp;<code>ModelContext</code>, a Core Data persistent container, or a purpose-built SQLite layer live here.</p>



<p class="wp-block-paragraph">The distinction matters during editing. Binding a field directly to a persistent model saves half-finished values. That may suit notes, but not a bank transfer or an object whose fields must remain consistent. In those cases, edit a draft, validate it, and commit the complete change in one transaction.</p>



<p class="wp-block-paragraph">A practical dependency direction is:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
SwiftUI view → use case / repository → local store
                                <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2198.png" alt="↘" class="wp-smiley" style="height: 1em; max-height: 1em;" /> sync outbox
</pre></div>


<p class="wp-block-paragraph">Views request operations such as&nbsp;<code>completeTask</code>; they do not decide how JSON is replaced or CloudKit records are merged. This makes offline behavior testable without UI or a real server.</p>



<h2 class="wp-block-heading">3. Choosing a Persistence Strategy</h2>



<p class="wp-block-paragraph">Choose the smallest persistence mechanism that preserves the data’s structure, query needs, migrations, and ownership.</p>



<p class="wp-block-paragraph"><strong>UserDefaults</strong>&nbsp;is for small preferences such as sort order or a dismissed onboarding flag. It is not a document database or an outbox.</p>



<p class="wp-block-paragraph"><strong>JSON or property-list files</strong>&nbsp;suit small, document-shaped datasets loaded and replaced as a unit. They are transparent and exportable. Once the app needs indexed queries, relationships, concurrent writers, or a large sync log, one JSON file becomes an improvised database.</p>



<p class="wp-block-paragraph"><strong>SwiftData</strong>&nbsp;is a natural high-level choice for many new Apple-platform apps. It integrates persistent models with Swift and SwiftUI queries. Its main context supports autosave in app configurations, manually created contexts do not inherit that behavior. Design schema migrations before a model rename ships (<a href="https://developer.apple.com/videos/play/wwdc2023/10196/">Apple: Dive deeper into SwiftData</a>,&nbsp;<a href="https://developer.apple.com/videos/play/wwdc2025/291/">Apple: schema migration</a>).</p>



<p class="wp-block-paragraph"><strong>Core Data</strong>&nbsp;remains strong for mature apps, complex graphs, and established migration plans.&nbsp;<code>NSPersistentContainer</code>encapsulates the stack, while persistent history can expose transactions made elsewhere. SwiftData is not merely “Core Data with nicer syntax”. Evaluate requirements instead of choosing by age.</p>



<p class="wp-block-paragraph"><strong>SQLite</strong>&nbsp;fits explicit schemas, specialized indexes, predictable SQL, or tight transaction control. An atomic commit makes all transaction changes visible or none. Write-ahead logging can let readers continue during writes, though checkpointing and durability settings still matter (<a href="https://sqlite.org/atomiccommit.html">SQLite: Atomic Commit</a>,&nbsp;<a href="https://sqlite.org/wal.html">SQLite: WAL</a>).</p>



<h2 class="wp-block-heading">4. Autosave and Data Integrity</h2>



<p class="wp-block-paragraph">Autosave is a user-experience policy, not an integrity mechanism. It answers&nbsp;<em>when the app attempts to persist</em>, not&nbsp;<em>whether a multi-part change is valid, atomic, or recoverable</em>.</p>



<p class="wp-block-paragraph">For free-form text, saving after every keystroke wastes work. A short debounce coalesces edits, but creates a window where input exists only in memory. Flush critical drafts when editing ends and when the scene changes phase.</p>



<p class="wp-block-paragraph">For files, write to an auxiliary file and replace the original only after success. Foundation’s atomic option follows this approach (<a href="https://developer.apple.com/documentation/foundation/nsdata/writingoptions/atomic">Apple:&nbsp;</a><code><a href="https://developer.apple.com/documentation/foundation/nsdata/writingoptions/atomic">NSData.WritingOptions.atomic</a></code>). Keep a last known-good version when corruption is costly, a backup matters only if restore is tested.</p>



<p class="wp-block-paragraph">For database persistence, group invariant-related changes in one transaction. Creating an order and decrementing inventory in separate saves exposes an impossible intermediate state after a crash. Transaction boundaries should follow domain meaning, not screen layout.</p>



<p class="wp-block-paragraph">Every model needs a migration story. Use stable identifiers independent of local row IDs, version schemas, and test upgrades from every supported release. Never answer migration failure by silently deleting the user’s store.</p>



<p class="wp-block-paragraph">Treat storage errors as first-class outcomes. Disk space can run out, encoding can fail, and validation can reject a save.&nbsp;<code>try? context.save()</code>&nbsp;may create a quiet interface while hiding that data was never durable.</p>



<h2 class="wp-block-heading">5. Sync Is a Trust Problem</h2>



<p class="wp-block-paragraph">Synchronization is often drawn as two arrows between phone and cloud. Inside are duplicate requests, reordering, partial failure, concurrent edits, deletion, and expired authentication.</p>



<p class="wp-block-paragraph">A trustworthy design separates&nbsp;<strong>local durability</strong>&nbsp;from&nbsp;<strong>remote synchronization</strong>. Each mutation creates the domain change and an outbox entry in one transaction. A worker sends operations, records acknowledgements, applies remote changes, and retries with backoff. After a crash, the outbox still exists.</p>



<p class="wp-block-paragraph">Each operation should be idempotent. Give it a stable operation ID so a server can recognize a retry. If the server receives the request but the client loses the response, retrying must not create a duplicate object or repeat a payment.</p>



<p class="wp-block-paragraph">Timestamps are weak ordering mechanisms because device clocks differ. Prefer server revisions, advancing change tokens, or per-record versions. SwiftData History exposes chronological transactions and explicitly supports remote sync and out-of-process changes (<a href="https://developer.apple.com/videos/play/wwdc2024/10075/">Apple: SwiftData history</a>,&nbsp;<a href="https://developer.apple.com/documentation/swiftdata/fetching-and-filtering-time-based-model-changes">Apple: time-based changes</a>).</p>



<p class="wp-block-paragraph">HTTP offers concurrency semantics: the server returns an&nbsp;<code>ETag</code>, and the client sends&nbsp;<code>If-Match</code>&nbsp;when updating. If the resource changed, the precondition fails instead of overwriting newer data (<a href="https://www.rfc-editor.org/rfc/rfc9110">RFC 9110</a>). CloudKit similarly gives&nbsp;<code>CKRecord</code>&nbsp;a change tag for synchronization (<a href="https://developer.apple.com/documentation/cloudkit/ckrecord">Apple:&nbsp;</a><code><a href="https://developer.apple.com/documentation/cloudkit/ckrecord">CKRecord</a></code>).</p>



<p class="wp-block-paragraph">The app should model sync state explicitly, for example:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
enum SyncState: Equatable {
    case localOnly
    case queued
    case syncing
    case synced(revision: String)
    case conflict
    case blocked(reason: BlockReason)
}
</pre></div>


<p class="wp-block-paragraph">Do not infer sync from the absence of an error. A request that has not started is not synchronized, and expired authentication differs from a timeout.</p>



<h2 class="wp-block-heading">6. Conflict Handling and External Sources</h2>



<p class="wp-block-paragraph">Conflict policy must be defined per entity and sometimes per field. “Last write wins” is simple, but it can silently erase work and becomes especially unsafe when “last” depends on device clocks.</p>



<p class="wp-block-paragraph">Some data merges automatically: independent fields can merge separately and tag sets may use union semantics. Collaborative text needs a purpose-built algorithm such as a CRDT. It should not be improvised from&nbsp;<code>updatedAt</code>.</p>



<p class="wp-block-paragraph">Other conflicts need a human. Preserve both versions, show meaningful differences, and offer “Your edit from 10:42” versus “Edit from iPad at 10:45,” not merely “local” and “remote.”</p>



<p class="wp-block-paragraph">Deletions deserve their own model. If a deleted record vanishes immediately, another offline device may later re-upload it. A tombstone—an identifier, deletion revision, and retention period—allows deletion to propagate. Purge it only after the system’s synchronization window and device assumptions make resurrection acceptably unlikely.</p>



<p class="wp-block-paragraph">External sources also need ownership rules:</p>



<ul class="wp-block-list">
<li><strong>Read-only reference data:</strong> cache locally, display its age, and replace it from the source. Never upload it as if the user authored it</li>



<li><strong>Imported data:</strong> record provenance and the external identifier. Decide whether import creates an owned snapshot or maintains a live link</li>



<li><strong>Locally editable mirrors:</strong> keep the source version alongside pending local changes. Rebase or surface a conflict when the source changes</li>



<li><strong>External deletion:</strong> distinguish “no longer available upstream” from “user deleted locally.” Preserve local notes or derived records when policy allows</li>
</ul>



<p class="wp-block-paragraph">CloudKit subscriptions can signal record creation, modification, and deletion, but they only trigger fetching. They do not replace a durable local store or change token (<a href="https://developer.apple.com/documentation/cloudkit/ckrecordzonesubscription">Apple:&nbsp;</a><code><a href="https://developer.apple.com/documentation/cloudkit/ckrecordzonesubscription">CKRecordZoneSubscription</a></code>).</p>



<h2 class="wp-block-heading">7. UX for Failure</h2>



<p class="wp-block-paragraph">Offline-first UX should communicate consequences, not infrastructure. Users need three answers: Is my work saved here? Is it available elsewhere? Do I need to act?</p>



<p class="wp-block-paragraph">Use calm, specific status language:</p>



<ul class="wp-block-list">
<li><strong>Saved on this iPhone</strong> — the local transaction committed</li>



<li><strong>Waiting to sync</strong> — no action is normally required</li>



<li><strong>Syncing…</strong> — work is in progress</li>



<li><strong>Couldn’t sync. We’ll retry.</strong> — the failure is transient</li>



<li><strong>Sign in to continue syncing</strong> — user action is required</li>



<li><strong>Two versions need your review</strong> — silent merging would risk data loss</li>
</ul>



<p class="wp-block-paragraph">Avoid blocking alerts for routine failures. Prefer inline status, a persistent account banner, or sync-details screen. Reserve modal interruption for unsafe actions or imminent data loss.</p>



<p class="wp-block-paragraph">Optimistic UI is appropriate only after the local commit succeeds. If a user marks a task complete, the interface can update immediately because the durable local state already represents that action. If the save fails, keep the draft visible, explain that it is not yet stored, and offer a retry or export path.</p>



<p class="wp-block-paragraph">Expose “last synchronized” and pending changes when consequential. Never show a cloud checkmark merely because the device has connectivity. Do not encode sync state only in color. Provide text for VoiceOver.</p>



<p class="wp-block-paragraph">Test sequences, not isolated errors: edit offline, terminate, relaunch, edit elsewhere, reconnect, receive a conflict, lose connectivity during resolution, and retry. Also test duplicate responses, full storage, corruption, external deletion, and schema upgrades with a non-empty outbox.</p>



<h2 class="wp-block-heading">8. Conclusion</h2>



<p class="wp-block-paragraph">Good offline-first architecture is mostly invisible. The app opens with useful data, accepts work immediately, survives interruption, and later converges without surprises. Achieving that experience requires more than adding a cache or calling&nbsp;<code>save()</code>&nbsp;from SwiftUI.</p>



<p class="wp-block-paragraph">Separate view state from durable domain state. Choose persistence by data shape and guarantees. Make writes atomic at meaningful boundaries. Track mutations with stable identities and versions. Treat sync as a retryable state machine, not a request callback. Define ownership, deletion, and conflict policies before the edge cases arrive. Above all, tell the truth in the interface about what is saved locally and what has reached another device.</p>



<p class="wp-block-paragraph">Users rarely praise an app for its outbox, migration plan, or tombstones. They simply decide that the app feels dependable. That judgment is the real product of an offline-first design.</p>



<h2 class="wp-block-heading">Sources and Further Reading</h2>



<ul class="wp-block-list">
<li>Apple, <a href="https://developer.apple.com/videos/play/wwdc2023/10196/">Dive deeper into SwiftData (WWDC23)</a>.</li>



<li>Apple, <a href="https://developer.apple.com/videos/play/wwdc2024/10075/">Track model changes with SwiftData history (WWDC24)</a>.</li>



<li>Apple, <a href="https://developer.apple.com/videos/play/wwdc2025/291/">SwiftData: Dive into inheritance and schema migration (WWDC25)</a>.</li>



<li>Apple, <a href="https://developer.apple.com/documentation/swiftdata/fetching-and-filtering-time-based-model-changes">Fetching and filtering time-based model changes</a>.</li>



<li>Apple, <code><a href="https://developer.apple.com/documentation/coredata/nspersistentcontainer">NSPersistentContainer</a></code>.</li>



<li>Apple, <code><a href="https://developer.apple.com/documentation/foundation/nsdata/writingoptions/atomic">NSData.WritingOptions.atomic</a></code>.</li>



<li>Apple, <code><a href="https://developer.apple.com/documentation/foundation/urlsessionconfiguration/waitsforconnectivity">URLSessionConfiguration.waitsForConnectivity</a></code>.</li>



<li>Apple, <code><a href="https://developer.apple.com/documentation/cloudkit/ckrecord">CKRecord</a></code> and <code><a href="https://developer.apple.com/documentation/cloudkit/ckrecordzonesubscription">CKRecordZoneSubscription</a></code>.</li>



<li>SQLite, <a href="https://sqlite.org/atomiccommit.html">Atomic Commit in SQLite</a> and <a href="https://sqlite.org/wal.html">Write-Ahead Logging</a>.</li>



<li>IETF, <a href="https://www.rfc-editor.org/rfc/rfc9110">RFC 9110: HTTP Semantics</a>.</li>
</ul>



<p class="wp-block-paragraph"></p>
<p>The post <a href="https://mobile.fhstp.ac.at/allgemein/designing-offline-first-ios-apps-local-state-persistence-and-sync-without-losing-user-trust/">Designing Offline-First iOS Apps: Local State, Persistence, and Sync Without Losing User Trust</a> appeared first on <a href="https://mobile.fhstp.ac.at">Mobile USTP MKL</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://mobile.fhstp.ac.at/allgemein/designing-offline-first-ios-apps-local-state-persistence-and-sync-without-losing-user-trust/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Building a Personal Planning App: From Interface Idea to Data-Driven iOS Prototype</title>
		<link>https://mobile.fhstp.ac.at/allgemein/building-a-personal-planning-app-from-interface-idea-to-data-driven-ios-prototype/</link>
					<comments>https://mobile.fhstp.ac.at/allgemein/building-a-personal-planning-app-from-interface-idea-to-data-driven-ios-prototype/#respond</comments>
		
		<dc:creator><![CDATA[Melanie Maier]]></dc:creator>
		<pubDate>Wed, 16 Sep 2026 07:37:26 +0000</pubDate>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[Native Development]]></category>
		<category><![CDATA[Projekte]]></category>
		<category><![CDATA[iOS]]></category>
		<category><![CDATA[mobile]]></category>
		<category><![CDATA[swift]]></category>
		<guid isPermaLink="false">https://mobile.fhstp.ac.at/?p=15909</guid>

					<description><![CDATA[<p>Software projects often begin with a feature list. This one began with a feeling: everyday planning tools are everywhere, and yet personal organization still often feels fragmented. Calendars live in one place, tasks in another, reminders somewhere else, and the mental work of connecting them is left to the user. The goal of this project <a class="read-more" href="https://mobile.fhstp.ac.at/allgemein/building-a-personal-planning-app-from-interface-idea-to-data-driven-ios-prototype/">[...]</a></p>
<p>The post <a href="https://mobile.fhstp.ac.at/allgemein/building-a-personal-planning-app-from-interface-idea-to-data-driven-ios-prototype/">Building a Personal Planning App: From Interface Idea to Data-Driven iOS Prototype</a> appeared first on <a href="https://mobile.fhstp.ac.at">Mobile USTP MKL</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Software projects often begin with a feature list. This one began with a feeling: everyday planning tools are everywhere, and yet personal organization still often feels fragmented. Calendars live in one place, tasks in another, reminders somewhere else, and the mental work of connecting them is left to the user. The goal of this project was not simply to build another productivity app, but to explore how a planning interface could feel more coherent, calmer, and closer to the way people actually think about their days.</p>



<p class="wp-block-paragraph">The app is still in development, and many of its final ideas are intentionally not public yet. For that reason, this article does not reveal the complete product concept or all planned functionality. Instead, it focuses on the development process so far: how the project evolved from a SwiftUI interface prototype into a more structured iOS application with custom data models, persistent storage, reusable components, and first steps toward external calendar integration.</p>



<p class="wp-block-paragraph">At the beginning, the project was mostly visual and exploratory. The first question was not “Which database should this use?” or “How should synchronization work?” but “What should this feel like on a phone?” Since the app is meant to be used frequently and quickly, the interface had to be approachable without becoming decorative for its own sake. SwiftUI was a natural choice because it allowed fast iteration on layout, navigation, state, and component structure. Early work focused on core screens: a home view, overview pages, detail pages, and small reusable interface elements that could later become the visual language of the app.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1540" height="800" src="https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/Wireframes-1540x800.png" alt="" class="wp-image-15918" srcset="https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/Wireframes-1540x800.png 1540w, https://mobile.fhstp.ac.at/wp-content/uploads/2026/09/Wireframes-770x400.png 770w" sizes="auto, (max-width: 1540px) 100vw, 1540px" /></figure>



<p class="wp-block-paragraph">One of the first lessons was that a planning app becomes complex faster than expected. Even if the user-facing idea sounds simple, the underlying structures are not. A calendar item is not just a title and a date. It may have a start and end time, an all-day state, a location, notes, tags, a source, an editability status, and possibly a connection to another system. A task is also more than a checkbox. It can belong to a list, have a due date, include notes, be marked as important, be connected to a reminder, or later need rules for rescheduling. Reminders introduce yet another rhythm, because they are not exactly tasks and not exactly events. They sit somewhere between intention and interruption.</p>



<p class="wp-block-paragraph">Because of that, the project moved relatively early from screen-building into model-building. Separate structures were created for calendars, events, lists, tasks, reminders, external sources, and calendar connections. This was an important shift. Instead of letting the UI define the data informally, the data model started to define what the interface could reliably express. Each object needed an identity, needed to be encodable, and needed to be flexible enough for future features without becoming vague. This part of the process was less visually exciting than building screens, but it made the rest of the application much more stable.</p>



<p class="wp-block-paragraph">The central data layer became an observable store that holds the current calendars, events, lists, tasks, reminders, and external connections. This store is used throughout the SwiftUI views via environment injection, which keeps the individual screens relatively focused. A home screen can ask for visible calendars, upcoming events, or incomplete tasks without owning all the logic itself. Detail pages can receive a selected object and rely on shared update and delete methods. This architecture is still lightweight, but it creates a clear boundary between application state and presentation.</p>



<p class="wp-block-paragraph">A useful turning point was implementing filtering and derived data. Once there were multiple entities in the store, the app needed answers to questions such as: Which events belong to this calendar? Which tasks belong to this list? Which events are upcoming? Which tasks are incomplete and still relevant? These may sound like small helper functions, but they changed how the app could be built. Instead of each screen duplicating filtering code, the store became the place where the application’s understanding of its data lived. That made the UI easier to read and helped reduce inconsistencies between screens.</p>



<p class="wp-block-paragraph">Another major step was persistence. In early prototypes, sample data is enough. It helps with layout and gives the app something to display. But a planning app cannot remain a prototype for long if data disappears every time it restarts. The current version stores a snapshot of the application data as JSON in the app’s documents directory. The snapshot includes the core collections and can be loaded again when the app starts. The saving process also keeps a backup file, so the app has a fallback if the primary file cannot be read.</p>



<p class="wp-block-paragraph">This persistence system is intentionally simple. It is not yet a large database layer, and that is partly deliberate. At this stage, JSON-based persistence makes the app easier to inspect, debug, and evolve. The project is still changing, and a lighter storage approach gives more freedom while the domain model continues to settle. At the same time, the persistence layer is separated from the store, so replacing or extending it later would not require rewriting the entire UI. This is one of the recurring themes of the project: avoid overengineering too early, but create enough structure that future changes do not become painful.</p>



<p class="wp-block-paragraph">Autosave introduced its own design questions. A planning app should not require the user to manually save after every small change. The current approach listens for changes across the main collections and saves the current snapshot after a short debounce. This means the app can react naturally to edits while avoiding excessive file writes. It also means the development process had to account for state changes that are not user edits, such as loading persisted data at launch. Small flags and guard conditions became necessary to prevent the app from immediately saving over freshly loaded state or treating internal setup as user activity.</p>



<p class="wp-block-paragraph">The interface also evolved significantly during this phase. The app now has a clearer structure of pages and components: overview views, detail views, card components, a navigation bar, headers, picker panels, floating action controls, and shared form elements. This componentization was not just about cleaner code. It also helped the app develop a consistent interaction style. Planning tools can easily become cluttered because they contain many object types and many possible actions. Reusable components make it easier to keep the experience predictable.</p>



<p class="wp-block-paragraph">One example is the creation flow. Adding something new should not feel like entering a completely different app. The current implementation uses a shared sheet for creating or editing different item types. It supports modes for events, tasks, and reminders, with separate draft objects and validation. This draft-based approach is important because forms are temporary by nature. A user can open a sheet, make changes, switch context, cancel, or save. Keeping draft state separate from the saved model avoids accidental writes and makes validation clearer.</p>



<p class="wp-block-paragraph">The form system also revealed how much detail is hidden inside “simple” input. Dates, times, optional fields, associations with calendars or lists, tags, icons, and reminder relationships all require careful handling. If these concerns are spread directly across the view code, the form quickly becomes difficult to maintain. By separating drafts, form rows, picker state, and saving logic, the app gained a structure that can grow without turning every new field into a cascade of fragile changes.</p>



<p class="wp-block-paragraph">Design-wise, the project has been moving toward a custom visual identity rather than relying entirely on default iOS components. Custom fonts, color assets, icons, rounded shapes, and card components give the app a more personal tone. This is not only aesthetic. For a planning tool, visual hierarchy matters. The user should be able to distinguish calendars, lists, upcoming items, actions, and details quickly. Colors and cards are not decoration here; they carry information and help reduce cognitive load.</p>



<p class="wp-block-paragraph">At the same time, building a custom interface in SwiftUI requires restraint. It is tempting to make every component unique, especially in a project that has a strong visual direction. But the more custom the interface becomes, the more responsibility the developer takes on for spacing, accessibility, responsiveness, and consistency. This has been one of the practical challenges of the project: finding the balance between a distinctive interface and a maintainable one. The current component structure is an attempt to make that balance explicit.</p>



<p class="wp-block-paragraph">The most technically demanding part so far has been external calendar integration. Local planning data is one thing; synchronizing with external systems is another. The app now contains service layers for Apple Calendar and Google Calendar, as well as a synchronization service that imports events into the app’s own model. This required thinking about authorization, external identifiers, read-only versus editable sources, date ranges, mapping between API objects and local models, and what should happen when external events change or disappear.</p>



<p class="wp-block-paragraph">Apple Calendar integration uses EventKit and must deal with platform-specific permission states. On newer iOS versions, access levels are more precise, so the app has to request and verify the correct kind of calendar access. The service can list available calendars and load events within a selected time range. These events are then mapped into the app’s internal event model, preserving information such as title, location, notes, URL, start and end date, all-day status, external identity, and sync metadata.</p>



<p class="wp-block-paragraph">Google Calendar integration is different because it goes through Google Sign-In and web API requests. This required handling OAuth scopes, restoring previous sign-in sessions, refreshing access tokens, making authenticated requests, decoding calendar lists and event responses, and converting Google’s date formats into local date values. All-day events need special handling because calendar APIs often represent them differently from timed events. These are the kinds of details that are easy to underestimate before implementation begins.</p>



<p class="wp-block-paragraph">The synchronization layer sits above the individual provider services. It loops through configured external calendar connections, loads events for each connection, imports them, tracks which external IDs were seen, updates sync timestamps, and reports failures. The store then upserts imported events instead of blindly appending them. This prevents duplicates and creates a place to handle conflicts. If a local event has pending changes and an external version arrives, the app can mark the situation as a conflict rather than silently overwriting data. Even though the full synchronization story is not finished, the current structure already reflects a key principle: user data should be treated carefully.</p>



<p class="wp-block-paragraph">This was one of the biggest conceptual lessons of the project. Synchronization is not just a technical feature. It is a trust feature. If users put their plans into an app, they need confidence that the app will not lose, duplicate, or unexpectedly modify important information. That means the code has to represent uncertainty. It needs states such as local-only, synced, pending local changes, conflict, or deleted externally. These states are not glamorous, but they are what make the difference between a demo and a tool people might rely on.</p>



<p class="wp-block-paragraph">Another lesson was that the app’s “domain” became clearer through implementation. At first, calendars, lists, tasks, and reminders may seem like familiar categories. But once they are modeled together, their relationships become more interesting. Some items belong to collections. Some can be associated with time. Some can be completed, others can only pass. Some are imported from outside and should not be edited locally. Some may later need richer rules. The development process has therefore been partly technical and partly analytical: understanding what each object means in the system.</p>



<p class="wp-block-paragraph">The current prototype also includes several navigation paths: a home view with upcoming information, calendar overviews and detail views, list overviews and detail views, event and task detail screens, and setup flows. This breadth created a new kind of challenge. Once the app had more than one or two screens, consistency became harder. A change in the model might affect a card, a detail page, a form, and a preview all at once. This is where reusable view components started to pay off. They made the app feel less like a set of separate screens and more like one coherent product.</p>



<p class="wp-block-paragraph">The project is still in an active development stage. There are visible signs of ongoing refactoring: components have been moved into clearer folders, global elements have been separated from list-specific and calendar-specific components, and some older file paths are being replaced by a more organized structure. This is a normal and healthy part of development. Early prototypes often grow organically. At some point, the structure has to catch up with the idea. The important part is not to make the architecture perfect immediately, but to keep improving it when the project’s shape becomes clearer.</p>



<p class="wp-block-paragraph">Looking back, the development so far can be described in phases. The first phase was interface exploration: building enough screens to understand the experience. The second phase was domain modeling: defining the objects the app actually needs. The third phase was state and persistence: making the app remember and update data reliably. The fourth phase was integration: connecting the local world of the app with external calendar systems. The current phase is consolidation: refining components, improving flows, reducing duplication, and preparing the project for more advanced behavior.</p>



<p class="wp-block-paragraph">For a student or early-stage software project, this progression is valuable because it shows how practical software development rarely follows a perfectly linear plan. The app did not begin with a complete architecture diagram and then simply fill in the pieces. Instead, each implementation step revealed the next architectural need. A form revealed the need for drafts. External calendars revealed the need for source metadata and sync states. Autosave revealed the need to distinguish loading from editing. Reusable cards revealed the need for stronger model relationships. The architecture emerged through contact with the problem.</p>



<p class="wp-block-paragraph">There is also a broader lesson about building products that are not ready to be fully disclosed. It can be difficult to talk about a project publicly when the most exciting parts are still private. But not every development story has to reveal the final product. It is possible to discuss the engineering process, the technical decisions, the mistakes avoided, and the problems encountered without giving away the complete concept. In some ways, this is more useful for an informatics audience. The real value is not only in what the app will eventually do, but in how the system is being shaped to make that possible.</p>



<p class="wp-block-paragraph">The next steps will likely focus on stability, refinement, and careful expansion. The persistence system will need to remain reliable as the data model grows. Synchronization will need more testing, especially around conflicts and edge cases. The interface will need continued polishing across different device sizes and user scenarios. Some flows that currently exist as early implementations will need to become more robust. And as the app moves closer to a publishable version, privacy, permissions, error handling, and user trust will become even more important.</p>



<p class="wp-block-paragraph">What makes this project interesting is that it sits at the intersection of design, data modeling, and everyday behavior. A planning app is not just a technical container for events and tasks. It is a tool that asks to be invited into a user’s routine. That creates a high bar: the app has to be useful without being noisy, structured without being rigid, and personal without becoming confusing. Reaching that balance takes iteration.</p>



<p class="wp-block-paragraph">So far, the development has already moved beyond a simple prototype. The app has a working SwiftUI foundation, a growing design system, structured models, persistent local data, reusable creation flows, and initial external calendar synchronization. More importantly, it has a clearer sense of direction. The final product is not ready to be revealed yet, but the development process has already shown what kind of challenge this is: not merely building screens, but building a coherent planning environment one careful layer at a time.</p>



<p class="wp-block-paragraph"></p>
<p>The post <a href="https://mobile.fhstp.ac.at/allgemein/building-a-personal-planning-app-from-interface-idea-to-data-driven-ios-prototype/">Building a Personal Planning App: From Interface Idea to Data-Driven iOS Prototype</a> appeared first on <a href="https://mobile.fhstp.ac.at">Mobile USTP MKL</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://mobile.fhstp.ac.at/allgemein/building-a-personal-planning-app-from-interface-idea-to-data-driven-ios-prototype/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>MongoDB Atlas an Overview</title>
		<link>https://mobile.fhstp.ac.at/allgemein/blogbeitrag-mongodb-atlas/</link>
		
		<dc:creator><![CDATA[Daniel Studera]]></dc:creator>
		<pubDate>Tue, 20 Jan 2026 11:22:12 +0000</pubDate>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[Development]]></category>
		<guid isPermaLink="false">https://mobile.fhstp.ac.at/?p=15246</guid>

					<description><![CDATA[<p>Introduction Cloud databases are now a central component of modern web and mobile applications. Instead of installing, maintaining, and scaling databases themselves, developers can rely on services provided via cloud platforms. The providers then take over tasks such as infrastructure management, updates, backups, and high availability. For companies, this means less operational effort and a <a class="read-more" href="https://mobile.fhstp.ac.at/allgemein/blogbeitrag-mongodb-atlas/">[...]</a></p>
<p>The post <a href="https://mobile.fhstp.ac.at/allgemein/blogbeitrag-mongodb-atlas/">MongoDB Atlas an Overview</a> appeared first on <a href="https://mobile.fhstp.ac.at">Mobile USTP MKL</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading">Introduction</h2>



<p class="wp-block-paragraph">Cloud databases are now a central component of modern web and mobile applications. Instead of installing, maintaining, and scaling databases themselves, developers can rely on services provided via cloud platforms. The providers then take over tasks such as infrastructure management, updates, backups, and high availability. For companies, this means less operational effort and a stronger focus on the actual application.</p>



<p class="wp-block-paragraph">In web and mobile development, NoSQL databases in particular have become established in recent years alongside relational databases. The main reason for this lies in their flexible data models and good horizontal scalability. While relational databases rely heavily on fixed schemas, NoSQL databases allow a more flexible data structure. This is especially helpful when data models change frequently or when different data types need to be stored.</p>



<p class="wp-block-paragraph">This blog post focuses on MongoDB Atlas as an example of a modern NoSQL cloud database. The goal is to classify the service from a technical perspective, highlight its strengths and limitations, and compare it with other widely used NoSQL database services.&nbsp;</p>



<h2 class="wp-block-heading">What is MongoDB Atlas?</h2>



<p class="wp-block-paragraph">MongoDB Atlas is a fully managed cloud database service based on the MongoDB database. The provider is the same company, MongoDB Inc.</p>



<p class="wp-block-paragraph">Atlas provides MongoDB clusters as a service and supports various cloud platforms such as Amazon Web Services (AWS), Google Cloud Platform, and Microsoft Azure. Users can choose both the cloud provider and the region in which their database is hosted. In addition, MongoDB Atlas also supports multi region or global cluster setups when data needs to be distributed across multiple geographic locations.</p>



<p class="wp-block-paragraph">Core features include automatic scaling, integrated backups, monitoring, and security mechanisms. Scaling can be performed both vertically and horizontally without manual intervention in the infrastructure, directly via the web interface. Backups are created automatically and can be restored at any time.</p>



<p class="wp-block-paragraph">As the name suggests, Atlas uses the document oriented MongoDB data model. Data is stored as BSON documents, which are very similar to JSON and allow nested structures. MongoDB supports ACID compliant transactions (Atomicity, Consistency, Isolation, Durability) across multiple documents, enabling the implementation of more complex business logic.</p>



<p class="wp-block-paragraph">For getting started, Atlas offers a free tier cluster. This is suitable for learning purposes, prototypes, and small applications. Higher performance clusters are billed based on usage.</p>



<h2 class="wp-block-heading">Technical foundation</h2>



<h3 class="wp-block-heading">Document oriented data model</h3>



<p class="wp-block-paragraph">Unlike relational databases, MongoDB stores data in documents that do not require a fixed table structure. Each document can contain different fields. This schema flexibility makes it easier to adapt data models over the course of development.</p>



<p class="wp-block-paragraph">For applications with dynamic requirements, such as APIs, this is a practical advantage. At the same time, MongoDB also supports optional schema validation to enforce basic structures.</p>



<h3 class="wp-block-heading">Scaling and sharding</h3>



<p class="wp-block-paragraph">MongoDB Atlas supports horizontal scaling through sharding. In this process, data is distributed across multiple nodes, known as shards. Atlas handles replication, load distribution, and balancing automatically.</p>



<p class="wp-block-paragraph">As the number of users grows or data volumes increase, the cluster can be scaled easily without downtime. Another major advantage is multi region setups, which make it possible to store data physically closer to users and thus reduce latency. However, multi region setups only provide real added value if the backend or connected services are also distributed across multiple regions and are not operated exclusively from a single central data center.</p>



<h3 class="wp-block-heading">Performance, monitoring, and operations</h3>



<p class="wp-block-paragraph">Atlas provides integrated monitoring features. These include metrics for utilization, query performance, and resource usage. Slow queries can be analyzed and subsequently optimized.</p>



<p class="wp-block-paragraph">There are also alerting features that automatically send notifications in the event of unusual behavior or errors. This further helps to keep the operational effort for development teams low.</p>



<h3 class="wp-block-heading">Advanced Atlas services</h3>



<p>
  In addition to the classic database, MongoDB Atlas also offers further services.
  Some of the most important ones are listed briefly below.
</p>

<ul>
  <li>
    <strong>Atlas Search</strong> is an integrated full text search based on Apache Lucene,
    which removes the need to develop a separate search system.
  </li>
  <li>
    <strong>Atlas Vector Search</strong> enables similarity searches based on vectors,
    for example for semantic search or AI related use cases.
  </li>
  <li>
    <strong>Atlas Triggers</strong> allow the execution of serverless functions in response
    to database events such as inserts or updates.
  </li>
  <li>
    <strong>Atlas App Services</strong> provide features such as authentication,
    serverless functions, device synchronization, and offline synchronization.
  </li>
</ul>



<h2 class="wp-block-heading">Comparison with other NoSQL cloud databases&nbsp;</h2>



<p class="wp-block-paragraph">MongoDB Atlas offers many features that make it attractive as a cloud database in web and mobile environments. In practice, however, the question arises whether Atlas is actually a good choice or whether other NoSQL services are better suited depending on the requirements. The following section compares MongoDB Atlas with common alternatives and classifies their respective strengths and weaknesses.&nbsp;</p>



<h3 class="wp-block-heading">MongoDB Atlas vs Google Cloud Firestore</h3>



<p class="wp-block-paragraph">Firestore is especially widespread in mobile and frontend focused environments. The comparison is obvious, since both databases are document oriented, schema free, and are often used for similar use cases.</p>



<p class="wp-block-paragraph">Firestore allows a very fast start and scales automatically, but it tightly binds applications to the Firebase ecosystem. Data access, authentication, and security rules are closely interconnected and rely on proprietary APIs. This results in a relatively high vendor lock in, since switching the database later usually requires significant changes to architecture and code.</p>



<p class="wp-block-paragraph">In addition, Firestore mainly supports simple, clearly defined queries. Which data can be queried and in what form must be defined early on. MongoDB Atlas offers more flexibility here, as more complex queries and aggregations can be implemented on the server side.</p>



<h3 class="wp-block-heading">MongoDB Atlas vs Couchbase Capella</h3>



<p class="wp-block-paragraph">Couchbase Capella is also a document oriented NoSQL database that is often mentioned in web and mobile contexts. It is likewise flexible in its document structure and suitable for scalable applications.</p>



<p class="wp-block-paragraph">Couchbase places a stronger focus on performance and combines document and key value access patterns. Capella also offers features for mobile first scenarios, such as offline synchronization. MongoDB Atlas, on the other hand, is more broadly applicable as a general purpose backend database and provides more flexible query and aggregation capabilities.</p>



<h3 class="wp-block-heading">MongoDB Atlas vs Azure Cosmos DB (MongoDB API)</h3>



<p class="wp-block-paragraph">Azure Cosmos DB is a globally distributed NoSQL database service from Microsoft. Cosmos DB offers a MongoDB compatible API and therefore covers similar use cases, especially within the Azure ecosystem.</p>



<p class="wp-block-paragraph">Cosmos DB provides automatic scaling and global replication, but relies on its own implementation of the MongoDB API. As a result, not all MongoDB features are fully available or behave in exactly the same way. MongoDB Atlas uses the original MongoDB engine and offers consistent feature support across versions.</p>



<p class="wp-block-paragraph">Cosmos DB is strongly tied to the Azure ecosystem, which results in higher vendor lock in. MongoDB Atlas is more flexible with regard to infrastructure and provider changes due to its multi cloud support and self hosting options.</p>



<h2 class="wp-block-heading">Use cases: when MongoDB Atlas is suitable and when it is not&nbsp;</h2>



<h3 class="wp-block-heading">Suitable use cases</h3>



<p class="wp-block-paragraph">MongoDB Atlas is particularly well suited for web and mobile applications with dynamic or frequently changing data models. Typical examples include content platforms, social applications, software as a service products, or API centered backends.</p>



<p class="wp-block-paragraph">It is also suitable for applications with a growing number of users, since scaling and operations are largely automated. Teams benefit from having to deal little or not at all with infrastructure, backups, or updates.</p>



<p class="wp-block-paragraph">Atlas is also a good choice when complex document structures, aggregations, or flexible queries are required, and when multi regional cloud operation is needed at the same time.</p>



<h3 class="wp-block-heading">Less suitable use cases</h3>



<p class="wp-block-paragraph">For applications with extremely high latency requirements but simple access patterns, specialized databases may be a better fit.</p>



<p class="wp-block-paragraph">In scenarios where full control over the infrastructure is required or cloud dependencies are to be avoided, a self hosted database stack may be more appropriate.</p>



<h2 class="wp-block-heading">Conclusion&nbsp;</h2>



<p class="wp-block-paragraph">MongoDB Atlas is a powerful and practical cloud database service for modern web and mobile applications. Its strengths lie in schema flexibility, easy scalability, and low operational overhead.</p>



<p class="wp-block-paragraph">For many typical use cases in web and app development, Atlas offers a balanced combination of flexibility and operational reliability. At the same time, it is important to analyze the specific workload and consider alternative databases when specialized requirements exist.</p>



<h2 class="wp-block-heading">Sources</h2>



<ol class="wp-block-list">
<li><a href="https://www.ibm.com/topics/database-as-a-service">https://www.ibm.com/topics/database-as-a-service</a></li>



<li><a href="https://www.ibm.com/think/topics/nosql-databases">https://www.ibm.com/think/topics/nosql-databases</a></li>



<li><a href="https://www.mongodb.com/docs/atlas/">https://www.mongodb.com/docs/atlas/</a></li>



<li><a href="https://medium.com/%40bdhanushka65/what-you-need-to-know-about-mongodb-atlas-b4743727e7f1">https://medium.com/%40bdhanushka65/what-you-need-to-know-about-mongodb-atlas-b4743727e7f1</a></li>



<li><a href="https://www.mongodb.com/cloud/atlas/multi-cloud">https://www.mongodb.com/cloud/atlas/multi-cloud</a></li>



<li><a href="https://www.mongodb.com/docs/atlas/global-clusters/">https://www.mongodb.com/docs/atlas/global-clusters/</a></li>



<li><a href="https://www.mongodb.com/docs/manual/core/databases-and-collections/">https://www.mongodb.com/docs/manual/core/databases-and-collections/</a></li>



<li><a href="https://www.mongodb.com/docs/manual/sharding/">https://www.mongodb.com/docs/manual/sharding/</a></li>



<li><a href="https://www.mongodb.com/docs/manual/core/transactions/">https://www.mongodb.com/docs/manual/core/transactions/</a></li>



<li><a href="https://bsonspec.org/">https://bsonspec.org/</a></li>



<li><a href="https://www.mongodb.com/docs/atlas/monitoring/">https://www.mongodb.com/docs/atlas/monitoring/</a></li>



<li><a href="https://www.mongodb.com/docs/atlas/backup/">https://www.mongodb.com/docs/atlas/backup/</a></li>



<li><a href="https://www.mongodb.com/docs/atlas/atlas-search/">https://www.mongodb.com/docs/atlas/atlas-search/</a></li>



<li><a href="https://cloud.google.com/firestore/docs/overview">https://cloud.google.com/firestore/docs/overview</a></li>



<li><a href="https://docs.couchbase.com/cloud/">https://docs.couchbase.com/cloud/</a></li>



<li><a href="https://risingwave.com/blog/mongodb-vs-firebase-firestore-vs-cosmos-db/?utm_source=chatgpt.com">https://risingwave.com/blog/mongodb-vs-firebase-firestore-vs-cosmos-db/?utm_source=chatgpt.com</a></li>



<li><a href="https://www.ionos.at/digitalguide/server/knowhow/couchbase-alternative/?utm_source=chatgpt.com">https://www.ionos.at/digitalguide/server/knowhow/couchbase-alternative/?utm_source=chatgpt.com</a></li>



<li><a href="https://learn.microsoft.com/en-us/azure/cosmos-db/mongodb/introduction">https://learn.microsoft.com/en-us/azure/cosmos-db/mongodb/introduction</a></li>
</ol>



<h2 class="wp-block-heading">Image Sources</h2>



<p class="wp-block-paragraph"><a href="https://www.mongodb.com/de-de/products/platform">https://www.mongodb.com/de-de/products/platform</a></p>



<h2 class="wp-block-heading">Other Projects</h2>



<p class="wp-block-paragraph"><a href="https://swiva.app">Swiva</a> is a mobile app for saving ideas, places, recipes and activities from TikTok, Instagram, Maps and the web, and actually turning them into plans.</p>
<p>The post <a href="https://mobile.fhstp.ac.at/allgemein/blogbeitrag-mongodb-atlas/">MongoDB Atlas an Overview</a> appeared first on <a href="https://mobile.fhstp.ac.at">Mobile USTP MKL</a>.</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
