Skip to content
All work
Web platformlive

Qooty

AI-driven shopping offers & flyers platform — 5 apps, SEO at scale, Gemini ingestion.

2025 Saudi Arabia Confidential (Saudi Arabia)

// Results

5
Deployable apps
4.8k
SEO URLs indexed
3.5x
Crawl boost
77%
AI cost reduction

A consumer-focused, multi-tenant deals & weekly-flyers aggregator covering Saudi Arabia's retail market. Spans 5 deployable applications — two Node.js backends, two Next.js 16 frontends, and a Flutter mobile app — backed by AI-driven flyer ingestion, an SEO infrastructure at scale, and a partner self-service portal.


Table of contents

  1. Executive summary
  2. System architecture
  3. Tech stack at a glance
  4. Admin backend (Node.js + AI pipeline)
  5. Client backend (Consumer API)
  6. Admin dashboard (Next.js 16)
  7. Public website (qooty.net, Next.js 16)
  8. Mobile application (Flutter)
  9. Cross-cutting concerns
  10. Highlights & engineering decisions
  11. Key metrics & achievements

Executive summary

Qooty is a shopping-companion platform that aggregates promotional flyers, weekly deals, and discounts from major Saudi retailers into a single, bilingual (Arabic/English) browsing experience. Users discover offers by city, store, brand, sub-category, or price tier; admins ingest flyers in bulk through three creation flows (URL link / PDF upload / web scraping); supermarket partners log into a self-service portal to manage their own listings; and a Gemini-powered AI pipeline extracts product cards, prices, and brand metadata from raw flyer images.

The platform is deployed as five independently scaled services orchestrated by PM2 (backend) and Vercel/Cloudflare (frontend), with MongoDB, Redis, BullMQ, Firebase, OpenAI, and Google Gemini as foundational services.


System architecture

                                 ┌────────────────────────┐
                                 │   Google Gemini /      │
                                 │   OpenAI / Firebase    │
                                 └───────────┬────────────┘
                                             │
        ┌────────────────────────────────────┼───────────────────────────────┐
        │                                    │                               │
        ▼                                    ▼                               ▼
┌───────────────┐   PM2 multi-proc  ┌───────────────────┐   Redis    ┌────────────────┐
│ Admin Backend │ ───────────────►  │ BullMQ PDF Worker │ ─────────► │ Daily Cron Jobs│
│  (manager.js, │                   └───────────────────┘            └────────────────┘
│  partner.js)  │
└──────┬────────┘                   ┌───────────────────┐
       │                            │ Client Backend    │  ◄──── Redis + node-cache
       │ MongoDB ◄──────────────────│   (index.js)      │
       │                            └────────┬──────────┘
       │                                     │
       ▼                                     ▼
┌───────────────┐                   ┌───────────────────┐
│ Dashboard     │                   │ qooty.net         │  ◄── Cloudflare CDN + Vercel
│ (Next.js 16)  │                   │ (Next.js 16)      │     SEO sitemaps + IndexNow
│ admin + store │                   │ ar/en, RTL        │
└───────────────┘                   └─────────┬─────────┘
                                              │
                                              ▼
                                    ┌───────────────────┐
                                    │ Flutter App       │  ◄── FCM push, deep brand
                                    │ Android/iOS/Web   │     content, PDF flyers
                                    └───────────────────┘

Tech stack at a glance

LayerStack
BackendsNode.js, Express 4, Mongoose 8 + MongoDB, BullMQ + Redis, PM2 (8 procs), Firebase Admin (FCM), JWT auth
AI ingestionGoogle Gemini 2.5 Pro/Flash, OpenAI GPT, prompt caching, Sharp image cropping
FrontendsNext.js 16 (App Router), React 19, TypeScript 5, Tailwind v4, SWR, Zustand, next-intl, Recharts, Playwright, Vitest
MobileFlutter (Cubit/BLoC), Firebase Auth + Messaging + Storage, Google & Apple Sign-In, Syncfusion PDF viewer, easy_localization
Storage & cacheMongoDB, Redis, node-cache (in-process LRU), MEGA cloud, Cloudflare CDN
CommsFirebase FCM, Nodemailer SMTP, IndexNow + Google/Bing pings
DevOpsPM2 ecosystems, Vercel hosting, Vercel cron, Cloudflare in front of Next.js

