<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Sohini Pattanayak</title>
    <description>The latest articles on DEV Community by Sohini Pattanayak (@sohinip).</description>
    <link>https://dev.to/sohinip</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F790174%2F0c1ffcb3-fdc2-4960-8db2-fbc726671f46.png</url>
      <title>DEV Community: Sohini Pattanayak</title>
      <link>https://dev.to/sohinip</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sohinip"/>
    <language>en</language>
    <item>
      <title>Skip the Extra Login Screen with Auth0’s `authorizationParams`</title>
      <dc:creator>Sohini Pattanayak</dc:creator>
      <pubDate>Fri, 13 Jun 2025 19:48:15 +0000</pubDate>
      <link>https://dev.to/sohinip/skip-the-extra-login-screen-with-auth0s-authorizationparams-48je</link>
      <guid>https://dev.to/sohinip/skip-the-extra-login-screen-with-auth0s-authorizationparams-48je</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Disclaimer: The views expressed in this post are my own and do not reflect those of Okta or its affiliates.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What We're Trying to Achieve?
&lt;/h2&gt;

&lt;p&gt;In many enterprise environments - especially SMBs using digital portals, customers ask for a streamlined login experience:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User clicks &lt;strong&gt;“Log In”&lt;/strong&gt; in your App.&lt;/li&gt;
&lt;li&gt;They are immediately redirected to &lt;strong&gt;their company’s IdP&lt;/strong&gt; (e.g. Azure AD, Okta).&lt;/li&gt;
&lt;li&gt;They do &lt;strong&gt;not&lt;/strong&gt; want to see an Auth0-branded login page.&lt;/li&gt;
&lt;li&gt;After authentication, they return to your application seamlessly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this flow, &lt;strong&gt;Auth0 acts purely as a broker&lt;/strong&gt; between your application and the enterprise IdP. It handles OAuth 2.0/OIDC mechanics security, PKCE, state, tokens-while allowing you to maintain full control over the user experience and comply with enterprise firewall requirements.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Role of &lt;code&gt;authorizationParams&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Using the &lt;code&gt;@auth0/auth0-react&lt;/code&gt; SDK, I've passed key parameters directly to Auth0’s &lt;code&gt;/authorize&lt;/code&gt; endpoint through &lt;code&gt;authorizationParams&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;loginWithRedirect({
  authorizationParams: {
    connection: 'your-connection-name',
    redirect_uri: 'https://yourapp.com/callback'
  }
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;connection&lt;/code&gt; specifies the enterprise IdP to use, skipping Auth0's Universal Login entirely.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;redirect_uri&lt;/code&gt; defines where Auth0 sends users after successful login.&lt;/p&gt;

&lt;p&gt;The SDK automatically includes essential OAuth parameters (client_id, state, PKCE, etc.).&lt;/p&gt;

&lt;p&gt;This yields a one-click, one-redirect flow, matching user expectations in a polished enterprise portal.&lt;/p&gt;




&lt;h2&gt;
  
  
  But then what's the point of Auth0 here?
&lt;/h2&gt;

&lt;p&gt;Auth0 simplifies authentication without compromising enterprise standards:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Identity broker&lt;/strong&gt;: Supports OIDC, SAML and multiple IdPs with minimal configuration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secure token handling&lt;/strong&gt;: Issues ID tokens and refresh tokens securely, following best practices.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Controlled redirects&lt;/strong&gt;: Enforces redirect_uri whitelist—critical for firewall compliance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalable and flexible&lt;/strong&gt;: Handling multiple enterprise IdPs requires only updating the connection parameter.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Minimal build effort&lt;/strong&gt;: No need to build or manage login UIs, PKCE, session handling, or protocol compliance.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;As a Solutions Engineer, I've worked with multiple SMBs requiring:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;White‑label branding&lt;/strong&gt;: Users should see only the company portal and their corporate IdP—not Auth0 branding.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Firewall whitelisting&lt;/strong&gt;: Login URLs must be static and predictable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multiple enterprise clients&lt;/strong&gt;: They may serve partners using Azure AD, Okta, Ping, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This pattern delivers a seamless, compliant, branded experience with minimal overhead.&lt;/p&gt;

&lt;p&gt;Here's a sample react code that i wrote using the auth0-react sdk for a short demo i created -&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// App.js
import React from 'react';
import { useAuth0 } from '@auth0/auth0-react';

function App() {
  const { loginWithRedirect, isAuthenticated, user, logout } = useAuth0();

  const loginToIdP = () =&amp;gt; {
    loginWithRedirect({
      authorizationParams: {
        connection: 'your-connection-name'
      }
    });
  };

  return (
    &amp;lt;div style={styles.container}&amp;gt;
      {!isAuthenticated ? (
        &amp;lt;div style={styles.loginBox}&amp;gt;
          &amp;lt;img src="/logo.png" alt="Company Logo" style={styles.logo} /&amp;gt;
          &amp;lt;h1 style={styles.heading}&amp;gt;Welcome to Evolve&amp;lt;/h1&amp;gt;
          &amp;lt;p style={styles.description}&amp;gt;
            Log in using your company’s single sign-on.
          &amp;lt;/p&amp;gt;
          &amp;lt;button style={styles.loginButton} onClick={loginToIdP}&amp;gt;
            Log in
          &amp;lt;/button&amp;gt;
        &amp;lt;/div&amp;gt;
      ) : (
        &amp;lt;div style={styles.sessionBox}&amp;gt;
          &amp;lt;h3&amp;gt;Welcome, {user.name}&amp;lt;/h3&amp;gt;
          &amp;lt;button onClick={() =&amp;gt; logout({ logoutParams: { returnTo: window.location.origin } })}&amp;gt;
            Log Out
          &amp;lt;/button&amp;gt;
        &amp;lt;/div&amp;gt;
      )}
    &amp;lt;/div&amp;gt;
  );
}

// ... styles omitted for brevity

export default App;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And this is the index.js - It Defines key OAuth parameters: &lt;code&gt;redirect_uri&lt;/code&gt; for where users return after login&lt;br&gt;
&lt;code&gt;client_id&lt;/code&gt;, token settings, and PKCE flows are handled under the hood by the SDK&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// index.js
import React from 'react';
import { createRoot } from 'react-dom/client';
import { Auth0Provider } from '@auth0/auth0-react';
import App from './App';

const domain = "your-auth0-app-domain-name";
const clientId = "your-auth0-app-client-id";

