<?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: Harsh Gupta</title>
    <description>The latest articles on DEV Community by Harsh Gupta (@harshgupta71).</description>
    <link>https://dev.to/harshgupta71</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%2F3214964%2Ff4e79036-4c0a-457a-8b86-b82b14a88f99.jpg</url>
      <title>DEV Community: Harsh Gupta</title>
      <link>https://dev.to/harshgupta71</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/harshgupta71"/>
    <language>en</language>
    <item>
      <title>Why Use Repository Pattern in Angular Applications - Best Practices</title>
      <dc:creator>Harsh Gupta</dc:creator>
      <pubDate>Sun, 14 Jun 2026 07:21:11 +0000</pubDate>
      <link>https://dev.to/harshgupta71/why-use-repository-pattern-in-angular-applications-best-practices-1dji</link>
      <guid>https://dev.to/harshgupta71/why-use-repository-pattern-in-angular-applications-best-practices-1dji</guid>
      <description>&lt;p&gt;In modern Angular applications, managing data efficiently is crucial for performance and maintainability. The Repository Pattern provides a clean abstraction layer between your components and data sources, offering significant benefits for enterprise applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is the Repository Pattern?
&lt;/h2&gt;

&lt;p&gt;The Repository Pattern is an architectural approach that acts as a mediator between the data source (database, API, etc.) and the business logic layers of an application. Rather than making direct API calls from components, you use repository services that:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Centralize data access logic&lt;/strong&gt; in one place&lt;br&gt;
&lt;strong&gt;Provide caching mechanisms&lt;/strong&gt; to reduce redundant network requests&lt;br&gt;
&lt;strong&gt;Offer reactive observables&lt;/strong&gt; for data changes&lt;br&gt;
&lt;strong&gt;Handle data loading and initialization&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Why Vineforce Teams Uses This Pattern
&lt;/h2&gt;

&lt;p&gt;At Vineforce, we've adopted the Repository Pattern for several key reasons:&lt;/p&gt;
&lt;h3&gt;
  
  
  Performance Optimization
&lt;/h3&gt;

&lt;p&gt;Reduces redundant API calls through intelligent caching&lt;br&gt;
Minimizes network overhead by storing frequently accessed data&lt;br&gt;
Enables optimistic UI updates for better user experience&lt;/p&gt;
&lt;h3&gt;
  
  
  Code Maintainability
&lt;/h3&gt;

&lt;p&gt;Centralizes data access logic in one place&lt;br&gt;
Promotes separation of concerns&lt;br&gt;
Makes components cleaner and more testable&lt;br&gt;
Simplifies debugging and troubleshooting&lt;/p&gt;
&lt;h3&gt;
  
  
  Developer Productivity
&lt;/h3&gt;

&lt;p&gt;Provides consistent API across different data types&lt;br&gt;
Enables reactive programming patterns&lt;br&gt;
Reduces boilerplate code in components&lt;/p&gt;
&lt;h2&gt;
  
  
  Implementation in Vineforce Teams
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Base Repository Class
&lt;/h3&gt;

&lt;p&gt;Our implementation starts with an abstract &lt;code&gt;Repository&lt;/code&gt; class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Repository&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&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;protected&lt;/span&gt; &lt;span class="na"&gt;dic&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="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;

    &lt;span class="cm"&gt;/** Provides an observable that will emit a new list every time a change occurs */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;observe&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&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="cm"&gt;/** Returns the item having that ID, only if already loaded in the repository */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="cm"&gt;/** Returns the item if present in the repository, otherwise loads it */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;getOrLoad&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="cm"&gt;/** Adds a range of items to the repository */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;addRange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[]):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="cm"&gt;/** Removes a range of items from the repository */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;removeRange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[]):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="nf"&gt;loadAll&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&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;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Concrete Implementation Example
&lt;/h3&gt;

&lt;p&gt;Here's how we extend the base class for team member data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;providedIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&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;class&lt;/span&gt; &lt;span class="nc"&gt;TeamMemberNamesRepositoryService&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Repository&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;TeamMemberNameDto&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="na"&gt;userService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserServiceProxy&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initialLoad&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Pre-load data when service is instantiated&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nf"&gt;loadAll&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;TeamMemberNameDto&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getTeamMembersByCurrentUser&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&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;members&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;members&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;n&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;}))))&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toPromise&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="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;TeamMemberNameDto&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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;h2&gt;
  
  
  Benefits for Vineforce Teams Developers
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Reduced API Calls
&lt;/h3&gt;

&lt;p&gt;With caching built into repositories, common data is only fetched once and reused across components:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Multiple components can access the same data without additional API calls&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;teamMembers$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;teamMemberRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;observe&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Consistent Data State
&lt;/h3&gt;

&lt;p&gt;All components using the same repository share the same data state, ensuring consistency:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// When data updates in one place, all components automatically reflect changes&lt;/span&gt;
&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;teamMemberRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;entityChanged&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;updateEntity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updatedMember&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Simplified Component Logic
&lt;/h3&gt;

&lt;p&gt;Components focus on presentation logic rather than data management:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-team-selector&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
    &amp;lt;select [(ngModel)]="selectedTeamMember"&amp;gt;
      &amp;lt;option *ngFor="let member of teamMembers$ | async" [value]="member.id"&amp;gt;
        {{ member.name }}
      &amp;lt;/option&amp;gt;
    &amp;lt;/select&amp;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;class&lt;/span&gt; &lt;span class="nc"&gt;TeamSelectorComponent&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;OnInit&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;teamMembers$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;teamMemberRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;observe&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;teamMemberRepository&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TeamMemberNamesRepositoryService&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

  &lt;span class="nf"&gt;ngOnInit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Repository handles loading automatically&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;h2&gt;
  
  
  Best Practices for Repository Implementation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Initialize Early
&lt;/h3&gt;

&lt;p&gt;Load frequently used data early in the application lifecycle:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;userService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserServiceProxy&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initialLoad&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Load data when service is created&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Handle Loading States
&lt;/h3&gt;

&lt;p&gt;Repositories provide built-in mechanisms for handling loading states:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Check if repository is ready&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isReady&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Repository has loaded data&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isReady&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Process loaded items&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;h3&gt;
  
  
  3. Update Repository on Data Changes
&lt;/h3&gt;

&lt;p&gt;Keep repositories synchronized with backend changes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// When an item is created/updated/deleted&lt;/span&gt;
&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;entityChanged&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;insertEntity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newItem&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;entityChanged&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;updateEntity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updatedItem&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;entityChanged&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;deletedEntity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;removedItem&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  When to Use Repository Pattern
&lt;/h2&gt;

&lt;p&gt;The Repository Pattern is particularly beneficial when:&lt;/p&gt;

&lt;p&gt;You have data that is used across multiple components&lt;br&gt;
You need to minimize network requests&lt;br&gt;
You want to implement caching strategies&lt;br&gt;
You need to maintain consistent data state across your application&lt;br&gt;
You're building enterprise applications with complex data relationships&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The Repository Pattern provides a robust and scalable approach to data management in Angular applications. By centralizing data access and implementing intelligent caching, repositories significantly improve both application performance and developer productivity.&lt;/p&gt;

