Skip to Content

App Store

Overview

The App Store (store.siyahfy.com) is the marketplace where Siyahfy store owners browse, search, and install apps for their online stores. It provides a consumer-grade app discovery experience with category navigation, full-text search, app detail pages with screenshots and features, one-click install/uninstall, and credit pack purchase history.

The store is a Next.js 16 app with server-side rendering for SEO and initial data loading, combined with client-side interactivity for search, install actions, and profile management via Zustand.

Runtime: Next.js 16 with React 19 Port: 3000 (development) Deployment: Production at store.siyahfy.com

Tech Stack

TechnologyVersionPurpose
Next.js16.1.6React framework with App Router
React19.2.3UI library
Zustand4.5.5Client-side state management (vendor profile)
Tailwind CSS4.xUtility-first CSS framework
TypeScript5.xType safety

Folder Structure

store.siyahfy.com/ ├── app/ │ ├── layout.tsx # Root layout (Header, Footer, vendor profile hydration) │ ├── page.tsx # Home page (app catalog, category sections) │ ├── globals.css # Global styles │ ├── robots.ts # Robots.txt (noindex -- private marketplace) │ ├── sitemap.ts # Sitemap generation │ ├── types/ │ │ └── app.ts # App interface definition │ ├── stores/ │ │ └── vendorProfileStore.ts # Zustand store for vendor profile │ ├── app/ │ │ └── [id]/ │ │ └── page.tsx # App detail page (screenshots, features, install) │ ├── search/ │ │ └── page.tsx # Search results page │ ├── api/ │ │ ├── auth-sync/ │ │ │ └── route.ts # Auth synchronization endpoint │ │ ├── logout/ │ │ │ └── route.ts # POST /api/logout (clears cookies) │ │ ├── me/ │ │ │ └── route.ts # GET /api/me (current user profile) │ │ └── store-apps/ │ │ ├── install/ │ │ │ └── route.ts # POST /api/store-apps/install │ │ ├── uninstall/ │ │ │ └── route.ts # POST /api/store-apps/uninstall │ │ ├── install-status/ │ │ │ └── [appId]/ │ │ │ └── route.ts # GET /api/store-apps/install-status/{appId} │ │ └── purchases/ │ │ └── route.ts # GET /api/store-apps/purchases │ └── components/ │ ├── Header.tsx # Sticky header (logo, search, profile dropdown) │ ├── Footer.tsx # Footer (brand, links, copyright) │ ├── HeroSearch.tsx # Hero section search input │ ├── CategoryNav.tsx # Sticky category pill navigation │ ├── CategorySection.tsx # Per-category horizontal scroll section │ ├── HorizontalAppScroller.tsx # Horizontal app card scroller │ ├── AppCard.tsx # App card (default + compact variants) │ ├── AppDetailTabs.tsx # Tab navigation on app detail page │ ├── InstallButton.tsx # Install/uninstall with progress bar │ ├── InstallCount.tsx # Live install count display │ ├── PurchaseHistory.tsx # Credit pack purchase history table + invoice modal │ └── VendorProfileHydrator.tsx # Hydrates Zustand store from SSR data ├── middleware.ts # Currently disabled (matcher: /__middleware_disabled__) ├── next.config.ts # Exposes FRONTEND_URL, ADMINURL, VENDOR_URL, BACKEND_URL ├── postcss.config.mjs ├── tsconfig.json └── package.json

Key Pages

Home Page (/)

The main app catalog page. Apps are fetched server-side from GET {BACKEND_URL}/api/store/apps.

Sections:

  • Hero — headline (“Discover apps for your store”), app count badge, full-width search input
  • Sticky Category Nav — horizontal scrollable pills with emoji icons per category (Marketing, Analytics, Media, AI, Integration, Productivity, Sales, Support) plus “All Apps”
  • Per-Category Horizontal Sections — each category renders a CategorySection with horizontally scrollable compact AppCard components
  • All Apps Grid — 3-column responsive grid of full AppCard components

App Detail (/app/[id])

Full app detail page with SSR metadata for SEO. Data from GET {ADMINURL}/api/store/apps/{id}.

Sections:

  • Breadcrumb — Apps > App Name
  • App Info Hero — icon (80x80), title, developer name, category, price, install count, desktop install button
  • Media Gallery — horizontal scrollable screenshots with YouTube embed support (auto-detects YouTube URLs)
  • About this app — full description
  • Features — 2-column checklist grid
  • Tabs — Overview and Purchase History (via AppDetailTabs component)
  • Sidebar — App details card (pricing, category, developer), support links (FAQ, Help Center), sticky on desktop
  • Mobile Install Button — shown below sidebar on small screens

Dynamic Metadata:

// Generates OpenGraph + Twitter cards per app export async function generateMetadata({ params }): Promise<Metadata> { const app = await getApp(id); return { title: app.title, description: truncate(app.description, 170), openGraph: { type: "article", url: `/app/${app.id}`, ... }, twitter: { card: "summary_large_image", ... } }; }

Search (/search?q={query})

Client-side search page with loading skeletons and empty states.

  • Fetches results from GET {ADMINURL}/api/store/apps/search/{query}
  • Renders results in the same 3-column AppCard grid
  • Shows skeleton loaders while searching
  • Empty state with “Browse all apps” link

