Skip to Content
Getting StartedArchitecture

Architecture

This page describes the system architecture of the Siyahfy platform, including how requests flow through the system, how the backend is organized, and how key subsystems like authentication and file storage work.

System Design

The platform follows a client-server architecture with multiple Next.js frontend applications communicating with a single Express.js backend API. A separate proxy server handles storefront routing for customer-facing stores.

Frontend Apps

All frontend apps communicate with the backend via REST API calls with JWT authentication.

AppURLPortPurpose
Vendor Dashboardapp.siyahfy.com3000Store management, products, orders, analytics
Theme Editoreditor.siyahfy.com3002Visual drag-and-drop theme customization
Developer Studiostudio.siyahfy.com3012IDE for theme developers
Developer Portaldeveloper.siyahfy.com3000App developer dashboard
App Storestore.siyahfy.com3000App marketplace for store owners
Marketing Sitesiyahfy.com3000Landing pages, pricing

Backend & Infrastructure

Storefront Proxy

Customer-facing stores go through the proxy layer:

External Services

ServicePurpose
Razorpay / CashfreePayment processing
Backblaze B2Product images storage
Cloudflare R2General file storage
Gmail SMTPTransactional emails
FirebasePush notifications, auth
DelhiveryShipping integration
WhatsApp APIMarketing messages
Google AnalyticsTracking

Request Flow

Every API request passes through several layers before reaching the route handler. Here is the typical flow for an authenticated request:

Backend Route Organization

The backend organizes routes by domain. All routes are mounted under the /api prefix in index.js. Here is a summary of the major route domains:

DomainRoute FilesKey Areas
Adminadmin.js, admin-affiliate.js, admin-plan-assign.jsPlatform admin login, settings, affiliate management, plan assignment
Vendorsvendors.js, vendor-store.js, vendor-access.js, vendor-affiliate.js, vendor-credits.jsVendor registration, store creation, access control, affiliate config, credits
Productsproducts.js, bulkupload.js, shopifyBulkUpload.js, catalog.js, inventory.js, product_metafield.jsProduct CRUD, bulk upload (CSV/Shopify), catalog management, inventory tracking, metafields
Categoriescategory.js, subcategory.js, dynamic_category.js, categoryStatistics.jsCategory tree, subcategories, dynamic filtering, analytics
Ordersorders.js, draftorder.js, orderStatistics.js, abandon_checkouts.jsOrder management, draft orders, order analytics, abandoned cart recovery
Returns & Refundsrefund.js, return.js, cancel.jsRefund processing, return handling, order cancellations
Paymentspayment-methods.js, razorpay/, codControl.jsPayment method config, Razorpay integration, COD control
Collectionscollections.js, bulk-collection.jsProduct collections, bulk collection operations
Marketingmarketing/, whatsapp-marketing.js, discount.js, referral.jsCampaign management, WhatsApp messaging, discount codes, referral programs
Contentblogs.js, pages.js, shorts.js, banner.js, banner-v2.jsBlog posts, custom pages, short-form content, banner management
Themestheme.js, theme-editor.js, theme-marketplace.js, store-templates.js, store-menus.jsTheme CRUD, editor API, marketplace, templates, navigation menus
Store Layouthome_layout.js, mobile_home_layout.jsHomepage layout builder (desktop and mobile)
Filesfiles.js, export.js, export-store.js, bg-remover.jsFile upload/management, data export, store export, AI background removal
Users & AuthuserRoles.js, customer.js, studio-auth.jsRole-based access, customer management, studio authentication
Developerdeveloper.js, developer-earnings.js, store-apps.js, app-credits.jsDeveloper accounts, earnings, app publishing, app credits
Affiliateaffiliate-portal.jsAffiliate dashboard, referral tracking, payout management
Plansplans/, addons/Subscription plans, add-on features
Storefront APIsapis/ (apis, product, usercategory, menus, usercart, customerapis, rating, collections, checkout, order, wishlist, brands, manage_search, cashfree, razorpay, new-system-user-creation)Public storefront APIs for customer-facing stores
Storefront V2template-v2-routes/ (index, customer, menusv2, categoryv2, search, referral_reward, wallet, usercartv2)Next-generation storefront APIs
Mobile Appapp_template_routes/ (category, app-api, product)Native mobile app APIs
InfrastructurecronJob.js, sitemap.js, envDetails.js, testing.js, pdfcreation.jsScheduled jobs, SEO sitemaps, environment info, testing endpoints, PDF generation
Integrationsconnect_store/amazon.js, delhivery_partner.js, prefilled-chat.jsAmazon store import, Delhivery shipping, WhatsApp pre-filled chat
Showcaseshowcase_api/Platform showcase/gallery

Authentication Middleware

The backend uses four authentication middleware functions, each designed for a different user type:

