<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Dsqrwym</title><description>Full-Stack Software Engineer</description><link>https://dsqrwym.es/</link><language>en</language><item><title>Building MaiAn: A Production B2B Multiplatform Commerce System</title><link>https://dsqrwym.es/posts/maian-b2b-platform/</link><guid isPermaLink="true">https://dsqrwym.es/posts/maian-b2b-platform/</guid><description>An architectural deep-dive into MaiAn — an open-source B2B commerce platform connecting wholesale distributors and retailers, built with Kotlin Multiplatform, Compose, and a NestJS/Fastify backend.</description><pubDate>Sun, 15 Nov 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;1. Project Overview &amp;amp; Motivation&lt;/h2&gt;
&lt;p&gt;In traditional wholesale distribution, transactions between suppliers (&lt;strong&gt;Wholesalers&lt;/strong&gt;) and retail shop owners (&lt;strong&gt;Retailers&lt;/strong&gt;) often depend on manual, fragmented processes: outdated printed or PDF catalogues, phone orders, messaging chat threads, manual stock reconciliation, and error-prone invoicing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;MaiAn&lt;/strong&gt; was built to solve this challenge through a unified digital platform. Conceived and delivered as my graduation capstone project (&lt;em&gt;Memoria del Proyecto Final de DAM&lt;/em&gt;) and continuously evolved as an open-source initiative, MaiAn connects wholesale distributors with retail merchants through dedicated client applications and a centralized, high-throughput cloud API.&lt;/p&gt;
&lt;p&gt;The system is deployed and running in production on a self-managed Linux environment with automated containerization.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;2. Live Demos &amp;amp; Credentials&lt;/h2&gt;
&lt;p&gt;You can test both client web portals directly in your browser:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Client Portal&lt;/th&gt;
&lt;th&gt;Demo Link&lt;/th&gt;
&lt;th&gt;Test Account&lt;/th&gt;
&lt;th&gt;Password&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Retailer (Standard)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://maian.dsqrwym.es/standard/&quot;&gt;Open Retailer Demo&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;standard@maian.com&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Standard123&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Wholesaler (Enterprise)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://maian.dsqrwym.es/enterprise/&quot;&gt;Open Wholesaler Demo&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;enterprise@maian.com&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Enterprise123&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;📦 &lt;strong&gt;GitHub Repository&lt;/strong&gt;: &lt;a href=&quot;https://github.com/dsqrwym/Maian&quot;&gt;github.com/dsqrwym/Maian&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;3. High-Level Architecture&lt;/h2&gt;
&lt;p&gt;MaiAn was engineered around a clean separation of concerns:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;┌────────────────────────────────────────────────────────────────────────┐
│                      Kotlin Multiplatform Monorepo                     │
│          Shared Core  ·  Retailer Client  ·  Wholesaler Client         │
│               (Android Native  ·  Desktop JVM  ·  Web Wasm)            │
└───────────────────────────────────┬────────────────────────────────────┘
                                    │ Ktor HTTP Client / REST APIs
