<?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: Vu xfi</title>
    <description>The latest articles on DEV Community by Vu xfi (@vuxfi).</description>
    <link>https://dev.to/vuxfi</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%2F1271340%2Ff170a9fc-d112-42a4-8082-2d3e46f96a9a.png</url>
      <title>DEV Community: Vu xfi</title>
      <link>https://dev.to/vuxfi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/vuxfi"/>
    <language>en</language>
    <item>
      <title>RestoApp: Why We Built an Open-Source Food Delivery Platform</title>
      <dc:creator>Vu xfi</dc:creator>
      <pubDate>Sat, 09 Aug 2025 08:35:30 +0000</pubDate>
      <link>https://dev.to/restoapp/restoapp-why-we-built-an-open-source-food-delivery-platform-2nb8</link>
      <guid>https://dev.to/restoapp/restoapp-why-we-built-an-open-source-food-delivery-platform-2nb8</guid>
      <description>&lt;h2&gt;
  
  
  From WordPress to Node.js
&lt;/h2&gt;

&lt;p&gt;When we first started building food delivery websites, we relied on tried-and-true tools — &lt;strong&gt;WordPress&lt;/strong&gt; and &lt;strong&gt;WooCommerce&lt;/strong&gt;.&lt;br&gt;
For one of our clients, we launched a fully functional delivery site on this stack, and at first glance, it worked. But under the hood, it was almost entirely rewritten: too many modifications, a messy structure, and major maintenance headaches.&lt;/p&gt;

&lt;p&gt;Technologies like &lt;strong&gt;PHP&lt;/strong&gt; were no longer inspiring — we wanted something modern, modular, and flexible. That’s when we decided to switch to &lt;strong&gt;Node.js&lt;/strong&gt; to create solutions that meet today’s web development standards.&lt;/p&gt;

&lt;p&gt;At the time, we chose &lt;strong&gt;Sails.js&lt;/strong&gt; as the framework — it was simple and easy to understand, allowing us to quickly build an MVP. Yes, it’s aging now and we’re considering migrating to a newer stack, but back then it was the optimal choice.&lt;/p&gt;


&lt;h2&gt;
  
  
  Why Food Delivery is Not Just E-commerce
&lt;/h2&gt;

&lt;p&gt;Food delivery is not just an “online store with a cart.” It works differently:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The website often serves as an &lt;strong&gt;external storefront&lt;/strong&gt;, while business processes and logistics live inside &lt;strong&gt;ERP systems&lt;/strong&gt; (iiko, r-Keeper, Poster, Loyverse, or any other).&lt;/li&gt;
&lt;li&gt;For an enterprise-grade solution, &lt;strong&gt;synchronization&lt;/strong&gt; with these systems is critical — but the site must also work &lt;strong&gt;autonomously&lt;/strong&gt;, without external dependencies.&lt;/li&gt;
&lt;li&gt;Unlike retail, speed is critical: real-time order processing, live menu updates, delivery zones, and instant delivery cost calculation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Our goal was to create a &lt;strong&gt;standalone, enterprise-level delivery site&lt;/strong&gt; that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Works equally well for a small café or a nationwide chain.&lt;/li&gt;
&lt;li&gt;Can easily integrate with &lt;strong&gt;any ERP&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Functions as a fully autonomous system, processing orders without third-party services.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  Why We Chose Open Source
&lt;/h2&gt;

&lt;p&gt;Today, our clients range from single restaurants to large chains and franchises. We’ve learned that traditional subscription or “percentage of sales” models often don’t work:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For large companies, they create unpredictable costs and vendor lock-in.&lt;/li&gt;
&lt;li&gt;Medium-sized businesses often seek &lt;strong&gt;lifetime licenses&lt;/strong&gt; for closed products.&lt;/li&gt;
&lt;li&gt;For long-term flexibility, &lt;strong&gt;Open Source&lt;/strong&gt; is increasingly the preferred choice.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We went fully &lt;strong&gt;open-source&lt;/strong&gt; for several reasons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Transparency&lt;/strong&gt; — anyone can review the code, check the architecture, and ensure its reliability.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flexibility&lt;/strong&gt; — integrate with any service or make custom changes without waiting for vendor updates.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Community&lt;/strong&gt; — build a network of developers and business owners around the platform.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalability&lt;/strong&gt; — use RestoApp not only for delivery websites but also to create aggregator-level platforms.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For us, Open Source is not just a philosophy. It’s a strategic decision that gives businesses &lt;strong&gt;control and independence&lt;/strong&gt;, while letting us grow the platform together with the community.&lt;/p&gt;


&lt;h2&gt;
  
  
  Technology Stack
&lt;/h2&gt;

