<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[LowStack]]></title><description><![CDATA[Practical insights for OutSystems, low-code, and modern builders.]]></description><link>https://lowstack.tegar.org</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1761432703731/8c88e6a6-0273-4dde-8c49-218c155e9dcb.png</url><title>LowStack</title><link>https://lowstack.tegar.org</link></image><generator>RSS for Node</generator><lastBuildDate>Sat, 18 Apr 2026 11:01:14 GMT</lastBuildDate><atom:link href="https://lowstack.tegar.org/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Default-Allow vs Default-Deny]]></title><description><![CDATA[When implementing role-based access in an application, we often face a fundamental choice: should access be denied by default or allowed by default? In practice, this means deciding whether every capability starts as false or true.
There is no single...]]></description><link>https://lowstack.tegar.org/default-allow-vs-default-deny</link><guid isPermaLink="true">https://lowstack.tegar.org/default-allow-vs-default-deny</guid><category><![CDATA[development]]></category><dc:creator><![CDATA[Tegar]]></dc:creator><pubDate>Fri, 30 Jan 2026 08:13:46 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1769760548372/01f110d5-2094-4b25-bc34-691838380e05.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When implementing role-based access in an application, we often face a fundamental choice: should access be <strong>denied by default</strong> or <strong>allowed by default</strong>? In practice, this means deciding whether every capability starts as <code>false</code> or <code>true</code>.</p>
<p>There is no single “correct” default. The right choice depends on <strong>what you are optimizing for at each layer,</strong> security, predictability, or speed of development<strong>.</strong> Choosing the wrong default in the wrong place can either slow teams down or introduce subtle, hard-to-detect risks.</p>
<p>In this post, I’ll try explore the reasoning behind default-allow and default-deny, and explain when and where, each design pattern makes the most sense.</p>
<h2 id="heading-default-allow-allow-by-default">👌Default-Allow (Allow-by-Default)</h2>
<h3 id="heading-definition">Definition</h3>
<p>If no rule exists, access or behavior is <strong>granted</strong>.</p>
<blockquote>
<p>“Unless something explicitly says no, it’s allowed.”</p>
</blockquote>
<hr />
<h3 id="heading-characteristics">Characteristics</h3>
<ul>
<li><p>Default state = <strong>true</strong></p>
</li>
<li><p>Rules exist mainly to <strong>restrict</strong></p>
</li>
<li><p>Absence of data = <strong>allow</strong></p>
</li>
</ul>
<hr />
<h3 id="heading-example">Example</h3>
<p><strong>Access control</strong></p>
<ul>
<li><p>No rule found → user <strong>can</strong> access the page</p>
</li>
<li><p>Rule found with <code>IsAllowed = false</code> → access blocked</p>
</li>
</ul>
<p><strong>Form fields</strong></p>
<ul>
<li><p>All fields are editable by default</p>
</li>
<li><p>Only specific fields are set to read-only</p>
</li>
</ul>
<hr />
<h3 id="heading-why-default-allow-optimizes-for-speed">Why Default-Allow Optimizes for Speed</h3>
<p><strong>1. Fewer decisions upfront</strong></p>
<p>You create a new screen:</p>
<ul>
<li><p>No access rule yet</p>
</li>
<li><p>No role mapping</p>
</li>
<li><p>No capability defined</p>
</li>
</ul>
<p>The screen is immediately accessible, allowing development and testing to continue without blockers.</p>
<p><strong>2. Smaller rule sets = faster change</strong></p>
<p>Rules only describe exceptions.</p>
<p>Example:</p>
<ul>
<li>Block admin screen for non-admins (1 rule)</li>
</ul>
<p>Versus deny-by-default:</p>
<ul>
<li><p>Allow admin screen for admins</p>
</li>
<li><p>Allow reports for analysts</p>
</li>
<li><p>Allow dashboard for managers</p>
<p>  (many rules)</p>
</li>
</ul>
<p>This reduces configuration overhead and speeds up iteration.</p>
<hr />
<h3 id="heading-trade-offs-important">Trade-Offs (Important)</h3>
<p>The same qualities that make default-allow fast also make it risky at scale:</p>
<ul>
<li><p>Missing rules</p>
</li>
<li><p>Implicit behavior</p>
</li>
<li><p>Assumptions instead of guarantees</p>
</li>
</ul>
<p>Used carelessly, this can lead to <strong>silent security bugs</strong>.</p>
<hr />
<h2 id="heading-default-deny-deny-by-default">🫷Default-Deny (Deny-by-Default)</h2>
<h3 id="heading-definition-1">Definition</h3>
<p>If no rule exists, access or behavior is <strong>denied</strong>.</p>
<blockquote>
<p>“Unless something explicitly says yes, it’s denied.”</p>
</blockquote>
<hr />
<h3 id="heading-characteristics-1">Characteristics</h3>
<ul>
<li><p>Default state = <strong>false</strong></p>
</li>
<li><p>Rules exist mainly to <strong>grant</strong></p>
</li>
<li><p>Absence of data = <strong>deny</strong></p>
</li>
</ul>
<hr />
<h3 id="heading-example-1">Example</h3>
<p><strong>Access control</strong></p>
<ul>
<li><p>No rule found → user <strong>cannot</strong> access the page</p>
</li>
<li><p>Rule found with <code>IsAllowed = true</code> → access granted</p>
</li>
</ul>
<p><strong>Form fields</strong></p>
<ul>
<li><p>All fields are read-only by default</p>
</li>
<li><p>Only specific fields are enabled</p>
</li>
</ul>
<hr />
<h3 id="heading-why-default-deny-optimizes-for-certainty">Why Default-Deny Optimizes for Certainty</h3>
<p><strong>1. Explicit permission = predictable behavior</strong></p>
<p>Every allowed action is intentional and traceable to a rule.</p>
<p>No surprises, no accidental access.</p>
<p><strong>2. Missing configuration is safe (fail-closed)</strong></p>
<p>If something goes wrong:</p>
<ul>
<li><p>Rules not loaded</p>
</li>
<li><p>API data missing</p>
</li>
<li><p>New screen added without permissions</p>
</li>
</ul>
<p>The result is safe:</p>
<ul>
<li><p>Access denied</p>
</li>
<li><p>Fields disabled</p>
</li>
<li><p>Buttons hidden</p>
</li>
</ul>
<p>The system fails <strong>closed</strong>, not open.</p>
<p><strong>3. Strong fit for security and authorization</strong></p>
<p>Deny-by-default is foundational for:</p>
<ul>
<li><p>Access control</p>
</li>
<li><p>Compliance systems</p>
</li>
<li><p>Financial workflows</p>
</li>
<li><p>Admin tools</p>
</li>
</ul>
<p>One accidental “allow” can be catastrophic.</p>
<p>One accidental “deny” is usually recoverable.</p>
<p><strong>4. Prevents permission drift</strong></p>
<p>New features don’t automatically grant access.</p>
<p>Old roles don’t silently gain new power.</p>
<blockquote>
<p>Silence does not grant authority.</p>
</blockquote>
<hr />
<h3 id="heading-trade-offs">Trade-Offs</h3>
<p>Deny-by-default feels slower because it requires:</p>
<ul>
<li><p>More upfront work</p>
</li>
<li><p>More configuration</p>
</li>
<li><p>More rules</p>
</li>
</ul>
<p>You pay a <strong>design tax early</strong> to avoid a <strong>security tax later</strong>.</p>
<h3 id="heading-best-practice">🎖️ Best Practice</h3>
<p>There is no single default that works everywhere. The key is to apply the right default <strong>per layer</strong>.</p>
<h3 id="heading-recommended-mapping">Recommended Mapping</h3>
<ul>
<li><p><strong>Security, services, and data boundaries</strong> → <strong>Deny-by-default</strong><br />  (APIs, server actions, data mutations, approvals)<br />  If it touches data or authority, access must be explicitly granted.</p>
</li>
<li><p><strong>Navigation and page access</strong> → <strong>Deny-by-default</strong><br />  Pages and flows should never be discoverable by accident.</p>
</li>
<li><p><strong>UI composition and visual behavior</strong> → <strong>Allow-by-default (controlled)</strong><br />  Field visibility and layout rules benefit from faster iteration and fewer configurations.</p>
</li>
<li><p><strong>Field editability and business rules</strong> → <strong>Deny-by-default</strong><br />  Viewing can be permissive, editing must be explicit.</p>
</li>
</ul>
<hr />
<h2 id="heading-the-hybrid-model-recommended">The Hybrid Model (Recommended)</h2>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Layer</td><td>Default</td></tr>
</thead>
<tbody>
<tr>
<td>Backend &amp; services</td><td>Deny-by-default</td></tr>
<tr>
<td>Page access &amp; actions</td><td>Deny-by-default</td></tr>
<tr>
<td>UI visibility &amp; helpers</td><td>Allow-by-default</td></tr>
</tbody>
</table>
</div><p>This keeps <strong>security predictable</strong>, <strong>UX flexible</strong>, and <strong>development fast</strong>.</p>
<hr />
<h2 id="heading-environment-based-strategy-optional">Environment-Based Strategy (Optional)</h2>
<ul>
<li><p><strong>Development</strong> → Allow-by-default</p>
</li>
<li><p><strong>UAT</strong> → Mixed</p>
</li>
<li><p><strong>Production</strong> → Deny-by-default</p>
</li>
</ul>
<p>This allows fast exploration early and strict control before release.</p>
]]></content:encoded></item><item><title><![CDATA[When Users Don’t Tell the Whole Story : The XY Problem]]></title><description><![CDATA[The XY problem is a communication issue that often arises in software development. It occurs when someone seeking help focuses on their attempted solution (Y) rather than the actual problem (X) they’re trying to solve.
It often plays out like this:

...]]></description><link>https://lowstack.tegar.org/xyproblem</link><guid isPermaLink="true">https://lowstack.tegar.org/xyproblem</guid><category><![CDATA[xyproblem]]></category><category><![CDATA[Developer]]></category><category><![CDATA[software development]]></category><category><![CDATA[user experience]]></category><category><![CDATA[project management]]></category><dc:creator><![CDATA[Tegar]]></dc:creator><pubDate>Tue, 14 Oct 2025 19:25:26 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1760469820659/64bf75e9-521a-4334-b63f-98a9c217ad0a.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The <strong>XY problem</strong> is a communication issue that often arises in software development. It occurs when someone seeking help focuses on their <em>attempted solution (Y)</em> rather than the <em>actual problem (X)</em> they’re trying to solve.</p>
<p>It often plays out like this:</p>
<ol>
<li><p>The user wants to solve <strong>X</strong>.</p>
</li>
<li><p>They think doing <strong>Y</strong> will help.</p>
</li>
<li><p>They don’t know how to do <strong>Y</strong>, so they ask for help with <strong>Y</strong>.</p>
</li>
<li><p>Others help with <strong>Y</strong>, but <strong>Y</strong> turns out irrelevant or inefficient.</p>
</li>
<li><p>Time is wasted before anyone realizes the real goal was <strong>X</strong> all along.</p>
</li>
</ol>
<hr />
<h3 id="heading-the-developers-dilemma">The Developer’s Dilemma</h3>
<p>In software projects, users or even product managers acting on their behalf often describe what they <em>want built</em> rather than what they <em>need solved</em>.</p>
<ul>
<li><p><strong>X</strong> = the real problem (the <em>why</em>)</p>
</li>
<li><p><strong>Y</strong> = the proposed solution (the <em>what</em>)</p>
</li>
</ul>
<hr />
<h3 id="heading-example">Example</h3>
<p>Users had a problem: they needed to <strong>find and correct failed sync records</strong> in a table that also contained successful ones. The real issue (X) was <strong>quickly identifying failed records</strong> for correction, but users proposed a solution (Y):</p>
<blockquote>
<p>“Can you add checkboxes so we can select and fix the failed ones?”</p>
</blockquote>
<p>The developer built the checkbox feature, but it didn’t help much. Users still had to go through every record manually and often missed some.</p>
<p>Then the developer asked:</p>
<blockquote>
<p>“Why do you need checkboxes?” “So we can correct the failed records,” the user said.</p>
</blockquote>
<p>That simple question revealed the real need. Instead of checkboxes, the developer added a <strong>filter for ‘Failed’ records</strong> and an <strong>Excel export option</strong>, allowing users to easily find and correct the failed data outside the system.</p>
<p><strong>Result:</strong> The process became faster, cleaner, and solved the real problem — not just the requested one.</p>
<hr />
<h3 id="heading-active-listening-matters">Active Listening Matters</h3>
<p>Developers shouldn’t just build what’s asked, they should <em>listen actively</em>. That means asking “why,” understanding context, and challenging assumptions.</p>
<p>The developer who only hears <em>“add checkboxes”</em> builds a limited feature. The developer who asks <em>“why”</em> builds a better product.</p>
<h3 id="heading-users-arent-product-designers">Users Aren’t Product Designers</h3>
<p>Users are experts in their own needs and frustrations, but they’re not experts in software design or technical trade-offs. Their proposed solution (Y) is often the most obvious one they can think of, not necessarily the most efficient or scalable.</p>
<p>A developer’s expertise is to uncover the real problem (X) and design the best solution for it.</p>
<hr />
<h3 id="heading-how-to-avoid-the-xy-problem">How to Avoid the XY Problem</h3>
<ol>
<li><p><strong>Ask “Why?” empathetically.</strong> Uncover the motivation behind every request.</p>
</li>
<li><p><strong>Focus on goals, not features.</strong> Talk about outcomes, not UI elements.</p>
</li>
<li><p><strong>Separate problems from solutions.</strong> Capture both during discussions.</p>
</li>
<li><p><strong>Prototype to validate.</strong> Test ideas early to confirm real needs.</p>
</li>
</ol>
<h3 id="heading-closing">Closing</h3>
<p>The XY problem highlights why listening to users is so tricky for developers. It reveals the gap between what users <em>ask for</em> and what they <em>actually need</em>.</p>
<p>Developers who focus only on the “what” risk building the wrong thing. Those who seek the “why” create meaningful, effective solutions.</p>
]]></content:encoded></item><item><title><![CDATA[Combining AES and RSA for Secure Key Management]]></title><description><![CDATA[Encryption is the foundation of secure communication and data storage. At its core, it scrambles information with a cryptographic key so that only authorized parties can read it. Decryption then reverses this process, restoring the original data.
But...]]></description><link>https://lowstack.tegar.org/combining-aes-and-rsa-for-secure-key-management</link><guid isPermaLink="true">https://lowstack.tegar.org/combining-aes-and-rsa-for-secure-key-management</guid><category><![CDATA[Cryptography]]></category><category><![CDATA[encryption]]></category><dc:creator><![CDATA[Tegar]]></dc:creator><pubDate>Fri, 29 Aug 2025 23:41:17 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1756510788076/050eff03-22db-4588-a715-5e6d8c611303.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Encryption is the foundation of secure communication and data storage. At its core, it scrambles information with a cryptographic key so that only authorized parties can read it. Decryption then reverses this process, restoring the original data.</p>
<p>But this raises a critical challenge: <strong>how do we keep communication secure when multiple users are involved?</strong> If a single key is shared among many users, it becomes a security risk. On the other hand, if each user has their own key, how can they all still access the same protected message without weakening security?</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756510115251/e4b5a9c3-b59d-495d-b772-4fde7c1b09b0.png" alt class="image--center mx-auto" /></p>
<p>The answer lies in combining two powerful algorithms: <strong>AES (Advanced Encryption Standard)</strong> and <strong>RSA (Rivest–Shamir–Adleman)</strong>.</p>
<hr />
<h2 id="heading-why-combine-aes-and-rsa">Why Combine AES and RSA?</h2>
<p>AES and RSA are two of the most widely used algorithms in modern cryptography, but they serve very different purposes:</p>
<ul>
<li><p><strong>AES</strong> is extremely fast and efficient for encrypting large amounts of data.</p>
</li>
<li><p><strong>RSA</strong> is slower, but excellent for securely sharing keys and providing authentication.</p>
</li>
</ul>
<p>By using them together, we get the best of both worlds: AES protects the data, while RSA ensures that the AES key itself is distributed safely.</p>
<hr />
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756510295097/1d4d7063-a4b0-4e53-9242-6121253585f0.png" alt class="image--center mx-auto" /></p>
<p><strong>AES</strong> is a <strong>symmetric</strong> algorithm, meaning the same key is used for both encryption and decryption.</p>
<ul>
<li><p><strong>Strengths</strong>: Very fast, suitable for encrypting files, databases, or network traffic.</p>
</li>
<li><p><strong>Challenge</strong>: The key must be shared securely—if it’s leaked, the entire system is compromised.</p>
</li>
</ul>
<hr />
<p><strong>RSA</strong> is an <strong>asymmetric</strong> algorithm, meaning it uses a <strong>key pair</strong>: one public and one private.</p>
<ul>
<li><p><strong>Strengths</strong>: Ideal for exchanging secrets like AES keys, and for authentication through digital signatures.</p>
</li>
<li><p><strong>Challenge</strong>: Computationally heavy and not efficient for encrypting large datasets directly.</p>
</li>
</ul>
<hr />
<h2 id="heading-how-the-hybrid-approach-works">How the Hybrid Approach Works</h2>
<p>The process of combining AES and RSA can be broken into two main parts: <strong>key establishment</strong> and <strong>message exchange</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756510063038/6e179d32-c678-4d14-ac53-2d5bb9ecc422.png" alt class="image--center mx-auto" /></p>
<ol>
<li><p><strong>Generate AES Secret Key</strong><br /> A random AES key is created. This will be used to encrypt the actual data.</p>
</li>
<li><p><strong>Generate RSA Key Pair</strong><br /> Each recipient generates an RSA public/private key pair.</p>
</li>
<li><p><strong>Encrypt AES Secret Key with RSA Public Key</strong><br /> The AES key is encrypted using the recipient’s RSA public key.</p>
<ol>
<li><strong><em>Distribute Encrypted AES Keys</em></strong><br /> The encrypted AES key (different for each recipient, since it’s encrypted with their unique public key) is distributed securely.</li>
</ol>
</li>
<li><p><strong>Encrypt Data with AES Key</strong><br /> The sender encrypts the plaintext message with the AES key, producing ciphertext.</p>
</li>
<li><p><strong>Recipient Decrypts AES Key with RSA Private Key</strong><br /> Each recipient uses their private RSA key to decrypt the AES key sent to them.</p>
</li>
<li><p><strong>Recipient Decrypts Data with AES Key</strong><br /> Finally, the recipient uses the recovered AES key to decrypt the ciphertext and obtain the original plaintext.</p>
</li>
</ol>
<hr />
<h2 id="heading-why-this-matters">Why This Matters</h2>
<ul>
<li><p><strong>Security</strong>: RSA secures key distribution; AES secures the data itself.</p>
</li>
<li><p><strong>Efficiency</strong>: AES handles the heavy work of encrypting large volumes of data, while RSA is only used for small key exchanges.</p>
</li>
<li><p><strong>Scalability</strong>: Each recipient can use their own RSA key pair to securely receive the same AES key, enabling secure communication across many users.</p>
</li>
</ul>
<hr />
<h2 id="heading-conclusion">Conclusion</h2>
<p>AES and RSA aren’t rivals, they’re partners. AES delivers the speed to encrypt massive amounts of data, while RSA ensures the keys are shared securely and with trust. Together, they form the backbone of modern encryption, balancing performance with security in a way that has stood the test of time.</p>
<p>I might dive deeper in a future post to explore how this hybrid approach implemented spesifically with OutSystems, stay tune.</p>
]]></content:encoded></item><item><title><![CDATA[Reducing Site Property Bloat with JSON]]></title><description><![CDATA[Managing configuration values in OutSystems can quickly lead to a bloated and messy list of Site Properties,one for every feature toggle, API key, timeout value, and more. While functional, this approach becomes increasingly difficult to scale, navig...]]></description><link>https://lowstack.tegar.org/reducing-site-property-bloat-with-json</link><guid isPermaLink="true">https://lowstack.tegar.org/reducing-site-property-bloat-with-json</guid><category><![CDATA[siteproperty]]></category><category><![CDATA[outsystems]]></category><category><![CDATA[json]]></category><category><![CDATA[optimization]]></category><dc:creator><![CDATA[Tegar]]></dc:creator><pubDate>Sat, 26 Jul 2025 23:47:41 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1753573561777/0697b313-03e5-41ef-b321-5023405684f0.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Managing configuration values in OutSystems can quickly lead to a bloated and messy list of Site Properties,one for every feature toggle, API key, timeout value, and more. While functional, this approach becomes increasingly difficult to scale, navigate, and maintain,especially as projects grow and teams expand.</p>
<p>After running into this issue multiple times, I discovered a more efficient approach: <strong>storing structured JSON inside a single Site Property.</strong> This simple shift offers big benefits: <em>cleaner configuration management, fewer properties to track, easier updates, and better grouping of related values.</em></p>
<p>Interestingly, there are <strong>58+ community-submitted ideas</strong> related to improving Site Property management in OutSystems,ranging from versioning and logging to value grouping and description support. Clearly, this is a pain point many developers face.</p>
<hr />
<h2 id="heading-the-problem-with-site-properties-today">The Problem with Site Properties Today</h2>
<p>Here’s why the default Site Property approach starts to break down at scale:</p>
<ol>
<li><p><strong>No Organization</strong> – There's no native way to sort or group properties, making it hard to find related items.</p>
</li>
<li><p><strong>Poor Grouping</strong> – Related values (like for a single feature) are scattered, not logically grouped.</p>
</li>
<li><p><strong>Hard to Maintain</strong> – As more properties get added, understanding their purpose becomes harder.</p>
</li>
<li><p><strong>No Logging</strong> – There’s no built-in history or change log for Site Property values.</p>
</li>
<li><p><strong>Polluted Configuration Space</strong> – Single-use keys or temporary values add noise to the list. Too many for simple needs.</p>
</li>
</ol>
<hr />
<h2 id="heading-why-json">Why JSON?</h2>
<p>Using JSON in a Site Property transforms the way you manage app settings. Here’s why:</p>
<h3 id="heading-key-benefits">Key Benefits</h3>
<ol>
<li><p><strong>Fewer Site Properties</strong> – Group multiple values under one JSON property.</p>
</li>
<li><p><strong>Logical Grouping</strong> – Keep related settings together, e.g., API configs or feature toggles.</p>
</li>
<li><p><strong>Dynamic Parsing</strong> – Deserialize only what you need, when you need it.</p>
</li>
<li><p><strong>Flexible &amp; Scalable</strong> – Easily add or remove keys.</p>
</li>
<li><p><strong>Simplified Versioning</strong> – Manage config as one JSON blob, easier to track changes.</p>
</li>
</ol>
<p>The <strong>two most impactful benefits</strong> are:</p>
<ul>
<li><p>Having <strong>multiple values within a single Site Property</strong></p>
</li>
<li><p>Allowing <strong>additional attributes</strong> per config item (like descriptions or types)</p>
</li>
</ul>
<hr />
<h2 id="heading-how-to-set-up-json-as-a-site-property">How to Set Up JSON as a Site Property</h2>
<h3 id="heading-step-1-create-the-site-property">Step 1: Create the Site Property</h3>
<ol>
<li><p>Create a new Site Property (e.g., <code>EnvironmentVariables</code>)</p>
</li>
<li><p>Set its data type to <strong>Text</strong></p>
</li>
<li><p>Leave the default value <strong>blank</strong> (to avoid escaping characters in JSON)</p>
</li>
</ol>
<hr />
<h3 id="heading-step-2-define-your-json-structure">Step 2: Define Your JSON Structure</h3>
<p>You can define a structure two ways:</p>
<ul>
<li><p><strong>Manually:</strong></p>
<p>  Go to <strong>Data &gt; Structures</strong> and create a new structure with attributes like <code>Name</code>, <code>Value</code>, and <code>Description</code>.</p>
</li>
<li><p><strong>From JSON:</strong></p>
<p>  Create your JSON first in an editor, then in Service Studio:</p>
<p>  <code>Right-click Structures &gt; Add Structure from JSON</code></p>
</li>
</ul>
<p>Example JSON:</p>
<pre><code class="lang-json">[
  {
    <span class="hljs-attr">"Name"</span>: <span class="hljs-string">"SiteProp1"</span>,
    <span class="hljs-attr">"Description"</span>: <span class="hljs-string">""</span>,
    <span class="hljs-attr">"Value"</span>: <span class="hljs-string">""</span>
  },
  {
    <span class="hljs-attr">"Name"</span>: <span class="hljs-string">"SiteProp2"</span>,
    <span class="hljs-attr">"Description"</span>: <span class="hljs-string">""</span>,
    <span class="hljs-attr">"Value"</span>: <span class="hljs-string">""</span>
  }
]
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753572755752/4776dab3-636d-41f9-8e63-1e67aaa38b4f.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-step-3-use-it-in-logic">Step 3: Use It in Logic</h3>
<ol>
<li><p>Create a server action (e.g., <code>GetEnvironmentVariables</code>)</p>
</li>
<li><p>Use <code>JSONDeserialize</code> to convert the JSON text to a <code>list of structures</code></p>
</li>
<li><p>Return the result for use throughout your app</p>
</li>
<li><p>Optionally, expose this through a <strong>Service Action</strong> if you're in a service module</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753572992537/c72175b6-227c-40c2-b716-0da09f1edb9b.png" alt class="image--center mx-auto" /></p>
<blockquote>
<h3 id="heading-tips">Tips</h3>
<ul>
<li><p>Leave value blank in design time: this avoids escaping issues (like quotes)</p>
</li>
<li><p>Use strings for booleans in JSON to simplify parsing</p>
</li>
<li><p>Validate JSON before updating to avoid runtime errors</p>
</li>
</ul>
</blockquote>
<h2 id="heading-going-further-nested-json-for-advanced-use-cases">Going Further: Nested JSON for Advanced Use Cases</h2>
<p>You can take this approach even further by using <strong>nested JSON</strong>. This enables parent-child relationships for more complex configuration scenarios.</p>
<p>Here’s an example from a feature I built called <strong>Quick Filtering</strong>, where saved search filters are bootstrapped from JSON:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"QuickFilters"</span>: [
    {
      <span class="hljs-attr">"Name"</span>: <span class="hljs-string">"Todays Report"</span>,
      <span class="hljs-attr">"Group"</span>: <span class="hljs-string">"Report"</span>,
      <span class="hljs-attr">"Description"</span>: <span class="hljs-string">"Open Today report"</span>,
      <span class="hljs-attr">"Filters"</span>: [
        { <span class="hljs-attr">"field"</span>: <span class="hljs-string">"Company"</span>, <span class="hljs-attr">"operator"</span>: <span class="hljs-string">"equals"</span>, <span class="hljs-attr">"value"</span>: <span class="hljs-string">""</span> },
        { <span class="hljs-attr">"field"</span>: <span class="hljs-string">"DateFrom"</span>, <span class="hljs-attr">"operator"</span>: <span class="hljs-string">"greaterThanOrEqual"</span>, <span class="hljs-attr">"value"</span>: <span class="hljs-string">"Today"</span> },
        { <span class="hljs-attr">"field"</span>: <span class="hljs-string">"DateTo"</span>, <span class="hljs-attr">"operator"</span>: <span class="hljs-string">"greaterThanOrEqual"</span>, <span class="hljs-attr">"value"</span>: <span class="hljs-string">"Today"</span> },
        { <span class="hljs-attr">"field"</span>: <span class="hljs-string">"BankName"</span>, <span class="hljs-attr">"operator"</span>: <span class="hljs-string">"equals"</span>, <span class="hljs-attr">"value"</span>: <span class="hljs-string">""</span> }
      ]
    }
  ]
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753573120809/ebc10603-4514-4a85-96f8-93da70f08d29.png" alt class="image--center mx-auto" /></p>
<p>I’ll cover this nested use case in more detail in a follow-up post.</p>
<hr />
<h2 id="heading-caveats-to-consider">Caveats to Consider</h2>
<p>Before adopting this approach, here are a few important considerations:</p>
<ol>
<li><p>Parsing Overhead Every time you read the JSON, you must parse it. This introduces a slight performance cost, especially if done frequently.</p>
</li>
<li><p>Manual Editing Risks Updating JSON via Service Center can be error-prone. there’s no validation or syntax highlighting, so a small typo can break parsing.</p>
</li>
<li><p>Loss of Type Safety Unlike native Site Properties, JSON values are stored as plain text and require manual type conversion, which can lead to runtime errors if not handled carefully.</p>
</li>
<li><p>Character Limit Awareness OutSystems doesn’t show how many characters you're using in the Site Property value. You’ll need to monitor this manually to avoid silent cut-offs or broken JSON.</p>
</li>
</ol>
<h2 id="heading-summary">Summary</h2>
<p>Switching to JSON-based Site Properties gives you a powerful way to streamline your configuration logic in OutSystems. It reduces clutter, adds flexibility, and makes your app easier to maintain over time,especially in large or fast-moving projects.</p>
<p>If you find yourself managing dozens of Site Properties with unclear names or single-use purposes, give this approach a try.</p>
]]></content:encoded></item><item><title><![CDATA[Clearing the Clutter: Tackling Unused Dependencies in OutSystems]]></title><description><![CDATA[While migrating one of our UI components, I discovered a dependency on an outdated version within one of our modules. This realization highlighted an important aspect of software development: unused dependencies, or "dead code."
Why Handling Unused D...]]></description><link>https://lowstack.tegar.org/clearing-the-clutter-tackling-unused-dependencies-in-outsystems</link><guid isPermaLink="true">https://lowstack.tegar.org/clearing-the-clutter-tackling-unused-dependencies-in-outsystems</guid><category><![CDATA[outsystems]]></category><category><![CDATA[dependencies]]></category><category><![CDATA[clean code]]></category><category><![CDATA[performance]]></category><dc:creator><![CDATA[Tegar]]></dc:creator><pubDate>Fri, 20 Dec 2024 06:47:38 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1734675538029/9c23e774-9888-46a8-851e-e6e7a62364f8.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>While migrating one of our UI components, I discovered a dependency on an outdated version within one of our modules. This realization highlighted an important aspect of software development: unused dependencies, or "dead code."</p>
<h3 id="heading-why-handling-unused-dependencies-matter">Why Handling Unused Dependencies Matter</h3>
<p><strong>Dead code</strong> refers to sections that are no longer executed or used. These remnants can stem from outdated features, experimental code, or debugging utilities. Over time, they bloat software, reduce efficiency, complicate maintenance, and <strong>increase the size of OutSystems modules—ultimately prolonging 1-Click Publish durations.</strong></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text"><strong>Unused Dependencies increase the size of OutSystems modules—ultimately prolonging 1-Click Publish durations.</strong></div>
</div>