&lt;p&gt;Key advantages of this pattern include:&lt;/p&gt;

&lt;p&gt;Reduced API calls through caching&lt;br&gt;
Cleaner component code&lt;br&gt;
Consistent data access patterns&lt;br&gt;
Built-in reactive programming support&lt;br&gt;
Easy synchronization with backend changes&lt;/p&gt;

&lt;p&gt;This pattern is especially valuable in enterprise applications like Vineforce Teams where multiple components need access to the same data sets, ensuring optimal performance and maintainability.&lt;/p&gt;

&lt;p&gt;For developers working with Vineforce Teams, understanding and utilizing the Repository Pattern will lead to more efficient, maintainable, and performant applications.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>dotnet</category>
      <category>productivity</category>
      <category>vineforce</category>
    </item>
    <item>
      <title>DefaultAzureCredential vs Client ID &amp; Client Secret for Azure Key Vault Authentication</title>
      <dc:creator>Harsh Gupta</dc:creator>
      <pubDate>Sun, 14 Jun 2026 07:20:28 +0000</pubDate>
      <link>https://dev.to/harshgupta71/defaultazurecredential-vs-client-id-client-secret-for-azure-key-vault-authentication-5ee4</link>
      <guid>https://dev.to/harshgupta71/defaultazurecredential-vs-client-id-client-secret-for-azure-key-vault-authentication-5ee4</guid>
      <description>&lt;p&gt;Securely accessing &lt;strong&gt;Azure Key Vault&lt;/strong&gt; is essential for modern cloud applications. This guide compares the &lt;strong&gt;&lt;code&gt;DefaultAzureCredential&lt;/code&gt;&lt;/strong&gt; (recommended) and the classic &lt;strong&gt;Client ID &amp;amp; Client Secret&lt;/strong&gt; authentication methods for Azure Key Vault, providing best‑practice recommendations, security considerations, and ready‑to‑use C# code samples.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Two Approaches
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. DefaultAzureCredential
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;DefaultAzureCredential&lt;/code&gt; is a &lt;strong&gt;composite credential&lt;/strong&gt; that sequentially attempts a set of credential sources (environment variables, managed identity, Visual Studio, Azure CLI, etc.) until one succeeds. It is designed to work &lt;strong&gt;out‑of‑the‑box&lt;/strong&gt; in local development, CI pipelines, and production environments. &lt;em&gt;&lt;a href="https://learn.microsoft.com/azure/developer/dotnet/azure-sdk-authentication" rel="noopener noreferrer"&gt;Azure SDK authentication overview (Azure Identity)&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Client ID &amp;amp; Client Secret
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;Client ID &amp;amp; Client Secret&lt;/strong&gt; method uses an Azure AD &lt;strong&gt;App Registration&lt;/strong&gt;. You explicitly provide the &lt;code&gt;tenantId&lt;/code&gt;, &lt;code&gt;clientId&lt;/code&gt;, and &lt;code&gt;clientSecret&lt;/code&gt; to the &lt;code&gt;ClientSecretCredential&lt;/code&gt;. This is a static credential that does not change based on the runtime environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Comparison Table
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;DefaultAzureCredential&lt;/th&gt;
&lt;th&gt;Client ID &amp;amp; Client Secret&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Security&lt;/td&gt;
&lt;td&gt;Leverages managed identities in Azure, never stores secrets in code or config. Secrets only exist in dev environment as env vars.&lt;/td&gt;
&lt;td&gt;Secret stored in configuration (env var, file, or secret store). Higher risk of leakage.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Local Development&lt;/td&gt;
&lt;td&gt;Works with Azure CLI, VS Code, or environment variables automatically. No extra code changes when moving between dev and prod.&lt;/td&gt;
&lt;td&gt;Requires developers to provision and manage a secret locally, often duplicated across machines.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Production Overhead&lt;/td&gt;
&lt;td&gt;Zero‑code changes when deploying to Azure services (App Service, AKS, Functions) that support Managed Identity.&lt;/td&gt;
&lt;td&gt;Must provision secret in each target environment (e.g., Azure Key Vault, App Settings).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Credential Rotation&lt;/td&gt;
&lt;td&gt;Managed identity tokens rotate automatically; no manual secret rotation needed.&lt;/td&gt;
&lt;td&gt;Secret rotation is manual – you must update the secret in every deployment artifact.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Compliance&lt;/td&gt;
&lt;td&gt;Aligns with Azure recommended best practices (least‑privilege, short‑lived tokens).&lt;/td&gt;
&lt;td&gt;May conflict with policies that forbid storing secrets in configuration files.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Complexity&lt;/td&gt;
&lt;td&gt;Slightly larger package size but simplifies code paths.&lt;/td&gt;
&lt;td&gt;Simpler code but adds operational complexity around secret handling.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Supported Languages&lt;/td&gt;
&lt;td&gt;All Azure SDKs that use Azure.Identity.&lt;/td&gt;
&lt;td&gt;All Azure SDKs that accept a TokenCredential.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Pros &amp;amp; Cons
&lt;/h2&gt;

&lt;h3&gt;
  
  
  DefaultAzureCredential
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Pros&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Automatic credential selection across environments.&lt;br&gt;
Seamless integration with Managed Identity – no secrets in production.&lt;br&gt;
Simplifies CI/CD pipelines.&lt;br&gt;
Recommended by Microsoft for new projects.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cons&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Slightly larger dependency footprint.&lt;br&gt;
Requires understanding of the credential chain for debugging.&lt;/p&gt;