&lt;p&gt;RestoApp is built on modern, high-performance tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Node.js&lt;/strong&gt; — fast, scalable server-side runtime.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sails.js&lt;/strong&gt; — straightforward, easy-to-learn framework for APIs and business logic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PostgreSQL&lt;/strong&gt; — reliable relational database.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docker&lt;/strong&gt; — deploy in minutes anywhere: locally, on a server, or in the cloud.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  Installing RestoApp
&lt;/h2&gt;

&lt;p&gt;We’ve made installation as simple as possible.&lt;/p&gt;
&lt;h3&gt;
  
  
  Quick Start
&lt;/h3&gt;

&lt;p&gt;Run RestoApp in Docker with one command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--name&lt;/span&gt; restoapp &lt;span class="nt"&gt;-p&lt;/span&gt; 8080:8080 webresto/restoapp:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the container starts, open your browser and go to:&lt;br&gt;
&lt;a href="http://localhost:8080" rel="noopener noreferrer"&gt;http://localhost:8080&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What’s Next
&lt;/h2&gt;

&lt;p&gt;RestoApp is already ready to use as a complete food delivery solution, but we’re moving forward:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Integration support for &lt;strong&gt;any ERP&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Extended modules for loyalty programs and promotions&lt;/li&gt;
&lt;li&gt;Capability to run delivery aggregators on top of the platform&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the next article, we’ll show you how to connect a restaurant management system and automate menu updates.&lt;/p&gt;




&lt;h2&gt;
  
  
  RestoApp Links
&lt;/h2&gt;

&lt;p&gt;🌐 &lt;a href="https://restoapp.org" rel="noopener noreferrer"&gt;RestoApp.org&lt;/a&gt;&lt;br&gt;
🐦 &lt;a href="https://twitter.com/restoapp_info" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; | 💬 &lt;a href="https://t.me/restoapp_community" rel="noopener noreferrer"&gt;Telegram&lt;/a&gt; | 🇷🇺 &lt;a href="https://vk.com/wall-229576548" rel="noopener noreferrer"&gt;VKontakte&lt;/a&gt; | 🎮 &lt;a href="https://discord.gg/mbT4AeBJZ6" rel="noopener noreferrer"&gt;Discord&lt;/a&gt; | ▶ &lt;a href="https://www.youtube.com/@restoapp_org" rel="noopener noreferrer"&gt;YouTube&lt;/a&gt;&lt;br&gt;
📘 &lt;a href="https://www.facebook.com/554037384466444" rel="noopener noreferrer"&gt;Facebook&lt;/a&gt; | 📷 &lt;a href="https://www.instagram.com/restoapp_org" rel="noopener noreferrer"&gt;Instagram&lt;/a&gt; | 🧵 &lt;a href="https://www.threads.net/@restoapp_org" rel="noopener noreferrer"&gt;Threads&lt;/a&gt; | 🌐 &lt;a href="https://bsky.app/profile/restoapp.bsky.social" rel="noopener noreferrer"&gt;BlueSky&lt;/a&gt; | 🎵 &lt;a href="https://www.tiktok.com/@restoapp_org" rel="noopener noreferrer"&gt;TikTok&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to Build a Realtime-Extensible Node.js SPA adminpanel</title>
      <dc:creator>Vu xfi</dc:creator>
      <pubDate>Thu, 19 Jun 2025 11:32:46 +0000</pubDate>
      <link>https://dev.to/adminizer/how-to-build-a-realtime-extensible-nodejs-spa-adminpanel-4c2b</link>
      <guid>https://dev.to/adminizer/how-to-build-a-realtime-extensible-nodejs-spa-adminpanel-4c2b</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;A quick look at our journey from classic templating engines to a dynamically extensible UI with Inertia.js.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Over the past five years, we’ve been searching for a convenient way to build the interface for our admin panel—something easy to update, expand, and scale. We started with &lt;strong&gt;Jade&lt;/strong&gt;, then moved to &lt;strong&gt;EJS&lt;/strong&gt;. Everything seemed fine. Later, we began removing &lt;strong&gt;jQuery&lt;/strong&gt; from the project and switched to &lt;strong&gt;Vue&lt;/strong&gt;. Vue had many strengths, but it turned out to be suboptimal for extensibility and scalability: each new component had to be bundled, and support for third-party libraries was often lacking.&lt;/p&gt;

&lt;p&gt;For our admin framework (&lt;a href="https://github.com/adminization/adminizer" rel="noopener noreferrer"&gt;Adminizer&lt;/a&gt;), one key requirement is extensibility &lt;strong&gt;without restarting the Node.js process&lt;/strong&gt;—in other words, &lt;strong&gt;realtime extensibility&lt;/strong&gt;. We need to allow developers to create custom controls for model fields via an internal API. Although Adminizer provides all the essential UI controls out of the box, sometimes more is needed.&lt;/p&gt;

