vasuzex 2.1.23 → 2.1.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -224,8 +224,9 @@ export class DatabaseConfigService {
224
224
  }
225
225
 
226
226
  /**
227
- * Load API configs (scope='api') from database
227
+ * Load API configs (scope='api' and scope='all') from database
228
228
  * These are the backend configs that get loaded into Config facade
229
+ * scope='all' means shared between frontend and backend (no duplication)
229
230
  * @private
230
231
  */
231
232
  async #loadApiConfigs() {
@@ -237,9 +238,9 @@ export class DatabaseConfigService {
237
238
  return;
238
239
  }
239
240
 
240
- // Load only API-scoped configs for backend
241
+ // Load API-scoped AND shared (scope='all') configs for backend
241
242
  const configs = await AppConfig.query()
242
- .where('scope', 'api')
243
+ .whereIn('scope', ['api', 'app', 'all'])
243
244
  .where('is_active', true)
244
245
  .where((query) => {
245
246
  query.where('environment', this.#environment)
@@ -12,8 +12,23 @@ import { createRequire } from 'module';
12
12
 
13
13
  const require = createRequire(import.meta.url);
14
14
 
15
- // Load environment variables
16
- dotenv.config({ path: resolve(process.cwd(), '.env') });
15
+ // Load environment variables based on NODE_ENV
16
+ const loadEnvFiles = () => {
17
+ const cwd = process.cwd();
18
+ const nodeEnv = process.env.NODE_ENV || 'development';
19
+
20
+ // Load base .env first
21
+ dotenv.config({ path: resolve(cwd, '.env') });
22
+
23
+ // Then load environment-specific .env file (overrides base)
24
+ const envFile = `.env.${nodeEnv}`;
25
+ const envPath = resolve(cwd, envFile);
26
+ if (existsSync(envPath)) {
27
+ dotenv.config({ path: envPath, override: true });
28
+ }
29
+ };
30
+
31
+ loadEnvFiles();
17
32
 
18
33
  /**
19
34
  * Generate GuruORM config from framework config
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vasuzex",
3
- "version": "2.1.23",
3
+ "version": "2.1.25",
4
4
  "description": "Laravel-inspired framework for Node.js monorepos - V2 with optimized dependencies",
5
5
  "type": "module",
6
6
  "main": "./framework/index.js",
@@ -1,688 +0,0 @@
1
- # Amazon-Style SRP Architecture & Data Audit (vasuzex-v2)
2
-
3
- ## 1. Conversation Overview
4
- - **Primary Objectives:**
5
- - Confirm slug helper in vasuzex-v2
6
- - Refactor customer `searchProducts` to match admin (single query, primary photo, no patching)
7
- - Design Amazon-style SRP: dynamic filters, multi-store logic, no assumptions/patching
8
- - **Session Context:**
9
- - Started with a helper query, escalated to strict, enterprise-grade requirements
10
- - **Intent Evolution:**
11
- - From helper to full DB/data audit and robust SRP architecture
12
-
13
- ## 2. Technical Foundation
14
- - **vasuzex-v2:**
15
- - Has `generateSlug` helper
16
- - Uses GuruORM models, BaseService patterns
17
- - **GuruORM:**
18
- - Eager loading, scopes, relationships
19
- - **Redux:**
20
- - For search state management
21
- - **PostgreSQL:**
22
- - Backing DB, schema audited via migrations/models
23
- - **Constraints:**
24
- - No patching, no assumptions, no fallback logic
25
-
26
- ## 3. Codebase Status
27
- - **ProductService.js (customer):**
28
- - Refactored `searchProducts` to use `BaseService.getList`, return only primary photo, fixed async bug
29
- - **ProductService.js (admin):**
30
- - Used as reference for single-query, robust search
31
- - **Models/Migrations Audited:**
32
- - Product, ProductVariant, StoreInventory, Brand, Category, Rating, Unit, Packaging, Store
33
- - **No dead code left behind**
34
-
35
- ## 4. Problem Resolution
36
- - **Issues:**
37
- - N+1 in `searchProducts`, async mapping bug, unclear filter dimensions
38
- - **Solutions:**
39
- - Refactored to single-query, fixed async bug, full DB/data audit
40
- - **Debugging:**
41
- - No patching, fallback, partials, or assumptions
42
- - **Lessons:**
43
- - Filters must be DB-driven, multi-store logic is critical, code must be robust/reusable
44
-
45
- ## 5. Progress Tracking
46
- - **Completed:**
47
- - Slug helper confirmed
48
- - `searchProducts` refactored and bugfixed
49
- - DB/data audit and filter matrix produced
50
- - **Partially Complete:**
51
- - Awaiting user answers to critical questions before SRP/filter implementation
52
- - **Validated:**
53
- - All code changes tested for single-query, primary photo, async correctness
54
-
55
- ## 6. Active Work State
56
- - **Current Focus:**
57
- - DB/data audit, filter matrix, SRP architecture, multi-store rules
58
- - **Recent Context:**
59
- - Reading models, migrations, services to map filterable fields and multi-store logic
60
- - **Working Code:**
61
- - `ProductService.js` `searchProducts` (single-query, primary photo, Promise.all fix)
62
- - **Immediate Context:**
63
- - Producing architecture and question list for user confirmation
64
-
65
- ## 7. Recent Operations
66
- - **Last Agent Commands:**
67
- - file_search, read_file, grep_search, apply_patch, multi_tool_use.parallel
68
- - **Tool Results:**
69
- - Models/migrations read for filterable fields
70
- - `ProductService.js` refactored and bugfixed
71
- - Filter matrix and architecture produced
72
- - **Pre-Summary State:**
73
- - Finalizing DB/data audit and architecture document for Amazon-style SRP
74
- - **Operation Context:**
75
- - All recent commands directly supported robust, DB-driven, multi-store search/filter system
76
-
77
- ## 8. Business Rules & Planning (Updated)
78
-
79
- ### Confirmed Business Rules
80
- - **Price Management:** Store manages inventory, inventory has pricing. MRP is always present for every product/variant.
81
- - **Variant Display:** Config-driven via `store.show_all_products` (boolean, public). System must respect this setting globally.
82
- - **Related Searches:** Strictly DB-driven. Static suggestions are not production-ready.
83
- - **Sponsored Products:** Full admin-driven workflow required (like Amazon/Flipkart). See detailed architecture below.
84
- - **Store Ratings:** Recommend global aggregation for multi-store, with per-store support for analytics and A/B testing.
85
-
86
- ### Actionable Implementation Plan
87
-
88
- #### Phase 1: Database Schema & Migrations
89
- 1. **Sponsored Products Schema:**
90
- - Add to `products` table:
91
- - `is_sponsored` (boolean, default false)
92
- - `sponsored_rank` (integer, nullable, for ordering)
93
- - `sponsored_start_date` (timestamp, nullable)
94
- - `sponsored_end_date` (timestamp, nullable)
95
- - `sponsored_store_id` (uuid, nullable, FK to stores - null = global)
96
- - `sponsored_budget` (decimal, nullable, for future bidding)
97
- - `sponsored_clicks` (integer, default 0, for analytics)
98
- - `sponsored_impressions` (integer, default 0, for analytics)
99
- - Indexes: `is_sponsored`, `sponsored_rank`, `sponsored_start_date`, `sponsored_end_date`, `sponsored_store_id`
100
-
101
- 2. **Related Searches Schema:**
102
- - Create `search_queries` table:
103
- - `id` (uuid, PK)
104
- - `query` (string, indexed)
105
- - `result_count` (integer)
106
- - `click_count` (integer)
107
- - `created_at`, `updated_at`
108
- - Create `related_searches` table:
109
- - `id` (uuid, PK)
110
- - `search_query_id` (uuid, FK)
111
- - `related_query_id` (uuid, FK)
112
- - `relevance_score` (decimal)
113
-
114
- 3. **Store Ratings Enhancement:**
115
- - Add to `ratings` table (if not exists):
116
- - `store_id` (uuid, nullable, FK to stores)
117
- - Indexes: `product_id`, `store_id`, `rating`
118
-
119
- #### Phase 2: Backend Search API
120
- 1. **Endpoint:** `GET /api/search/products`
121
- 2. **Query Parameters:**
122
- - `q` (string, search query)
123
- - `category_id` (uuid[])
124
- - `brand_id` (uuid[])
125
- - `price_min`, `price_max` (decimal)
126
- - `rating_min` (decimal)
127
- - `store_id` (uuid[])
128
- - `in_stock` (boolean)
129
- - `attributes` (json, e.g., `{"color": ["red", "blue"]}`)
130
- - `page`, `limit` (integer)
131
- - `sort` (string: price_asc, price_desc, rating_desc, relevance)
132
- 3. **Response:**
133
- ```json
134
- {
135
- "products": [],
136
- "filters": {
137
- "categories": [{"id": "", "name": "", "count": 0}],
138
- "brands": [{"id": "", "name": "", "count": 0}],
139
- "price_range": {"min": 0, "max": 0},
140
- "attributes": {"color": [{"value": "red", "count": 5}]}
141
- },
142
- "sponsored": [],
143
- "related_searches": [],
144
- "pagination": {"page": 1, "total": 100}
145
- }
146
- ```
147
- 4. **Business Logic:**
148
- - Single-query with joins: products, variants, inventory, brands, categories, ratings
149
- - Filter sponsored products separately (display at top or interspersed)
150
- - Respect `store.show_all_products` config for variant filtering
151
- - Aggregate ratings globally by default, support per-store filter
152
- - Generate dynamic filters based on search results (no hardcoding)
153
- - Track search query for related searches analytics
154
-
155
- #### Phase 3: Admin Panel - Sponsored Products
156
- 1. **UI Components:**
157
- - Product list with "Sponsor" action button
158
- - Sponsored product management page:
159
- - Schedule form (start/end dates)
160
- - Rank input (ordering)
161
- - Store targeting (global or specific stores)
162
- - Budget allocation (future)
163
- - Analytics dashboard (impressions, clicks, CTR)
164
- 2. **API Endpoints:**
165
- - `POST /api/admin/products/:id/sponsor`
166
- - `PUT /api/admin/products/:id/sponsor`
167
- - `DELETE /api/admin/products/:id/sponsor`
168
- - `GET /api/admin/sponsored-products` (list with filters)
169
- - `GET /api/admin/sponsored-products/analytics`
170
- 3. **Validation:**
171
- - Start date < end date
172
- - Rank must be unique per store (or global)
173
- - Budget > 0 (if provided)
174
- 4. **Audit Trail:**
175
- - Log all sponsored product changes (who, when, what)
176
- - Track performance metrics for reporting
177
-
178
- #### Phase 4: Frontend - SRP UI
179
- 1. **Components:**
180
- - `SearchResultsPage` (container)
181
- - `FilterSidebar` (dynamic filters)
182
- - `ProductGrid` (results display)
183
- - `SponsoredProductCard` (highlighted)
184
- - `RelatedSearches` (horizontal list)
185
- - `Pagination`
186
- 2. **Redux State:**
187
- ```javascript
188
- search: {
189
- query: '',
190
- filters: {},
191
- results: [],
192
- sponsored: [],
193
- relatedSearches: [],
194
- filterMetadata: {},
195
- loading: false,
196
- error: null,
197
- pagination: {}
198
- }
199
- ```
200
- 3. **Routing:**
201
- - `/search?q=laptop&category=electronics&price_min=500&price_max=1000`
202
- 4. **Features:**
203
- - Real-time filter updates (debounced)
204
- - Sponsored product highlighting (badge, border)
205
- - Variant display per store config
206
- - Store aggregation (show all stores with inventory)
207
- - Global ratings with per-store toggle (A/B test)
208
-
209
- #### Phase 5: Analytics & Market Study
210
- 1. **Store Ratings Research:**
211
- - Study Amazon, Flipkart, Walmart, Alibaba
212
- - Key questions:
213
- - How do they display ratings in multi-vendor scenarios?
214
- - Do they show per-seller ratings or global?
215
- - How do they handle rating aggregation?
216
- - Implement both global and per-store, track user engagement
217
- - A/B test: 50% users see global, 50% see per-store
218
- - Measure: CTR, conversion rate, user feedback
219
- 2. **Sponsored Products Analytics:**
220
- - Track impressions, clicks, conversions per sponsored product
221
- - ROI calculation for future bidding system
222
- - Admin dashboard with charts (daily/weekly/monthly)
223
- 3. **Related Searches Analytics:**
224
- - Track query popularity, click-through from related searches
225
- - Use for refining search algorithm and suggestions
226
-
227
- #### Phase 6: Testing & Validation
228
- 1. **Unit Tests:**
229
- - Search service logic
230
- - Filter generation
231
- - Sponsored product ranking
232
- 2. **Integration Tests:**
233
- - Search API with all filters
234
- - Admin sponsored product workflow
235
- - Multi-store inventory aggregation
236
- 3. **E2E Tests:**
237
- - Complete search flow
238
- - Filter interactions
239
- - Sponsored product display
240
- 4. **Performance Tests:**
241
- - Search query performance (target < 200ms)
242
- - Large result set handling (10k+ products)
243
- - Concurrent user load testing
244
-
245
- ---
246
-
247
- ## Filter Matrix & Data Audit (Summary)
248
-
249
- | Filter/Dimension | Source Table/Model | Notes/Constraints |
250
- |--------------------|------------------------|------------------------------------|
251
- | Category | categories | Hierarchical, DB-driven |
252
- | Brand | brands | DB-driven |
253
- | Price (MRP, Sale) | product_variants, store_inventory | Multi-store, per-variant, no fallback |
254
- | Rating | ratings | Aggregate, store-specific? |
255
- | Unit/Packaging | units, packaging | Variant-level |
256
- | Store | stores, store_inventory| Multi-store, must aggregate |
257
- | Stock/Availability | store_inventory | Per-store, per-variant |
258
- | Attributes | product_variants | Color, size, etc. |
259
- | ... | ... | ... |
260
-
261
- - **All filters must be DB-driven, no hardcoding.**
262
- - **Multi-store logic:**
263
- - Aggregate inventory, price, and availability per store
264
- - No patching or fallback if data missing
265
-
266
- ---
267
-
268
- ## SRP Architecture (Detailed)
269
-
270
- ### Backend Architecture
271
- - **Single Search API:**
272
- - Endpoint: `GET /api/search/products`
273
- - Single-query execution with optimized joins
274
- - DB-driven filters, no hardcoding
275
- - Multi-store aggregation at query level
276
- - Sponsored product injection (separate query or CTE)
277
- - **Service Layer:**
278
- - `SearchService.search(query, filters, pagination)`
279
- - `FilterService.generateFilters(searchResults)`
280
- - `SponsoredService.getSponsoredProducts(query, storeId)`
281
- - `RelatedSearchService.getRelatedSearches(query)`
282
- - **Data Flow:**
283
- 1. Receive search query and filters
284
- 2. Build dynamic SQL with filters (GuruORM query builder)
285
- 3. Execute single query with joins: products → variants → inventory → brands → categories → ratings
286
- 4. Fetch sponsored products (time-based filtering, ranking)
287
- 5. Generate dynamic filters from result set
288
- 6. Fetch related searches from analytics
289
- 7. Return unified response
290
- - **Performance:**
291
- - Database indexes on all filterable fields
292
- - Query caching (Redis) for popular searches
293
- - Pagination with cursor-based approach for large result sets
294
- - Target response time: < 200ms
295
-
296
- ### Frontend Architecture
297
- - **Component Structure:**
298
- ```
299
- SearchResultsPage
300
- ├── SearchBar (header)
301
- ├── FilterSidebar
302
- │ ├── CategoryFilter (hierarchical)
303
- │ ├── BrandFilter (checkbox list)
304
- │ ├── PriceRangeFilter (slider)
305
- │ ├── RatingFilter (stars)
306
- │ ├── StoreFilter (multi-select)
307
- │ ├── AttributeFilter (dynamic, per-category)
308
- │ └── AppliedFilters (removable chips)
309
- ├── SearchResults
310
- │ ├── SponsoredProducts (highlighted grid)
311
- │ ├── ProductGrid
312
- │ │ └── ProductCard (with store aggregation)
313
- │ └── Pagination
314
- └── RelatedSearches (horizontal list)
315
- ```
316
- - **Redux State Management:**
317
- ```javascript
318
- search: {
319
- query: string,
320
- filters: {
321
- categories: string[],
322
- brands: string[],
323
- priceRange: { min: number, max: number },
324
- rating: number,
325
- stores: string[],
326
- attributes: Record<string, string[]>,
327
- inStock: boolean
328
- },
329
- results: Product[],
330
- sponsored: Product[],
331
- relatedSearches: string[],
332
- filterMetadata: {
333
- categories: { id: string, name: string, count: number }[],
334
- brands: { id: string, name: string, count: number }[],
335
- priceRange: { min: number, max: number },
336
- attributes: Record<string, { value: string, count: number }[]>
337
- },
338
- loading: boolean,
339
- error: string | null,
340
- pagination: { page: number, total: number, limit: number }
341
- }
342
- ```
343
- - **Actions:**
344
- - `searchProducts(query, filters, page)`
345
- - `applyFilter(filterType, value)`
346
- - `removeFilter(filterType, value)`
347
- - `clearFilters()`
348
- - `sortResults(sortType)`
349
- - **Routing:**
350
- - `/search?q=laptop&category=electronics&brand=dell&price_min=500&price_max=1000&page=1`
351
- - URL sync with Redux state
352
- - Browser back/forward support
353
-
354
- ### Multi-Store Logic
355
- - **Display Strategy:**
356
- - Show all stores with inventory for each product/variant
357
- - Group by product, display available stores with prices
358
- - Highlight best price across stores
359
- - **Price Aggregation:**
360
- - Show price range if varies across stores
361
- - Display individual store prices on hover/expand
362
- - **Stock Aggregation:**
363
- - Respect `store.show_all_products` config
364
- - If true: show all variants regardless of stock
365
- - If false: show only in-stock variants
366
- - **No Fallback:**
367
- - If store data missing, don't display the product for that store
368
- - No patching, no assumptions
369
-
370
- ### Sponsored Products Logic
371
- - **Display Strategy:**
372
- - Top 3-5 sponsored products at page top (clearly marked)
373
- - Intersperse 1 sponsored product every 10 organic results
374
- - Clear "Sponsored" badge on each
375
- - **Ranking Algorithm:**
376
- - Sort by `sponsored_rank` (admin-defined)
377
- - Filter by date range (active sponsorships only)
378
- - Respect store targeting (if `sponsored_store_id` is set)
379
- - **Analytics Tracking:**
380
- - Track impressions on render
381
- - Track clicks on product card click
382
- - Send to analytics service (async)
383
-
384
- ### Variant Display Logic
385
- - **Config-Driven:**
386
- - Fetch `store.show_all_products` from settings/config
387
- - Apply globally across search, category pages, product lists
388
- - **Implementation:**
389
- - If true: `SELECT * FROM products JOIN variants ...`
390
- - If false: `SELECT * FROM products JOIN variants ... WHERE stock > 0`
391
-
392
- ### Store Ratings Logic
393
- - **Default: Global Aggregation**
394
- - `AVG(ratings.rating) FROM ratings WHERE product_id = ?`
395
- - Display as product's overall rating
396
- - **Optional: Per-Store Filter**
397
- - `AVG(ratings.rating) FROM ratings WHERE product_id = ? AND store_id = ?`
398
- - Show when user filters by specific store
399
- - **A/B Testing:**
400
- - 50% users see global ratings
401
- - 50% users see per-store ratings (when filtered)
402
- - Track CTR, conversion, user engagement
403
- - Decide final implementation based on data
404
-
405
- ---
406
-
407
- ## Sponsored Products: Complete Workflow
408
-
409
- ### Amazon/Flipkart-Style Sponsorship Model
410
-
411
- #### Admin Workflow
412
- 1. **Product Selection:**
413
- - Admin navigates to Products list
414
- - Selects product(s) to sponsor
415
- - Clicks "Sponsor Product" button
416
-
417
- 2. **Sponsorship Configuration:**
418
- - **Duration:** Start date & end date (with timezone)
419
- - **Targeting:** Global or specific store(s)
420
- - **Ranking:** Priority/position (1-100, lower = higher priority)
421
- - **Budget:** (Optional, for future bidding system)
422
- - **Display Settings:**
423
- - Show in search results (yes/no)
424
- - Show in category pages (yes/no)
425
- - Show on homepage (yes/no)
426
-
427
- 3. **Approval & Activation:**
428
- - Preview sponsored product display
429
- - Confirm and activate
430
- - Sponsorship goes live at start_date
431
-
432
- 4. **Monitoring & Analytics:**
433
- - Real-time dashboard with:
434
- - Impressions (how many times displayed)
435
- - Clicks (how many users clicked)
436
- - CTR (click-through rate)
437
- - Conversions (if user purchased)
438
- - Spend (if budget-based)
439
- - Export reports (CSV, PDF)
440
-
441
- 5. **Management:**
442
- - Pause/resume sponsorship
443
- - Edit dates, ranking, targeting
444
- - End sponsorship early
445
- - Clone sponsorship for new campaign
446
-
447
- #### Database Schema
448
-
449
- **Migration: `add_sponsored_products_fields.js`**
450
- ```javascript
451
- // Add to products table
452
- table.boolean('is_sponsored').defaultTo(false).index();
453
- table.integer('sponsored_rank').nullable().index();
454
- table.timestamp('sponsored_start_date').nullable().index();
455
- table.timestamp('sponsored_end_date').nullable().index();
456
- table.uuid('sponsored_store_id').nullable().references('id').inTable('stores').index();
457
- table.decimal('sponsored_budget', 10, 2).nullable();
458
- table.decimal('sponsored_spent', 10, 2).defaultTo(0);
459
- table.integer('sponsored_impressions').defaultTo(0);
460
- table.integer('sponsored_clicks').defaultTo(0);
461
- table.boolean('sponsored_show_in_search').defaultTo(true);
462
- table.boolean('sponsored_show_in_category').defaultTo(true);
463
- table.boolean('sponsored_show_in_homepage').defaultTo(false);
464
- ```
465
-
466
- **New Table: `sponsored_product_logs`**
467
- ```javascript
468
- table.uuid('id').primary();
469
- table.uuid('product_id').references('id').inTable('products');
470
- table.enum('event_type', ['impression', 'click', 'conversion']);
471
- table.uuid('user_id').nullable().references('id').inTable('users');
472
- table.uuid('store_id').nullable().references('id').inTable('stores');
473
- table.string('search_query').nullable();
474
- table.string('page_url').nullable();
475
- table.jsonb('metadata').nullable(); // IP, user agent, etc.
476
- table.timestamps();
477
-
478
- // Indexes
479
- table.index(['product_id', 'event_type', 'created_at']);
480
- table.index(['product_id', 'store_id']);
481
- ```
482
-
483
- **New Table: `search_queries` (for related searches)**
484
- ```javascript
485
- table.uuid('id').primary();
486
- table.string('query').index();
487
- table.integer('search_count').defaultTo(0);
488
- table.integer('result_count').defaultTo(0);
489
- table.integer('click_count').defaultTo(0);
490
- table.decimal('avg_position_clicked', 5, 2).nullable();
491
- table.timestamps();
492
- ```
493
-
494
- **New Table: `related_searches`**
495
- ```javascript
496
- table.uuid('id').primary();
497
- table.uuid('search_query_id').references('id').inTable('search_queries');
498
- table.uuid('related_query_id').references('id').inTable('search_queries');
499
- table.decimal('relevance_score', 5, 4); // 0.0 to 1.0
500
- table.integer('click_through_count').defaultTo(0);
501
- table.timestamps();
502
-
503
- // Indexes
504
- table.index(['search_query_id', 'relevance_score']);
505
- ```
506
-
507
- #### API Endpoints
508
-
509
- **Admin API:**
510
- - `POST /api/admin/products/:id/sponsor` - Create sponsorship
511
- - `PUT /api/admin/products/:id/sponsor` - Update sponsorship
512
- - `DELETE /api/admin/products/:id/sponsor` - End sponsorship
513
- - `GET /api/admin/sponsored-products` - List all sponsored products
514
- - `GET /api/admin/sponsored-products/:id/analytics` - Get analytics
515
- - `POST /api/admin/sponsored-products/:id/pause` - Pause
516
- - `POST /api/admin/sponsored-products/:id/resume` - Resume
517
-
518
- **Customer API:**
519
- - `POST /api/analytics/sponsored/impression` - Track impression
520
- - `POST /api/analytics/sponsored/click` - Track click
521
-
522
- #### Frontend Components
523
-
524
- **Admin Panel:**
525
- - `SponsoredProductsPage` - List and manage
526
- - `SponsorProductModal` - Create/edit form
527
- - `SponsoredAnalyticsDashboard` - Charts and metrics
528
- - `SponsoredProductCard` - Preview card
529
-
530
- **Customer App:**
531
- - `SponsoredProductBadge` - "Sponsored" label
532
- - `SponsoredProductCard` - Highlighted card with tracking
533
- - Update `ProductCard` to handle sponsored flag
534
-
535
- #### Business Logic
536
-
537
- **Fetching Sponsored Products:**
538
- ```javascript
539
- const now = new Date();
540
- const sponsoredProducts = await Product.query()
541
- .where('is_sponsored', true)
542
- .where('sponsored_start_date', '<=', now)
543
- .where('sponsored_end_date', '>=', now)
544
- .where(builder => {
545
- builder
546
- .whereNull('sponsored_store_id') // Global
547
- .orWhere('sponsored_store_id', currentStoreId); // Or specific store
548
- })
549
- .where('sponsored_show_in_search', true)
550
- .orderBy('sponsored_rank', 'asc')
551
- .limit(20);
552
- ```
553
-
554
- **Ranking & Display:**
555
- - Top 3 sponsored: positions 1-3 in results (above organic)
556
- - Interspersed: 1 sponsored every 10 organic results
557
- - Clear visual distinction (border, badge, background color)
558
-
559
- **Analytics Tracking:**
560
- ```javascript
561
- // On product card render
562
- trackImpression(productId, userId, searchQuery, storeId);
563
-
564
- // On product card click
565
- trackClick(productId, userId, searchQuery, storeId, pageUrl);
566
-
567
- // On purchase
568
- trackConversion(productId, userId, orderId, revenue);
569
- ```
570
-
571
- #### Future Enhancements
572
- 1. **Bidding System:**
573
- - Stores/sellers bid for sponsorship slots
574
- - Automated ranking based on bid amount + relevance
575
- - Real-time budget tracking and pause when exhausted
576
-
577
- 2. **A/B Testing:**
578
- - Test different sponsored product positions
579
- - Test sponsored vs organic CTR
580
- - Optimize for user experience and revenue
581
-
582
- 3. **Advanced Analytics:**
583
- - Cohort analysis (users who clicked sponsored vs didn't)
584
- - Heatmaps (where users click most)
585
- - Conversion funnel (impression → click → add to cart → purchase)
586
-
587
- 4. **Machine Learning:**
588
- - Predict which products to sponsor based on trends
589
- - Personalized sponsored products per user
590
- - Optimize ranking algorithm based on historical data
591
- ---
592
-
593
- ## Store Ratings: Market Study & Recommendations
594
-
595
- ### Research Questions
596
- 1. **How do major marketplaces handle ratings in multi-vendor scenarios?**
597
- - Amazon: Shows seller rating separately from product rating
598
- - Flipkart: Shows overall product rating (aggregated across sellers)
599
- - eBay: Shows both product rating and seller rating side-by-side
600
- - Alibaba: Shows supplier rating prominently
601
-
602
- 2. **What's the user expectation?**
603
- - Users generally expect to see product quality ratings (global)
604
- - Users also want to know store/seller reliability (per-store)
605
- - Best practice: Show both, but emphasize product rating
606
-
607
- 3. **What drives conversion?**
608
- - Product rating is primary decision factor
609
- - Store rating is secondary (trust factor)
610
- - Combination of both maximizes trust and conversion
611
-
612
- ### Recommended Implementation
613
-
614
- **Primary Display: Global Product Rating**
615
- - Aggregate all ratings for a product across all stores
616
- - Display prominently on product card and detail page
617
- - Formula: `AVG(rating) FROM ratings WHERE product_id = ?`
618
-
619
- **Secondary Display: Per-Store Rating (on hover/expand)**
620
- - Show when user hovers over store name or price
621
- - Display in store selection dropdown
622
- - Formula: `AVG(rating) FROM ratings WHERE product_id = ? AND store_id = ?`
623
-
624
- **Tertiary Display: Store/Seller Rating (separate)**
625
- - Show store's overall rating (across all products)
626
- - Display on store profile page and in search results (small badge)
627
- - Formula: `AVG(rating) FROM ratings WHERE store_id = ?`
628
-
629
- ### A/B Testing Plan
630
-
631
- **Test Groups:**
632
- - **Group A (50%):** Global product rating only
633
- - **Group B (50%):** Global product rating + per-store rating (on hover)
634
-
635
- **Metrics to Track:**
636
- - CTR (click-through rate)
637
- - Conversion rate
638
- - Time to purchase decision
639
- - Cart abandonment rate
640
- - User feedback/surveys
641
-
642
- **Duration:** 4 weeks
643
-
644
- **Success Criteria:**
645
- - If Group B shows 5%+ higher conversion: implement per-store ratings
646
- - If no significant difference: stick with global ratings (simpler UX)
647
-
648
- ### Implementation Timeline
649
-
650
- **Week 1-2: Database & Backend**
651
- - Implement search API with filters and sponsored products
652
- - Add global rating aggregation
653
- - Add per-store rating query (optional)
654
-
655
- **Week 3-4: Frontend - SRP**
656
- - Build search results page with dynamic filters
657
- - Implement product cards with global ratings
658
- - Add A/B test logic for per-store ratings
659
-
660
- **Week 5-6: Admin Panel**
661
- - Build sponsored products management UI
662
- - Build analytics dashboard
663
- - Implement sponsorship workflow
664
-
665
- **Week 7-8: Testing & Analytics**
666
- - Run A/B test for store ratings
667
- - Monitor sponsored products performance
668
- - Collect user feedback
669
-
670
- **Week 9-10: Optimization**
671
- - Analyze A/B test results
672
- - Optimize search query performance
673
- - Refine UI based on user feedback
674
-
675
- ---
676
-
677
- ## Critical Success Factors
678
-
679
- 1. **Performance:** Search must be fast (< 200ms)
680
- 2. **Accuracy:** Filters must reflect actual data, no patching
681
- 3. **Scalability:** Handle 10k+ products, 100+ concurrent users
682
- 4. **User Experience:** Intuitive filters, clear sponsored product marking
683
- 5. **Analytics:** Robust tracking for data-driven decisions
684
- 6. **Maintainability:** Clean code, well-documented, reusable components
685
-
686
- ---
687
-
688
- *Prepared by GitHub Copilot, 21 December 2025.*