Components

AppCard

Two variants:

  • default — full card with icon, title, price badge, category dot, description, feature tags, “View details” footer
  • compact — smaller card (220px wide) for horizontal scrollers with icon, title, category, price

Category-specific color coding:

Marketing -> orange Analytics -> blue Media -> pink AI -> violet Integration -> cyan Productivity -> green Sales -> emerald Support -> amber

InstallButton

Stateful client component managing the full install lifecycle:

  1. Checking — queries install status on mount
  2. Idle — “Install” button with confirmation modal
  3. Installing — animated progress bar (5-second minimum duration with smooth animation)
  4. Installed — green checkmark + “Uninstall” button
  5. Uninstalling — disabled “Uninstalling…” state

Uses confirmation modals for both install and uninstall actions. Reads the current store from storeSelectedSiyahfy cookie and the vendor profile from Zustand.

PurchaseHistory

Credit pack purchase history with invoice modal:

  • Table showing pack name, date, amount (INR), credits, payment status
  • Status badges: paid/captured (green), created (amber), failed (red)
  • Click any row to open invoice modal showing subtotal, GST (18%), total, credits, Razorpay order/payment IDs
  • Desktop: 6-column table; Mobile: compact card layout

Sticky glass-morphism header with:

  • Logo + “Siyahfy Store” badge
  • Search bar (hidden on homepage, shown on all other pages)
  • “Apps” navigation link
  • Profile dropdown (if logged in): name, email, Dashboard link, logout
  • Mobile search toggle
  • Login button (if not logged in) — gradient indigo-to-purple

CategoryNav

Sticky navigation bar below the header with horizontally scrollable category pills. Each pill shows an emoji icon, category name, and app count. Smooth-scrolls to the corresponding section on click.

Authentication

The app uses two cookies from the main vendor dashboard:

  • tokenVendorsSagartech — JWT auth token
  • storeSelectedSiyahfy — currently selected store slug

These cookies are set by the vendor dashboard (app.siyahfy.com) and shared across *.siyahfy.com subdomains.

Middleware

The middleware is currently disabled (matcher targets /__middleware_disabled__). Authentication is handled at the component level — unauthenticated users can browse apps freely but need to log in to install.

Server-Side Profile Fetch

The root layout fetches the vendor profile server-side if a token exists:

POST {ADMINURL}/api/getVendorLoginDetails Headers: Authorization: Bearer {token} Body: { store_name: "{storeSelectedSiyahfy}" }

The profile (name, email, stores array) is passed to VendorProfileHydrator which seeds the Zustand store on the client.

Zustand Store

vendorProfileStore

interface VendorProfile { name: string; email: string; stores?: { store_id: number; store_slug: string; store_name: string }[]; } interface VendorProfileState { profile: VendorProfile | null; setProfile: (profile: VendorProfile | null) => void; clearProfile: () => void; }

The store is hydrated server-side via VendorProfileHydrator (a client component that calls setProfile in a useEffect). Components like Header, InstallButton, and PurchaseHistory read from this store to show personalized UI and determine the active store.

API Routes (Next.js)

The app has several API route handlers that proxy requests to the Backend API with authentication:

RouteMethodDescription
/api/store-apps/installPOSTInstall app (proxies to {ADMINURL}/api/store/apps/install)
/api/store-apps/uninstallPOSTUninstall app (proxies to {ADMINURL}/api/store/apps/uninstall)
/api/store-apps/install-status/{appId}GETCheck if app is installed for current store
/api/store-apps/purchasesGETFetch credit pack purchase history
/api/auth-syncAuth synchronization
/api/logoutPOSTClear auth cookies
/api/meGETGet current user profile

All proxy routes extract tokenVendorsSagartech from cookies and forward it as Authorization: Bearer header to the Backend API.

API Calls to Backend

EndpointMethodUsed By
{BACKEND_URL}/api/store/appsGETHome page (app catalog)
{ADMINURL}/api/store/apps/{id}GETApp detail page
{ADMINURL}/api/store/apps/search/{query}GETSearch page
{ADMINURL}/api/store/apps/installPOSTInstall route handler
{ADMINURL}/api/store/apps/uninstallPOSTUninstall route handler
{ADMINURL}/api/getVendorLoginDetailsPOSTRoot layout (profile fetch)

Type Definitions

App

interface App { id: string; title: string; description: string; icon: string; category: string; price: string; features?: string[]; screenshots?: string[]; }

SEO Configuration

The app is currently configured as a private marketplace (noindex):

robots: { index: false, follow: false, googleBot: { index: false, follow: false } }

Individual app detail pages generate OpenGraph and Twitter card metadata dynamically using generateMetadata.

Environment Variables

# Public frontend URL FRONTEND_URL=https://store.siyahfy.com # Central Backend API (for server-side API calls) ADMINURL=https://backend.siyahfy.com # Backend URL (alternative, used for app catalog fetch) BACKEND_URL=https://backend.siyahfy.com # Vendor dashboard URL (for login redirect + Dashboard link) VENDOR_URL=https://app.siyahfy.com # Node environment NODE_ENV=production