&lt;h3&gt;
  
  
  Client ID &amp;amp; Client Secret
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Pros&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Explicit and deterministic – you know exactly which credential is used.&lt;br&gt;
Works in environments that lack Azure SDK support for managed identity.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cons&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Secrets must be stored and rotated manually.&lt;br&gt;
Higher risk of accidental exposure (e.g., committing to repo).&lt;br&gt;
Additional operational overhead for each deployment target.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to Use Which
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;Recommended Approach&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;New cloud‑native application running in Azure (App Service, AKS, Functions, etc.)&lt;/td&gt;
&lt;td&gt;DefaultAzureCredential – take advantage of managed identity.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Legacy on‑prem or non‑Azure environment where managed identity isn’t available&lt;/td&gt;
&lt;td&gt;Client ID &amp;amp; Client Secret – you must supply a static credential.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Quick prototype on a developer machine without Azure CLI installed&lt;/td&gt;
&lt;td&gt;Either works, but DefaultAzureCredential still recommended for consistency.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Strict compliance requiring no secrets in configuration files&lt;/td&gt;
&lt;td&gt;DefaultAzureCredential (managed identity) is the only compliant choice.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Code Samples (C# using Azure.Identity)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Using &lt;em&gt;DefaultAzureCredential&lt;/em&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Azure.Identity&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Azure.Security.KeyVault.Secrets&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// The credential automatically picks the best source:&lt;/span&gt;
&lt;span class="c1"&gt;// - Azure Managed Identity (production)&lt;/span&gt;
&lt;span class="c1"&gt;// - Azure CLI / Visual Studio credentials (local dev)&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;credential&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;DefaultAzureCredential&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;vaultUrl&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Uri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://my-keyvault.vault.azure.net/"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SecretClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vaultUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;credential&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Retrieve a secret&lt;/span&gt;
&lt;span class="n"&gt;KeyVaultSecret&lt;/span&gt; &lt;span class="n"&gt;secret&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetSecretAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MySecret"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Secret value: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Using Client ID &amp;amp; Client Secret
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Azure.Identity&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Azure.Security.KeyVault.Secrets&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;tenantId&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetEnvironmentVariable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"AZURE_TENANT_ID"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;clientId&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetEnvironmentVariable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"AZURE_CLIENT_ID"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;clientSecret&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetEnvironmentVariable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"AZURE_CLIENT_SECRET"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;credential&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ClientSecretCredential&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tenantId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;clientId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;clientSecret&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;vaultUrl&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Uri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://my-keyvault.vault.azure.net/"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SecretClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vaultUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;credential&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;KeyVaultSecret&lt;/span&gt; &lt;span class="n"&gt;secret&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetSecretAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MySecret"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Secret value: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; In production, store the environment variables securely (e.g., Azure App Service Application Settings or Azure Key Vault references). Never hard‑code secrets.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://learn.microsoft.com/azure/developer/dotnet/azure-sdk-authentication" rel="noopener noreferrer"&gt;Azure SDK authentication overview (Azure Identity)&lt;/a&gt;&lt;br&gt;
&lt;a href="https://learn.microsoft.com/dotnet/api/azure.identity.defaultazurecredential?view=azure-dotnet" rel="noopener noreferrer"&gt;DefaultAzureCredential class documentation&lt;/a&gt;&lt;br&gt;
&lt;a href="https://learn.microsoft.com/dotnet/api/azure.identity.clientsecretcredential?view=azure-dotnet" rel="noopener noreferrer"&gt;ClientSecretCredential class documentation&lt;/a&gt;&lt;br&gt;
&lt;a href="https://learn.microsoft.com/azure/key-vault/general/authentication" rel="noopener noreferrer"&gt;Azure Key Vault authentication guide&lt;/a&gt;&lt;br&gt;
&lt;a href="https://learn.microsoft.com/azure/active-directory/managed-identities-azure-resources/overview" rel="noopener noreferrer"&gt;Managed identities for Azure resources&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;DefaultAzureCredential&lt;/code&gt; is the &lt;strong&gt;recommended standard&lt;/strong&gt; for modern Azure applications. It provides a unified, secure, and low‑maintenance authentication experience that works consistently from local development to production with managed identities. The explicit Client ID &amp;amp; Client Secret approach still has a place for legacy or non‑Azure scenarios, but it introduces secret management overhead and security risk. Adopt &lt;code&gt;DefaultAzureCredential&lt;/code&gt; wherever possible to align with Azure’s best‑practice security model.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>dotnet</category>
      <category>productivity</category>
      <category>vineforce</category>
    </item>
    <item>
      <title>Docusaurus – The Modern Docs Framework</title>
      <dc:creator>Harsh Gupta</dc:creator>
      <pubDate>Sun, 14 Jun 2026 07:20:26 +0000</pubDate>
      <link>https://dev.to/harshgupta71/docusaurus-the-modern-docs-framework-22f4</link>
      <guid>https://dev.to/harshgupta71/docusaurus-the-modern-docs-framework-22f4</guid>
      <description>&lt;h2&gt;
  
  
  1. What is Docusaurus?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://docusaurus.io/" rel="noopener noreferrer"&gt;Docusaurus&lt;/a&gt; is an open‑source static‑site generator focused on documentation. Built and maintained by Meta (formerly Facebook), it lets you create, version, and deploy documentation sites with &lt;strong&gt;zero configuration&lt;/strong&gt; or &lt;strong&gt;full customisation&lt;/strong&gt; using React, Markdown, and MDX.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;What it means&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Static‑site generation&lt;/td&gt;
&lt;td&gt;Pre‑renders pages to plain HTML → fast loads, cheap hosting.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;React‑powered&lt;/td&gt;
&lt;td&gt;Use React components inside your docs (MDX).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Zero‑config defaults&lt;/td&gt;
&lt;td&gt;npm init docusaurus gives you a working site in seconds.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Extensible plugin ecosystem&lt;/td&gt;
&lt;td&gt;Add search, analytics, theme tweaks, etc., without touching core code.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  2. Why Developers &amp;amp; Organizations Should Use It
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Speed to ship&lt;/strong&gt; – A working docs site is ready after &lt;code&gt;npm start&lt;/code&gt;.&lt;br&gt;
&lt;strong&gt;Maintainable codebase&lt;/strong&gt; – Docs live alongside source code, enabling PR‑driven updates.&lt;br&gt;
&lt;strong&gt;Scalable&lt;/strong&gt; – Handles single‑page docs to multi‑version portals with the same build pipeline.&lt;br&gt;
&lt;strong&gt;Community &amp;amp; Vendor backing&lt;/strong&gt; – Backed by Meta, with an active ecosystem of plugins and themes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;: If you already use React or a Node‑based build system, Docusaurus fits naturally and reduces the overhead of maintaining separate documentation tooling.&lt;/p&gt;
&lt;h2&gt;
  
  
  3. Key Features &amp;amp; Benefits
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Benefit&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Built‑in versioning&lt;/td&gt;
&lt;td&gt;Publish docs for each app release; users can switch versions.&lt;/td&gt;
&lt;td&gt;npx docusaurus docs:version 2.3.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Markdown + MDX&lt;/td&gt;
&lt;td&gt;Write prose in Markdown, embed React components when needed.&lt;/td&gt;
&lt;td&gt;See MDX example below.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Search (Algolia, Lunr, etc.)&lt;/td&gt;
&lt;td&gt;Instant full‑text search without external services (optional).&lt;/td&gt;
&lt;td&gt;npm install @docusaurus/theme-search-algolia&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Blog support&lt;/td&gt;
&lt;td&gt;Publish release notes, tutorials, or team updates side‑by‑side with docs.&lt;/td&gt;
&lt;td&gt;npx docusaurus blog:write&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Theming &amp;amp; Customisation&lt;/td&gt;
&lt;td&gt;Override theme files or create a custom React theme.&lt;/td&gt;
&lt;td&gt;npm run swizzle @docusaurus/theme-classic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Plugin ecosystem&lt;/td&gt;
&lt;td&gt;Add sitemap, RSS, Google Analytics, PWA, and more with a single line in docusaurus.config.js.&lt;/td&gt;
&lt;td&gt;plugins: ['@docusaurus/plugin-sitemap']&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CI/CD‑ready&lt;/td&gt;
&lt;td&gt;Generates static assets (/build) – easy to cache on CDNs.&lt;/td&gt;
&lt;td&gt;npm run build &amp;amp;&amp;amp; npx serve ./build&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multi‑platform deployment&lt;/td&gt;
&lt;td&gt;Works on GitHub Pages, Azure Static Web Apps, Cloudflare Pages, Netlify, Vercel, etc.&lt;/td&gt;
&lt;td&gt;gh-pages -d build&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Internationalisation (i18n)&lt;/td&gt;
&lt;td&gt;Create docs in multiple languages with locale‑aware routing.&lt;/td&gt;
&lt;td&gt;i18n: { defaultLocale: 'en', locales: ['en','fr','zh'] }&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h2&gt;
  
  
  4. Simplifying Documentation Management
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Docs live in the repo&lt;/strong&gt; – No separate repository or wiki.&lt;br&gt;
&lt;strong&gt;PR‑driven updates&lt;/strong&gt; – Docs are changed through normal code review flow.&lt;br&gt;
&lt;strong&gt;Automatic linking&lt;/strong&gt; – &lt;code&gt;[@site]&lt;/code&gt; URLs resolve to the site’s base URL, avoiding hard‑coded links.&lt;br&gt;
&lt;strong&gt;Consistent styling&lt;/strong&gt; – A single theme ensures all pages look identical, reducing UI drift.&lt;/p&gt;
&lt;h3&gt;
  
  
  Typical Workflow
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1️⃣ Create a new page&lt;/span&gt;
npx docusaurus docs:create my-new-feature

&lt;span class="c"&gt;# 2️⃣ Write Markdown/MDX (edit docs/my-new-feature.md)&lt;/span&gt;

&lt;span class="c"&gt;# 3️⃣ Run locally&lt;/span&gt;
npm start

&lt;span class="c"&gt;# 4️⃣ Open PR → review → merge&lt;/span&gt;

&lt;span class="c"&gt;# 5️⃣ CI builds &amp;amp; deploys automatically&lt;/span&gt;

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

&lt;/div&gt;

&lt;h2&gt;
  
  
  5. CI/CD &amp;amp; Deployment
&lt;/h2&gt;

&lt;p&gt;Because Docusaurus outputs &lt;strong&gt;static HTML&lt;/strong&gt;, any CI system can treat it like a normal build artifact.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Example GitHub Actions workflow (docusaurus.yml)&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy Docusaurus site&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v3&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup Node&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v3&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;20'&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm ci&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run build&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy to Cloudflare Pages&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cloudflare/pages-action@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;apiToken&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.CF_PAGES_TOKEN }}&lt;/span&gt;
          &lt;span class="na"&gt;projectName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docusaurus-docs&lt;/span&gt;
          &lt;span class="na"&gt;directory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./build&lt;/span&gt;

      &lt;span class="c1"&gt;# Cloudflare Pages offers a generous free tier (up to 500 build minutes per month and unlimited bandwidth), perfect for open‑source docs. No credit‑card is required, and you can preview changes on PRs automatically.&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Replace the &lt;code&gt;cloudflare/pages-action&lt;/code&gt; step with &lt;code&gt;gh-pages&lt;/code&gt;, &lt;code&gt;Azure/static-web-apps-deploy&lt;/code&gt;, or &lt;code&gt;Netlify&lt;/code&gt; steps as needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Versioning Support
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create a new version folder (e.g., v2.0)&lt;/span&gt;
npx docusaurus docs:version 2.0

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

&lt;/div&gt;



&lt;p&gt;Docusaurus copies the current &lt;code&gt;docs/&lt;/code&gt; folder into &lt;code&gt;versioned_docs/version‑2.0/&lt;/code&gt;.&lt;br&gt;
A selector component appears automatically, letting visitors pick the version they need.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best‑Practice Tips&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Version only on major releases&lt;/strong&gt; – Keeps the version list short.&lt;br&gt;
&lt;strong&gt;Maintain a changelog&lt;/strong&gt; – Use the built‑in blog or a dedicated &lt;code&gt;CHANGELOG.md&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  7. Markdown &amp;amp; MDX
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Markdown&lt;/strong&gt; – Perfect for plain text, tables, code fences.&lt;br&gt;
&lt;strong&gt;MDX&lt;/strong&gt; – Allows JSX inside docs, letting you embed live components, charts, or interactive demos.&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="err"&gt;#&lt;/span&gt; &lt;span class="nx"&gt;My&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="nx"&gt;Demo&lt;/span&gt;

&lt;span class="nx"&gt;Here&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;live&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="nx"&gt;chart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;BarChart&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="s1"&gt;@site/src/components/BarChart&lt;/span&gt;&lt;span class="dl"&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="nc"&gt;BarChart&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;chartData&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;When to use MDX?&lt;/strong&gt; When you need dynamic UI (e.g., visualising API responses) or want to reuse existing React components.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Search Functionality
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Algolia DocSearch&lt;/strong&gt; (recommended for large sites) – Free tier for open‑source projects.&lt;br&gt;
&lt;strong&gt;Lunr.js&lt;/strong&gt; – Zero‑config, client‑side index for smaller docs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// docusaurus.config.js – Algolia example&lt;/span&gt;
&lt;span class="nx"&gt;themeConfig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;algolia&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;appId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;YOUR_APP_ID&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;YOUR_SEARCH_ONLY_API_KEY&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;indexName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;your-site&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;contextualSearch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  9. Blog &amp;amp; Documentation Features
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Area&lt;/th&gt;
&lt;th&gt;What Docusaurus Provides&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Blog&lt;/td&gt;
&lt;td&gt;Markdown‑based posts, RSS feed, pagination.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Docs&lt;/td&gt;
&lt;td&gt;Sidebar auto‑generation, version dropdown, edit‑URL links back to source.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pages&lt;/td&gt;
&lt;td&gt;Free‑form React pages (src/pages).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Internationalisation&lt;/td&gt;
&lt;td&gt;Language switcher + per‑locale routes.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  10. Customisation &amp;amp; Plugin Ecosystem
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Theme Swizzling&lt;/strong&gt; – Override any component by copying it into &lt;code&gt;src/theme&lt;/code&gt;.&lt;br&gt;
&lt;strong&gt;Official Plugins&lt;/strong&gt; – &lt;code&gt;@docusaurus/plugin-content-docs&lt;/code&gt;, &lt;code&gt;@docusaurus/plugin-content-blog&lt;/code&gt;, &lt;code&gt;@docusaurus/plugin-google-analytics&lt;/code&gt;, etc.&lt;br&gt;
&lt;strong&gt;Community Plugins&lt;/strong&gt; – &lt;code&gt;docusaurus-plugin-sitemap&lt;/code&gt;, &lt;code&gt;docusaurus-plugin-pwa&lt;/code&gt;, &lt;code&gt;docusaurus-plugin-openapi&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Quick Custom Theme Example
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx docusaurus swizzle @docusaurus/theme-classic Navbar

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

&lt;/div&gt;



&lt;p&gt;Edit &lt;code&gt;src/theme/Navbar/index.js&lt;/code&gt; to add a custom logo or extra navigation items.&lt;/p&gt;

&lt;h2&gt;
  
  
  11. Integration with CI Platforms
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Platform&lt;/th&gt;
&lt;th&gt;Typical Integration&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;GitHub&lt;/td&gt;
&lt;td&gt;Use GitHub Actions to run npm run build → gh-pages deploy.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Azure DevOps&lt;/td&gt;
&lt;td&gt;Add a pipeline step calling npm run build and publish the build/ folder to an Azure Static Web App.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cloudflare Pages&lt;/td&gt;
&lt;td&gt;Push the build/ directory to a Cloudflare Pages project; automatic preview URLs on PRs.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;All integrations rely on the same static artifact (&lt;code&gt;/build&lt;/code&gt;).&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  12. Real‑World Use Cases
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Company&lt;/th&gt;
&lt;th&gt;Use‑case&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Meta&lt;/td&gt;
&lt;td&gt;Internal product documentation for React Native and Jest.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Microsoft&lt;/td&gt;
&lt;td&gt;Docs for VS Code extensions, hosted on GitHub Pages.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Airbnb&lt;/td&gt;
&lt;td&gt;Public API reference &amp;amp; design system docs with versioning.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Open‑Source Projects (e.g., TensorFlow.js, Storybook)&lt;/td&gt;
&lt;td&gt;Community‑maintained docs, searchable, with a blog for release notes.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  13. Comparisons with Traditional Approaches
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Traditional Docs (e.g., MkDocs, Jekyll)&lt;/th&gt;
&lt;th&gt;Docusaurus&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Static‑only (no React)&lt;/td&gt;
&lt;td&gt;React + MDX – interactive demos possible&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Limited versioning&lt;/td&gt;
&lt;td&gt;Built‑in versioning via CLI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Plugin ecosystem&lt;/td&gt;
&lt;td&gt;Rich, officially supported plugins + community&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Zero‑config start&lt;/td&gt;
&lt;td&gt;npm init docusaurus gives a complete site instantly&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TypeScript support&lt;/td&gt;
&lt;td&gt;Full TS in custom components and config&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  14. Best Practices &amp;amp; Recommendations
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Keep docs in the same repo&lt;/strong&gt; as the code they describe.&lt;br&gt;
&lt;strong&gt;Use versioning&lt;/strong&gt; for every public release.&lt;br&gt;
&lt;strong&gt;Leverage MDX&lt;/strong&gt; for component demos; avoid over‑using React in simple prose.&lt;br&gt;
&lt;strong&gt;Enable Algolia DocSearch&lt;/strong&gt; for larger sites (free for OSS).&lt;br&gt;
&lt;strong&gt;Add a “Edit this page” link&lt;/strong&gt; – &lt;code&gt;editUrl&lt;/code&gt; in &lt;code&gt;docusaurus.config.js&lt;/code&gt; encourages community contributions.&lt;br&gt;
&lt;strong&gt;Automate deployment&lt;/strong&gt; in your CI pipeline – a single &lt;code&gt;npm run build &amp;amp;&amp;amp; deploy-step&lt;/code&gt; is enough.&lt;br&gt;
&lt;strong&gt;Monitor bundle size&lt;/strong&gt; – Docusaurus ships a default theme (~200 KB gzipped); prune unused plugins for faster builds.&lt;/p&gt;

&lt;h2&gt;
  
  
  15. References
&lt;/h2&gt;

&lt;p&gt;Official site &amp;amp; docs – &lt;a href="https://docusaurus.io/" rel="noopener noreferrer"&gt;https://docusaurus.io&lt;/a&gt;&lt;br&gt;
GitHub repo – &lt;a href="https://github.com/facebook/docusaurus" rel="noopener noreferrer"&gt;https://github.com/facebook/docusaurus&lt;/a&gt;&lt;br&gt;
Algolia DocSearch – &lt;a href="https://docsearch.algolia.com/" rel="noopener noreferrer"&gt;https://docsearch.algolia.com/&lt;/a&gt;&lt;br&gt;
“Getting Started” tutorial – &lt;a href="https://docusaurus.io/docs/next/installation" rel="noopener noreferrer"&gt;https://docusaurus.io/docs/next/installation&lt;/a&gt;&lt;br&gt;
Blog post on versioning – &lt;a href="https://docusaurus.io/docs/next/versioning" rel="noopener noreferrer"&gt;https://docusaurus.io/docs/next/versioning&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Ready to publish?&lt;/em&gt; Save this file as &lt;code&gt;docusaurus-overview.md&lt;/code&gt; (or any slug you prefer) and run the CLI if you want to regenerate, or edit directly. Let me know if you need any further tweaks.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>dotnet</category>
      <category>productivity</category>
      <category>vineforce</category>
    </item>
    <item>
      <title>How to Add a Module in the ABP.io Application?</title>
      <dc:creator>Harsh Gupta</dc:creator>
      <pubDate>Wed, 23 Jul 2025 09:45:19 +0000</pubDate>
      <link>https://dev.to/harshgupta71/how-to-add-a-module-in-the-abpio-application-1ccf</link>
      <guid>https://dev.to/harshgupta71/how-to-add-a-module-in-the-abpio-application-1ccf</guid>
      <description>&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%2F5qcu3qssxdoa82lznvgj.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%2F5qcu3qssxdoa82lznvgj.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you’re building your application with ABP.io, you’re already on the right path to creating scalable and professional software. One of the best things about ABP.io is how it supports modular architecture. But what does that really mean?&lt;/p&gt;

&lt;p&gt;In simple words, a module in ABP.io is like a complete feature package. It comes with its own logic, database setup, APIs, and even user interface parts. Think of it as a plug-and-play part of your application that keeps your code clean, reusable, and easy to manage.&lt;/p&gt;

&lt;p&gt;ABP.io provides many useful built-in modules like Identity, Tenant Management, and Audit Logging. These help you quickly add common features without writing everything from scratch.&lt;/p&gt;

&lt;p&gt;But sometimes, you need to go beyond the default options. Maybe your project has unique requirements. That’s when creating a custom module becomes important.&lt;/p&gt;

&lt;p&gt;In this guide, I’ll show you how to add a custom module, like Vineforce.ProjectManagement, into your existing ABP.io application. You’ll learn how to do it step by step on both the backend using .NET and the frontend using Angular.&lt;/p&gt;

&lt;p&gt;Whether you’re just starting with ABP.io or already have experience, this blog is made to help you integrate modules smoothly and with confidence.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What You’ll Learn in This Guide&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to prepare your system for module integration&lt;/li&gt;
&lt;li&gt;How to add the module to your ABP.io backend using NuGet&lt;/li&gt;
&lt;li&gt;How to configure the database context and migrations&lt;/li&gt;
&lt;li&gt;How to link the Angular frontend with the module using npm&lt;/li&gt;
&lt;li&gt;Common pitfalls to avoid during integration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Prerequisites &amp;amp; Setup&lt;/strong&gt;&lt;br&gt;
Before you begin, make sure the following tools and environments are set up properly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1.1 Required Software&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;.NET SDK (compatible with your ABP.io version)&lt;/li&gt;
&lt;li&gt;Node.js and npm&lt;/li&gt;
&lt;li&gt;Angular CLI (installed globally)&lt;/li&gt;
&lt;li&gt;ABP CLI (installed via dotnet tool)&lt;/li&gt;
&lt;li&gt;Visual Studio or Rider for .NET&lt;/li&gt;
&lt;li&gt;Git for version control&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;1.2 ABP.io Application Ready&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Ensure you have an existing ABP.io application up and running. The application should be in either &lt;a href="https://www.vineforce.net/project-management-module/" rel="noopener noreferrer"&gt;Modular Monolith&lt;/a&gt; or Microservice architecture.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2: Backend Integration Using NuGet (C# / .NET)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We’ll start by connecting your backend application to the custom module using NuGet packages.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.1 Add Required Packages "Vineforce.Admin.HttpApi.Host"&lt;/strong&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%2F26wu04edqzzq9qwnq3lm.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%2F26wu04edqzzq9qwnq3lm.png" alt=" " width="800" height="450"&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%2Fym16c6awxtlx0j3h9sg3.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%2Fym16c6awxtlx0j3h9sg3.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.nuget.org/packages/Vineforce.ProjectManagement.Application" rel="noopener noreferrer"&gt;Vineforce.ProjectManagement.Application&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.nuget.org/packages/Vineforce.ProjectManagement.HttpApi" rel="noopener noreferrer"&gt;Vineforce.ProjectManagement.HttpApi&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%2Ft7yo3b1zo803rdieijax.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%2Ft7yo3b1zo803rdieijax.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.2 Register Module Dependencies&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open the file AdminHttpApiHostModule.cs&lt;/li&gt;
&lt;li&gt;Add the module dependencies inside the [DependsOn] attribute:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[DependsOn(
    typeof(ProjectManagementHttpApiModule),
    typeof(ProjectManagementApplicationModule),
    typeof(ProjectManagementEntityFrameworkCoreModule),
    typeof(ProjectManagementDomainSharedModule)
)]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fnlj7u6ihqk0g9ifr8ohg.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%2Fnlj7u6ihqk0g9ifr8ohg.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Also, add the using statements at the top:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;using Vineforce.ProjectManagement;
using Vineforce.ProjectManagement.EntityFrameworkCore;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;2.3 Add Required Packages "Vineforce.Admin.EntityFrameworkCore"&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%2Fmhc5lpbb1umn3bar0rcg.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%2Fmhc5lpbb1umn3bar0rcg.png" alt=" " width="800" height="450"&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%2Fqg6kxttaqccqqg65v3tb.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%2Fqg6kxttaqccqqg65v3tb.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Also, add the using statements at the top:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Vineforce.ProjectManagement.EntityFrameworkCore
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2.4 Update Your DbContext&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   1. Open AdminDbContext.cs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fjr0hwwoyvdasz7bu4lqk.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%2Fjr0hwwoyvdasz7bu4lqk.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Inside the OnModelCreating method, add the following:&lt;/li&gt;
&lt;/ol&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%2Fv5b0lbavdpspuj7s19b5.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%2Fv5b0lbavdpspuj7s19b5.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;builder.ConfigureProjectManagement();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This step tells your database context to load and apply table configurations from the ProjectManagement module.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.5 Apply Migrations&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Once you update the DbContext, run EF Core migrations to apply the updated schema to your database.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option A: Using Terminal / PowerShell&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;cd src/Vineforce.Admin.EntityFrameworkCore
dotnet ef migrations add Add_ProjectManagement_Module
dotnet ef database update
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, the new tables from the module will be added to your main database.&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%2Fju3rynolrwl9m8kt5lf4.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%2Fju3rynolrwl9m8kt5lf4.png" alt=" " width="787" height="717"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3: Frontend Integration Using npm (Angular)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Once the backend is configured, let’s integrate the Angular frontend with the module.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.1 Install the Angular Module&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open your Angular project root (usually /angular)&lt;/li&gt;
&lt;li&gt;Run this command in the terminal:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i @vineforce-modules/project-management
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;You can view this link to copy the command: &lt;a href="https://www.npmjs.com/package/@vineforce-modules/project-management" rel="noopener noreferrer"&gt;@vineforce-modules/project-management&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;This will also add the following entry in package.json:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"@vineforce-modules/project-management": "^9.0.0"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fe7ho0pxj1i2ym73ni2zv.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%2Fe7ho0pxj1i2ym73ni2zv.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.2 Update the app-routing.module.ts file&lt;/strong&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%2Ftuk8d2u9kxqhzoxjye18.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%2Ftuk8d2u9kxqhzoxjye18.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  path: 'project-management',
  loadChildren: () =&amp;gt;
    import('@vineforce-modules/project-management').then(m =&amp;gt; m.ProjectManagementModule.forLazy()),
},
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This step makes the ProjectManagement module visible in the frontend UI.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4: Test the Integration&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now that everything is configured, it’s time to test.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4.1 Backend Checklist&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run the application using Visual Studio or dotnet run&lt;/li&gt;
&lt;li&gt;Check if there are any build errors&lt;/li&gt;
&lt;li&gt;Confirm that new database tables were created&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;4.2 Frontend Checklist&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run npm start or ng serve for Angular&lt;/li&gt;
&lt;li&gt;Log in to the app&lt;/li&gt;
&lt;li&gt;Navigate through the new module in the side menu&lt;/li&gt;
&lt;li&gt;Test create/edit/delete operations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Common Issues &amp;amp; Troubleshooting&lt;/strong&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%2Fuvtsr2958972sb7jbggr.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%2Fuvtsr2958972sb7jbggr.png" alt=" " width="800" height="195"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Final Summary&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You have now successfully done it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Added a module to your ABP.io backend&lt;/li&gt;
&lt;li&gt;Linked it with your database and ran migrations&lt;/li&gt;
&lt;li&gt;Integrated the Angular module using npm&lt;/li&gt;
&lt;li&gt;Updated routing and tested the entire module&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This setup allows you to build and scale your application using modular principles without repeating core logic again and again.&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%2Fv5edxx609t9dubpr005q.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%2Fv5edxx609t9dubpr005q.png" alt=" " width="800" height="410"&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%2Fb2u2xko33r92ompj5yny.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%2Fb2u2xko33r92ompj5yny.png" alt=" " width="800" height="416"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;br&gt;
Adding a custom module to your ABP.io application is not just a technical task, it is a smart way to keep your project scalable and organized. By following this step-by-step guide, you have successfully connected your backend using NuGet, updated your database context, applied migrations, and linked the frontend through npm and Angular routing.&lt;/p&gt;

&lt;p&gt;This process helps you avoid repeating code, improves maintainability, and prepares your application for future growth. Whether you are adding one module or planning to build a fully modular system, this method will save time and reduce errors.&lt;/p&gt;

&lt;p&gt;If you face any issues or want expert assistance, the Vineforce team is always ready to help with ABP.io development, custom modules, and performance optimization. You can reach us at &lt;a href="mailto:info@vineforce.net"&gt;info@vineforce.net&lt;/a&gt; for support or consultation.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Guide to Add Custom Modules in ABP.IO App</title>
      <dc:creator>Harsh Gupta</dc:creator>
      <pubDate>Thu, 29 May 2025 06:26:05 +0000</pubDate>
      <link>https://dev.to/vineforce/guide-to-add-custom-modules-in-abpio-app-45m</link>
      <guid>https://dev.to/vineforce/guide-to-add-custom-modules-in-abpio-app-45m</guid>
      <description>&lt;p&gt;If you want to extend your ABP.IO application with a custom module, like Vineforce.Test—this guide is for you. Whether you’re building a new feature or organizing your code into reusable parts, creating a custom module helps keep your application clean, scalable, and maintainable.&lt;/p&gt;

&lt;p&gt;In this guide, we’ll walk through the full integration process step by step, covering both the backend and the Angular frontend. You’ll learn how to properly register the module, configure dependencies, and connect the UI layer to your logic. By the end, you’ll have a working module that’s fully integrated into your ABP.IO solution, following best practices.&lt;/p&gt;

&lt;p&gt;No guesswork, no skipping steps—just a clear path to getting your custom module up and running.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prerequisites&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Install ABP CLI&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If not already installed, run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dotnet tool install -g Volo.Abp.Cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Create the main Apb.io application with the name “Vineforce.Admin”&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;abp new Vineforce.Admin -t app -u angular -m none --separate-auth-server --database-provider ef -csf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2F76akokznkm5t55xjaz14.webp" 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%2F76akokznkm5t55xjaz14.webp" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It creates the structure of backend of main abp application as follows:&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%2Fgjuzej0v7numd1gtgb90.webp" 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%2Fgjuzej0v7numd1gtgb90.webp" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Configure appsettings.json of the main ABP.IO&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Edit the appsettings.json files in the two projects below to include the correct connection strings:&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Vineforce.Admin.HttpApi.Host&lt;/li&gt;
&lt;li&gt;Vineforce.Admin.DbMigrator &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;4. Create the Module folder in main application as Follow the official guide to create your module:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://abp.io/docs/4.3/Startup-Templates/Module" rel="noopener noreferrer"&gt;Official Guide&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%2Framr0dtys396gtf3l4hk.webp" 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%2Framr0dtys396gtf3l4hk.webp" alt="Image description" width="758" height="632"&gt;&lt;/a&gt;&lt;br&gt;
If you choose Angular as the UI framework (by using the -u angular option), the generated solution will include a folder named angular. This folder contains all the client-side code for the application. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; A module named Vineforce.Test was created using the Angular UI option.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. When you open the angular folder in an IDE, the folder structure will appear as follows:&lt;/strong&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%2Fym1f0cdh5miyehbt6jgx.webp" 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%2Fym1f0cdh5miyehbt6jgx.webp" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. And backend structure as follows:&lt;/strong&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%2Fo4ofnexe7942rv9fhqfc.webp" 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%2Fo4ofnexe7942rv9fhqfc.webp" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Configure appsettings.json&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Edit the appsettings.json file in the Host projects to include correct connection strings: &lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Vineforce.Test.AuthServer &lt;/li&gt;
&lt;li&gt;Vineforce.Test.HttpApi.Host &lt;/li&gt;
&lt;li&gt;Vineforce.Test.Web.Unified
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"ConnectionStrings": { "Default": "Server=servername;Database=Test_Main;Trusted_Connection=True;TrustServerCertificate=True", "Test": "Server=VINEFORCE-SHIVA;Database=Test_Module;Trusted_Connection=True;TrustServerCertificate=True" }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Make sure the server names and database details match your development environment.&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%2Fbayhaf6ez7qpuk2y6hgv.webp" 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%2Fbayhaf6ez7qpuk2y6hgv.webp" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Apply Database Update&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;In the Package Manager Console (under the EntityFrameworkCore project), run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Update-Database
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2F9t8kwg5ze4dwi9vhf1cl.webp" 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%2F9t8kwg5ze4dwi9vhf1cl.webp" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Run the Application&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Set Vineforce.Test.Web.Unified as the startup project and launch the application using the default credentials:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Username: admin &lt;/li&gt;
&lt;li&gt;Password: 1q2w3E*&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;6. Ensure Redis Is Running&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Redis is used for distributed caching. Make sure Redis is installed and running before starting the application.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7. Application Startup Order&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Run the following projects in order:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;*.AuthServer or *.IdentityServer
*.HttpApi.Host
*.Web.Unified
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;1. Adding a Module to the Backend of the Main Application&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;cd C:\Users\Vineforce\source\repos\AbpAdmin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Add All Required Projects of the module to the Main ABP.IO Solution&lt;/strong&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%2Fzn4nynus8yf4emkrakms.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%2Fzn4nynus8yf4emkrakms.jpg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To include various parts of your module (such as Domain, Application, EntityFrameworkCore, and HttpApi) in the main ABP solution, run the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dotnet sln add modules\vineforce.test\src\Vineforce.Test.Domain\Vineforce.Test.Domain.csproj
dotnet sln add modules\vineforce.test\src\Vineforce.Test.Application\Vineforce.Test.Application.csproj
dotnet sln add modules\vineforce.test\src\Vineforce.Test.EntityFrameworkCore\Vineforce.Test.EntityFrameworkCore.csproj
dotnet sln add modules\vineforce.test\src\Vineforce.Test.HttpApi\Vineforce.Test.HttpApi.csproj
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Projects are added as 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%2F7fvp3e7mkhrx7g6e2zsj.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%2F7fvp3e7mkhrx7g6e2zsj.jpg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Add Project References Using Visual Studio&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;In the Vineforce.Admin.HttpApi.Host project: Right-click the project and select “Add” → “Project Reference”.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. In the dialog that appears, check the following projects:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Vineforce.Test.Application &lt;/li&gt;
&lt;li&gt;Vineforce.Test.EntityFrameworkCore &lt;/li&gt;
&lt;li&gt;Vineforce.Test.HttpApi &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2. Click OK to confirm and add the references.&lt;/strong&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%2Ftxixiehuq7ut4kyq2lug.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%2Ftxixiehuq7ut4kyq2lug.jpg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. After adding the project &amp;gt; reference, here you can add all module references you want.&lt;/strong&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%2Fmvm6d6ul82p1kco7w8qd.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%2Fmvm6d6ul82p1kco7w8qd.jpg" alt="Image description" width="800" height="450"&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%2Fjxtqgptui8owtg1tuqg0.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%2Fjxtqgptui8owtg1tuqg0.jpg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Register Module Dependencies in AdminHttpApiHostModule.cs&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;In AdminHttpApiHostModule.cs, update the [DependsOn(...)] attribute:.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2F7jghsfgavvqc33im31kr.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%2F7jghsfgavvqc33im31kr.jpg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;typeof(TestHttpApiModule),
typeof(TestApplicationModule),
typeof(TestEntityFrameworkCoreModule),
typeof(TestDomainSharedModule)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also, add the necessary using statements:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;using Vineforce.Test;
using Vineforce.Test.EntityFrameworkCore;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fuf7nlc37crunyjipzuqm.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%2Fuf7nlc37crunyjipzuqm.jpg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Configure the Module in the EntityFrameworkCore Project&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;To ensure that schema, table mappings, and other Entity Framework configurations from the module are applied in the main ABP.IO application, follow these steps:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Add a Project Reference:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Right-click on the Vineforce.Admin.EntityFrameworkCore project. &lt;br&gt;
Select &lt;strong&gt;Add → Project Reference.&lt;/strong&gt; &lt;br&gt;
Check and add: Vineforce.Test.EntityFrameworkCore &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%2F67a5q3brh3cvhlxz41i1.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%2F67a5q3brh3cvhlxz41i1.jpg" alt="Image description" width="800" height="450"&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%2F40ebdqipjw64pcldrota.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%2F40ebdqipjw64pcldrota.jpg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update the DbContext Configuration&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open AdminDbContext.cs.&lt;/li&gt;
&lt;li&gt;Inside the OnModelCreating method, add the following line to apply the module’s configuration:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;builder.ConfigureTest();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fvzf1yd0fe8pl9dnvevay.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%2Fvzf1yd0fe8pl9dnvevay.jpg" alt="Image description" width="800" height="450"&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%2Fnlg3nz8siqq6zax9phsd.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%2Fnlg3nz8siqq6zax9phsd.jpg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can verify this by navigating to the Vineforce.Test.EntityFrameworkCore module and opening the TestDbContext class. &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%2F1zsyd4q0f0h9kre2psdr.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%2F1zsyd4q0f0h9kre2psdr.jpg" alt="Image description" width="800" height="450"&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%2F1txkc18xde517n8k112j.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%2F1txkc18xde517n8k112j.jpg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Apply Migrations to Update the Database Schema&lt;/strong&gt;  &lt;/p&gt;

&lt;p&gt;After completing the integration steps, you need to apply Entity Framework migrations to reflect the module’s schema changes in the database.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option 1: Using PowerShell or Terminal&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open a &lt;strong&gt;PowerShell&lt;/strong&gt; or &lt;strong&gt;terminal&lt;/strong&gt; window. &lt;/li&gt;
&lt;li&gt;Navigate to the EntityFrameworkCore project directory of your main application, for example:cd src/Vineforce.Admin.EntityFrameworkCore&lt;/li&gt;
&lt;li&gt;Run the following command to create a new migration:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dotnet ef migrations add Add_Test_Module
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Option 2: Using the Package Manager Console in Visual Studio&lt;/strong&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open the &lt;strong&gt;Package Manager Console&lt;/strong&gt; (Tools → NuGet Package Manager → Package Manager Console). &lt;/li&gt;
&lt;li&gt;Set the &lt;strong&gt;Default Project&lt;/strong&gt; to src\Vineforce.Admin.EntityFrameworkCore. &lt;/li&gt;
&lt;li&gt;Run the following command:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PM&amp;gt; Add-Migration Add_Test_Module
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This will generate a new migration that includes all Entity Framework changes from the integrated module.&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%2Fyakw4yzy41d9brhejlne.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%2Fyakw4yzy41d9brhejlne.jpg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then run the following command to apply the migration and update the database:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Update-Database
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Steps to add the module application to the main ABP.IO application&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Build the Angular Module&lt;/strong&gt;  &lt;/p&gt;

&lt;p&gt;Navigate to the module’s frontend directory and build the module using the Angular CLI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng build test --configuration production
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command compiles the test Angular module in production mode and outputs the build artifacts to the dist folder. &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%2Fdvsfav87lli2kgowsbu3.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%2Fdvsfav87lli2kgowsbu3.jpg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Output folder: &lt;br&gt;
C:\Users\Vineforce\source\repos\AbpAdmin\modules\Vineforce.Test\angular\dist &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%2Famqyi3ef0kgd1qwfeekq.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%2Famqyi3ef0kgd1qwfeekq.jpg" alt="Image description" width="768" height="104"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2: Copy Module Output to Main App&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go to your main app’s angular folder: C:\Users\Vineforce\source\repos\AbpAdmin\angular&lt;/li&gt;
&lt;li&gt;Create a projects folder inside it. &lt;/li&gt;
&lt;li&gt;Copy the test folder from the dist directory into projects.&lt;/li&gt;
&lt;li&gt;Final pathC:\Users\Vineforce\source\repos\AbpAdmin\angular\projects\test&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%2Ffbzyginn7g7ht65zza6n.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%2Ffbzyginn7g7ht65zza6n.jpg" alt="Image description" width="768" height="777"&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%2Fyhjumw4koqz9z22bbd7j.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%2Fyhjumw4koqz9z22bbd7j.png" alt="Image description" width="768" height="144"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3: Update App Routing&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;Open app-routing.module.ts in the main app: &lt;/p&gt;

&lt;p&gt;C:\Users\Vineforce\source\repos\AbpAdmin\angular\src\app\app-routing.module.ts &lt;/p&gt;

&lt;p&gt;In app-routing.module.ts, import the module’s routing configuration and add it to the main route definitions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  path: 'test',
  loadChildren: () =&amp;gt;
    import('test').then(m =&amp;gt; m.TestModule.forLazy())
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 4: Link the Module in package.json&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;Open the package.json file having path C:\Users\Vineforce\source\repos\AbpAdmin\angular  add the following line under the “dependencies” section to link your local module:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"test": "file:projects/test"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fv2n54lo306bdinpq1bbo.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%2Fv2n54lo306bdinpq1bbo.jpg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then install dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can now see the Test Module API controller in the Swagger UI of the main application.&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%2Fpj7uwm1vituv247ychk7.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%2Fpj7uwm1vituv247ychk7.jpg" alt="Image description" width="800" height="428"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can now log in to the main application &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%2Fn2u3pg480lr6fiztongs.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%2Fn2u3pg480lr6fiztongs.png" alt="Image description" width="800" height="398"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Test module now appears in the main application. You can add, edit, or delete items according to the assigned permissions. &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%2F4fq2v2v39ei9yg2qfwyc.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%2F4fq2v2v39ei9yg2qfwyc.png" alt="Image description" width="800" height="169"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Country ‘Russia’ has been added. You can view, edit, or delete it on the page&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%2Fxfdecanqzema7nyzh7qd.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%2Fxfdecanqzema7nyzh7qd.png" alt="Image description" width="800" height="160"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can grant or revoke permission by this following page &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%2Fxej6gt39xgqm0xy91u39.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%2Fxej6gt39xgqm0xy91u39.png" alt="Image description" width="800" height="195"&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%2Faruxrz6hdoigfy5gjugf.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%2Faruxrz6hdoigfy5gjugf.png" alt="Image description" width="800" height="236"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now Edit permission has been disabled for the current user/page.&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%2Frsi3zlhd0lgrut7rz94x.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%2Frsi3zlhd0lgrut7rz94x.png" alt="Image description" width="800" height="544"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Currently, the delete option is visible, but the edit option is not showing on the pagepermission has been disabled for the current user/page.&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%2Fkbkeyk699j0cqa2n4r2k.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%2Fkbkeyk699j0cqa2n4r2k.png" alt="Image description" width="800" height="202"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By following this step-by-step guide, you’ve learned how to successfully integrate a custom module—like Vineforce.Test—into your ABP.IO application. From backend setup to Angular frontend integration, you now have a solid foundation for building scalable, maintainable, and modular applications. With best practices in place, your ABP.IO projects are ready to grow more efficiently.&lt;/p&gt;

&lt;p&gt;If you're looking for expert help with ABP.IO SaaS development, feel free to reach out to &lt;a href="https://www.vineforce.net/contact-us/" rel="noopener noreferrer"&gt;Vineforce&lt;/a&gt;. For more tutorials and insights like this, be sure to explore the &lt;a href="https://blog.vineforce.net/" rel="noopener noreferrer"&gt;Vineforce Blog&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>abp</category>
      <category>vineforce</category>
      <category>angular</category>
      <category>netcore</category>
    </item>
  </channel>
</rss>