MiddlewareLocationToken SourceVerifies AgainstAttaches to req
authenticatelib/index.jsAuthorization header, tokenSagartech cookie, tokenVendorsSagartech cookie, token cookieSECRET_KEY env varreq.userId, req.role_id
authorizeVendormiddleware/index.jsAuthorization header (Bearer token)Hardcoded JWT secret, then looks up api_key in stores tablereq.apiKey, req.store_name, req.vendor_id
authorizeCustomermiddleware/user.jsauthorization-customer header or authorization headerSECRET_KEY env varreq.userId
authenticateAffiliateroutes/affiliate-portal.jsAuthorization header or affiliateToken cookieSECRET_KEY env varreq.affiliateId, req.affiliateEmail

How authenticate Works

The primary authenticate middleware (lib/index.js) follows this logic:

  1. Check the Authorization header for a Bearer token
  2. If no header token, parse cookies and check tokenSagartech, then tokenVendorsSagartech, then token
  3. Strip surrounding quotes and redundant “Bearer ” prefixes
  4. Validate the token matches JWT format (three dot-separated base64 segments)
  5. Verify the token signature using jwt.verify(token, process.env.SECRET_KEY)
  6. Check token expiration
  7. Attach req.userId and req.role_id from the decoded payload
  8. Call next() to pass control to the route handler

How authorizeVendor Works

The authorizeVendor middleware (middleware/index.js) is used for storefront API calls:

  1. Extract Bearer token from Authorization header
  2. If the token is longer than 20 characters, treat it as a JWT and verify it to extract the api_key claim
  3. If the token is 20 characters or fewer, treat it directly as an API key
  4. Query the stores table to find a store whose api_key JSONB array contains a matching apiKey value
  5. Attach req.apiKey, req.store_name (slug), req.og_store_name, and req.vendor_id

Data Flow Example: Customer Places an Order

This sequence shows the complete flow when a customer places an order through a vendor’s storefront:

File Storage Architecture

The platform uses two cloud storage providers for different purposes:

Backblaze B2

  • Primary use: Product images, category images, brand logos
  • Integration: AWS S3-compatible SDK (@aws-sdk/client-s3)
  • Upload flow: Multer receives files on the backend, Sharp processes/resizes images, then the S3 SDK uploads to Backblaze B2
  • URL pattern: https://<bucket>.s3.<region>.backblazeb2.com/<folder>/<filename>
  • Folders: Organized by type (e.g., products/, categories/, brands/)

Cloudflare R2

  • Primary use: General file storage, exports, documents
  • Integration: AWS S3-compatible SDK with Cloudflare endpoint
  • URL pattern: https://<public-url>.r2.dev/<filename>
  • Bucket: Single bucket (siyahfy-files) with path-based organization

Upload Flow

Storefront Proxy Architecture

The backend-store.siyahfy.com service is a reverse proxy that routes incoming storefront requests to the correct Next.js theme server based on the store’s domain or subdomain.

Resolution Flow

  1. A customer visits myshop.site.siyahfy.com or custom-domain.com
  2. The proxy extracts the hostname and determines the store slug
  3. It queries PostgreSQL for the store’s theme server URL based on the vendor’s subscription plan
  4. The request is proxied to the correct theme server
  5. Theme resolution results are cached in memory for 60 seconds

Domain Types

PatternResolution
*.site.siyahfy.comExtract slug from subdomain, query stores table
Custom domain (e.g., example.com)Query store_domains table for verified domain
*.localhostSlug-based resolution for local development

Custom Domain Flow

When a vendor connects a custom domain:

  1. Vendor adds the domain in the dashboard
  2. Domain record is created in store_domains table with verified=false
  3. Vendor configures DNS A record to point to the server IP
  4. Domain verification is completed and verified is set to true
  5. Traefik automatically issues a Let’s Encrypt SSL certificate on first HTTPS request
  6. All subsequent requests are routed through the proxy to the store’s theme server

Database Architecture

PostgreSQL is the sole relational database. Key architectural decisions:

  • Multi-tenant by convention: All stores share the same database. Tables use store_name / store_slug / vendor_id columns to scope data to a specific store.
  • Auto-migrations: The backend runs pending SQL migrations from backend.siyahfy.com/migrations/ on every startup. A _migrations table tracks which files have been executed.
  • JSONB usage: Several columns use PostgreSQL JSONB for flexible schema (e.g., api_key in stores, product attributes, theme configuration).
  • No ORM: All queries are raw SQL via the pg driver. The connection pool is configured in config/index.js.

Caching Strategy

Redis is used as an optional caching layer:

  • Connection: Configured in config/redis.js, connects to redis://127.0.0.1:6379 in development and redis://redis:6379 in production
  • Graceful degradation: The backend starts and functions without Redis. Cache misses simply hit the database directly.
  • Storefront proxy: The backend-store.siyahfy.com proxy uses in-memory caching (60-second TTL) for theme server resolution, independent of Redis.