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
| Technology | Version | Purpose |
|---|---|---|
| Next.js | 16.1.6 | React framework with App Router |
| React | 19.2.3 | UI library |
| Zustand | 4.5.5 | Client-side state management (vendor profile) |
| Tailwind CSS | 4.x | Utility-first CSS framework |
| TypeScript | 5.x | Type 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.jsonKey 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
CategorySectionwith horizontally scrollable compactAppCardcomponents - All Apps Grid — 3-column responsive grid of full
AppCardcomponents
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
AppDetailTabscomponent) - 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
AppCardgrid - 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 -> amberInstallButton
Stateful client component managing the full install lifecycle:
- Checking — queries install status on mount
- Idle — “Install” button with confirmation modal
- Installing — animated progress bar (5-second minimum duration with smooth animation)
- Installed — green checkmark + “Uninstall” button
- 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
Header
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
Cookie-Based Auth
The app uses two cookies from the main vendor dashboard:
tokenVendorsSagartech— JWT auth tokenstoreSelectedSiyahfy— 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:
| Route | Method | Description |
|---|---|---|
/api/store-apps/install | POST | Install app (proxies to {ADMINURL}/api/store/apps/install) |
/api/store-apps/uninstall | POST | Uninstall app (proxies to {ADMINURL}/api/store/apps/uninstall) |
/api/store-apps/install-status/{appId} | GET | Check if app is installed for current store |
/api/store-apps/purchases | GET | Fetch credit pack purchase history |
/api/auth-sync | — | Auth synchronization |
/api/logout | POST | Clear auth cookies |
/api/me | GET | Get 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
| Endpoint | Method | Used By |
|---|---|---|
{BACKEND_URL}/api/store/apps | GET | Home page (app catalog) |
{ADMINURL}/api/store/apps/{id} | GET | App detail page |
{ADMINURL}/api/store/apps/search/{query} | GET | Search page |
{ADMINURL}/api/store/apps/install | POST | Install route handler |
{ADMINURL}/api/store/apps/uninstall | POST | Uninstall route handler |
{ADMINURL}/api/getVendorLoginDetails | POST | Root 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