┌───────────────────────────────────▼────────────────────────────────────┐
│                    Cloud Backend (NestJS v11 + Fastify)                │
│    Modular Domain APIs  │  CASL Permissions  │  Drizzle ORM Persistence│
└───────────────────┬────────────────────────────────┬───────────────────┘
                    ▼                                ▼
       PostgreSQL 17 Relational DB        Dual Redis (Cache + BullMQ)
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Client Layer&lt;/strong&gt;: Written in &lt;strong&gt;Kotlin 2.3+&lt;/strong&gt; and &lt;strong&gt;Compose Multiplatform 1.11+&lt;/strong&gt;, compiling natively to &lt;strong&gt;Android&lt;/strong&gt;, &lt;strong&gt;Desktop (JVM)&lt;/strong&gt;, and &lt;strong&gt;Web (Wasm)&lt;/strong&gt; from a unified codebase.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Backend Tier&lt;/strong&gt;: Powered by &lt;strong&gt;NestJS 11&lt;/strong&gt; using the &lt;strong&gt;Fastify&lt;/strong&gt; engine rather than Express for superior I/O throughput and lower latency.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Database &amp;amp; Caching&lt;/strong&gt;: &lt;strong&gt;PostgreSQL 17&lt;/strong&gt; with &lt;strong&gt;Drizzle ORM&lt;/strong&gt; for compile-time type-safe relational queries, combined with &lt;strong&gt;dual Redis instances&lt;/strong&gt; (one for sessions and caching, one for BullMQ asynchronous task queues).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Zero-Trust Infrastructure&lt;/strong&gt;: Containerized with &lt;strong&gt;Docker Compose&lt;/strong&gt; on Linux, securely exposed via &lt;strong&gt;Cloudflare Tunnel&lt;/strong&gt; with automated TLS and zero open host ports.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;4. Retailer Experience: Frictionless Procurement&lt;/h2&gt;
&lt;p&gt;The retailer module is designed for quick catalogue exploration, supplier-specific shopping, and automated order splitting.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./retailer-catalog-mobile.png&quot; alt=&quot;Global Product Catalog (Mobile)&quot; /&gt;
&lt;em&gt;Fig 1. Retailer mobile catalogue with instant search, category filters, and product status indicators.&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;Automatic Multi-Wholesaler Cart Splitting&lt;/h3&gt;
&lt;p&gt;In B2B commerce, retailers frequently purchase goods from different distributors in a single session. MaiAn solves this with an &lt;strong&gt;automatic split-cart engine&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;When products from multiple wholesalers are added, the cart automatically groups items by distributor.&lt;/li&gt;
&lt;li&gt;Subtotals, minimum order quantities (MOQ), and commercial tax rates are calculated independently per supplier.&lt;/li&gt;
&lt;li&gt;Checkout atomically generates individual purchase orders for each distributor.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;./retailer-cart-grouped.png&quot; alt=&quot;Grouped Cart by Wholesaler&quot; /&gt;
&lt;em&gt;Fig 2. Cart automatically grouping items by wholesaler, with independent sub-order totals.&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;Order Tracking &amp;amp; Document Generation&lt;/h3&gt;
&lt;p&gt;Retailers can monitor order lifecycles in real time (Confirmed → In Preparation → Shipped → Delivered) and download automated business PDF invoices on demand.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./retailer-order-tracking.png&quot; alt=&quot;Order Tracking and PDF Generation&quot; /&gt;
&lt;em&gt;Fig 3. Real-time order status tracking with cancellation options and automated PDF invoice download.&lt;/em&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;5. Wholesaler Operations: The Backoffice Cockpit&lt;/h2&gt;
&lt;p&gt;Wholesale distributors have access to a comprehensive backoffice cockpit for inventory management, variant pricing, and order fulfillment.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./enterprise-dashboard.png&quot; alt=&quot;Wholesaler Dashboard&quot; /&gt;
&lt;em&gt;Fig 4. Operational dashboard displaying order fulfillment rates, revenue trends via Vico charts, and top-selling SKUs.&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;Product Variant Matrices &amp;amp; Stock Control&lt;/h3&gt;
&lt;p&gt;Wholesale goods require complex variant configurations (sizes, package units, minimum order tiers). Wholesalers can configure multi-attribute pricing matrices, stock thresholds, and tax codes directly.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./enterprise-product-variants.png&quot; alt=&quot;Product Variants and Pricing Matrix&quot; /&gt;
&lt;em&gt;Fig 5. Variant matrix editor for configuring per-size wholesale pricing and stock levels.&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;Order Pipeline &amp;amp; Rejection Handling&lt;/h3&gt;
&lt;p&gt;Incoming orders follow an explicit state machine. If an order cannot be fulfilled due to inventory or logistical constraints, rejections require a mandatory written justification communicated to the buyer.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./enterprise-order-management.png&quot; alt=&quot;Incoming Order Management&quot; /&gt;
&lt;em&gt;Fig 6. Incoming order pipeline with filtering by commercial status and date.&lt;/em&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;6. Security, Multi-Tenancy &amp;amp; Access Control&lt;/h2&gt;
&lt;p&gt;B2B platforms require strict data segregation between competing distributors and privacy across independent retail buyers.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Role-Based Authentication&lt;/strong&gt;: Separate authentication gateways for Retailers, Wholesalers, and Internal Employees (warehouse, delivery, support).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Refresh Token Rotation&lt;/strong&gt;: Web client sessions use &lt;code&gt;httpOnly&lt;/code&gt; secure cookies with token rotation on each refresh to prevent session hijacking.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Declarative CASL Rules&lt;/strong&gt;: Every controller route evaluates granular ability rules before querying data (e.g. &lt;code&gt;can(&apos;manage&apos;, &apos;Product&apos;, { wholesalerId: user.companyId })&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Isolated Client Binaries&lt;/strong&gt;: Frontends for retailers and wholesalers are packaged with independent navigation graphs, preventing cross-app token reuse.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;7. Design Engineering &amp;amp; Accessibility&lt;/h2&gt;
&lt;p&gt;Following Material Design 3 guidelines, MaiAn delivers responsive adaptations across desktop, tablet, and mobile viewports, including full Dark Mode support and dynamic font scaling.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./app-dark-mode.png&quot; alt=&quot;Catalog in Dark Mode&quot; /&gt;
&lt;em&gt;Fig 7. Complete dark theme adaptation adhering to Material Design contrast standards.&lt;/em&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;8. Cloud Infrastructure &amp;amp; Zero-Trust Deployment&lt;/h2&gt;
&lt;p&gt;The backend and database run entirely within an isolated Docker bridge network on an unexposed Linux VPS:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./ops-swagger.png&quot; alt=&quot;OpenAPI / Swagger Documentation&quot; /&gt;
&lt;em&gt;Fig 8. Interactive OpenAPI / Swagger interface for backend endpoint discovery and testing.&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;No Inbound Open Ports&lt;/strong&gt;: The host firewall blocks all incoming HTTP/HTTPS ports. The &lt;code&gt;cloudflared&lt;/code&gt; daemon creates outbound encrypted tunnels to Cloudflare edge nodes, providing DDoS protection and automated TLS certificate rotation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dual Redis Topology&lt;/strong&gt;: Redis 1 handles volatile session storage and API rate limiting; Redis 2 is dedicated to BullMQ persistent background queues (email alerts for low stock and order status changes).&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;9. Key Takeaways &amp;amp; Lessons Learned&lt;/h2&gt;
&lt;p&gt;Building MaiAn as a solo full-stack project provided invaluable practical lessons:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Kotlin Multiplatform Delivers Real Productivity&lt;/strong&gt;: Sharing 100% of data models, network logic (Ktor), and DI (Koin) between Desktop and Android eliminated cross-platform logic discrepancies.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fastify and Drizzle ORM Provide Clean Performance&lt;/strong&gt;: Pairing NestJS with Fastify and Drizzle resulted in a lightweight backend with zero ORM runtime bloat and compile-time SQL safety.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Production Deployment Forces Better Architecture&lt;/strong&gt;: Setting up Docker, Cloudflare Tunnel, database migrations, and automated PDF engines taught me far more than any local sandbox project could.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Feel free to explore the live application at &lt;a href=&quot;https://maian.dsqrwym.es/&quot;&gt;maian.dsqrwym.es&lt;/a&gt; or review the source code on &lt;a href=&quot;https://github.com/dsqrwym/Maian&quot;&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
</content:encoded></item></channel></rss>