createRoot(document.getElementById('root')).render(
  &amp;lt;Auth0Provider
  domain={domain}
  clientId={clientId}
  authorizationParams={{
    connection: 'your-connection-name',
    response_type: 'code',
    redirect_uri: 'http://localhost:3000/callback',
  }}
&amp;gt;

    &amp;lt;App /&amp;gt;
  &amp;lt;/Auth0Provider&amp;gt;
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One button triggers direct login via Azure AD. From the user's perspective, it’s a single click experience. Auth0 manages the entire auth protocol quietly in the background.&lt;/p&gt;




&lt;h2&gt;
  
  
  What’s Configured in the Auth0 Tenant?
&lt;/h2&gt;

&lt;p&gt;In the Auth0 dashboard, you’ll set up:&lt;/p&gt;

&lt;p&gt;Application with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Allowed Callback URL matching &lt;a href="https://yourapp.com/callback" rel="noopener noreferrer"&gt;https://yourapp.com/callback&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Enterprise connection &lt;/li&gt;
&lt;li&gt;Optional custom domain for full branding (auth.yourcompany.com)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By combining Auth0’s enterprise-grade broker capabilities with a simple authorizationParams configuration, you get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A frictionless, branded login experience.&lt;/li&gt;
&lt;li&gt;Full enterprise security and compliance.&lt;/li&gt;
&lt;li&gt;Scalable support for multiple IdPs—all with minimal development effort.&lt;/li&gt;
&lt;li&gt;This pattern is ideal for partner portals, retailer dashboards, and B2B apps needing polished user experiences with enterprise authentication standards.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Watch this video to get a demo!&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/d5psnLExf3w"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>auth0</category>
      <category>authorizationparameter</category>
      <category>tutorial</category>
      <category>react</category>
    </item>
    <item>
      <title>Using Auth0 to Authenticate External Users into SharePoint via Microsoft Entra</title>
      <dc:creator>Sohini Pattanayak</dc:creator>
      <pubDate>Tue, 27 May 2025 11:21:16 +0000</pubDate>
      <link>https://dev.to/sohinip/using-auth0-to-authenticate-external-users-into-sharepoint-via-microsoft-entra-22a8</link>
      <guid>https://dev.to/sohinip/using-auth0-to-authenticate-external-users-into-sharepoint-via-microsoft-entra-22a8</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Disclaimer:&lt;/strong&gt; The views expressed in this post are my own and do not reflect those of Okta or its affiliates.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This write-up walks through how to set up &lt;strong&gt;Auth0 as a SAML Identity Provider (IdP)&lt;/strong&gt; with &lt;strong&gt;Microsoft Entra ID&lt;/strong&gt;, specifically to &lt;strong&gt;support external user login to SharePoint Online&lt;/strong&gt; without needing to pre-create their accounts in Azure AD.&lt;/p&gt;

&lt;p&gt;It’s especially useful if you already manage your external customers or partners in Auth0 and want Microsoft Entra to take care of &lt;strong&gt;Just-in-Time (JIT) provisioning&lt;/strong&gt; the first time a user logs in.&lt;/p&gt;

&lt;p&gt;While &lt;strong&gt;Okta Workforce Identity&lt;/strong&gt; is a more complete solution for this scenario, the same can be achieved using &lt;strong&gt;Auth0&lt;/strong&gt; — especially if you're already using Auth0 to manage authentication for other apps.&lt;/p&gt;




&lt;p&gt;Let's assume that users &lt;strong&gt;do not yet exist in Auth0&lt;/strong&gt;. They will be created at the time of login via &lt;strong&gt;an invite flow built through sharepoint site, your app or signup portal.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Flow
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Let external users authenticate through &lt;strong&gt;Auth0&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Redirect login requests from Microsoft Entra to Auth0&lt;/li&gt;
&lt;li&gt;Automatically &lt;strong&gt;create the user in Microsoft Entra ID (JIT)&lt;/strong&gt; when they log in for the first time&lt;/li&gt;
&lt;li&gt;Grant access to &lt;strong&gt;SharePoint Online&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2plrro062s4ecdd7cagp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2plrro062s4ecdd7cagp.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Set Up a SAML Connection in Auth0
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Go to &lt;strong&gt;Auth0 Dashboard → Applications → Applications → + Create Application&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Name it something like &lt;code&gt;SAML for Entra&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;Regular Web Application&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyqrddxu1bgvbqwnizopg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyqrddxu1bgvbqwnizopg.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In the newly created application, go to &lt;strong&gt;Addons → Enable SAML2 Web App&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fne45b7a79hbupac4n8gy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fne45b7a79hbupac4n8gy.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once enabled, it pops up a few configurations, simply click on download&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6rhuuwvr57peym8a01d2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6rhuuwvr57peym8a01d2.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;From the &lt;code&gt;usage&lt;/code&gt; tab, switch over to the &lt;code&gt;settings&lt;/code&gt; tab and don't forget to paste this - &lt;code&gt;https://login.microsoftonline.com/login.srf&lt;/code&gt; in the Application Callback URL. The SAML token will be posted in this URL when the user tries to sign in.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0xhn5nz179h0haee5jdf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0xhn5nz179h0haee5jdf.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Close the SAML add on pop up and navigate to the &lt;code&gt;settings&lt;/code&gt; tab of your Regular Web App, scroll down to the section that says - &lt;code&gt;Application URIs&lt;/code&gt; and make sure that you place the same URL on these 3 input fields - &lt;code&gt;Allowed Callback URLs&lt;/code&gt;, &lt;code&gt;Allowed Logout URLs&lt;/code&gt;, &lt;code&gt;Allowed Web Origins&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzcmqfcwzv2nlfnuoj8tf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzcmqfcwzv2nlfnuoj8tf.png" alt=" "&gt;&lt;/a&gt; &lt;/p&gt;




&lt;h3&gt;
  
  
  Configure Microsoft Entra to Trust Auth0
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Go to &lt;strong&gt;Microsoft Entra Admin Center&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Navigate to: &lt;strong&gt;Entra ID → External Identities → All Identity Providers → Custom&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg81inirntkakrjjqovv5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg81inirntkakrjjqovv5.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click &lt;strong&gt;Add new &amp;gt; SAML/WS-Fed&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0qw029j8pgyjw1zme82k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0qw029j8pgyjw1zme82k.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fill in the following:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Display name&lt;/strong&gt;: Auth0 Federation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Protocol&lt;/strong&gt;: SAML&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Domain name of federating IdP&lt;/strong&gt;: You can put down the domain name from your Auth0 Regular Web App. To fetch that, go to your Auth0 &lt;strong&gt;Tenant &amp;gt; Applications &amp;gt; Saml for Entra &amp;gt; Settings &amp;gt; Domain&lt;/strong&gt; or if you'd like to use your own domain e.g., &lt;code&gt;customers.example.com&lt;/code&gt;, you'd need to look at the next step on how to add DNS TXT Record for Federation Validation (the domain of the users you'll authenticate)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5d0xgzmglwjoiiiujbd4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5d0xgzmglwjoiiiujbd4.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxn4eusum7qqyzwvw576i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxn4eusum7qqyzwvw576i.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;💡 In Auth0, domain names of apps are defined by the tenant name. However, if you'd want to learn more about custom domains, this is a good documentation to go over that - &lt;a href="https://auth0.com/docs/customize/custom-domains" rel="noopener noreferrer"&gt;Custom Domains&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After you've put in the domain in your Entra ID Tenant (Refer to the first image above), navigate to the dropdown field that says - &lt;strong&gt;Select a method for populating metadata&lt;/strong&gt;&lt;br&gt;
and choose - &lt;strong&gt;Parse metadata file&lt;/strong&gt;, and upload the metadata XML downloaded from Auth0&lt;/p&gt;


&lt;h3&gt;
  
  
  Add DNS TXT Record for Federation Validation
&lt;/h3&gt;

&lt;p&gt;If your Auth0 domain (e.g., &lt;code&gt;your-tenant.auth0.com&lt;/code&gt;) does &lt;strong&gt;not match&lt;/strong&gt; the email domain of your users (e.g., &lt;code&gt;@customers.example.com&lt;/code&gt;), you'll need to prove domain ownership by adding a DNS TXT record.&lt;/p&gt;

&lt;p&gt;In the DNS settings for &lt;code&gt;customers.example.com&lt;/code&gt;, add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@ IN TXT DirectFedAuthUrl=https://your-tenant.auth0.com/samlp/&amp;lt;client_id&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Replace &lt;code&gt;&amp;lt;client_id&amp;gt;&lt;/code&gt; with the client ID of your Auth0 SAML app&lt;/li&gt;
&lt;li&gt;Wait 10–30 minutes for the DNS to propagate&lt;/li&gt;
&lt;li&gt;Use tools like &lt;code&gt;nslookup&lt;/code&gt; or Google’s DIG to verify&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Enable User Sign-ins using Auth0
&lt;/h3&gt;

&lt;p&gt;Ensure that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The application has that database connection enabled under &lt;strong&gt;Connections → Database&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F11z4zsa2eynavba24tax.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F11z4zsa2eynavba24tax.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Optional: Customize the &lt;strong&gt;signin page&lt;/strong&gt; using Auth0's Universal Login&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzwwcsc8prt0erm36j168.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzwwcsc8prt0erm36j168.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For this demo - the name of my organization is Echoes Enterprise, and so I have kept the branding that way. You'll also see my sharepoint site url to be the same.&lt;/p&gt;




&lt;h3&gt;
  
  
  Invite the User in SharePoint
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;To invite a user, navigate to the Sharepoint Site, and click on &lt;code&gt;Site Access&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk6u5s8ex67ci5o22kq2c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk6u5s8ex67ci5o22kq2c.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enter the user's email (e.g., &lt;code&gt;alice@identity-stack-001.cic-demo-platform.auth0app.com&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Invite&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Go to your Auth0 Tenant and now &lt;code&gt;create the same user&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvho3r89chlbxa987lujr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvho3r89chlbxa987lujr.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The user will receive a link to access the resource. When they click it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Microsoft Entra detects the federated domain&lt;/li&gt;
&lt;li&gt;Redirects to Auth0&lt;/li&gt;
&lt;li&gt;Auth0 authenticates the user&lt;/li&gt;
&lt;li&gt;Microsoft Entra &lt;strong&gt;JIT-provisions the user&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;The user is granted access (e.g., SharePoint Online)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Success Criteria (What Happens Behind the Scenes) - Important for your understanding!
&lt;/h2&gt;

&lt;p&gt;When the user clicks the invite link or tries to access SharePoint:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Microsoft Entra detects the user’s email domain and recognizes it as federated.&lt;/li&gt;
&lt;li&gt;Entra redirects the login request to Auth0’s SAML endpoint.&lt;/li&gt;
&lt;li&gt;The user lands on Auth0’s Universal Login Page and enters their credentials.&lt;/li&gt;
&lt;li&gt;Auth0 authenticates the user, then issues a SAML Response back to Entra with claims like: &lt;code&gt;NameID&lt;/code&gt; (persistent format), &lt;code&gt;emailaddress&lt;/code&gt;(optional), upn, name, etc.&lt;/li&gt;
&lt;li&gt;Microsoft Entra validates the SAML assertion, and if successful:

&lt;ul&gt;
&lt;li&gt;Creates a guest user (JIT)&lt;/li&gt;
&lt;li&gt;Grants access to the SharePoint resource&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;At no point is the user created ahead of time in Entra — they are auto-provisioned upon first successful login.&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;To watch the end user flow for Alice, watch this video   &lt;iframe src="https://www.youtube.com/embed/ytxmiKYqmic"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;




&lt;h2&gt;
  
  
  🛠 Common Pitfalls
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Issue&lt;/th&gt;
&lt;th&gt;Fix&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;AADSTS50020&lt;/code&gt; (user not found)&lt;/td&gt;
&lt;td&gt;Make sure the user was invited in Entra&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Federation domain rejected&lt;/td&gt;
&lt;td&gt;Add the required TXT record in DNS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auth0 doesn't send correct claims&lt;/td&gt;
&lt;td&gt;Check &lt;code&gt;mappings&lt;/code&gt; and SAML Action overrides&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JIT fails despite invite&lt;/td&gt;
&lt;td&gt;Ensure SAML assertion contains &lt;code&gt;NameID&lt;/code&gt; and &lt;code&gt;emailaddress&lt;/code&gt; claims&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;This integration allows you to decouple external user authentication from Azure AD, while still keeping governance within Microsoft Entra. It's ideal if you're managing users in Auth0 and want a seamless way to provide access to Microsoft resources — like SharePoint — without duplicating identities across systems.&lt;/p&gt;

</description>
      <category>auth0</category>
      <category>sharepoint</category>
      <category>authentication</category>
      <category>microsoft</category>
    </item>
    <item>
      <title>Building a Real-Time Collaborative Notes Application with htmx 2.0</title>
      <dc:creator>Sohini Pattanayak</dc:creator>
      <pubDate>Fri, 05 Jul 2024 22:05:54 +0000</pubDate>
      <link>https://dev.to/sohinip/building-a-real-time-collaborative-notes-application-with-htmx-20-1l4</link>
      <guid>https://dev.to/sohinip/building-a-real-time-collaborative-notes-application-with-htmx-20-1l4</guid>
      <description>&lt;p&gt;Hey everyone! 👋&lt;/p&gt;

&lt;p&gt;If you caught my blog last week about Remix and React Router, you know I've been diving into new technologies over the weekends. This time, I decided to play around with htmx 2.0, and I came up with a neat little project: a real-time collaborative notes application. Let me tell you all about it! 🚀&lt;/p&gt;

&lt;h3&gt;
  
  
  What I Built
&lt;/h3&gt;

&lt;p&gt;I built a collaborative notes application where you can add, edit, and delete notes in real-time. The coolest part? All of this is done with minimal JavaScript, thanks to htmx!&lt;/p&gt;

&lt;h3&gt;
  
  
  Why htmx 2.0?
&lt;/h3&gt;

&lt;p&gt;htmx 2.0 is pretty awesome for a few reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Partial Page Updates&lt;/strong&gt;: You can update specific parts of a webpage without refreshing the whole thing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enhanced Interactivity&lt;/strong&gt;: It helps you create interactive web apps with less JavaScript.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simplified Data Handling&lt;/strong&gt;: Managing data operations dynamically is super easy with htmx.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Key Features
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Real-time Updates&lt;/strong&gt;: Add, edit, and delete notes, and see changes instantly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Minimal JavaScript&lt;/strong&gt;: htmx handles dynamic content updates for us.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Server-Side Rendering&lt;/strong&gt;: Notes are rendered on the server and updated dynamically on the client side.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Code Snippets
&lt;/h3&gt;

&lt;p&gt;Here are some snippets to show how I used htmx:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Adding a New Note:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"add-note-form"&lt;/span&gt; &lt;span class="na"&gt;hx-post=&lt;/span&gt;&lt;span class="s"&gt;"/add-note"&lt;/span&gt; &lt;span class="na"&gt;hx-swap=&lt;/span&gt;&lt;span class="s"&gt;"beforeend:#notes-list"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"add-note-form"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"title"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Note Title"&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;textarea&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"content"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Note Content"&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/textarea&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Add Note&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This form uses htmx’s &lt;code&gt;hx-post&lt;/code&gt; to send the new note to the server and &lt;code&gt;hx-swap&lt;/code&gt; to append the note to the list without reloading the page.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Editing a Note:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"edit-button"&lt;/span&gt; &lt;span class="na"&gt;hx-get=&lt;/span&gt;&lt;span class="s"&gt;"/edit-note/${note.id}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Edit&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The edit button sends a GET request to fetch the edit form for a specific note, allowing in-place editing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deleting a Note:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"delete-button"&lt;/span&gt; &lt;span class="na"&gt;hx-delete=&lt;/span&gt;&lt;span class="s"&gt;"/delete-note/${note.id}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Delete&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The delete button sends a DELETE request to remove the note, instantly updating the UI.&lt;/p&gt;

&lt;h3&gt;
  
  
  Project Structure
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;index.html&lt;/strong&gt;: The main HTML file.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;server.js&lt;/strong&gt;: A simple Express.js server to handle requests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;style.css&lt;/strong&gt;: Basic styling for the application.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can find the complete code for this project on my &lt;a href="https://github.com/sohinipattanayak/html-notes" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;This project was a lot of fun and showcased the power of htmx 2.0 for creating dynamic web applications. I hope you find this project as exciting as I did!&lt;/p&gt;

&lt;p&gt;Check out the screenshot below to see the app in action:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd1d3xv5uexzlrylu2zgl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd1d3xv5uexzlrylu2zgl.png" alt="Image description" width="800" height="389"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Happy coding! ✨&lt;br&gt;
Sohini&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>htmx</category>
      <category>javascript</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Building a Modern Blog with Remix and React Router</title>
      <dc:creator>Sohini Pattanayak</dc:creator>
      <pubDate>Sat, 29 Jun 2024 18:46:48 +0000</pubDate>
      <link>https://dev.to/sohinip/building-a-modern-blog-with-remix-and-react-router-2jo3</link>
      <guid>https://dev.to/sohinip/building-a-modern-blog-with-remix-and-react-router-2jo3</guid>
      <description>&lt;p&gt;Hey everyone! 🎉&lt;/p&gt;

&lt;p&gt;This weekend, I decided to roll up my sleeves and dive into something new: building a blog using Remix and React Router. As someone who loves staying hands-on with the latest tech, this was the perfect opportunity to explore what these tools have to offer.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Remix and React Router?
&lt;/h3&gt;

&lt;p&gt;Remix and React Router are a powerful combo for modern web development. Remix is a full-stack framework that leverages the best of React and the web platform to create fast, slick, and scalable applications. React Router, as the go-to standard for routing in React apps, complements Remix perfectly.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Project: What We Did with Remix
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Setting Up the Project
&lt;/h4&gt;

&lt;p&gt;Getting started with Remix is straightforward. Here's a quick rundown:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Install Remix&lt;/strong&gt;: Create a new Remix project with this command:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   npx create-remix@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Set Up Your Routes&lt;/strong&gt;: In Remix, routing is file-based. Just create files in the &lt;code&gt;routes&lt;/code&gt; directory, and they automatically become routes in your app.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here's a peek at my routes:&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;app/routes/index.jsx&lt;/code&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Link&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@remix-run/react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Index&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Welcome to the Blog&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;nav&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt; &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Home&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt; &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/about"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;About&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt; &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/posts"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Posts&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;nav&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This snippet shows off &lt;strong&gt;Nested Routing&lt;/strong&gt;. The navigation links let users switch between different routes (&lt;code&gt;/&lt;/code&gt;, &lt;code&gt;/about&lt;/code&gt;, and &lt;code&gt;/posts&lt;/code&gt;), rendering components within the main layout.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;app/routes/about.jsx&lt;/code&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;About&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;About Us&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;This blog is built with Remix and React Router, showcasing modern web development.&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;code&gt;app/routes/posts.jsx&lt;/code&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Link&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useLoaderData&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@remix-run/react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Define the loader function to fetch data&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;loader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://jsonplaceholder.typicode.com/posts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;posts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Posts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;posts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useLoaderData&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Posts&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt; &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"new"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Create New Post&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt; &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`/posts/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This part highlights &lt;strong&gt;Data Loading and Mutations&lt;/strong&gt;. The &lt;code&gt;loader&lt;/code&gt; function fetches data from an API endpoint (&lt;code&gt;https://jsonplaceholder.typicode.com/posts&lt;/code&gt;), and the &lt;code&gt;useLoaderData&lt;/code&gt; hook accesses this data within the component. It makes data fetching a breeze, integrating seamlessly into the component lifecycle.&lt;/p&gt;

&lt;h3&gt;
  
  
  Handling Layouts and Links
&lt;/h3&gt;

&lt;p&gt;In Remix, you can define a root component (this is key ⭐️) to handle the layout, including meta tags, links, scripts, and live reload functionality. Here’s how my &lt;code&gt;app/root.jsx&lt;/code&gt; looks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;Links&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;LiveReload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Meta&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Outlet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Scripts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;ScrollRestoration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@remix-run/react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;links&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;rel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;stylesheet&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/styles.css&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt; &lt;span class="na"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Meta&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Links&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;header&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Welcome to the Blog&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;header&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;nav&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Home&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/about"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;About&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/posts"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Posts&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;nav&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"container"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Outlet&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ScrollRestoration&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Scripts&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;LiveReload&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This setup shows off &lt;strong&gt;Progressive Enhancement&lt;/strong&gt; and &lt;strong&gt;Nested Routing&lt;/strong&gt;. The &lt;code&gt;Links&lt;/code&gt;, &lt;code&gt;Meta&lt;/code&gt;, and &lt;code&gt;Scripts&lt;/code&gt; components ensure the app is well-structured, SEO-friendly, and progressively enhanced. The &lt;code&gt;Outlet&lt;/code&gt; component is used for nested routing, rendering different child components within the main layout.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lessons Learned
&lt;/h3&gt;

&lt;p&gt;Working on this project, I faced some challenges with environment configuration and resolving module issues. But overcoming these hurdles wasn't tiring at all! Fun experience 😎&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;This project was more than just building a blog, it was about exploring the capabilities of Remix and React Router and keeping my technical skills sharp. It's a powerful tool that can enhance your development workflow significantly for sure!!&lt;/p&gt;

&lt;p&gt;Stay tuned for more updates, and happy coding! 🚀&lt;/p&gt;

&lt;p&gt;Sohini ❤️&lt;/p&gt;

</description>
      <category>react</category>
      <category>remixrun</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Part 1 - LittleHorse Advanced Concept Series: Conditionals</title>
      <dc:creator>Sohini Pattanayak</dc:creator>
      <pubDate>Wed, 27 Mar 2024 11:09:54 +0000</pubDate>
      <link>https://dev.to/littlehorse/part-1-littlehorse-advanced-concept-series-conditionals-49hp</link>
      <guid>https://dev.to/littlehorse/part-1-littlehorse-advanced-concept-series-conditionals-49hp</guid>
      <description>&lt;p&gt;Welcome to our blog series on IT Incident Management using LittleHorse! If you're into coding, workflow automation, or just looking to up your IT game, you're in the right place. This series will walk you through creating responsive and efficient workflows to manage IT incidents like a pro. As a bonus, this series will introduce many key LittleHorse concepts that will allow you to apply LittleHorse to any domain, not just IT incident management.&lt;/p&gt;

&lt;p&gt;While dealing with IT incident management, being able to make decisions based on different scenarios is key. That's where conditionals come into play. Think of conditionals as the decision-makers in your workflow, helping your system figure out what to do next based on what's happening.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F05c7omx93f2qhfft0vq6.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F05c7omx93f2qhfft0vq6.gif" alt="Image description" width="500" height="230"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Conditionals allow your workflows to behave differently depending on the situation, rather than repeatedly doing the same thing over-and-over (like BB-8 above).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Let's set the stage for our incident management system. &lt;/p&gt;

&lt;h3&gt;
  
  
  Our mission?
&lt;/h3&gt;

&lt;p&gt;To develop a workflow that can identify IT incidents, figure out how serious they are, and take action. We'll break it down into two main types of incidents: the "Oh no!" kind (critical) and the "We've got this" kind (non-critical). Along the way, we’ll become LittleHorse pro’s so that you can apply LittleHorse to any business domain, whether related to IT incident management or otherwise.&lt;/p&gt;

&lt;p&gt;To get started, make sure you have completed the below steps:&lt;/p&gt;

&lt;p&gt;Have LittleHorse installed on your computer.&lt;br&gt;
Have docker up and running&lt;/p&gt;

&lt;p&gt;Once we’re all set with the above prerequisites, we’ll build a system that intelligently assesses IT incidents and decides the best course of action.&lt;/p&gt;
&lt;h3&gt;
  
  
  Creating the Workflow
&lt;/h3&gt;

&lt;p&gt;Our first step is to create the file ConditionalsExample.java. This is where we'll map out the logic that determines how our workflow will handle incidents. Open up your favorite Java IDE or text editor, and let's get started.&lt;/p&gt;
&lt;h3&gt;
  
  
  Defining the Workflow Structure
&lt;/h3&gt;

&lt;p&gt;In &lt;strong&gt;ConditionalsExample.java&lt;/strong&gt;, we'll start by defining our workflow structure. Here's a simple outline to get us started:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package lh.it.demo;

import io.littlehorse.sdk.common.proto.*;
import io.littlehorse.sdk.wfsdk.*;

public class ConditionalsExample {

    public static final String WF_NAME = "it-incident";
    public static final String VERIFY_TASK = "verify-incident";
    public static final String SEND_CRITICAL_ALERT_TASK = "send-critical-alert-task";
    public static final String PERIODIC_CHECK_TASK = "periodic-check-task";

    public void defineWorkflow(WorkflowThread wf) {
        // We'll flesh this out in a moment
    }

    public Workflow getWorkflow() {
        return Workflow.newWorkflow(WF_NAME, this::defineWorkflow);
    }

    // Additional methods will go here

}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This sets up a class ConditionalsExample that will hold our workflow logic. We've also declared constants for our workflow name and task names, which will come in handy later. These constants have specific use case:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;WF_NAME&lt;/strong&gt;: Identifies the workflow, used to start or reference it within LittleHorse.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;VERIFY_TASK&lt;/strong&gt;: Represents a task that checks and categorizes the incident details.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SEND_CRITICAL_ALERT_TASK&lt;/strong&gt;: Triggers an alert mechanism for incidents deemed critical.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PERIODIC_CHECK_TASK&lt;/strong&gt;: Executes regular checks to update the status of an ongoing incident.&lt;/p&gt;

&lt;p&gt;The variables we define in our workflow are not standalone; they interact and often depend on each other. For instance, the incidentSeverity variable determines whether to run the VERIFY_TASK or not. Similarly, the outcome of VERIFY_TASK might affect whether SEND_CRITICAL_ALERT_TASK is executed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Implementing Conditional Logic
&lt;/h3&gt;

&lt;p&gt;Now, we'll add the brains of our operation: the conditional logic. This logic checks incident severity and routes the workflow accordingly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Inside ConditionalsExample.defineWorkflow method

WfRunVariable incidentSeverity = wf.addVariable("severity", VariableType.INT);

WorkflowCondition isCritical = wf.condition(incidentSeverity, Comparator.GREATER_THAN, 5);

wf.doIf(
    isCritical,
    ifBody -&amp;gt; {
        ifBody.execute(VERIFY_TASK, incidentSeverity);
        // We'll add more here later
    }
);

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code snippet introduces a workflow variable incidentSeverity and a conditional isCritical. If the severity of an incident is above 5, the workflow considers it critical and executes the VERIFY_TASK. You can check out our youtube tutorial on this example to develop a comprehensive idea of how conditionals work out!&lt;/p&gt;

&lt;h3&gt;
  
  
  Building Out the Workflow
&lt;/h3&gt;

&lt;p&gt;With our conditionals set up, we'll now chalk out what happens in the critical and non-critical paths. But before we do that, let's pause and understand why this matters.&lt;/p&gt;

&lt;p&gt;Conditionals are powerful because they allow our workflow to be not just a static sequence of tasks but a dynamic, decision-making process. Depending on the severity of an incident, our workflow can trigger alerts, involve different team members, or escalate issues automatically.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why can’t we test the command yet?
&lt;/h3&gt;

&lt;p&gt;To test if conditionals are fully working, we need to pass a command through our terminal. We cannot run it at this point because our workflow is not fully implemented. We have just begun to sketch out the structure in ConditionalsExample.java. The lhctl run command is used to initiate a workflow when all components, including the main application file (App.java) and the task definition files, are complete and integrated.&lt;/p&gt;

&lt;h3&gt;
  
  
  Next Steps
&lt;/h3&gt;

&lt;p&gt;In our next blog post, we'll continue building our ConditionalsExample.java, adding more tasks and integrating more advanced LittleHorse features. We'll see how our workflow can not only detect and verify incidents but also take proactive steps to resolve them.&lt;/p&gt;

</description>
      <category>microservices</category>
      <category>workflows</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Interpreting Loan Predictions with TrustyAI: Part 3</title>
      <dc:creator>Sohini Pattanayak</dc:creator>
      <pubDate>Wed, 08 Nov 2023 13:56:07 +0000</pubDate>
      <link>https://dev.to/trustycore/interpreting-loan-predictions-with-trustyai-part-3-2h4a</link>
      <guid>https://dev.to/trustycore/interpreting-loan-predictions-with-trustyai-part-3-2h4a</guid>
      <description>&lt;h2&gt;
  
  
  Implementing Visualizations
&lt;/h2&gt;

&lt;p&gt;Hello again, dear readers! In our previous sessions, we understood LIME explanations in TrustyAI and implemented a simple linear model to explain loan approvals. While seeing the saliency values of each feature is insightful, a graphical representation can offer a clearer understanding of model decisions. Let's delve deeper!&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating a LIME Feature Impact Visualization
&lt;/h3&gt;

&lt;p&gt;Before we begin, ensure you've gone through Part 2 of our series.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Setting Up:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Ensure you've imported the necessary libraries:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import matplotlib.pyplot as plt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Generating LIME Explanations:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Using the TrustyAI library, generate the LIME explanations for your model as shown in the previous tutorial.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Visualizing Feature Impact:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Each feature's impact can be visualized as a bar in a bar chart. The height (positive or negative) indicates the magnitude of influence, and the color (blue for positive, red for negative, and green for the most influential) signifies the nature of the impact.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Transform the explanation to a dataframe and sort by saliency
    exp_df = lime_explanation['output-0'].sort_values(by="Saliency")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4. Extract feature names and their saliencies&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; y_axis = list(exp_df['Saliency'])
    x_axis = ["Annual Income", "Number of Open Accounts", "Late Payments", "Debt-to-Income Ratio", "Credit Inquiries"]

    # Color-coding bars
    colors = ["green" if value == max(y_axis) else "blue" if value &amp;gt; 0 else "red" for value in y_axis]

    # Plotting
    fig, ax = plt.subplots()
    ax.set_facecolor("#f2f2f2")
    ax.bar(x_axis, y_axis, color=colors)
    plt.title('LIME: Feature Impact on Loan Approval Decision')
    plt.xticks(rotation=45, ha='right')
    plt.axhline(0, color="black")  # x-axis line
    plt.show()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And there you go!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnw370qo8wfxz0owwtkp4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnw370qo8wfxz0owwtkp4.png" alt="Image description" width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Like the blog? Do hit a Like, send me some unicorns, and don't forget to share it with your friends!&lt;/p&gt;

&lt;p&gt;Thank you!&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>explainableai</category>
      <category>python</category>
      <category>ai</category>
    </item>
    <item>
      <title>Interpreting Loan Predictions with TrustyAI: Part 2</title>
      <dc:creator>Sohini Pattanayak</dc:creator>
      <pubDate>Sat, 28 Oct 2023 10:22:04 +0000</pubDate>
      <link>https://dev.to/trustycore/interpreting-loan-predictions-with-trustyai-part-2-3o6b</link>
      <guid>https://dev.to/trustycore/interpreting-loan-predictions-with-trustyai-part-2-3o6b</guid>
      <description>&lt;h2&gt;
  
  
  A Developer’s Guide
&lt;/h2&gt;

&lt;p&gt;In the previous blog, we gained a good overview of the use case of TrustyAI and developed an understanding of the goal of our tutorial today. If not, you can go through the previous blog again - &lt;a href="https://dev.to/trustycore/interpreting-loan-predictions-with-trustyai-part-1-1m5n"&gt;Part 1: An Overview&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Let’s get started now!&lt;/em&gt; 🚀&lt;/p&gt;

&lt;p&gt;Once we have our environment ready with our &lt;code&gt;demo.py&lt;/code&gt; file open, we’ll first import all the necessary libraries for this tutorial -&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import numpy as np
from trustyai.model import Model
from trustyai.explainers import LimeExplainer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the first three lines, we're importing the necessary libraries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;numpy: A library in Python used for numerical computations. Here, it will help us create and manipulate arrays for our linear model.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Model: This class from TrustyAI wraps our linear model, allowing it to be used with various explainers. TrustyAI library supports any type of model, it is enough to specify the predict function to invoke.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;LimeExplainer: The main attraction! &lt;strong&gt;LIME (Local Interpretable Model-Agnostic Explanations)&lt;/strong&gt; is a technique to explain predictions of machine learning models.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can learn more about LIME from here - &lt;a href="https://www.trustycore.com/post/how-does-the-lime-method-for-explainable-ai-work" rel="noopener noreferrer"&gt;How does the LIME Method for Explainable AI work?&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, we'll define a set of weights for our linear model using the numpy function &lt;code&gt;np.random.uniform()&lt;/code&gt;. These weights are randomly chosen between &lt;code&gt;-5&lt;/code&gt; and &lt;code&gt;5&lt;/code&gt; for our five features. These weights determine the &lt;strong&gt;importance of each feature in the creditworthiness decision&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;weights = np.random.uniform(low=-5, high=5, size=5)
print(f"Weights for Features: {weights}")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We’ll build the Linear Model now, it’ll represent our predictive model. It will calculate the dot product between the input features x and the weights. This dot product gives a score, representing the creditworthiness of an applicant.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def linear_model(x):
    return np.dot(x, weights)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It’s time to wrap up our linear function, Using TrustyAI's Model class preparing it for explanation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;model = Model(linear_model)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let us create a random sample of data for an applicant. The data is an array of five random numbers (each representing a feature like annual income, number of open accounts, etc.). We then feed this data to our model to get &lt;code&gt;predicted_credit_score&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;applicant_data = np.random.rand(1, 5)
predicted_credit_score = model(applicant_data)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once this is done, the crucial part comes in. We initialize the LimeExplainer with specific parameters.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;lime_explainer = LimeExplainer(samples=1000, normalise_weights=False)
lime_explanation = lime_explainer.explain(
    inputs=applicant_data,
    outputs=predicted_credit_score,
    model=model)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We then use this explainer to explain our model's prediction on the applicant's data. The lime_explanation object holds the results.&lt;/p&gt;

&lt;p&gt;And then we display the explanation -&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;print(lime_explanation.as_dataframe())
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Based on the predicted_credit_score, we provide a summary. If the score is positive, it indicates the applicant is likely to be approved, and vice versa.&lt;/p&gt;

&lt;p&gt;And finally, we loop through our features and their respective weights, printing them out for clarity.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;print("Feature weights:")
for feature, weight in zip(["Annual Income", "Number of Open Accounts", "Number of times Late Payment in the past", "Debt-to-Income Ratio", "Number of Credit Inquiries in the last 6 months"], weights):
  print(f"{feature}: {weight:.2f}")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that is it! You can now find the complete code below!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import numpy as np
from trustyai.model import Model
from trustyai.explainers import LimeExplainer

# Define weights for the linear model.

weights = np.random.uniform(low=-5, high=5, size=5)
print(f"Weights for Features: {weights}")

# Simple linear model

def linear_model(x):
    return np.dot(x, weights)

model = Model(linear_model)

# Sample data for an applicant

applicant_data = np.random.rand(1, 5)
predicted_credit_score = model(applicant_data)

lime_explainer = LimeExplainer(samples=1000, normalise_weights=False)
lime_explanation = lime_explainer.explain(
    inputs=applicant_data,
    outputs=predicted_credit_score,
    model=model)

print(lime_explanation.as_dataframe())

# Interpretation

print("Summary of the explanation:")
if predicted_credit_score &amp;gt; 0:
  print("The applicant is likely to be approved for a loan.")
else:
  print("The applicant is unlikely to be approved for a loan.")

# Display weights

print("Feature weights:")
features = ["Annual Income", "Number of Open Accounts", "Number of times Late Payment in the past", "Debt-to-Income Ratio", "Number of Credit Inquiries in the last 6 months"]
for feature, weight in zip(features, weights):
  print(f"{feature}: {weight:.2f}")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Interpretation of the Output:
&lt;/h3&gt;

&lt;p&gt;Running the code gives us the following output:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvfcdphfmig175i8gjxci.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvfcdphfmig175i8gjxci.jpg" alt="Image description" width="800" height="475"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These weights are influential in shaping the model's decision. For instance, the "Annual Income" has a weight of -2.56, suggesting that an increase in the annual income might negatively impact the creditworthiness in this model – a rather unexpected observation, highlighting an area Jane might want to reassess.&lt;/p&gt;

&lt;p&gt;Additionally, with the help of the &lt;em&gt;LimeExplainer, we obtain the saliency of each feature&lt;/em&gt;. A higher absolute value of saliency indicates a stronger influence of that feature on the decision.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion:
&lt;/h3&gt;

&lt;p&gt;Through TrustyAI, Jane not only developed a predictive model but also successfully interpreted its decisions, ensuring compliance with financial regulations. This tutorial underscores the importance of interpretability in machine learning models and showcases how developers can harness TrustyAI to bring transparency to their solutions.&lt;/p&gt;

&lt;p&gt;Developers keen on adopting TrustyAI should consider its vast range of capabilities that go beyond LIME, offering a comprehensive suite of tools to make AI/ML models trustworthy. As data-driven decisions become ubiquitous, tools like TrustyAI will become indispensable, ensuring a balance between model accuracy and transparency.&lt;/p&gt;

&lt;p&gt;Like the blog? Do hit a Like, send me some unicorns, and don't forget to share it with your friends! &lt;/p&gt;

</description>
      <category>explainableai</category>
      <category>ai</category>
      <category>machinelearning</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Interpreting Loan Predictions with TrustyAI: Part 1</title>
      <dc:creator>Sohini Pattanayak</dc:creator>
      <pubDate>Fri, 27 Oct 2023 09:32:22 +0000</pubDate>
      <link>https://dev.to/trustycore/interpreting-loan-predictions-with-trustyai-part-1-1m5n</link>
      <guid>https://dev.to/trustycore/interpreting-loan-predictions-with-trustyai-part-1-1m5n</guid>
      <description>&lt;h2&gt;
  
  
  An Overview
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Introduction
&lt;/h3&gt;

&lt;p&gt;AI/ML predictive models are essential for decision-making, but they need to be both accurate and interpretable, especially in regulated industries. TrustyAI provides the tools to understand and explain model decisions. &lt;/p&gt;

&lt;p&gt;Imagine a bank using a machine learning model as part of the logic to approve loans. The model is accurate and has helped the bank make more profitable decisions. However, the bank needs to be able to explain why the model approved or denied a loan to a particular applicant. This is where TrustyAI can help!&lt;/p&gt;

&lt;p&gt;TrustyAI can provide the bank with insights into the model's decision-making process, helping to ensure transparency and fairness.&lt;/p&gt;

&lt;h3&gt;
  
  
  Background
&lt;/h3&gt;

&lt;p&gt;Jane, a data scientist at a bank, is building a model to predict applicant’s loan creditworthiness based on specific features. But there's a catch. Regulatory mandates stipulate that any loan decisions made by the bank must be interpretable. Hence, declining an application isn't enough!&lt;/p&gt;

&lt;p&gt;There has to be an explanation behind this decision.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Predictive Model:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The features Jane considers for her model are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Annual Income&lt;/li&gt;
&lt;li&gt;Number of Open Accounts&lt;/li&gt;
&lt;li&gt;Number of times Late Payments in the past&lt;/li&gt;
&lt;li&gt;Debt-to-Income ratio&lt;/li&gt;
&lt;li&gt;Number of Credit Inquiries in the last 6 months&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Jane's initial model is a &lt;em&gt;straightforward linear one&lt;/em&gt;, with weights assigned to each feature based on their importance.&lt;/p&gt;

&lt;p&gt;Before we get started on the actual code in the next part of this blog, make sure to &lt;strong&gt;follow the prerequisites&lt;/strong&gt; before you plan on executing the code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Python&lt;/strong&gt;: Ensure you have Python version 3.8 or higher. If not, download and install it from the official Python website.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pip&lt;/strong&gt;: Pip, the package installer for Python, should be installed by default with Python &amp;gt;=3.8, or we can also use an online platform like &lt;a href="https://mybinder.org/" rel="noopener noreferrer"&gt;Binder&lt;/a&gt; or Google &lt;a href="https://colab.google/" rel="noopener noreferrer"&gt;Collab&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;IDE&lt;/strong&gt;: An Integrated Development Environment (IDE) makes it easier to write and run Python code. Some popular options include &lt;a href="https://www.jetbrains.com/pycharm/" rel="noopener noreferrer"&gt;PyCharm&lt;/a&gt; or &lt;a href="https://code.visualstudio.com/docs/datascience/jupyter-notebooks" rel="noopener noreferrer"&gt;VsCode&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A virtual environment is a self-contained directory that contains a Python installation for a particular version of Python, plus a number of additional packages, hence please create that.&lt;/p&gt;

&lt;p&gt;With your virtual environment activated, it's time to install the &lt;code&gt;trustyAI&lt;/code&gt; package: &lt;code&gt;pip install trustyai&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You're now ready to proceed with the tutorial.&lt;/p&gt;

&lt;p&gt;For this tutorial, I have taken all references from the TrustyAI Python Documentation website - &lt;a href="https://trustyai-explainability-python.readthedocs.io/en/latest/" rel="noopener noreferrer"&gt;https://trustyai-explainability-python.readthedocs.io/en/latest/&lt;/a&gt;, you can follow this to build similar examples.&lt;/p&gt;

&lt;p&gt;Follow &lt;a href="https://dev.to/trustycore/interpreting-loan-predictions-with-trustyai-part-2-3o6b"&gt;the next blog&lt;/a&gt; to get started with the technical tutorial for this example! &lt;/p&gt;

</description>
      <category>explainableai</category>
      <category>ai</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>Entando 7.2: The ultimate feature release</title>
      <dc:creator>Sohini Pattanayak</dc:creator>
      <pubDate>Wed, 14 Jun 2023 08:23:52 +0000</pubDate>
      <link>https://dev.to/sohinip/entando-72-the-ultimate-feature-release-305b</link>
      <guid>https://dev.to/sohinip/entando-72-the-ultimate-feature-release-305b</guid>
      <description>&lt;p&gt;Entando has just released its latest version, Entando 7.2. This new release builds on the platform's strengths and provides even more powerful tools for enterprises that need to create scalable, modular, and flexible web applications.&lt;/p&gt;

&lt;p&gt;This latest version of Entando introduces several new features that enhance the platform's capabilities for modernising and building web applications.&lt;/p&gt;

&lt;p&gt;In this blog post, we'll take a closer look at the key features and benefits of Entando 7.2.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6mv52qwoxuqhdi1lzgh7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6mv52qwoxuqhdi1lzgh7.png" alt="Image description" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What's New in Entando 7.2?
&lt;/h2&gt;

&lt;p&gt;This release will provide users with several new capabilities to enhance their experience.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hub 3.1 - Private Catalogs and More
&lt;/h3&gt;

&lt;p&gt;Entando 7.2 presents an upgraded Hub 3.1, with the option to create private catalogs. Each installation of the enterprise Entando Hub can have many catalogs, some public and some private, all managed from the Hub UI. A new feature in the Hub UI generates API keys, which is required for connecting a private catalog to an Entando App Builder, making it easier to access shared components.&lt;/p&gt;

&lt;h3&gt;
  
  
  Multitenancy
&lt;/h3&gt;

&lt;p&gt;A significant new feature on Entando 7.2 is multitenancy. With it, a single Entando instance can support multiple tenants, each with its own subdomain or domain. This allows for full isolation of data and content associated with each tenant. Additionally, each tenant has its own identity domain, managed via distinct realms of the same or different Keycloak instances. Redis is used for cache management, Apache Solr for enterprise search, and Entando's Content Delivery Server (CDS) for static asset and content delivery. And with Liquibase implementation to configure and update databases, managing multiple tenants has never been easier. &lt;/p&gt;

&lt;p&gt;Entando Blueprint Upgrade to JHipster 7.9.3 and Keycloak 18+ Support&lt;/p&gt;

&lt;p&gt;The Entando Blueprint has been upgraded to JHipster 7.9.3, including updates to the Entando bill of materials (BOM) and support for Keycloak 18+. &lt;/p&gt;

&lt;p&gt;Performance, Security, and Dependency Improvements&lt;/p&gt;

&lt;p&gt;In addition to multitenancy and other major upgrades, Entando 7.2 includes numerous performance, security, and dependency improvements. &lt;/p&gt;

&lt;p&gt;Entando 7.2 is a major feature release that brings a wealth of new options and improvements to the platform. With support for multitenancy, private catalogs with the Entando Hub, and upgrades to the Entando Blueprint, your enterprise can take advantage of the latest and significant web development technologies. &lt;/p&gt;

&lt;p&gt;So what are you waiting for? Upgrade to Entando 7.2 today and take your enterprise's web development to the next level!&lt;/p&gt;

&lt;p&gt;Take a look at the complete &lt;a href="https://developer.entando.com/v7.2/docs/releases/" rel="noopener noreferrer"&gt;release notes&lt;/a&gt;, and we’ll be back with new blog posts soon!&lt;/p&gt;

</description>
      <category>multitenancy</category>
      <category>application</category>
      <category>composition</category>
      <category>opensource</category>
    </item>
    <item>
      <title>The Transition from Developer Advocacy to Product</title>
      <dc:creator>Sohini Pattanayak</dc:creator>
      <pubDate>Tue, 15 Nov 2022 18:55:21 +0000</pubDate>
      <link>https://dev.to/sohinip/transition-from-developer-advocacy-to-product-17og</link>
      <guid>https://dev.to/sohinip/transition-from-developer-advocacy-to-product-17og</guid>
      <description>&lt;p&gt;And sometimes, taking a "risk" 💣 pays off! 🚀&lt;/p&gt;

&lt;p&gt;I switched to product management lately from developer advocacy. I'll be frank— I was afraid. I couldn't stop wondering if this was the best course of action. However, I've always wanted this, so it makes sense. I've always wanted to grow, learn, and help build products. As a result, I understood that I needed to make this move even though I knew it could be a little challenging for me at first.&lt;/p&gt;

&lt;p&gt;I initially thought I had stopped coding(which happens sometimes when you come from an engineering background). But I decided not to put the blame on my job or role. I continue to spend some of my evenings learning new languages and occasionally developing new tools, frameworks, libraries, and languages.&lt;/p&gt;

&lt;p&gt;I was a little anxious when my role changed as an APM (Associate Product Manager). The first few days left me unsure of where to begin. But having a supportive team around me has made and continues to make me incredibly lucky. At Pragmatic Institute, I took two courses to get started, which was a great idea. However, I never feel like I've learned enough, so I continue to study product management for an hour every evening.&lt;/p&gt;

&lt;p&gt;I won't go into detail on how to get started with product management in this article because there are many resources already available. But I would rather discuss how different it is for me to picture myself as an APM versus a Developer Advocate.&lt;/p&gt;

&lt;p&gt;As a Dev Advocate, I would, however, primarily concentrate on producing written and video tutorials, live streaming, blog entries, community interaction, and much more. My daily tasks would be to learn about new subjects and produce content for developer and partner education. As a developer advocate, I, therefore, concentrated on increasing engagement for the product once it had been developed and released. However, things are a little bit different with being an APM. It's more like I've made progress toward the thing I was supporting!&lt;/p&gt;

&lt;p&gt;Now, rather than evangelising the product, I spend most of my time focusing on building it. My current priorities include defining product requirements, developing user stories, conducting market research, understanding users and consumers, and contributing to product positioning. It's a lot of fun, but occasionally scary. It would be scary because I would feel imposter syndrome. Given that I am relatively new to the product, I would experience it even more. But that's what motivates us to improve, isn't it?&lt;/p&gt;

&lt;p&gt;This concludes this short article. I won't make it any longer. I'll continue to share my opinions, insights, and thoughts in the future! If you have any questions or comments for me before then, please don't hesitate to contact me!&lt;/p&gt;

&lt;p&gt;Sohini&lt;/p&gt;

</description>
      <category>developer</category>
      <category>product</category>
      <category>career</category>
      <category>transition</category>
    </item>
    <item>
      <title>Entando 7.1 Release Overview</title>
      <dc:creator>Sohini Pattanayak</dc:creator>
      <pubDate>Tue, 08 Nov 2022 09:48:48 +0000</pubDate>
      <link>https://dev.to/entando/entando-71-release-overview-2dl3</link>
      <guid>https://dev.to/entando/entando-71-release-overview-2dl3</guid>
      <description>&lt;p&gt;Entando Application Composition Platform Version 7.1 is now available to support enterprises who are modernizing applications to accelerate development, reduce runtime costs, and streamline maintenance through the use of a composable application architecture.   Entando brings developer joy to the creation, curation, and composition of modular enterprise applications.   &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqut24tdgbf3sbk0e7yf4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqut24tdgbf3sbk0e7yf4.png" alt="Image description" width="800" height="413"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Background:&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;Even before the 21st century, enterprises have been advancing infrastructure and strategies to solve business problems.  From the development of web applications on-prem, to their subsequent move to the cloud, and now, modularization in the cloud, each move has accelerated development, lowered cost and streamlined maintenance.  &lt;/p&gt;

&lt;p&gt;This new phase of modularity focused on decoupling (or breaking up) both the backend code and the monolithic frontend by bundling microservices and micro frontends into &lt;a href="https://youtu.be/RkGBpLQ-070" rel="noopener noreferrer"&gt;Packaged Business Capabilities (PBCs)&lt;/a&gt;. These PBCs could be shared across development teams and projects within an Enterprise Hub and assembled into applications via a low-code Application Builder, all within a unified Application Composition Platform.  &lt;/p&gt;

&lt;p&gt;The updates available in Entando Application Composition Platform v7.1 are focused on the pro-code creators. It provides many new capabilities to support the development of modern composable applications, which include: &lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;New:  Entando Platform Capability (EPC)&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;To accelerate application development, Entando 7.1 now supports a pluggable framework to allow Creators and Composers to easily expand the functionality of the Entando App Builder, add external services. Like the PBC, an EPC is a packaged capability and it adds functionality to the platform like menu options or an API management page. An EPC can be a headless CMS like Strapi, that is bundled, stored on Entando Cloud Hub, and implemented in the App Builder.&lt;/p&gt;

&lt;p&gt;A sample configuration is shown below: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzdf1dd24l2vcjulf6e9q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzdf1dd24l2vcjulf6e9q.png" alt="Image description" width="800" height="287"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The headless system (e.g., Strapi) uses the Entando App Builder as a templating mechanism to create and manage pages, content layout, and content versioning. &lt;/p&gt;

&lt;p&gt;1) An EPC can be deployed to the Entando Hub (or Entando Cloud Hub, the publically accessible version of the hub), &lt;/p&gt;

&lt;p&gt;2) Composers can access and install EPCs into the Entando App Builder, adding a new menu item to the builder, which &lt;/p&gt;