1. Admin backend — qooty_admin_backend

The platform's control plane: powers the admin dashboard, partner portal, AI flyer-extraction pipeline, PDF/image workers, and scheduled cron jobs. Runs as 8 PM2 processes (manager, partner, worker, cron — prod + dev variants).

Stack

Express 4 · Mongoose 8 · MongoDB · BullMQ 5 + IORedis · JWT + bcrypt · Sharp · pdf-lib / pdf2pic / pdf-images · @google/generative-ai (Gemini) · openai · firebase-admin · nodemailer · multer · megajs · node-cron · winston · p-limit · PM2.

Architecture

Layered MVC: routers/ (23) → controllers/ (21) → services/models/ (22). Dedicated ai/, scripts/ (cron utilities), services/pdf2images/ (BullMQ worker), services/watermark/, utils/ (FCM, mailer, IndexNow, brand auto-fill, SEO copy prompts).

Entities (22 Mongoose models)

adminModel · affiliateModel · appSettingsModel · bannerModel · blogPostModel · brandModel · cartModel · categoryModel · citiesGroupModel · cityModel · featuredDealModel · marketModel · notifyModel · offerModel · pageModel · productModel · ratingAggregateModel · ratingModel · redirectModel · seoSettingsModel · subCategoryModel · userModel

Feature domains

Catalog & Commerce

  • Products with bilingual fields and AI-driven brand auto-fill
  • Hierarchical Categories + Sub-categories
  • Brands (auto-generated metadata + multi-source logo discovery)
  • Offers with PDF flyer upload and automatic expiry
  • Featured Deals (curated promotions)
  • Markets (retail chains) + Branches (geo-located stores)
  • Cities + City Groups (regional segmentation)
  • Homepage Banners

CMS & Content

  • Blog Posts (admin + public read API)
  • CMS Pages (slug-based, served to mobile/web)
  • Mobile-app Ads Config (remote feature flags)
  • App Settings

SEO infrastructure

  • Per-entity SEO Settings (override + template merge)
  • App SEO endpoints for the mobile/web app
  • 301/302 Redirects manager
  • IndexNow notifier — internal webhook that triggers Next.js ISR revalidation + Google/Bing/IndexNow pings
  • AI SEO copy generatorseoCopyGenController.js produces meta titles/descriptions via Gemini

Users & Auth

  • Admin auth (JWT + bcrypt)
  • Market-scoped partner auth — supermarket suppliers only see their own data (multi-tenant isolation)
  • Affiliate / referral tracking
  • Ratings + aggregated rating model

Notifications

  • Firebase Cloud Messaging push (per-device + topic broadcasts)
  • In-app notification inbox
  • Cron-driven daily push at 05:00 Riyadh time, topic "all"
  • Transactional email via Nodemailer

Dashboard analytics

  • Aggregated KPI endpoint feeding the admin dashboard charts

AI flyer-extraction pipeline (ai/)

ModulePurpose
gemini_flyer_parser.jsGemini 2.5 Pro spatial product-card detection — bounding boxes (0..1000 normalized), bilingual labels, price extraction, brand hints
extract_products.js / extract_products_gemini.js / extract_products_method3.jsThree strategies: OpenAI Vision, Gemini, and hybrid YOLO+Flash (method 3 = 77% cost reduction)
multi_product_parser_with_batch.jsConcurrent batch processing using p-limit
image2boxes.js, crop_index_overlay.jsSharp-based cropping using AI bounding boxes
parsers/gemini_prompt_cache.jsGemini context caching — avoids re-billing system prompts
parsers/gemini_batch_parser.jsBatched batch-API parser
parsers/gemini_client.jsRetry/backoff wrapper