&lt;p&gt;For example, in earlier versions of the admin panel, you could inject any component (e.g., &lt;code&gt;JsonEditor&lt;/code&gt;) using a &lt;code&gt;&amp;lt;head&amp;gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag and mount it via EJS to any database field requiring it. But how can we replicate this behavior in a &lt;strong&gt;SPA&lt;/strong&gt;—&lt;strong&gt;without rebuilding or restarting&lt;/strong&gt;?&lt;/p&gt;

&lt;h2&gt;
  
  
  How We Came to the Idea of Dynamic Bundling
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Why we abandoned full rebundling and turned to dynamic component loading.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;One of our developers raised a fundamental question: why bundle everything upfront? A SPA doesn’t need everything in one file, and modern tooling allows for dynamic component loading. So why not load the components we need—on demand, as independent modules?&lt;/p&gt;

&lt;p&gt;That idea clicked. We envisioned an admin panel where each module is a separate UI component that gets injected into the system on the fly, without any recompilation—just via HTTP requests.&lt;/p&gt;

&lt;p&gt;This led us to the concept of a &lt;em&gt;modular SPA&lt;/em&gt;, and the technology that enabled it was &lt;strong&gt;Inertia.js&lt;/strong&gt;. While this approach is widely used in Laravel/PHP, we had to make some adjustments for it to work well with our Node.js-based framework.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Inertia.js Was the Perfect Fit
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Explaining how Inertia.js stands out from other frameworks.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Inertia is designed to work with components. When it needs to render a page, it gets the component name from the server response and uses a &lt;strong&gt;manifest&lt;/strong&gt; to locate the appropriate file. All we had to do was write a wrapper component that dynamically imports the path passed through props.&lt;/p&gt;

&lt;p&gt;Inertia acts as a &lt;strong&gt;bridge&lt;/strong&gt; between the server and the SPA: on the backend, we specify which component to render, and Inertia takes care of loading and displaying it. The best part? That component doesn’t even need to exist at boot time—it can be created later and used immediately, without any need to rebuild the frontend.&lt;/p&gt;

&lt;p&gt;The result? We can display anything we want on the page. Since React is globally available via the window context, the entire admin system becomes controllable as a live SPA. In theory, it could even be wrapped in Cordova to deliver a mobile app version (though we haven’t tested this yet—that’s for another article).&lt;/p&gt;

&lt;h2&gt;
  
  
  How the New Admin Architecture Works
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Describing the practical implementation of dynamic extensibility.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Our new admin panel behaves like a modular SPA framework. &lt;code&gt;Vite&lt;/code&gt; loads &lt;code&gt;React&lt;/code&gt; globally via &lt;code&gt;window&lt;/code&gt;. When initializing a controller, we specify which component to load and from where—and if it exists, it gets rendered immediately. Most components live in individual modules, often inside &lt;code&gt;node_modules&lt;/code&gt;, and they require no rebundling.&lt;/p&gt;

&lt;p&gt;Inertia handles routing and delivery. It “understands” what needs to be rendered, even for routes we didn’t explicitly configure. It parses HTML and embedded JSON metadata, loads only what’s necessary, and even keeps a request log for caching and rollback.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Matters: Real-World Use Cases
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Why we needed this flexibility—and what it enables.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Modules can now not only extend the UI but also inject custom fields, interactive controls, or even entire standalone pages. For example, if a module needs a special editing interface, it simply defines it—and it just works. All of this happens &lt;strong&gt;without touching the main admin codebase&lt;/strong&gt; and &lt;strong&gt;without triggering a rebuild&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;We believe this architecture is close to ideal for an admin panel, where modularity and flexibility are critical.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion: Where We Are Now
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;What’s done and what comes next.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;We now have a fully working &lt;strong&gt;version 4&lt;/strong&gt; of our admin panel, built with this modular Inertia.js approach. It’s already running in production. We’re currently polishing the last parts and preparing documentation to share this solution with the community.&lt;/p&gt;

&lt;p&gt;Hopefully, it’ll help others looking to build a flexible, scalable, and truly extensible admin panel—&lt;strong&gt;without the pain of constant rebuilds or server restarts&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Source code: &lt;a href="https://github.com/adminization/adminizer" rel="noopener noreferrer"&gt;https://github.com/adminization/adminizer&lt;/a&gt;&lt;/p&gt;

</description>
      <category>node</category>
      <category>inertia</category>
      <category>adminpanel</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