&lt;p&gt;3) when accessed, opens the headless interface, where content can be managed and you can return to the App Builder at any time.&lt;/p&gt;

&lt;p&gt;4) Users can access the external system’s APIs and resources, deploying them into applications using the page designer. Many types of EPCs can be built for Entando 7.1, including Headless CMS (Strapi.io is coming soon),  Workflow, AI/ML, API Mgmt, and more.  &lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;New: Pro-code bundle Templates&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;v7.1 introduces Pro-code Bundle Templates to enable developers, system integrators, and enterprises to create new Packaged Business Capabilities by reusing existing micro frontends and microservices allowing consistency and acceleration from a core PBC library.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;New: Service Discovery&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;With v7.1, communication between micro frontends and microservices is decoupled and service discovery is made simpler with the API claims mechanism orchestrated by the ent CLI. It eliminates the need to define and manage API endpoints, both in local development and within a running instance.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Updated: Create Tooling&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;v7.1 mainly focuses on developers. The local development process was improved and now developers can easily initialize a bundle from scratch or download one from a hub. They can add components and populate the bundle descriptor with micro frontends, microservices, and platform components with the ent CLI. They can run, build, and install with only a few commands. Bundles that have worked on 7.0 will work on 7.1 as well. More details can be found here: &lt;a href="https://developer.entando.com/v7.1/docs/getting-started/ent-bundle.html#entando-7-1-bundle-development" rel="noopener noreferrer"&gt;https://developer.entando.com/v7.1/docs/getting-started/ent-bundle.html#entando-7-1-bundle-development&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Updated: Docker Image Specification&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Previously, developers used Git repositories to manage both code sources and bundle versioning. Now bundle packaging and publishing has moved to Docker which handle the image specifications. With this, one can still manage code sources on their preferred Git provider but each release will be done through an image registry.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Updated: Entando Command Line Interface (CLI)&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;We have enhanced the &lt;strong&gt;Entando CLI&lt;/strong&gt; for Mac and Windows. The CLI can now create new bundles from templates downloaded from the Hub, providing a wider range of commands to perform various actions. Some examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a Docker Image of the Bundle&lt;/li&gt;
&lt;li&gt;Docker-based bundle management commands&lt;/li&gt;
&lt;li&gt;Easily Publish a bundle inside Docker Hub&lt;/li&gt;
&lt;li&gt;API management&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Updated: Entando Hub&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The Entando Hub was introduced in v7.0 and provides a repository for PBCs, solution templates, components, and/or component collections. Enterprises, Development Teams, System Integrators and others can implement an Entando Hub as a central repository from which the Entando App Builder can discover and quickly access entries. Entando Hub updates include: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Docker bundle name generation update&lt;/li&gt;
&lt;li&gt;Added security check on bundleGroupVersion details page&lt;/li&gt;
&lt;li&gt;Update install instructions to use ent ecr deploy&lt;/li&gt;
&lt;li&gt;Refined AppBuilder BundleGroups retrieval to sort if no pageSize provided.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Summary&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;To learn more about Entando 7.1, or to get started with Composable Applications, see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A complete look at the 7.1 &lt;a href="https://developer.entando.com/next/docs/releases/#summary" rel="noopener noreferrer"&gt;release notes&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Docs - &lt;a href="https://developer.entando.com/v7.1/docs/" rel="noopener noreferrer"&gt;https://developer.entando.com/v7.1/docs/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Tutorials - &lt;a href="https://developer.entando.com/v7.1/docs/" rel="noopener noreferrer"&gt;https://developer.entando.com/v7.1/docs/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Base install guide (manual, not the one liner until official launch): &lt;a href="https://developer.entando.com/v7.1/docs/getting-started/#install-kubernetes" rel="noopener noreferrer"&gt;https://developer.entando.com/v7.1/docs/getting-started/#install-kubernetes&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Platform install guides: &lt;a href="https://developer.entando.com/v7.1/tutorials/#operations" rel="noopener noreferrer"&gt;https://developer.entando.com/v7.1/tutorials/#operations&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Watch a video with industry experts

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=fWbLQDZBEio" rel="noopener noreferrer"&gt;With Massimo Pezzini, formerly VP Distinguished Analyst 
with Gartner&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=_pAILlnkLck" rel="noopener noreferrer"&gt;With Luca Mezzalira, Serverless Solutions Specialists 
at Amazon Web Services&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=Lo5rfCNLCvo" rel="noopener noreferrer"&gt;With James Governor Red Monk Analyst and Co-founder&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;a href="https://discover.entando.com/en-us/what-is-an-application-composition-platform" rel="noopener noreferrer"&gt;Download the “What is an Application Composition Platform" whitepaper&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href="https://entando.com/page/en/demo" rel="noopener noreferrer"&gt;Book a guided demo&lt;/a&gt;&lt;/li&gt;