Brand auto-fill (utils/brandAutoFill.js) — Gemini-driven brand entity creation: bilingual name/description, country of origin, parent company, website. Multi-source logo discovery: Clearbit → Brandfetch → Gemini-suggested URLs → Sharp validation → slug-based upsert with in-flight de-duplication.

Background processing

  • BullMQ + Redis PDF queue (pdf2images queue) — pdf2pic rasterizes flyer PDFs at 300 DPI to 1200 px PNGs, then watermarks via Sharp
  • pdf-lib, pdf-images, compress-pdf for additional manipulation
  • Worker runs as its own PM2 process

Cron jobs (scripts/)

  • daily_notification.js — node-cron 05:00 Riyadh time → FCM topic broadcast
  • delete_expired_offers.js — purges expired offers
  • run_delete_expired_offers_now.js — manual trigger variant

Partner portal (partner.js)

Separate Express app on its own port. Same router code, but every controller is scoped through marketAuth middleware so partners only ever see/edit their own market's offers and products. Tied into the dashboard's (store) route group.

Integrations

Google Gemini · OpenAI · Firebase Admin (FCM) · Clearbit + Brandfetch (logos) · IndexNow · MEGA (archival) · SMTP.


2. Client backend — qooty_client_backend

The consumer-facing read-optimized API serving the public website and mobile app under /v1/app.

Stack

Express 4 · Mongoose 8 · MongoDB · Redis client + node-cache (dual-tier cache) · firebase-admin (FCM) · winston · PM2.

Architecture

21 routers → 21 controllers → 22 models. middlewares/auth.js (user JWT) + adminAuth.js (admin-scoped routes). Single entry: index.js.

Feature domains

Catalog browsing — Products · Sub-categories · Brands · Offers · Featured Deals · Banners · Markets + Branches · Cities

Search & discovery — universal search router · recentRouter for "recently viewed" personalization

User-facing — Registration/login/profile · Cart · Ratings · Subscriptions (newsletter/topic) · Affiliate/referrer attribution · In-app notifications inbox

CMS / public — Blog reader endpoints · public SEO meta endpoints (drives Next.js SSR/ISR) · Redirects resolution · Remote app config

Notable capabilities

  • Dual-tier cache — Redis (distributed) + node-cache (in-process LRU) for hot data
  • FCM push to end users
  • IndexNow integration (shares utility with admin backend)
  • Arabic text normalizationnormalize_products_arabic.js handles diacritics + alef variants
  • SEO slug backfillbackfill_subcategory_slugs.js

3. Admin dashboard — qooty_dashboard_frontend

Internal control panel + supermarket-partner self-service portal. Next.js 16 + React 19, Arabic-default RTL, runs on port 3001.

Stack

Next.js 16.1 (App Router, Turbopack-ready) · React 19 · TypeScript 5 · Tailwind v4 · SWR 2 · react-hook-form + zod · Recharts 3 · lucide-react · CVA · Vitest (unit) · Playwright (E2E) · Tajawal font (next/font).

Routing structure (src/app/)

Four route groups: (auth) · (admin) · (store-auth) · (store).

Admin auth ((auth)) /login · /forgot-password · /reset-password

Store-owner auth ((store-auth)) /store/login

Store-owner sub-portal ((store)) /store (dashboard) · /store/offers · /store/offers/new · /store/offers/[offerId]/edit

Admin section ((admin)) — each entity has list + new + [id]/edit: /dashboard · /admins · /affiliates · /blog · /brands · /categories · /subcategories · /cities · /city-groups · /markets · /featured-deals · /redirects · /offers (with three creation flows: /create/link, /create/pdf, /create/scraping) · /offers/[offerId]/products (nested product management per offer) · /pages (CMS) · /banners · /ads · /ratings · /profile · /settings