<h3 id="heading-a-common-oversight">A Common Oversight</h3>
<p>Often, developers leave behind temporary or "just-in-case" code, believing it may be useful later. In reality, these assumptions create unnecessary complexities, violating the YAGNI principle ("You Aren’t Gonna Need It"):</p>
<blockquote>
<p><strong>Key takeaway:</strong><br />Only include what’s needed now, not what might be needed in the future.</p>
</blockquote>
<h3 id="heading-best-practices-for-dependencies-avoid">Best Practices for Dependencies Avoid:</h3>
<ul>
<li><p><strong>Avoid :</strong> Large, bloated dependencies.</p>
</li>
<li><p><strong>Prefer :</strong> Smaller, specific modules with only the elements you actually use.</p>
</li>
</ul>
<p>This aligns with the <strong>Interface Segregation Principle</strong>, where code depends only on relevant, smaller interfaces rather than massive, unwieldy packages.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text"><strong>✨Interface Segregation Principle : </strong>No code should be forced to depend on methods it does not use.</div>
</div>

<hr />
<h1 id="heading-removing-unused-dependencies-in-outsystems">Removing Unused Dependencies in OutSystems</h1>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1734677140284/f0295fd6-4a4e-4f74-bf53-522a6a6a9ff3.png" alt class="image--center mx-auto" /></p>
<p>OutSystems offers two key tools to address unused dependencies:</p>
<h3 id="heading-ai-mentor">AI Mentor</h3>
<p>Detects unused aggregates, SQL queries, and module actions. However, it doesn’t detect referenced elements without usage, so manual checks may still be required.</p>
<h3 id="heading-service-studios-remove-unused-dependencies-feature">Service Studio’s "Remove Unused Dependencies" Feature</h3>
<p>Automatically identifies and removes unused dependencies from your module.</p>
<h2 id="heading-steps-to-remove-unused-dependencies">Steps to Remove Unused Dependencies</h2>
<ol>
<li><p>Open Service Studio and navigate to each application layer (Interface, Logic, Data, Process).</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1734677107076/19f42022-f0b1-46cf-990f-430fea108549.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>Right-click the module name.</p>
</li>
<li><p>Select Remove Unused Dependencies.</p>
</li>
<li><p>Repeat for all layers.</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1734677072312/05680596-8caa-49a6-8608-aba45e99bf2c.png" alt class="image--center mx-auto" /></p>
<p>By following these practices, you can simplify your modules, improve performance, and ensure clean, maintainable code. Don’t let unused dependencies weigh your application down!</p>
]]></content:encoded></item><item><title><![CDATA[Managing Data Concurrency]]></title><description><![CDATA[While attending a session on OutSystems Tech Talk: Performance Best Practices in OutSystems 11, one of the key tips discussed was data model design best practices. One that stood out to me, and which I’ve seen my team grapple with in real-world scena...]]></description><link>https://lowstack.tegar.org/managing-data-concurrency</link><guid isPermaLink="true">https://lowstack.tegar.org/managing-data-concurrency</guid><category><![CDATA[outsystems]]></category><category><![CDATA[performance]]></category><dc:creator><![CDATA[Tegar]]></dc:creator><pubDate>Fri, 27 Sep 2024 07:09:12 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1727420791798/707352e0-00b7-4138-95a7-b1c82e4ca70b.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>While attending a session on <a target="_blank" href="https://www.outsystems.com/webinars/performance-best-practices/"><strong>OutSystems Tech Talk: Performance Best Practices in OutSystems 11</strong></a>, one of the key tips discussed was <strong>data model design best practices</strong>. One that stood out to me, and which I’ve seen my team grapple with in real-world scenarios, was the recommendation to <strong>"avoid data access concurrency"</strong> issues.</p>
<p>This is a topic that keeps growing in importance as my experience deepens, and I thought I’d develop it into an article. Let’s explore what <strong>data concurrency</strong> is, why it matters, and how to handle it effectively.</p>
<hr />
<h3 id="heading-what-is-data-access-concurrency">What is Data Access Concurrency?</h3>
<p>In essence, <strong>data access concurrency</strong> refers to situations where multiple processes or threads attempt to access or modify the same data simultaneously. If not managed properly, concurrency can lead to serious problems like <strong>data corruption</strong> or degraded <strong>performance</strong>, especially in systems designed for parallel operations (e.g., databases, multi-threaded applications, or cloud-based architectures like OutSystems).</p>
<p>Managing concurrency is crucial to ensuring <strong>data integrity</strong>, <strong>consistency</strong>, and optimal performance in these systems.</p>
<hr />
<h3 id="heading-concurrency-pitfalls-race-conditions-and-deadlocks">Concurrency Pitfalls: Race Conditions and Deadlocks</h3>
<p>Before we dive into management strategies, let’s look at the conditions you want to avoid:</p>
<h4 id="heading-race-conditions"><strong>Race Conditions</strong></h4>
<p>A <strong>race condition</strong> occurs when two or more processes simultaneously access the same data, and the final result depends on the order of execution. The timing discrepancy can cause unpredictable behavior, leading to data corruption or inconsistencies.</p>
<p>Imagine two threads trying to update a shared record at the same time. If both execute simultaneously, they might overwrite each other's changes without realizing it, creating flawed data.</p>
<h4 id="heading-deadlocks"><strong>Deadlocks</strong></h4>
<p>A <strong>deadlock</strong> is another concurrency nightmare. It happens when two or more processes are stuck in a stalemate, each waiting for the other to release a resource (lock). This results in a system standstill, where none of the processes can proceed. In database environments, deadlocks can severely affect performance, forcing the system to abort transactions.</p>
<hr />
<h3 id="heading-using-locks-to-manage-concurrency">Using Locks to Manage Concurrency</h3>
<p>To prevent race conditions and deadlocks, we use <strong>locks</strong> to control data access.</p>
<p><strong>Locks</strong> are mechanisms that restrict access to shared resources, ensuring that only one process or thread can modify data at a time. When used correctly, they protect data integrity but must be managed carefully to avoid performance degradation or deadlocks.</p>
<h4 id="heading-types-of-locks">Types of Locks:</h4>
<ul>
<li><p><strong>Read Locks (Shared Locks):</strong> Multiple threads can read data simultaneously, but no writing is allowed. This is useful when ensuring that read operations don’t interfere with each other.</p>
</li>
<li><p><strong>Write Locks (Exclusive Locks):</strong> Only one thread can write to the data, and no other operations (read or write) can access it until the lock is released.</p>
</li>
</ul>
<hr />
<h3 id="heading-isolation-levels-balancing-performance-and-consistency">Isolation Levels: Balancing Performance and Consistency</h3>
<p>In database systems, <strong>isolation levels</strong> determine the visibility of changes made by one transaction to others. Different levels offer trade-offs between <strong>data consistency</strong> and <strong>performance</strong>, and selecting the right level can prevent issues like <strong>dirty reads</strong>, <strong>non-repeatable reads</strong>, or <strong>phantom reads</strong>.</p>
<p>Here are the common isolation levels:</p>
<ul>
<li><p><strong>Read Uncommitted:</strong></p>
<ul>
<li>Transactions can see uncommitted changes from other transactions. This is the least strict level and offers the highest performance but at the cost of potential data inconsistencies.</li>
</ul>
</li>
<li><p><strong>Read Committed:</strong></p>
<ul>
<li>Transactions can only see committed changes. This level is a good balance between performance and consistency, as it avoids reading uncommitted data.</li>
</ul>
</li>
<li><p><strong>Repeatable Read:</strong></p>
<ul>
<li>Ensures that if a transaction reads data, it will see the same data throughout its execution. It protects against non-repeatable reads but can lead to performance bottlenecks in high-transaction environments.</li>
</ul>
</li>
<li><p><strong>Serializable:</strong></p>
<ul>
<li>The strictest isolation level, ensuring full isolation by making transactions appear as though they were executed sequentially. It provides the highest level of consistency but can significantly impact performance in large systems.</li>
</ul>
</li>
</ul>
<hr />
<h3 id="heading-optimistic-vs-pessimistic-concurrency-control">Optimistic vs. Pessimistic Concurrency Control</h3>
<p>Concurrency control can generally be classified into two approaches: <strong>Optimistic</strong> and <strong>Pessimistic</strong>. Each has its own use cases, depending on the likelihood of conflicts.</p>
<h4 id="heading-optimistic-concurrency-control"><strong>Optimistic Concurrency Control</strong></h4>
<p>In optimistic concurrency, conflicts are considered rare. Therefore, multiple transactions proceed without locking resources, and checks for conflicts are made only when changes are being committed. This approach works well in environments where transactions mostly don’t interfere with each other, offering better performance.</p>
<h4 id="heading-pessimistic-concurrency-control"><strong>Pessimistic Concurrency Control</strong></h4>
<p>In pessimistic concurrency, we assume that conflicts are likely. As a result, locks are placed early in the process to prevent other transactions from accessing the same data. This approach is ideal in systems with high contention for resources, but it may introduce performance overhead due to frequent locking.</p>
<hr />
<h3 id="heading-why-concurrency-management-matters">Why Concurrency Management Matters</h3>
<p>Proper concurrency management ensures:</p>
<ul>
<li><p><strong>Data Integrity</strong>: Preventing corruption by coordinating access to shared resources.</p>
</li>
<li><p><strong>Consistency</strong>: Ensuring transactions yield reliable outcomes, regardless of how they're interleaved.</p>
</li>
<li><p><strong>System Performance</strong>: Avoiding bottlenecks or crashes that can result from deadlocks or unnecessary locking.</p>
</li>
</ul>
<p>In complex applications like those built on <strong>OutSystems</strong>, the performance impact of concurrency issues can scale rapidly. This makes it critical to design the data model and access layers with concurrency in mind, using the right balance of locking mechanisms, isolation levels, and concurrency control strategies.</p>
<hr />
<h3 id="heading-final-thoughts">Final Thoughts</h3>
<p>The topic of <strong>data access concurrency</strong> is vast and continues to evolve as my understanding deepens through real-world experience. Managing concurrency isn't just about preventing conflicts—it's about finding the right trade-off between <strong>data integrity</strong>, <strong>performance</strong>, and <strong>scalability</strong>. Whether you’re working with a high-transactional system or a distributed architecture like OutSystems, mastering concurrency control can dramatically improve your application’s stability and responsiveness.</p>
<p>Stay tuned as I continue to expand on this topic in future posts, diving deeper into specific case studies and optimization techniques!</p>
]]></content:encoded></item><item><title><![CDATA[How to Use Lottie Animations in OutSystems]]></title><description><![CDATA[Lottie animations have revolutionized the way developers add high-quality, interactive animations to applications. These lightweight animations, stored in JSON format, can be seamlessly integrated into OutSystems to enhance user experiences without c...]]></description><link>https://lowstack.tegar.org/how-to-use-lottie-animations-in-outsystems</link><guid isPermaLink="true">https://lowstack.tegar.org/how-to-use-lottie-animations-in-outsystems</guid><category><![CDATA[outsystems]]></category><category><![CDATA[Lottie]]></category><category><![CDATA[animation]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[React]]></category><dc:creator><![CDATA[Tegar]]></dc:creator><pubDate>Mon, 16 Sep 2024 12:06:33 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1726482971773/07e9ae14-8630-4545-80ae-7429108c42cf.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Lottie animations have revolutionized the way developers add high-quality, interactive animations to applications. These lightweight animations, stored in JSON format, can be seamlessly integrated into OutSystems to enhance user experiences without compromising performance or load times. In this blog post, we will cover what Lottie animations are, their advantages, and guide you step by step on how to integrate them into a <strong>Reactive Web Application</strong> in OutSystems.</p>
<h2 id="heading-what-is-a-lottie-animation">What is a Lottie Animation?</h2>
<p>Lottie animations are a versatile, JSON-based animation format that allows for smooth, high-quality animations across platforms, from mobile apps to web applications. Initially developed by Airbnb, Lottie has gained widespread adoption due to its simplicity and flexibility. The biggest advantage? Lottie files are small and scalable, meaning they don’t lose quality when resized and are ideal for use in modern UI design.</p>
<h3 id="heading-key-features-of-lottie-animations">Key Features of Lottie Animations:</h3>
<ul>
<li><p><strong>Multi-Platform Support</strong>: Lottie animations can be embedded into iOS, Android, and web applications with ease, using platform-specific libraries.</p>
</li>
<li><p><strong>Small File Size</strong>: Compared to GIFs or videos, Lottie animations are lightweight, resulting in faster load times and improved performance.</p>
</li>
<li><p><strong>Large Animation Library</strong>: LottieFiles, the leading resource for Lottie animations, offers thousands of free animations that can be used or customized.</p>
</li>
<li><p><strong>Customizable</strong>: The JSON format allows for easy editing of the animations to match your design needs, whether it’s color changes, speed adjustments, or other custom behaviors.</p>
</li>
</ul>
<iframe src="https://lottie.host/embed/ef585b5a-e039-45f7-b621-f24b7192c3fa/K3CiJKg5WE.json"></iframe>