&lt;/ul&gt;

</description>
      <category>release</category>
      <category>opensource</category>
      <category>cloud</category>
      <category>docker</category>
    </item>
    <item>
      <title>What is the Entando Hub?</title>
      <dc:creator>Sohini Pattanayak</dc:creator>
      <pubDate>Thu, 16 Jun 2022 10:33:50 +0000</pubDate>
      <link>https://dev.to/entando/what-is-the-entando-hub-1ic</link>
      <guid>https://dev.to/entando/what-is-the-entando-hub-1ic</guid>
      <description>&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/frHvMrK8Sig"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;em&gt;What do you imagine when someone says Hub?&lt;/em&gt; &lt;/p&gt;

&lt;p&gt;It's a center or place to hold a collection of things, or several kinds of things. And an &lt;strong&gt;Entando Hub&lt;/strong&gt; is a repository (local, remote, public, or private), that contains components. To be more specific, the App Builder, the UI of the Entando Platform, can connect to one or more Entando Hub.&lt;/p&gt;

&lt;p&gt;In my recent blog on Entando 7.0 release, I wrote a bit about the Entando Hub. You can check that out &lt;a href="https://dev.to/entando/whats-new-with-the-entando-70-release-3gfa"&gt;here&lt;/a&gt;. But, in this blog, I’ll give a technical overview of the Hub.&lt;/p&gt;