SEO suite /seo/global · /seo/cities · /seo/markets · /seo/offers · /seo/templates · /seo/robots · /seo/sitemap · /seo/bulk-generate

Internal API routes

  • api/auth/admin/{login,logout,session,forgot-password,reset-password} — HTTP-only cookie sessions
  • api/auth/store/{login,logout,session} — partner sessions
  • api/manager/[...path] — admin backend proxy (forwards session cookie)
  • api/store/[...path] — partner backend proxy
  • api/app/[...path] — public-app API proxy

src/lib/server/{cookies,proxy,security}.ts centralizes cookie + upstream proxy logic; upstream URLs are never exposed to the browser.

UI building blocks (components/common/)

entity-table · data-toolbar · pagination-bar · confirm-delete-dialog · form-section · form-actions · upload-field · multi-select-field · localized-name-fields (paired ar/en inputs) · seo-editor-card · page-scaffold · state-panel · status-badge · city-group-selector

components/dashboard/kpi-card, trends-chart, store-trends-chart (Recharts). components/offer/ — base/market/static selectors shared across all three offer-creation flows.

Type-safety + forms

  • Centralized zod schemas in lib/forms/schemas.ts
  • lib/types.ts shared API types
  • lib/client/api.ts typed SWR client
  • hooks/use-entity-list — generic SWR list pattern reused across every CRUD page