<h2 id="heading-getting-started-with-lottie-animations-in-outsystems">Getting Started with Lottie Animations in OutSystems</h2>
<p>Before diving into the implementation, it's important to note that this tutorial is applicable to <strong>Reactive Web Applications</strong> in OutSystems. If you’re ready, let’s begin.</p>
<h3 id="heading-step-1-access-and-download-lottie-animations">Step 1: Access and Download Lottie Animations</h3>
<p>To integrate Lottie animations, the first step is to find and download an animation file in the correct format. Follow these steps:</p>
<h4 id="heading-11-navigate-to-lottiefiles">1.1. Navigate to LottieFiles</h4>
<p>Visit <a target="_blank" href="https://lottiefiles.com/featured-free-animations">LottieFiles</a>, where you can find a large library of free and premium animations. It’s a great place to start if you’re looking for professional animations ready to be used in your projects.</p>
<h4 id="heading-12-download-the-json-animation-file">1.2. Download the JSON Animation File</h4>
<ul>
<li><p>Once you find an animation that suits your project, click on it and choose the <strong>JSON format</strong> for downloading.</p>
</li>
<li><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1726488096486/fe197a14-5532-414e-b97f-0409a63acb88.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>Save the file to a location on your local machine.</p>
</li>
</ul>
<h3 id="heading-step-2-set-up-in-outsystems-studio">Step 2: Set Up in OutSystems Studio</h3>
<p>Now that you have the animation file, you can begin integrating it into your OutSystems application.</p>
<h4 id="heading-21-install-the-lottie-animation-component-from-forge">2.1. Install the Lottie Animation Component from Forge</h4>
<ul>
<li><p><strong>Go to Forge</strong>: Open OutSystems Service Studio, navigate to the <strong>Forge</strong> tab, and search for <strong>Lottie Animation</strong>.</p>
<p>  <a target="_blank" href="https://www.outsystems.com/forge/component-overview/2914/lottie-animations-o11">Lottie Animation Forge Component</a></p>
</li>
<li><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1726488045914/808141ed-e758-4bde-9370-a3caf0fea5f8.png" alt class="image--center mx-auto" /></p>
</li>
<li><p><strong>Install the Component</strong>: Once you’ve found the Lottie Animation component, install it into your environment.</p>
</li>
<li><p><strong>Manage Dependencies</strong>: After installation, navigate to <strong>Manage Dependencies</strong> within your application.</p>
<ul>
<li><p>Search for the <strong>Lottie Animation</strong> component that you just installed.</p>
</li>
<li><p><strong>Check all dependencies</strong> related to this component, and click <strong>Apply</strong> to include it in your project.</p>
</li>
</ul>
</li>
</ul>
<h4 id="heading-22-set-up-the-lottie-animation-in-your-screen">2.2. Set Up the Lottie Animation in Your Screen</h4>
<p>Now, you’re ready to display the animation on your screen. Here’s how:</p>
<ol>
<li><p><strong>Upload the JSON File</strong>:</p>
<ul>
<li><p>Go to the <strong>Data Tab</strong> and click on <strong>Resources</strong>.</p>
</li>
<li><p>Upload the Lottie JSON file you downloaded earlier into the resources section.</p>
</li>
<li><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1726488080871/3d3d345e-1e4c-441b-81c5-283d18991df4.png" alt class="image--center mx-auto" /></p>
</li>
</ul>
</li>
<li><p><strong>Add a Blank Container</strong>:</p>
<ul>
<li><p>Drag a <strong>Blank Container</strong> onto the screen where you want to display the animation. This will serve as a wrapper for the Lottie Animation Block.</p>
</li>
<li><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1726488124571/d0c19fc4-5403-4407-9694-27eef98c7f5e.png" alt class="image--center mx-auto" /></p>
</li>
</ul>
</li>
<li><p><strong>Insert the Lottie Animation Block</strong>:</p>
<ul>
<li><p>Inside the Blank Container, drag and drop the <strong>Lottie Animation Block</strong>.</p>
</li>
<li><p>In the Lottie Animation Block’s <strong>properties panel</strong>, link the uploaded JSON file under the <strong>Animation Data</strong> property.</p>
</li>
</ul>
</li>
<li><p><strong>Configure the Animation</strong>:</p>
<ul>
<li><p>You can customize the behavior of the animation by adjusting the <strong>autoplay</strong> or <strong>loop</strong> settings, depending on your needs.</p>
</li>
<li><p>To control the <strong>width</strong> and <strong>height</strong> of the animation, set these properties in the <strong>Blank Container</strong> rather than the Lottie Block itself, which allows for more flexibility in your layout.</p>
</li>
</ul>
</li>
<li><p><strong>Publish and Test</strong>:</p>
<ul>
<li><p>Once you’ve set everything up, click <strong>Publish</strong> to deploy your application.</p>
</li>
<li><p>Navigate to the screen where you added the animation, and you should see it playing smoothly as part of your application.</p>
</li>
<li><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1726488153566/c6ecae95-29b2-49df-b465-1fd47140aaff.png" alt class="image--center mx-auto" /></p>
</li>
</ul>
</li>
</ol>
<h3 id="heading-conclusion">Conclusion</h3>
<p>Lottie animations are an excellent way to introduce visually engaging, responsive animations to your OutSystems application. With their small file sizes and multi-platform support, they are ideal for modern development workflows. By following this guide, you can easily integrate stunning animations into your reactive web applications, improving both user engagement and UI aesthetics.</p>
<p>Whether you’re building mobile or web apps, leveraging Lottie animations is a simple yet powerful tool to bring your user interfaces to life.</p>
<p>If you haven’t experimented with Lottie yet, now is the perfect time to explore its potential and elevate your applications to the next level!</p>
]]></content:encoded></item></channel></rss>