&lt;p&gt;Before I start, let’s find out &lt;strong&gt;&lt;em&gt;why&lt;/em&gt;&lt;/strong&gt; we needed a Hub. &lt;/p&gt;

&lt;p&gt;In the previous blogs, we learned about the 4Cs. If you don’t know about that,  you can take a look at this &lt;a href="https://dev.to/entando/part-1-what-is-entando-platform-cbb"&gt;blog&lt;/a&gt;. from the 4 essential roles of application composition, one thing is clear: the set of components built by creators are &lt;strong&gt;reusable&lt;/strong&gt; and &lt;strong&gt;absolutely flexible&lt;/strong&gt;. But, to make them easy to reuse, there was a need to create a Hub, where they could reside and be available to a larger audience. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Now, the question is, what are some of the capabilities of the Hub?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The Hub lets you share &lt;strong&gt;Single Components, Component Collections, Solution Templates,  Packaged Business Capabilities (PBCs)&lt;/strong&gt; that creators build. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkscccdkszxuj84ny0spb.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkscccdkszxuj84ny0spb.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Single components are a building block for apps. It  can be a page template, content template, micro frontend, microservice, UX Fragment,content type…&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F68f7b4scd7k1wr2tasm1.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F68f7b4scd7k1wr2tasm1.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Component collections are a packaged set of single components. They are assembled components that are in some way functionally unrelated but useful to a Composer.  (e.g. a set of Page Templates, a set of content templates or content types + widgets + MFE or a mix of them)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F60531iqnf1sawt482uyk.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F60531iqnf1sawt482uyk.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Solution templates are a pre-packaged set of PBCs, component collections, and single components providing full-featured, domain-specific solutions. (eg: Task Tracker, Supplier Portal, Customer Portal, Partner Portal, E-commerce, …)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fecs83jgovgcjychu6cvn.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fecs83jgovgcjychu6cvn.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And PBCs are encapsulated software components that represent a well-defined business capability, recognizable as such by a business user, and packaged for programmatic access. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnfh9zoudvka3zvsu0eqf.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnfh9zoudvka3zvsu0eqf.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Any and all of these can be assembled in the Hub, where new items and new versions are continuously made available. But to avoid errors or issues, we should follow some best practices.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The PBCs and/or components we build as a creator must be well sized. It shouldn’t either be too small or too big. It should be business-driven with a definite business value. There are several scenarios in this case. For example, a PBC can have many components which can make it large, or it can have fewer components, making the size smaller. But in this case, a Composer may need to install several items to get what they need. It is a tradeoff between functionality and ease of use. Hence, we must judge wisely, making sure the component isn’t too large or too small. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Our Components and PBCs should be easily configurable. By this I mean, we must avoid hard-coded stuff. It is preferable to use separate configuration files or database tables to  store any value that’s needed in your component.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It is best to use a package manager as it can help us with the right dependency versioning strategy. A package manager helps us by updating all the packages and/or software frequently. These packages run tests to check security and other things. It also saves us a lot of time.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;While we discuss these best practices, we must know that the Curator oversees the Hub, managing the components available there for the organization. Hence, the Curator should do a Security Analysis. They should perform a thorough analysis of the dependencies, security alert or code vulnerabilities.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use code quality metrics to measure and determine if the code we have written for the PBC is of high quality. Certain variables are checked under this quality analysis, like code complexity, portability, reusability, etc. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;And finally, we should add proper documentation for our PBC. It’s the first thing that provides clarity about our PBC. This documentation should be made in such a manner that it is well understood by both business and technical people. Also, it is a good coding practice!&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, it’s time we take a look at the Hub.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzu1kokn9p65nr892es1h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzu1kokn9p65nr892es1h.png" alt="Image description" width="800" height="560"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you see here, there are many PBCs, Component Collections, Solution Templates, and Single Components under “Catalog”. After the Curator performs the validation checks, these building blocks made by Creators are published in the Hub.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;How can we use the Hub?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This Hub can be used with Entando 7.0. This &lt;a href="https://developer.entando.com/v7.0/tutorials/solution/entando-hub.html#overview" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; can help us get started after installing the Hub on Entando 7.0. But in the upcoming blogs, I’ll definitely share how it can be installed in our App Builder. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Is the Hub open source?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The Entando Hub is under the ​​&lt;a href="https://github.com/entando-samples/entando-hub/blob/main/LICENSE" rel="noopener noreferrer"&gt;LGPL-3.0&lt;/a&gt; license and is open source. We can easily contribute to it by referring to this &lt;a href="https://github.com/entando-samples/entando-hub" rel="noopener noreferrer"&gt;repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Lastly, before we wrap up, I’d like to explain the Entando Cloud Hub.&lt;/p&gt;

&lt;p&gt;The Entando Cloud Hub is a SaaS instance of an Entando Hub that contains a public and private collection of components. &lt;/p&gt;

&lt;p&gt;Well, that’s all about the Hub for now. We are in the process of creating more tutorials around the Hub and those will be released over the next few weeks. &lt;/p&gt;

&lt;p&gt;But, for now, I would love to see you all try out the Hub for yourselves and send in your feedback to the comment section below!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw572a10t4yyg3uwvmujt.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw572a10t4yyg3uwvmujt.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Lastly, we at Entando are building an exciting community that spreads awareness of composability and modular applications. We call it the Modular Squad, and we’d love to invite you to &lt;a href="https://discord.gg/N64a3QMd9X" rel="noopener noreferrer"&gt;join us&lt;/a&gt; and be part of this journey!&lt;/p&gt;

&lt;p&gt;Thank you!&lt;/p&gt;

</description>
      <category>entando</category>
      <category>beginners</category>
      <category>tutorial</category>
      <category>hub</category>
    </item>
  </channel>
</rss>