Hardening

  • next.config.ts restrictive remote image patterns (api.qooty.net only)
  • Global security headers: X-Content-Type-Options: nosniff · X-Frame-Options: DENY · Referrer-Policy: strict-origin-when-cross-origin · Permissions-Policy locking down camera/mic/geolocation/FLoC
  • robots: { index: false, follow: false } at layout level
  • images.unoptimized: true (admin app doesn't need optimization)

Test coverage

  • /tests/unit Vitest suites
  • /tests/e2e Playwright suites: admin login, store login, password-reset flow, responsive UI sanity

4. Public website — qooty_client_frontend — qooty.net

Public bilingual (ar/en, RTL/LTR) SEO-driven storefront. Heavily performance- and SEO-engineered.

Stack

Next.js 16.1 · React 19 · TypeScript 5 · Tailwind v4 · next-intl 4 · SWR + axios · Zustand · swiper 12 · react-pageflip + react-zoom-pan-pinch (brochure viewer) · leaflet 1.9 (branch maps) · @vercel/speed-insights · lucide-react · Cairo + Inter via next/font.

Routing (src/app/[locale]/)

Locales: ar (default) and en, with localePrefix: "always".

Core pages / (home) · /about · /app (mobile-app landing) · /blog · /blog/[slug]

Brands /brands · /brand/[brandSlug] · /brand/[brandSlug]/deals · /brand/[brandSlug]/deals/[subcategorySlug]

Compare /compare · /compare/[storesSlug] — multi-store comparison landing pages

Featured / curated /featured-deals

KSA city hub (the SEO long tail) /ksa/cities · /ksa/[city] · /ksa/[city]/[marketSlug] · /ksa/[city]/brand/[brandSlug] · /ksa/[city]/deals/[subcategorySlug] · /ksa/deals · /ksa/deals/[subcategorySlug] · /ksa/deals/[subcategorySlug]/price · /ksa/deals/[subcategorySlug]/price/[bucket] (price-bucket landings) · /ksa/weekly-flyers · /ksa/weekly-flyers/[week] (ISO-week scoped)

Offers, products, stores /offer/[offerId]/[slug] (flyer/brochure viewer) · /product/[productId]/[...slug] · /products · /store/[marketSlug] · /stores

Misc /compare/[storesSlug] · /wishlist · /page/[slug] (CMS) · /[...slug] catch-all · /nf (localized 404 landing)

Unscoped routes

/ads.txt · /llms.txt · /q/seo/notify · /q/seo/daily-ping · /q/web-vitals · /qproxy

Built-in API routes

  • api/proxy — generic backend passthrough
  • api/seo/notify — IndexNow + search-engine notification webhook
  • api/seo/daily-ping — daily Vercel cron (09:00 UTC) hitting /q/seo/daily-ping
  • api/web-vitals — CWV beacon endpoint
  • /img/[...path]same-origin image proxy that fetches api.qooty.net/uploads/*, transcodes to WebP via Sharp, re-emits 1-year immutable Cache-Control (197 KB → 3.8 KB real-world wins recorded)

SEO infrastructure (the headline feature)

Sitemap fan-out — index + 18 partitioned sitemaps: sitemap-static · -blog · -brands · -brand-subcategories · -cities · -city-brands · -city-deals · -compare · -featured-deals · -hubs · -images · -offers · -price-ranges · -products · -store-hubs · -stores · -subcategories · -weekly-flyers

Atom/RSS feedsblog.xml · offers.xml · products.xml · weekly-flyers.xml

Dynamic OG / Twitter images — Edge ImageResponse for app, blog/[slug], brand/[brandSlug], featured-deals, ksa/[city], ksa/[city]/deals/[sub], ksa/deals/[sub], ksa/weekly-flyers, offer/[offerId]/[slug], product/[productId], store/[marketSlug] — shared template in app/_og/.

JSON-LD — Organization, WebSite, Breadcrumbs, plus per-page schemas. FAQ generators for brand, brand-subcategory, compare, store, subcategory, and weekly-flyers pages.

robots.ts + IndexNow key file (qooty-indexnow-{token}.txt).

Dashboard-managed overrides — template + override merge pattern (lib/seo.ts + lib/seo-api.ts).

Middleware (Node.js runtime)

  1. 301 redirect managerloadActiveRedirects() cached via unstable_cache (tag redirects-cache, admin-invalidated); fire-and-forget recordRedirectHit() analytics
  2. Unknown-segment guard — whitelist of known first segments; unknown locale-prefixed paths rewrite to /[locale]/nf (preserving locale header) instead of a generic 404
  3. next-intl delegation with X-NEXT-INTL-LOCALE forwarded to layout
  4. Edge cache injection — overrides next-intl's default private, no-cache by injecting CDN-Cache-Control: public, s-maxage=3600, stale-while-revalidate=86400 on anonymous SEO routes (~865 ms TTFB savings on deep pages)

Performance engineering

  • experimental.optimizePackageImports: ["lucide-react", "swiper"] — kills barrel-import bloat
  • staticPageGenerationTimeout: 180 for heavy city aggregates
  • Custom image loader (src/lib/image-loader.ts) rewrites api.qooty.net URLs to the same-origin /img/... proxy with ?w=&q= for proper srcset
  • images.formats: ["image/avif", "image/webp"]
  • Per-route explicit CDN-Cache-Control to bypass Cloudflare's default Vary-header rejection
  • 1-year immutable Cache-Control on /_next/static/* and /img/*
  • Preloaded LCP hero (hero.webp + hero-layer.avif)
  • Recorded results: Lighthouse 84 → 87 on mobile; payload 3.1 MB → 1.0 MB; Speed Index 3.6 s → 1.8 s

Notable interactive features

  • Flyer/brochure viewer — react-pageflip + zoom-pan-pinch + flip-sound effects (public/sounds/flip_sound.mp3, turnPage.mp3); responsive desktop and mobile
  • Clickable products inside flyer — pixel-mapped to bounding boxes from the AI extractor
  • Product modal with similar products and navigation
  • Multi-store comparison with price-bucket SEO landings
  • Leaflet branch maps with Google Places–backed geocoding (30-day cached)
  • Wishlist persisted in Zustand
  • Anonymous tracking ID for personalization without auth (lib/anon-id.ts)

Ezoic ad monetization

Two-tier ad system: 3 global slots + targeted route slots across 28 routes. Components: AdsProvider, AdScript, AdSlot, AdGrid, GlobalAds, EzoicRouteHandler (re-init on client-nav). Server-side config fetch via lib/ads-api.ts.

Analytics & telemetry

Google Analytics · ViewTrackers · WebVitalsReporter (beacon → /api/web-vitals) · Vercel Speed Insights.

Deployment

vercel.json — explicit JS chunk Content-Type workaround + daily SEO ping cron. Dev script offers webpack and Turbopack modes.


5. Mobile application — qooty-mobile-application

Production Flutter app (Android + iOS + Web). Internal name Wafarak (offers_app v1.0.7+9).

Stack

Flutter (Dart >=2.18.5 <3.0.0) · flutter_bloc 8 (Cubit pattern) · Dio 4 · Firebase Core/Auth/Messaging/Storage · google_sign_in + sign_in_with_apple · easy_localization · Cairo via google_fonts · cached_network_image · syncfusion_flutter_pdfviewer + pdfx · photo_view · shimmer · lottie · flutter_local_notifications · permission_handler · share_plus · screenshot · flutter_phoenix · json_serializable + build_runner.

Architecture

Feature-modular: Views → Cubits → Repositories → Dio → Models. 108 Dart files in lib/. Custom internal package packages/utilities (path-referenced) centralizes networking, state primitives, styles, and helpers.

lib/
├── core/                    # app shell, theme, helpers (auth, FCM, navigation, locale, networking)
├── modules/
│   ├── auth/                # AuthCubit, GetUserDataCubit, repositories, views
│   └── home/                # 9 cubits, models, shimmers, views, widgets
├── views/                   # root, splash
├── widgets/                 # 13 shared widgets
└── generated/               # assets.gen.dart, locale_keys.g.dart

Cubits

AuthAuthCubit, GetUserDataCubit HomeFetchAllDataCubit, FetchCitiesCubit, FetchFavouritesDataCubit, FetchMarketDetailsCubit, FetchMarketsCubit, FetchNotifiesCubit, FetchRecentDataCubit, FetchSimilarProductsCubit, SearchDataCubit

Features

Authentication — Email/password · Google Sign-In · Apple Sign-In (iOS compliance) · Firebase Auth backbone · Persistent session via SharedPreferences · Localized phone validation

Home & discovery — Tabbed home (Favourites · Explore · dynamic category tabs) · City selector (searchable dropdown) gating data · Pull-to-refresh · Shimmer skeletons per section

Offers — Browse offers · Detail screen with embedded PDF (Syncfusion or pdfx) · Screenshot → share-to-social (screenshot + share_plus) · Lottie empty/error states

Products — Listings · Detail with pinch-zoom imagery (photo_view) · Similar products recommendations · Recently viewed history

Markets / branches — All markets · Single market with branches · City + text filtering

Search — Debounced cross-domain search (markets, products, offers) scoped by city

Favourites — Auto-loaded on app start · Toggle from product/offer cards

NotificationsFCM topic "all" subscription · Foreground display via flutter_local_notifications bridge · onMessageOpenedApp tap-through navigation · In-app inbox · Runtime permission

Profile & settings — Profile screen · Account settings · Firebase Storage profile image upload · Logout with full app restart via flutter_phoenix

Localization & theming — Arabic-first RTL with English (ar-EG, en-US) · Live language switching with Phoenix restart · language_change_dialog widget · Cairo font · Direction-aware widgets and icons

App shell — Splash with auth-state routing · Root scaffold with bottom nav + drawer · Privacy & Terms screens

Notable capabilities

CapabilityImplementation
Offline detectionobserve_internet_connectivity + data_connection_checker_nulls with no_internet widget + Lottie
Image cachingcached_network_image + flutter_cache_manager
Push notificationsFirebase Messaging + flutter_local_notifications bridge — foreground/background/terminated coverage
Multi-provider authEmail + Google + Apple (platform-gated)
PDF viewingSyncfusion + pdfx fallback
Screenshot sharingWidget → PNG → native share sheet
App restartPhoenix for locale and auth resets
Code generationflutter_gen (assets), easy_localization (locale keys), json_serializable (models)
Skeleton UIPer-feature shimmer screens

Internal package — packages/utilities

A reusable Flutter package (v0.0.2) providing: base_networking, request_options, exceptions (Dio abstractions) · error_state, pagination_state (Bloc primitives) · style helpers (CColors, breakpoints) · navigation service · date_time, hex_color, locale, number_formatter, package_info, scroll_controller, strings, time_debouncer. Path-referenced from the main pubspec.yaml — clean monorepo layering.

Platform support

Android (Gradle + keystore configured) · iOS (Podfile + Firebase plist + Apple Sign-In capability) · Web (PWA-capable scaffold with manifest + favicon).


Cross-cutting concerns

Authentication model

RealmMechanismStorage
Admin dashboardJWT issued by admin backend, stored in HTTP-only cookieCookie
Partner / store-ownerMarket-scoped JWT via marketAuth middlewareCookie
Mobile app usersFirebase Auth (email + Google + Apple)SharedPreferences
WebsiteAnonymous (anon-id.ts) + optional FirebaseLocal storage

Multi-tenancy

The admin backend's partner.js boots a separate Express app sharing all routes/controllers, but every request passes through marketAuth middleware that scopes Mongoose queries to the partner's marketId. Partners never see siblings' offers, products, or analytics.

Caching layers

  1. MongoDB indexes on slug, city, market, expiry
  2. Client backend Redis (distributed) + node-cache (in-process LRU)
  3. Next.js unstable_cache with tag-based invalidation (redirects, SEO overrides)
  4. Per-route Cloudflare CDN-Cache-Control for anonymous SEO pages (1 h fresh, 24 h SWR)
  5. Same-origin /img/ proxy with 1-year immutable Cache-Control

Real-time invalidation

Admin actions → backend webhook → frontend api/seo/notifyrevalidateTag() + IndexNow + Bing/Yandex pings → Cloudflare cache busts on next miss.

Localization

Arabic (default, RTL) + English (LTR) across dashboard, website (next-intl), and mobile (easy_localization). Bilingual entity fields stored as { ar, en } documents in Mongo, with localized-name-fields admin component enforcing paired entry.

Image pipeline

Sharp on backend (watermark, WebP encode, AVIF) · Next.js custom loader on website rewriting to same-origin proxy · cached_network_image on mobile.

Observability

Winston logging (backends) · bloc_observer.dart (mobile) · Vercel Speed Insights · Google Analytics · WebVitalsReporter beacon → /api/web-vitals.

Deployment topology

  • Backends — PM2 ecosystem on VPS (8 procs admin + worker + cron, 1 proc client). deploy.sh for client backend.
  • Frontends — Vercel for the public site (with daily SEO ping cron), separate Vercel/Node target for dashboard. Cloudflare CDN in front.
  • Mobile — Android + iOS app-store distribution; web build available.

Engineering highlights

  1. AI-driven content ingestion pipeline — Gemini 2.5 Pro extracts bilingual product cards with bounding boxes from raw flyer images; Gemini context caching cut prompt-billing cost ~5× on repeated invocations; method-3 hybrid (YOLO + Flash) cut total flyer-extraction cost by 77 %. Brand auto-fill chains Clearbit → Brandfetch → Gemini for logo discovery with Sharp validation.

  2. SEO infrastructure at scale — 18 partitioned sitemaps + index, 4 Atom feeds, dynamic OG/Twitter ImageResponse for every entity, JSON-LD (Organization, WebSite, Breadcrumb, FAQ generators across 6 entity types), template+override merge, dashboard-managed overrides, IndexNow + Google/Bing pings, robots.ts, llms.txt, daily Vercel cron, anonymous-only edge caching.

  3. Performance-engineered Next.js 16 — Same-origin image proxy with Sharp WebP transcoding (197 KB → 3.8 KB wins recorded); optimizePackageImports for swiper/lucide; per-route Cloudflare CDN-Cache-Control injection (~865 ms TTFB win on deep pages); preloaded AVIF/WebP LCP hero; Lighthouse 84→87, payload 3.1 MB→1.0 MB, Speed Index 3.6 s→1.8 s.

  4. Bilingual RTL/LTR throughout — next-intl on the website with localePrefix: "always" and separate fonts per locale; easy_localization on mobile with live-restart switching; localized-name-fields on the dashboard enforcing paired ar/en entry; bilingual Mongoose schemas.

  5. Sophisticated middleware — Cached redirect manager with fire-and-forget hit analytics, unknown-path rewrite to localized 404, conditional edge-cache injection — all running on Next.js Node runtime.

  6. Multi-tenant partner portal — Single codebase running as a second PM2 process (partner.js), enforcing per-market data isolation via JWT-scoped middleware, paired with a dedicated (store) route group in the dashboard.

  7. Multi-process PM2 deployment — 8 named processes (manager, partner, PDF worker, expiry cron, daily notification cron) × prod/dev variants, all managed by ecosystem.config.js.

  8. Interactive brochure viewer — react-pageflip + zoom-pan-pinch + page-flip sound effects, mapping clicks on flyer pixels back to AI-extracted product bounding boxes.

  9. Dashboard depth — ~25 entity CRUD modules + 3 distinct offer-creation flows (URL, PDF upload, web scraping), full SEO control surface, redirect manager, store-owner sub-portal with separate auth — all sharing a reusable entity-table / data-toolbar / pagination-bar pattern and zod-typed forms.

  10. Test coverage on the dashboard — Vitest unit + Playwright E2E covering auth, password reset, and responsive UI.

  11. Custom Flutter monorepo packagepackages/utilities extracted with shared networking, state primitives, styles, and helpers, path-referenced from the main app.

  12. Security hardening — HTTP-only cookie sessions, server-side proxies hiding upstream API, strict global headers (X-Frame-Options DENY, no-sniff, restrictive Permissions-Policy), restrictive image remote-patterns, market-scoped multi-tenant auth.


Key metrics & achievements

MetricResult
Lighthouse mobile (qooty.net)84 → 87
Mobile payload3.1 MB → 1.0 MB
Speed Index3.6 s → 1.8 s
Image proxy savings (representative)197 KB → 3.8 KB
Deep-page TTFB savings (CDN cache injection)~865 ms
AI extraction cost reduction (method 3)77 %
Gemini prompt caching savings (method 1)~5×
GSC crawl boost after SEO push3.5×
SEO URLs indexed~4.8k (28-agent SEO initiative)
Backend PM2 processes8 (admin) + 1 (client)
Sitemaps in fan-out18 partitioned + index
Atom feeds4
Routes with explicit CDN cache headers~10 SEO route prefixes
Localized routes per locale40+ under [locale]
Mongoose models22 (admin) + 22 (client)
Dashboard CRUD modules~25
Mobile cubits11
Mobile platformsAndroid + iOS + Web

Repository layout

qooty-platform/
├── qooty_admin_backend/         # Node.js — admin API, partner API, AI pipeline, worker, crons
├── qooty_client_backend/        # Node.js — consumer-facing read API
├── qooty_dashboard_frontend/    # Next.js 16 — admin + store-owner dashboard
├── qooty_client_frontend/       # Next.js 16 — qooty.net public website
├── qooty-mobile-application/    # Flutter — Android + iOS + Web
└── docs/                        # Specs (Ezoic integration, SEO strategy, etc.)

Built and shipped by Mahmood Makhloof.

// Gallery

WhatsApp