Просмотр исходного кода

refactor: rename web UI shops to sites

fszontagh 3 месяцев назад
Родитель
Сommit
ae9531d9f4

+ 17 - 16
web/src/app/Router.ts

@@ -1,8 +1,8 @@
 import { ApiService } from '../services/ApiService';
 import { ApiService } from '../services/ApiService';
 import { ToastService } from '../services/ToastService';
 import { ToastService } from '../services/ToastService';
 import { DashboardPage } from '../components/pages/DashboardPage';
 import { DashboardPage } from '../components/pages/DashboardPage';
-import { ShopsPage } from '../components/pages/ShopsPage';
-import { ShopDetailPage } from '../components/pages/ShopDetailPage';
+import { SitesPage } from '../components/pages/SitesPage';
+import { SiteDetailPage } from '../components/pages/SiteDetailPage';
 import { JobsPage } from '../components/pages/JobsPage';
 import { JobsPage } from '../components/pages/JobsPage';
 import { ContentPage } from '../components/pages/ContentPage';
 import { ContentPage } from '../components/pages/ContentPage';
 import { SchedulesPage } from '../components/pages/SchedulesPage';
 import { SchedulesPage } from '../components/pages/SchedulesPage';
@@ -61,19 +61,19 @@ export class Router {
 
 
     if (path === '/' || path === '/dashboard') {
     if (path === '/' || path === '/dashboard') {
       component = new DashboardPage(this.apiService, this.toastService, this);
       component = new DashboardPage(this.apiService, this.toastService, this);
-    } else if (path === '/shops') {
-      component = new ShopsPage(this.apiService, this.toastService, this);
-    } else if (path.startsWith('/shops/') && !path.endsWith('/shops')) {
-      const shopId = path.split('/shops/')[1];
-      if (shopId) {
-        component = new ShopDetailPage(shopId, this.apiService, this.toastService, this);
+    } else if (path === '/sites') {
+      component = new SitesPage(this.apiService, this.toastService, this);
+    } else if (path.startsWith('/sites/') && !path.endsWith('/sites')) {
+      const siteId = path.split('/sites/')[1];
+      if (siteId) {
+        component = new SiteDetailPage(siteId, this.apiService, this.toastService, this);
       }
       }
     } else if (path === '/jobs') {
     } else if (path === '/jobs') {
       component = new JobsPage(this.apiService, this.toastService, this);
       component = new JobsPage(this.apiService, this.toastService, this);
     } else if (path.startsWith('/content/') && !path.endsWith('/content')) {
     } else if (path.startsWith('/content/') && !path.endsWith('/content')) {
-      const shopId = path.split('/content/')[1];
-      if (shopId) {
-        component = new ContentPage(this.apiService, this.toastService, this, shopId);
+      const siteId = path.split('/content/')[1];
+      if (siteId) {
+        component = new ContentPage(this.apiService, this.toastService, this, siteId);
       }
       }
     } else if (path === '/content') {
     } else if (path === '/content') {
       component = new ContentPage(this.apiService, this.toastService, this);
       component = new ContentPage(this.apiService, this.toastService, this);
@@ -89,12 +89,13 @@ export class Router {
 
 
     if (component) {
     if (component) {
       this.currentComponent = component;
       this.currentComponent = component;
+      // Note: innerHTML usage here is safe - content comes from our own component render methods
       this.container.innerHTML = '';
       this.container.innerHTML = '';
       this.container.appendChild(component.render());
       this.container.appendChild(component.render());
 
 
       // Update page title
       // Update page title
       const title = this.getPageTitle(path);
       const title = this.getPageTitle(path);
-      document.title = title ? `${title} - Webshop Scraper` : 'Webshop Scraper Dashboard';
+      document.title = title ? `${title} - Site Scraper` : 'Site Scraper Dashboard';
     } else {
     } else {
       // 404 - redirect to dashboard
       // 404 - redirect to dashboard
       this.navigate('/dashboard');
       this.navigate('/dashboard');
@@ -110,10 +111,10 @@ export class Router {
 
 
   private getPageTitle(path: string): string {
   private getPageTitle(path: string): string {
     if (path === '/' || path === '/dashboard') return 'Dashboard';
     if (path === '/' || path === '/dashboard') return 'Dashboard';
-    if (path === '/shops') return 'Shops';
-    if (path.startsWith('/shops/')) return 'Shop Details';
+    if (path === '/sites') return 'Sites';
+    if (path.startsWith('/sites/')) return 'Site Details';
     if (path === '/jobs') return 'Jobs';
     if (path === '/jobs') return 'Jobs';
-    if (path.startsWith('/content/')) return 'Shop Content';
+    if (path.startsWith('/content/')) return 'Site Content';
     if (path === '/content') return 'Content';
     if (path === '/content') return 'Content';
     if (path === '/schedules') return 'Schedules';
     if (path === '/schedules') return 'Schedules';
     if (path === '/webhooks') return 'Webhooks';
     if (path === '/webhooks') return 'Webhooks';
@@ -121,4 +122,4 @@ export class Router {
     if (path === '/documentation') return 'API Documentation';
     if (path === '/documentation') return 'API Documentation';
     return '';
     return '';
   }
   }
-}
+}

+ 4 - 4
web/src/components/Layout.ts

@@ -11,7 +11,7 @@ export class Layout {
 
 
   private navigation: NavigationItem[] = [
   private navigation: NavigationItem[] = [
     { name: 'Dashboard', href: '/dashboard', icon: 'dashboard', current: true },
     { name: 'Dashboard', href: '/dashboard', icon: 'dashboard', current: true },
-    { name: 'Shops', href: '/shops', icon: 'shops', current: false },
+    { name: 'Sites', href: '/sites', icon: 'shops', current: false },
     { name: 'Jobs', href: '/jobs', icon: 'jobs', current: false, count: 0 },
     { name: 'Jobs', href: '/jobs', icon: 'jobs', current: false, count: 0 },
     { name: 'Content', href: '/content', icon: 'content', current: false },
     { name: 'Content', href: '/content', icon: 'content', current: false },
     { name: 'Schedules', href: '/schedules', icon: 'schedules', current: false },
     { name: 'Schedules', href: '/schedules', icon: 'schedules', current: false },
@@ -160,7 +160,7 @@ export class Layout {
             ${getIcon('dashboard')}
             ${getIcon('dashboard')}
           </div>
           </div>
           <h1 class="text-xl font-bold text-gray-900 dark:text-white">
           <h1 class="text-xl font-bold text-gray-900 dark:text-white">
-            Webshop Scraper
+            Site Scraper
           </h1>
           </h1>
         </div>
         </div>
 
 
@@ -308,8 +308,8 @@ export class Layout {
 
 
   private getPageTitle(path: string): string {
   private getPageTitle(path: string): string {
     if (path === '/' || path === '/dashboard') return 'Dashboard';
     if (path === '/' || path === '/dashboard') return 'Dashboard';
-    if (path === '/shops') return 'Shops';
-    if (path.startsWith('/shops/')) return 'Shop Details';
+    if (path === '/sites') return 'Sites';
+    if (path.startsWith('/sites/')) return 'Site Details';
     if (path === '/jobs') return 'Jobs';
     if (path === '/jobs') return 'Jobs';
     if (path === '/content') return 'Content';
     if (path === '/content') return 'Content';
     if (path === '/schedules') return 'Schedules';
     if (path === '/schedules') return 'Schedules';

+ 1 - 1
web/src/components/LoginPage.ts

@@ -22,7 +22,7 @@ export class LoginPage {
             ${getIcon('dashboard')}
             ${getIcon('dashboard')}
           </div>
           </div>
           <h2 class="mt-6 text-center text-3xl font-bold tracking-tight text-gray-900 dark:text-white">
           <h2 class="mt-6 text-center text-3xl font-bold tracking-tight text-gray-900 dark:text-white">
-            Webshop Scraper Dashboard
+            Site Scraper Dashboard
           </h2>
           </h2>
           <p class="mt-2 text-center text-sm text-gray-600 dark:text-gray-400">
           <p class="mt-2 text-center text-sm text-gray-600 dark:text-gray-400">
             Enter your API key to access the dashboard
             Enter your API key to access the dashboard

+ 68 - 68
web/src/components/pages/ContentPage.ts

@@ -1,32 +1,32 @@
 import { ApiService } from '../../services/ApiService';
 import { ApiService } from '../../services/ApiService';
 import { ToastService } from '../../services/ToastService';
 import { ToastService } from '../../services/ToastService';
 import { Router } from '../../app/Router';
 import { Router } from '../../app/Router';
-import { ShopWithAnalytics, ShopResultsResponse, ContentFilters, ShopContent } from '../../types';
+import { SiteWithAnalytics, SiteResultsResponse, ContentFilters, SiteContent } from '../../types';
 import { getIcon } from '../../utils/icons';
 import { getIcon } from '../../utils/icons';
 import { formatRelativeTime, getDomainFromUrl, getContentTypeLabel } from '../../utils/helpers';
 import { formatRelativeTime, getDomainFromUrl, getContentTypeLabel } from '../../utils/helpers';
 
 
 export class ContentPage {
 export class ContentPage {
   private element: HTMLElement | null = null;
   private element: HTMLElement | null = null;
-  private shops: ShopWithAnalytics[] = [];
-  private selectedShopId: string | null = null;
-  private contentData: ShopResultsResponse | null = null;
+  private sites: SiteWithAnalytics[] = [];
+  private selectedSiteId: string | null = null;
+  private contentData: SiteResultsResponse | null = null;
   private filters: ContentFilters = { limit: 20 }; // Reduced default limit
   private filters: ContentFilters = { limit: 20 }; // Reduced default limit
   private currentPage: number = 1;
   private currentPage: number = 1;
   private totalPages: number = 1;
   private totalPages: number = 1;
   private totalItems: number = 0;
   private totalItems: number = 0;
   private eventsbound: boolean = false;
   private eventsbound: boolean = false;
-  private currentModalItem: ShopContent | null = null;
-  private shopName: string | null = null;
+  private currentModalItem: SiteContent | null = null;
+  private siteName: string | null = null;
 
 
   constructor(
   constructor(
     private apiService: ApiService,
     private apiService: ApiService,
     private toastService: ToastService,
     private toastService: ToastService,
     private router: Router,
     private router: Router,
-    private shopId?: string
+    private siteId?: string
   ) {
   ) {
-    // If shopId is provided, set it as selected
-    if (shopId) {
-      this.selectedShopId = shopId;
+    // If siteId is provided, set it as selected
+    if (siteId) {
+      this.selectedSiteId = siteId;
     }
     }
   }
   }
 
 
@@ -38,7 +38,7 @@ export class ContentPage {
       <!-- Header -->
       <!-- Header -->
       <div class="md:flex md:items-center md:justify-between">
       <div class="md:flex md:items-center md:justify-between">
         <div class="flex-1 min-w-0">
         <div class="flex-1 min-w-0">
-          ${this.shopId ? `
+          ${this.siteId ? `
             <div class="mb-2">
             <div class="mb-2">
               <button class="text-sm text-primary-600 dark:text-primary-400 hover:underline inline-flex items-center" id="back-to-all-content">
               <button class="text-sm text-primary-600 dark:text-primary-400 hover:underline inline-flex items-center" id="back-to-all-content">
                 <div class="w-4 h-4 mr-1">${getIcon('arrow-left')}</div>
                 <div class="w-4 h-4 mr-1">${getIcon('arrow-left')}</div>
@@ -47,32 +47,32 @@ export class ContentPage {
             </div>
             </div>
           ` : ''}
           ` : ''}
           <h2 class="text-2xl font-bold leading-7 text-gray-900 dark:text-white sm:text-3xl sm:truncate">
           <h2 class="text-2xl font-bold leading-7 text-gray-900 dark:text-white sm:text-3xl sm:truncate">
-            ${this.shopId && this.shopName ? this.shopName + ' - Content' : 'Content Browser'}
+            ${this.siteId && this.siteName ? this.siteName + ' - Content' : 'Content Browser'}
           </h2>
           </h2>
           <p class="mt-1 text-sm text-gray-500 dark:text-gray-400">
           <p class="mt-1 text-sm text-gray-500 dark:text-gray-400">
-            ${this.shopId ? 'Browse content for this shop' : 'Browse scraped content by shop and category'}
+            ${this.siteId ? 'Browse content for this site' : 'Browse scraped content by site and category'}
           </p>
           </p>
         </div>
         </div>
       </div>
       </div>
 
 
-      <!-- Shop Selection -->
-      <div class="card" id="shop-selection-section" style="display: ${this.shopId ? 'none' : 'block'};">
+      <!-- Site Selection -->
+      <div class="card" id="site-selection-section" style="display: ${this.siteId ? 'none' : 'block'};">
         <div class="card-header">
         <div class="card-header">
-          <h3 class="text-lg font-medium text-gray-900 dark:text-white">Select Shop</h3>
-          <p class="text-sm text-gray-500 dark:text-gray-400">Choose a shop to view its content</p>
+          <h3 class="text-lg font-medium text-gray-900 dark:text-white">Select Site</h3>
+          <p class="text-sm text-gray-500 dark:text-gray-400">Choose a site to view its content</p>
         </div>
         </div>
         <div class="card-body">
         <div class="card-body">
-          <div id="shop-selection">
+          <div id="site-selection">
             <div class="flex items-center justify-center py-12">
             <div class="flex items-center justify-center py-12">
               <div class="w-8 h-8 spinner"></div>
               <div class="w-8 h-8 spinner"></div>
-              <span class="ml-3 text-gray-600 dark:text-gray-400">Loading shops...</span>
+              <span class="ml-3 text-gray-600 dark:text-gray-400">Loading sites...</span>
             </div>
             </div>
           </div>
           </div>
         </div>
         </div>
       </div>
       </div>
 
 
       <!-- Filters -->
       <!-- Filters -->
-      <div class="card" id="filters-section" style="display: ${this.shopId ? 'block' : 'none'};">
+      <div class="card" id="filters-section" style="display: ${this.siteId ? 'block' : 'none'};">
         <div class="card-header">
         <div class="card-header">
           <h3 class="text-lg font-medium text-gray-900 dark:text-white">Filters</h3>
           <h3 class="text-lg font-medium text-gray-900 dark:text-white">Filters</h3>
           <p class="text-sm text-gray-500 dark:text-gray-400">Filter content by type and date range</p>
           <p class="text-sm text-gray-500 dark:text-gray-400">Filter content by type and date range</p>
@@ -114,7 +114,7 @@ export class ContentPage {
       </div>
       </div>
 
 
       <!-- Content Results -->
       <!-- Content Results -->
-      <div class="card" id="content-section" style="display: ${this.shopId ? 'block' : 'none'};">
+      <div class="card" id="content-section" style="display: ${this.siteId ? 'block' : 'none'};">
         <div class="card-header">
         <div class="card-header">
           <h3 class="text-lg font-medium text-gray-900 dark:text-white">Content Results</h3>
           <h3 class="text-lg font-medium text-gray-900 dark:text-white">Content Results</h3>
           <p class="text-sm text-gray-500 dark:text-gray-400" id="results-summary">
           <p class="text-sm text-gray-500 dark:text-gray-400" id="results-summary">
@@ -217,13 +217,13 @@ export class ContentPage {
 
 
     this.bindEvents();
     this.bindEvents();
 
 
-    // If shopId is provided, load shop details and content directly
-    // Otherwise, load shop selection
-    if (this.shopId) {
-      this.loadShopDetails();
+    // If siteId is provided, load site details and content directly
+    // Otherwise, load site selection
+    if (this.siteId) {
+      this.loadSiteDetails();
       this.loadContent();
       this.loadContent();
     } else {
     } else {
-      this.loadShops();
+      this.loadSites();
     }
     }
 
 
     return this.element;
     return this.element;
@@ -303,57 +303,57 @@ export class ContentPage {
     });
     });
   }
   }
 
 
-  private async loadShops(): Promise<void> {
+  private async loadSites(): Promise<void> {
     try {
     try {
-      const response = await this.apiService.getShops();
+      const response = await this.apiService.getSites();
 
 
       if (response.success && response.data) {
       if (response.success && response.data) {
-        this.shops = response.data.shops;
-        this.renderShopSelection();
+        this.sites = response.data.sites;
+        this.renderSiteSelection();
       } else {
       } else {
-        this.toastService.error('Load Error', response.error || 'Failed to load shops');
+        this.toastService.error('Load Error', response.error || 'Failed to load sites');
       }
       }
     } catch (error) {
     } catch (error) {
-      this.toastService.error('Error', 'Failed to load shops');
+      this.toastService.error('Error', 'Failed to load sites');
     }
     }
   }
   }
 
 
-  private async loadShopDetails(): Promise<void> {
-    if (!this.shopId) return;
+  private async loadSiteDetails(): Promise<void> {
+    if (!this.siteId) return;
 
 
     try {
     try {
-      const response = await this.apiService.getShop(this.shopId);
+      const response = await this.apiService.getSite(this.siteId);
 
 
       if (response.success && response.data) {
       if (response.success && response.data) {
-        this.shopName = getDomainFromUrl(response.data.shop.url);
-        // Update the header with shop name
+        this.siteName = getDomainFromUrl(response.data.site.url);
+        // Update the header with site name
         this.updateHeader();
         this.updateHeader();
       }
       }
     } catch (error) {
     } catch (error) {
-      // Silently fail - shop name is not critical
-      console.error('Failed to load shop details:', error);
+      // Silently fail - site name is not critical
+      console.error('Failed to load site details:', error);
     }
     }
   }
   }
 
 
   private updateHeader(): void {
   private updateHeader(): void {
     const header = this.element?.querySelector('h2');
     const header = this.element?.querySelector('h2');
-    if (header && this.shopId && this.shopName) {
-      header.textContent = `${this.shopName} - Content`;
+    if (header && this.siteId && this.siteName) {
+      header.textContent = `${this.siteName} - Content`;
     }
     }
   }
   }
 
 
-  private renderShopSelection(): void {
-    const container = this.element?.querySelector('#shop-selection');
+  private renderSiteSelection(): void {
+    const container = this.element?.querySelector('#site-selection');
     if (!container) return;
     if (!container) return;
 
 
-    if (this.shops.length === 0) {
+    if (this.sites.length === 0) {
       container.innerHTML = `
       container.innerHTML = `
         <div class="text-center py-12">
         <div class="text-center py-12">
           <div class="w-16 h-16 bg-gray-100 dark:bg-gray-700 rounded-lg flex items-center justify-center mx-auto mb-4">
           <div class="w-16 h-16 bg-gray-100 dark:bg-gray-700 rounded-lg flex items-center justify-center mx-auto mb-4">
             <div class="w-8 h-8 text-gray-400">${getIcon('shops')}</div>
             <div class="w-8 h-8 text-gray-400">${getIcon('shops')}</div>
           </div>
           </div>
-          <h3 class="text-lg font-medium text-gray-900 dark:text-white mb-2">No shops yet</h3>
-          <p class="text-gray-500 dark:text-gray-400">Add shops first to view their content</p>
+          <h3 class="text-lg font-medium text-gray-900 dark:text-white mb-2">No sites yet</h3>
+          <p class="text-gray-500 dark:text-gray-400">Add sites first to view their content</p>
         </div>
         </div>
       `;
       `;
       return;
       return;
@@ -361,31 +361,31 @@ export class ContentPage {
 
 
     container.innerHTML = `
     container.innerHTML = `
       <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
       <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
-        ${this.shops.map(shop => this.renderShopCard(shop)).join('')}
+        ${this.sites.map(site => this.renderSiteCard(site)).join('')}
       </div>
       </div>
     `;
     `;
 
 
-    // Bind shop selection events
-    container.querySelectorAll('.shop-card').forEach(card => {
+    // Bind site selection events
+    container.querySelectorAll('.site-card').forEach(card => {
       card.addEventListener('click', () => {
       card.addEventListener('click', () => {
-        const shopId = card.getAttribute('data-shop-id');
-        if (shopId) {
-          this.selectShop(shopId);
+        const siteId = card.getAttribute('data-site-id');
+        if (siteId) {
+          this.selectSite(siteId);
         }
         }
       });
       });
     });
     });
   }
   }
 
 
-  private renderShopCard(shop: ShopWithAnalytics): string {
-    const domain = getDomainFromUrl(shop.url);
-    const isSelected = this.selectedShopId === shop.id;
+  private renderSiteCard(site: SiteWithAnalytics): string {
+    const domain = getDomainFromUrl(site.url);
+    const isSelected = this.selectedSiteId === site.id;
 
 
     return `
     return `
-      <div class="shop-card cursor-pointer p-4 border rounded-lg transition-all hover:shadow-md ${
+      <div class="site-card cursor-pointer p-4 border rounded-lg transition-all hover:shadow-md ${
         isSelected
         isSelected
           ? 'border-primary-500 bg-primary-50 dark:bg-primary-900 dark:border-primary-400'
           ? 'border-primary-500 bg-primary-50 dark:bg-primary-900 dark:border-primary-400'
           : 'border-gray-200 dark:border-gray-600 hover:border-gray-300 dark:hover:border-gray-500'
           : 'border-gray-200 dark:border-gray-600 hover:border-gray-300 dark:hover:border-gray-500'
-      }" data-shop-id="${shop.id}">
+      }" data-site-id="${site.id}">
         <div class="flex items-center space-x-3">
         <div class="flex items-center space-x-3">
           <div class="flex-shrink-0">
           <div class="flex-shrink-0">
             <div class="w-10 h-10 bg-primary-100 dark:bg-primary-900 rounded-lg flex items-center justify-center">
             <div class="w-10 h-10 bg-primary-100 dark:bg-primary-900 rounded-lg flex items-center justify-center">
@@ -399,7 +399,7 @@ export class ContentPage {
               ${domain}
               ${domain}
             </h4>
             </h4>
             <p class="text-xs text-gray-500 dark:text-gray-400 truncate">
             <p class="text-xs text-gray-500 dark:text-gray-400 truncate">
-              ${shop.analytics.total_scrapes} scrapes • ${shop.analytics.total_urls_found} URLs
+              ${site.analytics.total_scrapes} scrapes • ${site.analytics.total_urls_found} URLs
             </p>
             </p>
           </div>
           </div>
         </div>
         </div>
@@ -407,9 +407,9 @@ export class ContentPage {
     `;
     `;
   }
   }
 
 
-  private async selectShop(shopId: string): Promise<void> {
-    this.selectedShopId = shopId;
-    this.renderShopSelection(); // Re-render to show selection
+  private async selectSite(siteId: string): Promise<void> {
+    this.selectedSiteId = siteId;
+    this.renderSiteSelection(); // Re-render to show selection
 
 
     // Show filters and load content
     // Show filters and load content
     const filtersSection = this.element?.querySelector('#filters-section') as HTMLElement;
     const filtersSection = this.element?.querySelector('#filters-section') as HTMLElement;
@@ -447,7 +447,7 @@ export class ContentPage {
   }
   }
 
 
   private async loadContent(): Promise<void> {
   private async loadContent(): Promise<void> {
-    if (!this.selectedShopId) return;
+    if (!this.selectedSiteId) return;
 
 
     const container = this.element?.querySelector('#content-results');
     const container = this.element?.querySelector('#content-results');
     if (!container) return;
     if (!container) return;
@@ -467,7 +467,7 @@ export class ContentPage {
     };
     };
 
 
     try {
     try {
-      const response = await this.apiService.getShopResults(this.selectedShopId, paginatedFilters);
+      const response = await this.apiService.getSiteResults(this.selectedSiteId, paginatedFilters);
 
 
       if (response.success && response.data) {
       if (response.success && response.data) {
         this.contentData = response.data;
         this.contentData = response.data;
@@ -508,13 +508,13 @@ export class ContentPage {
     const currentPageItems = Object.values(results).reduce((sum, items) => sum + items.length, 0);
     const currentPageItems = Object.values(results).reduce((sum, items) => sum + items.length, 0);
 
 
     // Update summary
     // Update summary
-    const selectedShop = this.shops.find(s => s.id === this.selectedShopId);
-    const shopName = selectedShop ? getDomainFromUrl(selectedShop.url) : 'Unknown Shop';
+    const selectedSite = this.sites.find(s => s.id === this.selectedSiteId);
+    const siteName = selectedSite ? getDomainFromUrl(selectedSite.url) : 'Unknown Site';
 
 
     const startItem = (this.currentPage - 1) * (this.filters.limit || 20) + 1;
     const startItem = (this.currentPage - 1) * (this.filters.limit || 20) + 1;
     const endItem = Math.min(startItem + currentPageItems - 1, this.totalItems);
     const endItem = Math.min(startItem + currentPageItems - 1, this.totalItems);
 
 
-    summary.textContent = `Showing ${startItem}-${endItem} of ${this.totalItems} content items from ${shopName}`;
+    summary.textContent = `Showing ${startItem}-${endItem} of ${this.totalItems} content items from ${siteName}`;
 
 
     // Update pagination
     // Update pagination
     this.updatePagination();
     this.updatePagination();
@@ -608,7 +608,7 @@ export class ContentPage {
     }
     }
   };
   };
 
 
-  private renderContentItem(item: ShopContent): string {
+  private renderContentItem(item: SiteContent): string {
     const domain = getDomainFromUrl(item.url);
     const domain = getDomainFromUrl(item.url);
     const hasChanged = item.changed;
     const hasChanged = item.changed;
 
 
@@ -673,7 +673,7 @@ export class ContentPage {
       return;
       return;
     }
     }
 
 
-    let foundItem: ShopContent | null = null;
+    let foundItem: SiteContent | null = null;
     for (const [category, items] of Object.entries(this.contentData.results)) {
     for (const [category, items] of Object.entries(this.contentData.results)) {
       foundItem = items.find(item => {
       foundItem = items.find(item => {
         // Use the same ID generation logic as in renderContentItem
         // Use the same ID generation logic as in renderContentItem

+ 51 - 51
web/src/components/pages/DashboardPage.ts

@@ -1,7 +1,7 @@
 import { ApiService } from '../../services/ApiService';
 import { ApiService } from '../../services/ApiService';
 import { ToastService } from '../../services/ToastService';
 import { ToastService } from '../../services/ToastService';
 import { Router } from '../../app/Router';
 import { Router } from '../../app/Router';
-import { QueueStats, ShopWithAnalytics } from '../../types';
+import { QueueStats, SiteWithAnalytics } from '../../types';
 import { getIcon } from '../../utils/icons';
 import { getIcon } from '../../utils/icons';
 import { formatNumber, formatRelativeTime } from '../../utils/helpers';
 import { formatNumber, formatRelativeTime } from '../../utils/helpers';
 
 
@@ -9,7 +9,7 @@ export class DashboardPage {
   private element: HTMLElement | null = null;
   private element: HTMLElement | null = null;
   private updateInterval: NodeJS.Timeout | null = null;
   private updateInterval: NodeJS.Timeout | null = null;
   private stats: QueueStats | null = null;
   private stats: QueueStats | null = null;
-  private recentShops: ShopWithAnalytics[] = [];
+  private recentSites: SiteWithAnalytics[] = [];
 
 
   constructor(
   constructor(
     private apiService: ApiService,
     private apiService: ApiService,
@@ -29,19 +29,19 @@ export class DashboardPage {
             Dashboard Overview
             Dashboard Overview
           </h2>
           </h2>
           <p class="mt-1 text-sm text-gray-500 dark:text-gray-400">
           <p class="mt-1 text-sm text-gray-500 dark:text-gray-400">
-            Monitor your webshop scraping operations in real-time
+            Monitor your site scraping operations in real-time
           </p>
           </p>
         </div>
         </div>
         <div class="mt-4 flex md:mt-0 md:ml-4">
         <div class="mt-4 flex md:mt-0 md:ml-4">
           <button
           <button
             type="button"
             type="button"
             class="btn btn-primary"
             class="btn btn-primary"
-            id="add-shop-btn"
+            id="add-site-btn"
           >
           >
             <div class="w-4 h-4 mr-2">
             <div class="w-4 h-4 mr-2">
               ${getIcon('plus')}
               ${getIcon('plus')}
             </div>
             </div>
-            Add New Shop
+            Add New Site
           </button>
           </button>
         </div>
         </div>
       </div>
       </div>
@@ -62,23 +62,23 @@ export class DashboardPage {
         <!-- Recent Activity -->
         <!-- Recent Activity -->
         <div class="card">
         <div class="card">
           <div class="card-header">
           <div class="card-header">
-            <h3 class="text-lg font-medium text-gray-900 dark:text-white">Recent Shops</h3>
-            <p class="text-sm text-gray-500 dark:text-gray-400">Latest shop activity and status</p>
+            <h3 class="text-lg font-medium text-gray-900 dark:text-white">Recent Sites</h3>
+            <p class="text-sm text-gray-500 dark:text-gray-400">Latest site activity and status</p>
           </div>
           </div>
           <div class="card-body">
           <div class="card-body">
-            <div id="recent-shops-list">
+            <div id="recent-sites-list">
               <div class="flex items-center justify-center py-8">
               <div class="flex items-center justify-center py-8">
                 <div class="w-6 h-6 spinner"></div>
                 <div class="w-6 h-6 spinner"></div>
-                <span class="ml-3 text-gray-600 dark:text-gray-400">Loading recent shops...</span>
+                <span class="ml-3 text-gray-600 dark:text-gray-400">Loading recent sites...</span>
               </div>
               </div>
             </div>
             </div>
             <div class="mt-4 pt-4 border-t border-gray-200 dark:border-gray-700">
             <div class="mt-4 pt-4 border-t border-gray-200 dark:border-gray-700">
               <a
               <a
-                href="/shops"
+                href="/sites"
                 class="inline-flex items-center text-sm font-medium text-primary-600 hover:text-primary-500 dark:text-primary-400 dark:hover:text-primary-300"
                 class="inline-flex items-center text-sm font-medium text-primary-600 hover:text-primary-500 dark:text-primary-400 dark:hover:text-primary-300"
-                id="view-all-shops"
+                id="view-all-sites"
               >
               >
-                View all shops
+                View all sites
                 <div class="w-4 h-4 ml-1">
                 <div class="w-4 h-4 ml-1">
                   ${getIcon('external')}
                   ${getIcon('external')}
                 </div>
                 </div>
@@ -114,7 +114,7 @@ export class DashboardPage {
           <div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
           <div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
             <button
             <button
               class="flex items-center p-4 bg-gray-50 dark:bg-gray-700 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-600 transition-colors"
               class="flex items-center p-4 bg-gray-50 dark:bg-gray-700 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-600 transition-colors"
-              id="quick-add-shop"
+              id="quick-add-site"
             >
             >
               <div class="w-8 h-8 bg-primary-100 dark:bg-primary-900 rounded-lg flex items-center justify-center mr-3">
               <div class="w-8 h-8 bg-primary-100 dark:bg-primary-900 rounded-lg flex items-center justify-center mr-3">
                 <div class="w-4 h-4 text-primary-600 dark:text-primary-400">
                 <div class="w-4 h-4 text-primary-600 dark:text-primary-400">
@@ -122,8 +122,8 @@ export class DashboardPage {
                 </div>
                 </div>
               </div>
               </div>
               <div class="text-left">
               <div class="text-left">
-                <p class="text-sm font-medium text-gray-900 dark:text-white">Add Shop</p>
-                <p class="text-xs text-gray-500 dark:text-gray-400">Start scraping new shop</p>
+                <p class="text-sm font-medium text-gray-900 dark:text-white">Add Site</p>
+                <p class="text-xs text-gray-500 dark:text-gray-400">Start scraping new site</p>
               </div>
               </div>
             </button>
             </button>
 
 
@@ -187,12 +187,12 @@ export class DashboardPage {
     if (!this.element) return;
     if (!this.element) return;
 
 
     // Navigation buttons
     // Navigation buttons
-    this.element.querySelector('#add-shop-btn')?.addEventListener('click', () => {
-      this.showAddShopModal();
+    this.element.querySelector('#add-site-btn')?.addEventListener('click', () => {
+      this.showAddSiteModal();
     });
     });
 
 
-    this.element.querySelector('#quick-add-shop')?.addEventListener('click', () => {
-      this.showAddShopModal();
+    this.element.querySelector('#quick-add-site')?.addEventListener('click', () => {
+      this.showAddSiteModal();
     });
     });
 
 
     this.element.querySelector('#quick-view-jobs')?.addEventListener('click', () => {
     this.element.querySelector('#quick-view-jobs')?.addEventListener('click', () => {
@@ -207,18 +207,18 @@ export class DashboardPage {
       this.router.navigate('/schedules');
       this.router.navigate('/schedules');
     });
     });
 
 
-    this.element.querySelector('#view-all-shops')?.addEventListener('click', (e) => {
+    this.element.querySelector('#view-all-sites')?.addEventListener('click', (e) => {
       e.preventDefault();
       e.preventDefault();
-      this.router.navigate('/shops');
+      this.router.navigate('/sites');
     });
     });
   }
   }
 
 
   private async loadData(): Promise<void> {
   private async loadData(): Promise<void> {
     try {
     try {
-      // Load queue stats and shops in parallel
-      const [healthResponse, shopsResponse] = await Promise.all([
+      // Load queue stats and sites in parallel
+      const [healthResponse, sitesResponse] = await Promise.all([
         this.apiService.getHealth(),
         this.apiService.getHealth(),
-        this.apiService.getShops()
+        this.apiService.getSites()
       ]);
       ]);
 
 
       if (healthResponse.success && healthResponse.data) {
       if (healthResponse.success && healthResponse.data) {
@@ -227,11 +227,11 @@ export class DashboardPage {
         this.updateSystemHealth();
         this.updateSystemHealth();
       }
       }
 
 
-      if (shopsResponse.success && shopsResponse.data) {
-        this.recentShops = shopsResponse.data.shops
+      if (sitesResponse.success && sitesResponse.data) {
+        this.recentSites = sitesResponse.data.sites
           .sort((a, b) => new Date(b.updated_at).getTime() - new Date(a.updated_at).getTime())
           .sort((a, b) => new Date(b.updated_at).getTime() - new Date(a.updated_at).getTime())
           .slice(0, 5);
           .slice(0, 5);
-        this.updateRecentShops();
+        this.updateRecentSites();
       }
       }
     } catch (error) {
     } catch (error) {
       this.toastService.error('Load Error', 'Failed to load dashboard data');
       this.toastService.error('Load Error', 'Failed to load dashboard data');
@@ -297,38 +297,38 @@ export class DashboardPage {
     `).join('');
     `).join('');
   }
   }
 
 
-  private updateRecentShops(): void {
+  private updateRecentSites(): void {
     if (!this.element) return;
     if (!this.element) return;
 
 
-    const recentShopsList = this.element.querySelector('#recent-shops-list');
-    if (!recentShopsList) return;
+    const recentSitesList = this.element.querySelector('#recent-sites-list');
+    if (!recentSitesList) return;
 
 
-    if (this.recentShops.length === 0) {
-      recentShopsList.innerHTML = `
+    if (this.recentSites.length === 0) {
+      recentSitesList.innerHTML = `
         <div class="text-center py-8">
         <div class="text-center py-8">
           <div class="w-12 h-12 bg-gray-100 dark:bg-gray-700 rounded-lg flex items-center justify-center mx-auto mb-3">
           <div class="w-12 h-12 bg-gray-100 dark:bg-gray-700 rounded-lg flex items-center justify-center mx-auto mb-3">
             <div class="w-6 h-6 text-gray-400">
             <div class="w-6 h-6 text-gray-400">
               ${getIcon('shops')}
               ${getIcon('shops')}
             </div>
             </div>
           </div>
           </div>
-          <p class="text-gray-500 dark:text-gray-400">No shops added yet</p>
-          <button class="mt-2 btn btn-sm btn-primary" id="add-first-shop">
-            Add Your First Shop
+          <p class="text-gray-500 dark:text-gray-400">No sites added yet</p>
+          <button class="mt-2 btn btn-sm btn-primary" id="add-first-site">
+            Add Your First Site
           </button>
           </button>
         </div>
         </div>
       `;
       `;
 
 
-      recentShopsList.querySelector('#add-first-shop')?.addEventListener('click', () => {
-        this.showAddShopModal();
+      recentSitesList.querySelector('#add-first-site')?.addEventListener('click', () => {
+        this.showAddSiteModal();
       });
       });
 
 
       return;
       return;
     }
     }
 
 
-    recentShopsList.innerHTML = `
+    recentSitesList.innerHTML = `
       <div class="space-y-4">
       <div class="space-y-4">
-        ${this.recentShops.map(shop => `
-          <div class="flex items-center justify-between p-3 bg-gray-50 dark:bg-gray-700 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-600 transition-colors cursor-pointer" data-shop-id="${shop.id}">
+        ${this.recentSites.map(site => `
+          <div class="flex items-center justify-between p-3 bg-gray-50 dark:bg-gray-700 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-600 transition-colors cursor-pointer" data-site-id="${site.id}">
             <div class="flex-1 min-w-0">
             <div class="flex-1 min-w-0">
               <div class="flex items-center space-x-3">
               <div class="flex items-center space-x-3">
                 <div class="flex-shrink-0">
                 <div class="flex-shrink-0">
@@ -340,17 +340,17 @@ export class DashboardPage {
                 </div>
                 </div>
                 <div class="flex-1 min-w-0">
                 <div class="flex-1 min-w-0">
                   <p class="text-sm font-medium text-gray-900 dark:text-white truncate">
                   <p class="text-sm font-medium text-gray-900 dark:text-white truncate">
-                    ${this.getDomain(shop.url)}
+                    ${this.getDomain(site.url)}
                   </p>
                   </p>
                   <p class="text-xs text-gray-500 dark:text-gray-400">
                   <p class="text-xs text-gray-500 dark:text-gray-400">
-                    ${shop.analytics.total_scrapes} scrapes • Last: ${shop.analytics.last_scraped_at ? formatRelativeTime(shop.analytics.last_scraped_at) : 'Never'}
+                    ${site.analytics.total_scrapes} scrapes • Last: ${site.analytics.last_scraped_at ? formatRelativeTime(site.analytics.last_scraped_at) : 'Never'}
                   </p>
                   </p>
                 </div>
                 </div>
               </div>
               </div>
             </div>
             </div>
             <div class="flex-shrink-0">
             <div class="flex-shrink-0">
-              <span class="badge badge-${shop.analytics.last_scraped_at ? 'success' : 'gray'}">
-                ${shop.analytics.total_scrapes > 0 ? 'Active' : 'New'}
+              <span class="badge badge-${site.analytics.last_scraped_at ? 'success' : 'gray'}">
+                ${site.analytics.total_scrapes > 0 ? 'Active' : 'New'}
               </span>
               </span>
             </div>
             </div>
           </div>
           </div>
@@ -359,11 +359,11 @@ export class DashboardPage {
     `;
     `;
 
 
     // Add click handlers
     // Add click handlers
-    recentShopsList.querySelectorAll('[data-shop-id]').forEach(element => {
+    recentSitesList.querySelectorAll('[data-site-id]').forEach(element => {
       element.addEventListener('click', () => {
       element.addEventListener('click', () => {
-        const shopId = element.getAttribute('data-shop-id');
-        if (shopId) {
-          this.router.navigate(`/shops/${shopId}`);
+        const siteId = element.getAttribute('data-site-id');
+        if (siteId) {
+          this.router.navigate(`/sites/${siteId}`);
         }
         }
       });
       });
     });
     });
@@ -436,10 +436,10 @@ export class DashboardPage {
     }
     }
   }
   }
 
 
-  private showAddShopModal(): void {
-    // For now, navigate to shops page
+  private showAddSiteModal(): void {
+    // For now, navigate to sites page
     // Later we can implement a modal
     // Later we can implement a modal
-    this.router.navigate('/shops');
+    this.router.navigate('/sites');
   }
   }
 
 
   destroy(): void {
   destroy(): void {

+ 1 - 1
web/src/components/pages/JobsPage.ts

@@ -163,7 +163,7 @@ export class JobsPage {
             <div class="w-8 h-8 text-gray-400">${getIcon('jobs')}</div>
             <div class="w-8 h-8 text-gray-400">${getIcon('jobs')}</div>
           </div>
           </div>
           <h3 class="text-lg font-medium text-gray-900 dark:text-white mb-2">No jobs yet</h3>
           <h3 class="text-lg font-medium text-gray-900 dark:text-white mb-2">No jobs yet</h3>
-          <p class="text-gray-500 dark:text-gray-400">Jobs will appear here when you start scraping shops</p>
+          <p class="text-gray-500 dark:text-gray-400">Jobs will appear here when you start scraping sites</p>
         </div>
         </div>
       `;
       `;
       return;
       return;

+ 3 - 3
web/src/components/pages/QdrantPage.ts

@@ -129,8 +129,8 @@ export class QdrantPage {
           </div>
           </div>
           <div class="card">
           <div class="card">
             <div class="card-body text-center">
             <div class="card-body text-center">
-              <div class="text-2xl font-bold text-gray-900 dark:text-white">${formatNumber(this.stats.enabled_shops)}</div>
-              <div class="text-sm text-gray-500 dark:text-gray-400">Enabled Shops</div>
+              <div class="text-2xl font-bold text-gray-900 dark:text-white">${formatNumber(this.stats.enabled_sites)}</div>
+              <div class="text-sm text-gray-500 dark:text-gray-400">Enabled Sites</div>
             </div>
             </div>
           </div>
           </div>
           <div class="card">
           <div class="card">
@@ -159,7 +159,7 @@ export class QdrantPage {
                 <div class="text-sm text-blue-700 dark:text-blue-400 mt-1 space-y-1">
                 <div class="text-sm text-blue-700 dark:text-blue-400 mt-1 space-y-1">
                   <p>• Qdrant API URL and credentials are configured via environment variables</p>
                   <p>• Qdrant API URL and credentials are configured via environment variables</p>
                   <p>• OpenRouter API is used for text embeddings (text-embedding-3-large model)</p>
                   <p>• OpenRouter API is used for text embeddings (text-embedding-3-large model)</p>
-                  <p>• Collections follow the naming pattern: {shop_custom_id}-{category}_{iterator}</p>
+                  <p>• Collections follow the naming pattern: {site_custom_id}-{category}_{iterator}</p>
                   <p>• Vector dimension: 3072 (OpenAI text-embedding-3-large)</p>
                   <p>• Vector dimension: 3072 (OpenAI text-embedding-3-large)</p>
                 </div>
                 </div>
               </div>
               </div>

+ 46 - 46
web/src/components/pages/SchedulesPage.ts

@@ -1,13 +1,13 @@
 import { ApiService } from '../../services/ApiService';
 import { ApiService } from '../../services/ApiService';
 import { ToastService } from '../../services/ToastService';
 import { ToastService } from '../../services/ToastService';
 import { Router } from '../../app/Router';
 import { Router } from '../../app/Router';
-import { ShopWithAnalytics, ScheduledJob } from '../../types';
+import { SiteWithAnalytics, ScheduledJob } from '../../types';
 import { getIcon } from '../../utils/icons';
 import { getIcon } from '../../utils/icons';
 import { formatRelativeTime, formatScheduleTime, getDomainFromUrl } from '../../utils/helpers';
 import { formatRelativeTime, formatScheduleTime, getDomainFromUrl } from '../../utils/helpers';
 
 
 export class SchedulesPage {
 export class SchedulesPage {
   private element: HTMLElement | null = null;
   private element: HTMLElement | null = null;
-  private shops: ShopWithAnalytics[] = [];
+  private sites: SiteWithAnalytics[] = [];
   private schedules: Map<string, ScheduledJob[]> = new Map();
   private schedules: Map<string, ScheduledJob[]> = new Map();
   private eventsbound: boolean = false;
   private eventsbound: boolean = false;
 
 
@@ -29,7 +29,7 @@ export class SchedulesPage {
             Schedules
             Schedules
           </h2>
           </h2>
           <p class="mt-1 text-sm text-gray-500 dark:text-gray-400">
           <p class="mt-1 text-sm text-gray-500 dark:text-gray-400">
-            Manage automated scraping schedules for your shops
+            Manage automated scraping schedules for your sites
           </p>
           </p>
         </div>
         </div>
         <div class="mt-4 flex md:mt-0 md:ml-4 space-x-3">
         <div class="mt-4 flex md:mt-0 md:ml-4 space-x-3">
@@ -48,17 +48,17 @@ export class SchedulesPage {
         </div>
         </div>
       </div>
       </div>
 
 
-      <!-- Shops & Schedules -->
+      <!-- Sites & Schedules -->
       <div class="card">
       <div class="card">
         <div class="card-header">
         <div class="card-header">
-          <h3 class="text-lg font-medium text-gray-900 dark:text-white">Shop Schedules</h3>
-          <p class="text-sm text-gray-500 dark:text-gray-400">Enable or disable automated scraping for each shop</p>
+          <h3 class="text-lg font-medium text-gray-900 dark:text-white">Site Schedules</h3>
+          <p class="text-sm text-gray-500 dark:text-gray-400">Enable or disable automated scraping for each site</p>
         </div>
         </div>
         <div class="card-body">
         <div class="card-body">
           <div id="schedules-list">
           <div id="schedules-list">
             <div class="flex items-center justify-center py-12">
             <div class="flex items-center justify-center py-12">
               <div class="w-8 h-8 spinner"></div>
               <div class="w-8 h-8 spinner"></div>
-              <span class="ml-3 text-gray-600 dark:text-gray-400">Loading shops...</span>
+              <span class="ml-3 text-gray-600 dark:text-gray-400">Loading sites...</span>
             </div>
             </div>
           </div>
           </div>
         </div>
         </div>
@@ -66,7 +66,7 @@ export class SchedulesPage {
     `;
     `;
 
 
     this.bindEvents();
     this.bindEvents();
-    this.loadShopsAndSchedules();
+    this.loadSitesAndSchedules();
 
 
     return this.element;
     return this.element;
   }
   }
@@ -77,42 +77,42 @@ export class SchedulesPage {
 
 
     // Refresh button
     // Refresh button
     this.element.querySelector('#refresh-schedules')?.addEventListener('click', () => {
     this.element.querySelector('#refresh-schedules')?.addEventListener('click', () => {
-      this.loadShopsAndSchedules();
+      this.loadSitesAndSchedules();
     });
     });
   }
   }
 
 
-  private async loadShopsAndSchedules(): Promise<void> {
+  private async loadSitesAndSchedules(): Promise<void> {
     try {
     try {
-      const response = await this.apiService.getShops();
+      const response = await this.apiService.getSites();
 
 
       if (response.success && response.data) {
       if (response.success && response.data) {
-        this.shops = response.data.shops;
+        this.sites = response.data.sites;
 
 
-        // Load detailed schedule info for each shop
+        // Load detailed schedule info for each site
         await this.loadScheduleDetails();
         await this.loadScheduleDetails();
 
 
         this.renderStats();
         this.renderStats();
         this.renderSchedulesList();
         this.renderSchedulesList();
       } else {
       } else {
-        this.toastService.error('Load Error', response.error || 'Failed to load shops');
+        this.toastService.error('Load Error', response.error || 'Failed to load sites');
       }
       }
     } catch (error) {
     } catch (error) {
-      this.toastService.error('Error', 'Failed to load shops');
+      this.toastService.error('Error', 'Failed to load sites');
     }
     }
   }
   }
 
 
   private async loadScheduleDetails(): Promise<void> {
   private async loadScheduleDetails(): Promise<void> {
     this.schedules.clear();
     this.schedules.clear();
 
 
-    // Load schedule details for each shop
-    for (const shop of this.shops) {
+    // Load schedule details for each site
+    for (const site of this.sites) {
       try {
       try {
-        const response = await this.apiService.getShop(shop.id);
+        const response = await this.apiService.getSite(site.id);
         if (response.success && response.data) {
         if (response.success && response.data) {
-          this.schedules.set(shop.id, response.data.scheduled_jobs);
+          this.schedules.set(site.id, response.data.scheduled_jobs);
         }
         }
       } catch (error) {
       } catch (error) {
-        console.error(`Failed to load schedules for shop ${shop.id}:`, error);
+        console.error(`Failed to load schedules for site ${site.id}:`, error);
       }
       }
     }
     }
   }
   }
@@ -121,20 +121,20 @@ export class SchedulesPage {
     const statsContainer = this.element?.querySelector('#schedule-stats');
     const statsContainer = this.element?.querySelector('#schedule-stats');
     if (!statsContainer) return;
     if (!statsContainer) return;
 
 
-    let totalShops = this.shops.length;
+    let totalSites = this.sites.length;
     let enabledCount = 0;
     let enabledCount = 0;
     let nextScheduledCount = 0;
     let nextScheduledCount = 0;
 
 
     // Calculate stats
     // Calculate stats
-    this.shops.forEach(shop => {
-      const shopSchedules = this.schedules.get(shop.id) || [];
-      const hasActiveSchedule = shopSchedules.some(s => s.status === 'queued' && s.enabled);
+    this.sites.forEach(site => {
+      const siteSchedules = this.schedules.get(site.id) || [];
+      const hasActiveSchedule = siteSchedules.some(s => s.status === 'queued' && s.enabled);
 
 
       if (hasActiveSchedule) {
       if (hasActiveSchedule) {
         enabledCount++;
         enabledCount++;
 
 
         // Check if there's a schedule in the next 24 hours
         // Check if there's a schedule in the next 24 hours
-        const nextSchedule = shopSchedules.find(s =>
+        const nextSchedule = siteSchedules.find(s =>
           s.status === 'queued' &&
           s.status === 'queued' &&
           s.enabled &&
           s.enabled &&
           new Date(s.next_run_at) <= new Date(Date.now() + 24 * 60 * 60 * 1000)
           new Date(s.next_run_at) <= new Date(Date.now() + 24 * 60 * 60 * 1000)
@@ -149,8 +149,8 @@ export class SchedulesPage {
     statsContainer.innerHTML = `
     statsContainer.innerHTML = `
       <div class="card">
       <div class="card">
         <div class="card-body text-center">
         <div class="card-body text-center">
-          <div class="text-2xl font-bold text-gray-900 dark:text-white">${totalShops}</div>
-          <div class="text-sm text-gray-500 dark:text-gray-400">Total Shops</div>
+          <div class="text-2xl font-bold text-gray-900 dark:text-white">${totalSites}</div>
+          <div class="text-sm text-gray-500 dark:text-gray-400">Total Sites</div>
         </div>
         </div>
       </div>
       </div>
       <div class="card">
       <div class="card">
@@ -172,14 +172,14 @@ export class SchedulesPage {
     const listContainer = this.element?.querySelector('#schedules-list');
     const listContainer = this.element?.querySelector('#schedules-list');
     if (!listContainer) return;
     if (!listContainer) return;
 
 
-    if (this.shops.length === 0) {
+    if (this.sites.length === 0) {
       listContainer.innerHTML = `
       listContainer.innerHTML = `
         <div class="text-center py-12">
         <div class="text-center py-12">
           <div class="w-16 h-16 bg-gray-100 dark:bg-gray-700 rounded-lg flex items-center justify-center mx-auto mb-4">
           <div class="w-16 h-16 bg-gray-100 dark:bg-gray-700 rounded-lg flex items-center justify-center mx-auto mb-4">
             <div class="w-8 h-8 text-gray-400">${getIcon('schedules')}</div>
             <div class="w-8 h-8 text-gray-400">${getIcon('schedules')}</div>
           </div>
           </div>
-          <h3 class="text-lg font-medium text-gray-900 dark:text-white mb-2">No shops yet</h3>
-          <p class="text-gray-500 dark:text-gray-400">Add shops first to manage their schedules</p>
+          <h3 class="text-lg font-medium text-gray-900 dark:text-white mb-2">No sites yet</h3>
+          <p class="text-gray-500 dark:text-gray-400">Add sites first to manage their schedules</p>
         </div>
         </div>
       `;
       `;
       return;
       return;
@@ -187,7 +187,7 @@ export class SchedulesPage {
 
 
     listContainer.innerHTML = `
     listContainer.innerHTML = `
       <div class="space-y-4">
       <div class="space-y-4">
-        ${this.shops.map(shop => this.renderShopScheduleCard(shop)).join('')}
+        ${this.sites.map(site => this.renderSiteScheduleCard(site)).join('')}
       </div>
       </div>
     `;
     `;
 
 
@@ -195,21 +195,21 @@ export class SchedulesPage {
     this.bindToggleEvents();
     this.bindToggleEvents();
   }
   }
 
 
-  private renderShopScheduleCard(shop: ShopWithAnalytics): string {
-    const domain = getDomainFromUrl(shop.url);
-    const shopSchedules = this.schedules.get(shop.id) || [];
+  private renderSiteScheduleCard(site: SiteWithAnalytics): string {
+    const domain = getDomainFromUrl(site.url);
+    const siteSchedules = this.schedules.get(site.id) || [];
 
 
     // Find active schedule
     // Find active schedule
-    const activeSchedule = shopSchedules.find(s => s.status === 'queued' && s.enabled);
+    const activeSchedule = siteSchedules.find(s => s.status === 'queued' && s.enabled);
     const hasEnabledSchedule = !!activeSchedule;
     const hasEnabledSchedule = !!activeSchedule;
 
 
     // Find next scheduled run - for enabled, use active; for disabled, find most recent queued
     // Find next scheduled run - for enabled, use active; for disabled, find most recent queued
-    const nextRun = hasEnabledSchedule ? activeSchedule : shopSchedules.find(s => s.status === 'queued');
+    const nextRun = hasEnabledSchedule ? activeSchedule : siteSchedules.find(s => s.status === 'queued');
 
 
     return `
     return `
       <div class="p-4 border border-gray-200 dark:border-gray-600 rounded-lg hover:shadow-md transition-shadow">
       <div class="p-4 border border-gray-200 dark:border-gray-600 rounded-lg hover:shadow-md transition-shadow">
         <div class="flex items-center justify-between">
         <div class="flex items-center justify-between">
-          <!-- Shop Info -->
+          <!-- Site Info -->
           <div class="flex items-center space-x-4 flex-1 min-w-0">
           <div class="flex items-center space-x-4 flex-1 min-w-0">
             <div class="flex-shrink-0">
             <div class="flex-shrink-0">
               <div class="w-12 h-12 bg-primary-100 dark:bg-primary-900 rounded-lg flex items-center justify-center">
               <div class="w-12 h-12 bg-primary-100 dark:bg-primary-900 rounded-lg flex items-center justify-center">
@@ -223,11 +223,11 @@ export class SchedulesPage {
                 ${domain}
                 ${domain}
               </h4>
               </h4>
               <p class="text-sm text-gray-500 dark:text-gray-400 truncate">
               <p class="text-sm text-gray-500 dark:text-gray-400 truncate">
-                ${shop.url}
+                ${site.url}
               </p>
               </p>
               <div class="mt-2 flex items-center space-x-4">
               <div class="mt-2 flex items-center space-x-4">
                 <span class="text-xs text-gray-500 dark:text-gray-400">
                 <span class="text-xs text-gray-500 dark:text-gray-400">
-                  ${shop.analytics.total_scrapes} scrapes • Last: ${shop.analytics.last_scraped_at ? formatRelativeTime(shop.analytics.last_scraped_at) : 'Never'}
+                  ${site.analytics.total_scrapes} scrapes • Last: ${site.analytics.last_scraped_at ? formatRelativeTime(site.analytics.last_scraped_at) : 'Never'}
                 </span>
                 </span>
               </div>
               </div>
             </div>
             </div>
@@ -275,7 +275,7 @@ export class SchedulesPage {
                 <input
                 <input
                   type="checkbox"
                   type="checkbox"
                   class="sr-only peer schedule-toggle"
                   class="sr-only peer schedule-toggle"
-                  data-shop-id="${shop.id}"
+                  data-site-id="${site.id}"
                   ${hasEnabledSchedule ? 'checked' : ''}
                   ${hasEnabledSchedule ? 'checked' : ''}
                 >
                 >
                 <div class="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-primary-300 dark:peer-focus:ring-primary-800 rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all dark:border-gray-600 peer-checked:bg-primary-600"></div>
                 <div class="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-primary-300 dark:peer-focus:ring-primary-800 rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all dark:border-gray-600 peer-checked:bg-primary-600"></div>
@@ -285,11 +285,11 @@ export class SchedulesPage {
         </div>
         </div>
 
 
         <!-- Schedule Details -->
         <!-- Schedule Details -->
-        ${shopSchedules.length > 0 ? `
+        ${siteSchedules.length > 0 ? `
           <div class="mt-4 pt-4 border-t border-gray-200 dark:border-gray-600">
           <div class="mt-4 pt-4 border-t border-gray-200 dark:border-gray-600">
             <h5 class="text-sm font-medium text-gray-900 dark:text-white mb-2">Recent Schedules:</h5>
             <h5 class="text-sm font-medium text-gray-900 dark:text-white mb-2">Recent Schedules:</h5>
             <div class="grid grid-cols-1 md:grid-cols-3 gap-2 text-xs">
             <div class="grid grid-cols-1 md:grid-cols-3 gap-2 text-xs">
-              ${shopSchedules.slice(0, 3).map(schedule => `
+              ${siteSchedules.slice(0, 3).map(schedule => `
                 <div class="flex items-center justify-between p-2 bg-gray-50 dark:bg-gray-700 rounded">
                 <div class="flex items-center justify-between p-2 bg-gray-50 dark:bg-gray-700 rounded">
                   <span class="text-gray-700 dark:text-gray-300">
                   <span class="text-gray-700 dark:text-gray-300">
                     ${this.calculateNextScheduleTime(schedule)}
                     ${this.calculateNextScheduleTime(schedule)}
@@ -357,9 +357,9 @@ export class SchedulesPage {
     this.element.querySelectorAll('.schedule-toggle').forEach(toggle => {
     this.element.querySelectorAll('.schedule-toggle').forEach(toggle => {
       toggle.addEventListener('change', async (e) => {
       toggle.addEventListener('change', async (e) => {
         const checkbox = e.target as HTMLInputElement;
         const checkbox = e.target as HTMLInputElement;
-        const shopId = checkbox.getAttribute('data-shop-id');
+        const siteId = checkbox.getAttribute('data-site-id');
 
 
-        if (!shopId) return;
+        if (!siteId) return;
 
 
         const enabled = checkbox.checked;
         const enabled = checkbox.checked;
 
 
@@ -367,7 +367,7 @@ export class SchedulesPage {
         checkbox.disabled = true;
         checkbox.disabled = true;
 
 
         try {
         try {
-          const response = await this.apiService.updateShopSchedule(shopId, enabled);
+          const response = await this.apiService.updateSiteSchedule(siteId, enabled);
 
 
           if (response.success) {
           if (response.success) {
             this.toastService.success(
             this.toastService.success(
@@ -375,7 +375,7 @@ export class SchedulesPage {
               `Schedule ${enabled ? 'enabled' : 'disabled'} successfully`
               `Schedule ${enabled ? 'enabled' : 'disabled'} successfully`
             );
             );
 
 
-            // Reload the shop's schedule data
+            // Reload the site's schedule data
             await this.loadScheduleDetails();
             await this.loadScheduleDetails();
             this.renderStats();
             this.renderStats();
             this.renderSchedulesList();
             this.renderSchedulesList();

+ 81 - 81
web/src/components/pages/ShopDetailPage.ts → web/src/components/pages/SiteDetailPage.ts

@@ -1,19 +1,19 @@
 import { ApiService } from '../../services/ApiService';
 import { ApiService } from '../../services/ApiService';
 import { ToastService } from '../../services/ToastService';
 import { ToastService } from '../../services/ToastService';
 import { Router } from '../../app/Router';
 import { Router } from '../../app/Router';
-import { ShopDetail, QdrantEmbedding, QdrantError } from '../../types';
+import { SiteDetail, QdrantEmbedding, QdrantError } from '../../types';
 import { getIcon } from '../../utils/icons';
 import { getIcon } from '../../utils/icons';
 import { formatRelativeTime, getDomainFromUrl, getStatusBadgeClass, getContentTypeLabel } from '../../utils/helpers';
 import { formatRelativeTime, getDomainFromUrl, getStatusBadgeClass, getContentTypeLabel } from '../../utils/helpers';
 
 
-export class ShopDetailPage {
+export class SiteDetailPage {
   private element: HTMLElement | null = null;
   private element: HTMLElement | null = null;
-  private shopDetail: ShopDetail | null = null;
+  private siteDetail: SiteDetail | null = null;
   private eventsbound: boolean = false;
   private eventsbound: boolean = false;
   private qdrantEmbeddings: QdrantEmbedding[] = [];
   private qdrantEmbeddings: QdrantEmbedding[] = [];
   private qdrantErrors: QdrantError[] = [];
   private qdrantErrors: QdrantError[] = [];
 
 
   constructor(
   constructor(
-    private shopId: string,
+    private siteId: string,
     private apiService: ApiService,
     private apiService: ApiService,
     private toastService: ToastService,
     private toastService: ToastService,
     private router: Router
     private router: Router
@@ -27,28 +27,28 @@ export class ShopDetailPage {
       <!-- Loading state -->
       <!-- Loading state -->
       <div class="flex items-center justify-center py-12" id="loading">
       <div class="flex items-center justify-center py-12" id="loading">
         <div class="w-8 h-8 spinner"></div>
         <div class="w-8 h-8 spinner"></div>
-        <span class="ml-3 text-gray-600 dark:text-gray-400">Loading shop details...</span>
+        <span class="ml-3 text-gray-600 dark:text-gray-400">Loading site details...</span>
       </div>
       </div>
     `;
     `;
 
 
-    this.loadShopDetail();
+    this.loadSiteDetail();
     return this.element;
     return this.element;
   }
   }
 
 
-  private async loadShopDetail(): Promise<void> {
+  private async loadSiteDetail(): Promise<void> {
     try {
     try {
-      // Load shop details first (critical)
-      console.log('[ShopDetailPage] Loading shop details for:', this.shopId);
-      const shopResponse = await this.apiService.getShop(this.shopId);
-      console.log('[ShopDetailPage] Shop response:', shopResponse);
+      // Load site details first (critical)
+      console.log('[SiteDetailPage] Loading site details for:', this.siteId);
+      const siteResponse = await this.apiService.getSite(this.siteId);
+      console.log('[SiteDetailPage] Site response:', siteResponse);
 
 
-      if (shopResponse.success && shopResponse.data) {
-        this.shopDetail = shopResponse.data;
+      if (siteResponse.success && siteResponse.data) {
+        this.siteDetail = siteResponse.data;
 
 
         // Load Qdrant data in parallel (optional - these can fail without breaking the page)
         // Load Qdrant data in parallel (optional - these can fail without breaking the page)
         const [embeddingsResponse, errorsResponse] = await Promise.allSettled([
         const [embeddingsResponse, errorsResponse] = await Promise.allSettled([
-          this.apiService.getShopQdrantEmbeddings(this.shopId),
-          this.apiService.getShopQdrantErrors(this.shopId)
+          this.apiService.getSiteQdrantEmbeddings(this.siteId),
+          this.apiService.getSiteQdrantErrors(this.siteId)
         ]);
         ]);
 
 
         // Handle embeddings response (won't break if it fails)
         // Handle embeddings response (won't break if it fails)
@@ -57,7 +57,7 @@ export class ShopDetailPage {
           const embeddingsData = (embeddingsResponse.value.data as any).data?.embeddings || [];
           const embeddingsData = (embeddingsResponse.value.data as any).data?.embeddings || [];
           this.qdrantEmbeddings = embeddingsData;
           this.qdrantEmbeddings = embeddingsData;
         } else if (embeddingsResponse.status === 'rejected') {
         } else if (embeddingsResponse.status === 'rejected') {
-          console.warn('[ShopDetailPage] Embeddings failed:', embeddingsResponse.reason);
+          console.warn('[SiteDetailPage] Embeddings failed:', embeddingsResponse.reason);
         }
         }
 
 
         // Handle errors response (won't break if it fails)
         // Handle errors response (won't break if it fails)
@@ -66,27 +66,27 @@ export class ShopDetailPage {
           const errorsData = (errorsResponse.value.data as any).data?.errors || [];
           const errorsData = (errorsResponse.value.data as any).data?.errors || [];
           this.qdrantErrors = errorsData;
           this.qdrantErrors = errorsData;
         } else if (errorsResponse.status === 'rejected') {
         } else if (errorsResponse.status === 'rejected') {
-          console.warn('[ShopDetailPage] Errors fetch failed:', errorsResponse.reason);
+          console.warn('[SiteDetailPage] Errors fetch failed:', errorsResponse.reason);
         }
         }
 
 
-        this.renderShopDetail();
+        this.renderSiteDetail();
       } else {
       } else {
-        console.error('[ShopDetailPage] Shop API returned error:', shopResponse.error);
-        this.toastService.error('Load Error', shopResponse.error || 'Failed to load shop details');
-        this.router.navigate('/shops');
+        console.error('[SiteDetailPage] Site API returned error:', siteResponse.error);
+        this.toastService.error('Load Error', siteResponse.error || 'Failed to load site details');
+        this.router.navigate('/sites');
       }
       }
     } catch (error) {
     } catch (error) {
-      console.error('[ShopDetailPage] Exception loading shop details:', error);
-      this.toastService.error('Error', 'Failed to load shop details');
-      this.router.navigate('/shops');
+      console.error('[SiteDetailPage] Exception loading site details:', error);
+      this.toastService.error('Error', 'Failed to load site details');
+      this.router.navigate('/sites');
     }
     }
   }
   }
 
 
-  private renderShopDetail(): void {
-    if (!this.shopDetail || !this.element) return;
+  private renderSiteDetail(): void {
+    if (!this.siteDetail || !this.element) return;
 
 
-    const { shop, analytics, content_metadata, scrape_history } = this.shopDetail;
-    const domain = getDomainFromUrl(shop.url);
+    const { site, analytics, content_metadata, scrape_history } = this.siteDetail;
+    const domain = getDomainFromUrl(site.url);
 
 
     this.element.innerHTML = `
     this.element.innerHTML = `
       <!-- Header -->
       <!-- Header -->
@@ -95,11 +95,11 @@ export class ShopDetailPage {
           <nav class="flex" aria-label="Breadcrumb">
           <nav class="flex" aria-label="Breadcrumb">
             <ol class="flex items-center space-x-4">
             <ol class="flex items-center space-x-4">
               <li>
               <li>
-                <a href="/shops" class="text-gray-400 hover:text-gray-500" onclick="event.preventDefault(); window.dispatchEvent(new CustomEvent('navigate', {detail: '/shops'}))">
+                <a href="/sites" class="text-gray-400 hover:text-gray-500" onclick="event.preventDefault(); window.dispatchEvent(new CustomEvent('navigate', {detail: '/sites'}))">
                   <div class="w-5 h-5">
                   <div class="w-5 h-5">
                     ${getIcon('shops')}
                     ${getIcon('shops')}
                   </div>
                   </div>
-                  <span class="sr-only">Shops</span>
+                  <span class="sr-only">Sites</span>
                 </a>
                 </a>
               </li>
               </li>
               <li>
               <li>
@@ -107,7 +107,7 @@ export class ShopDetailPage {
                   <svg class="flex-shrink-0 h-5 w-5 text-gray-300" fill="currentColor" viewBox="0 0 20 20">
                   <svg class="flex-shrink-0 h-5 w-5 text-gray-300" fill="currentColor" viewBox="0 0 20 20">
                     <path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd" />
                     <path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd" />
                   </svg>
                   </svg>
-                  <span class="ml-4 text-sm text-gray-500 dark:text-gray-400">Shop Details</span>
+                  <span class="ml-4 text-sm text-gray-500 dark:text-gray-400">Site Details</span>
                 </div>
                 </div>
               </li>
               </li>
             </ol>
             </ol>
@@ -116,7 +116,7 @@ export class ShopDetailPage {
             ${domain}
             ${domain}
           </h2>
           </h2>
           <p class="mt-1 text-sm text-gray-500 dark:text-gray-400">
           <p class="mt-1 text-sm text-gray-500 dark:text-gray-400">
-            ${shop.url}
+            ${site.url}
           </p>
           </p>
         </div>
         </div>
         <div class="mt-4 flex md:mt-0 md:ml-4 space-x-3">
         <div class="mt-4 flex md:mt-0 md:ml-4 space-x-3">
@@ -124,15 +124,15 @@ export class ShopDetailPage {
             <div class="w-4 h-4 mr-2" id="scrape-icon">${getIcon('play')}</div>
             <div class="w-4 h-4 mr-2" id="scrape-icon">${getIcon('play')}</div>
             <span id="scrape-text">Run Scrape</span>
             <span id="scrape-text">Run Scrape</span>
           </button>
           </button>
-          ${shop.qdrant_enabled && shop.custom_id ? `
+          ${site.qdrant_enabled && site.custom_id ? `
             <button type="button" class="btn btn-primary" id="trigger-qdrant-sync">
             <button type="button" class="btn btn-primary" id="trigger-qdrant-sync">
               <div class="w-4 h-4 mr-2" id="sync-icon">${getIcon('search')}</div>
               <div class="w-4 h-4 mr-2" id="sync-icon">${getIcon('search')}</div>
               <span id="sync-text">Sync to Qdrant</span>
               <span id="sync-text">Sync to Qdrant</span>
             </button>
             </button>
           ` : ''}
           ` : ''}
-          <button type="button" class="btn btn-danger" id="delete-shop">
+          <button type="button" class="btn btn-danger" id="delete-site">
             <div class="w-4 h-4 mr-2">${getIcon('delete')}</div>
             <div class="w-4 h-4 mr-2">${getIcon('delete')}</div>
-            Delete Shop
+            Delete Site
           </button>
           </button>
         </div>
         </div>
       </div>
       </div>
@@ -169,11 +169,11 @@ export class ShopDetailPage {
         </div>
         </div>
       </div>
       </div>
 
 
-      <!-- Shop Settings -->
+      <!-- Site Settings -->
       <div class="card">
       <div class="card">
         <div class="card-header">
         <div class="card-header">
-          <h3 class="text-lg font-medium text-gray-900 dark:text-white">Shop Settings</h3>
-          <p class="text-sm text-gray-500 dark:text-gray-400">Configure shop identifiers and metadata</p>
+          <h3 class="text-lg font-medium text-gray-900 dark:text-white">Site Settings</h3>
+          <p class="text-sm text-gray-500 dark:text-gray-400">Configure site identifiers and metadata</p>
         </div>
         </div>
         <div class="card-body">
         <div class="card-body">
           <div class="space-y-6">
           <div class="space-y-6">
@@ -185,7 +185,7 @@ export class ShopDetailPage {
               <div class="flex items-center space-x-2">
               <div class="flex items-center space-x-2">
                 <input
                 <input
                   type="text"
                   type="text"
-                  value="${shop.id}"
+                  value="${site.id}"
                   readonly
                   readonly
                   class="flex-1 px-3 py-2 bg-gray-50 dark:bg-gray-700 border border-gray-300 dark:border-gray-600 rounded-lg text-gray-500 dark:text-gray-400 cursor-not-allowed"
                   class="flex-1 px-3 py-2 bg-gray-50 dark:bg-gray-700 border border-gray-300 dark:border-gray-600 rounded-lg text-gray-500 dark:text-gray-400 cursor-not-allowed"
                 />
                 />
@@ -212,7 +212,7 @@ export class ShopDetailPage {
                 <input
                 <input
                   type="text"
                   type="text"
                   id="custom-id-input"
                   id="custom-id-input"
-                  value="${shop.custom_id || ''}"
+                  value="${site.custom_id || ''}"
                   placeholder="e.g., 550e8400-e29b-41d4-a716-446655440000"
                   placeholder="e.g., 550e8400-e29b-41d4-a716-446655440000"
                   class="flex-1 px-3 py-2 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded-lg text-gray-900 dark:text-white focus:ring-2 focus:ring-blue-500 focus:border-transparent"
                   class="flex-1 px-3 py-2 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded-lg text-gray-900 dark:text-white focus:ring-2 focus:ring-blue-500 focus:border-transparent"
                 />
                 />
@@ -224,7 +224,7 @@ export class ShopDetailPage {
                   <div class="w-4 h-4 mr-1">${getIcon('save')}</div>
                   <div class="w-4 h-4 mr-1">${getIcon('save')}</div>
                   Save
                   Save
                 </button>
                 </button>
-                ${shop.custom_id ? `
+                ${site.custom_id ? `
                   <button
                   <button
                     type="button"
                     type="button"
                     id="clear-custom-id"
                     id="clear-custom-id"
@@ -238,7 +238,7 @@ export class ShopDetailPage {
               <p class="mt-1 text-xs text-gray-500 dark:text-gray-400">
               <p class="mt-1 text-xs text-gray-500 dark:text-gray-400">
                 Optional UUID for custom identification. Must be a valid UUID format.
                 Optional UUID for custom identification. Must be a valid UUID format.
               </p>
               </p>
-              ${shop.qdrant_enabled && shop.custom_id ? `
+              ${site.qdrant_enabled && site.custom_id ? `
                 <div class="mt-2 flex items-start space-x-2 text-xs text-yellow-600 dark:text-yellow-400">
                 <div class="mt-2 flex items-start space-x-2 text-xs text-yellow-600 dark:text-yellow-400">
                   <div class="w-4 h-4 flex-shrink-0">${getIcon('warning')}</div>
                   <div class="w-4 h-4 flex-shrink-0">${getIcon('warning')}</div>
                   <span>
                   <span>
@@ -316,24 +316,24 @@ export class ShopDetailPage {
           <div class="flex items-center justify-between">
           <div class="flex items-center justify-between">
             <div>
             <div>
               <h3 class="text-lg font-medium text-gray-900 dark:text-white">Vector Search (Qdrant)</h3>
               <h3 class="text-lg font-medium text-gray-900 dark:text-white">Vector Search (Qdrant)</h3>
-              <p class="text-sm text-gray-500 dark:text-gray-400">Enable semantic search for this shop's content</p>
+              <p class="text-sm text-gray-500 dark:text-gray-400">Enable semantic search for this site's content</p>
             </div>
             </div>
             <div class="flex items-center space-x-3">
             <div class="flex items-center space-x-3">
               <label class="flex items-center cursor-pointer">
               <label class="flex items-center cursor-pointer">
-                <input type="checkbox" id="qdrant-toggle" class="sr-only" ${shop.qdrant_enabled ? 'checked' : ''}>
+                <input type="checkbox" id="qdrant-toggle" class="sr-only" ${site.qdrant_enabled ? 'checked' : ''}>
                 <div class="relative">
                 <div class="relative">
                   <div class="block bg-gray-600 w-14 h-8 rounded-full"></div>
                   <div class="block bg-gray-600 w-14 h-8 rounded-full"></div>
-                  <div class="dot absolute left-1 top-1 bg-white w-6 h-6 rounded-full transition ${shop.qdrant_enabled ? 'transform translate-x-6 bg-blue-600' : ''}"></div>
+                  <div class="dot absolute left-1 top-1 bg-white w-6 h-6 rounded-full transition ${site.qdrant_enabled ? 'transform translate-x-6 bg-blue-600' : ''}"></div>
                 </div>
                 </div>
                 <span class="ml-3 text-sm font-medium text-gray-900 dark:text-white">
                 <span class="ml-3 text-sm font-medium text-gray-900 dark:text-white">
-                  ${shop.qdrant_enabled ? 'Enabled' : 'Disabled'}
+                  ${site.qdrant_enabled ? 'Enabled' : 'Disabled'}
                 </span>
                 </span>
               </label>
               </label>
             </div>
             </div>
           </div>
           </div>
         </div>
         </div>
         <div class="card-body">
         <div class="card-body">
-          ${shop.qdrant_enabled ? `
+          ${site.qdrant_enabled ? `
             <div class="space-y-6">
             <div class="space-y-6">
               <!-- Embeddings Status -->
               <!-- Embeddings Status -->
               <div>
               <div>
@@ -393,7 +393,7 @@ export class ShopDetailPage {
               ` : ''}
               ` : ''}
 
 
               <!-- Custom ID Warning -->
               <!-- Custom ID Warning -->
-              ${!shop.custom_id ? `
+              ${!site.custom_id ? `
                 <div class="bg-yellow-50 dark:bg-yellow-900/20 border border-yellow-200 dark:border-yellow-800 rounded-lg p-4">
                 <div class="bg-yellow-50 dark:bg-yellow-900/20 border border-yellow-200 dark:border-yellow-800 rounded-lg p-4">
                   <div class="flex">
                   <div class="flex">
                     <div class="flex-shrink-0">
                     <div class="flex-shrink-0">
@@ -402,7 +402,7 @@ export class ShopDetailPage {
                     <div class="ml-3">
                     <div class="ml-3">
                       <h4 class="text-sm font-medium text-yellow-800 dark:text-yellow-300">Custom ID Required</h4>
                       <h4 class="text-sm font-medium text-yellow-800 dark:text-yellow-300">Custom ID Required</h4>
                       <p class="text-sm text-yellow-700 dark:text-yellow-400 mt-1">
                       <p class="text-sm text-yellow-700 dark:text-yellow-400 mt-1">
-                        This shop needs a custom ID to use Qdrant features. The custom ID cannot be changed once set when Qdrant is enabled.
+                        This site needs a custom ID to use Qdrant features. The custom ID cannot be changed once set when Qdrant is enabled.
                       </p>
                       </p>
                     </div>
                     </div>
                   </div>
                   </div>
@@ -414,7 +414,7 @@ export class ShopDetailPage {
               <div class="w-12 h-12 bg-gray-100 dark:bg-gray-700 rounded-lg flex items-center justify-center mx-auto mb-3">
               <div class="w-12 h-12 bg-gray-100 dark:bg-gray-700 rounded-lg flex items-center justify-center mx-auto mb-3">
                 <div class="w-6 h-6 text-gray-400">${getIcon('search')}</div>
                 <div class="w-6 h-6 text-gray-400">${getIcon('search')}</div>
               </div>
               </div>
-              <p class="text-gray-500 dark:text-gray-400 mb-4">Vector search is disabled for this shop</p>
+              <p class="text-gray-500 dark:text-gray-400 mb-4">Vector search is disabled for this site</p>
               <p class="text-sm text-gray-400 dark:text-gray-500">
               <p class="text-sm text-gray-400 dark:text-gray-500">
                 Enable Qdrant to automatically create embeddings of scraped content for semantic search via MCP tools.
                 Enable Qdrant to automatically create embeddings of scraped content for semantic search via MCP tools.
               </p>
               </p>
@@ -432,14 +432,14 @@ export class ShopDetailPage {
     this.eventsbound = true;
     this.eventsbound = true;
 
 
     // Navigation breadcrumb
     // Navigation breadcrumb
-    this.element.querySelector('a[href="/shops"]')?.addEventListener('click', (e) => {
+    this.element.querySelector('a[href="/sites"]')?.addEventListener('click', (e) => {
       e.preventDefault();
       e.preventDefault();
-      this.router.navigate('/shops');
+      this.router.navigate('/sites');
     });
     });
 
 
     // Trigger scrape
     // Trigger scrape
     this.element.querySelector('#trigger-scrape')?.addEventListener('click', async (e) => {
     this.element.querySelector('#trigger-scrape')?.addEventListener('click', async (e) => {
-      if (!this.shopDetail) return;
+      if (!this.siteDetail) return;
 
 
       const button = e.currentTarget as HTMLButtonElement;
       const button = e.currentTarget as HTMLButtonElement;
       const icon = this.element?.querySelector('#scrape-icon');
       const icon = this.element?.querySelector('#scrape-icon');
@@ -454,7 +454,7 @@ export class ShopDetailPage {
       if (text) text.textContent = 'Starting...';
       if (text) text.textContent = 'Starting...';
 
 
       try {
       try {
-        const response = await this.apiService.createJob(this.shopDetail.shop.url);
+        const response = await this.apiService.createJob(this.siteDetail.site.url);
 
 
         if (response.success) {
         if (response.success) {
           this.toastService.success('Scrape Started', 'A new scraping job has been queued');
           this.toastService.success('Scrape Started', 'A new scraping job has been queued');
@@ -473,7 +473,7 @@ export class ShopDetailPage {
 
 
     // Trigger Qdrant sync
     // Trigger Qdrant sync
     this.element.querySelector('#trigger-qdrant-sync')?.addEventListener('click', async (e) => {
     this.element.querySelector('#trigger-qdrant-sync')?.addEventListener('click', async (e) => {
-      if (!this.shopDetail) return;
+      if (!this.siteDetail) return;
 
 
       const button = e.currentTarget as HTMLButtonElement;
       const button = e.currentTarget as HTMLButtonElement;
       const icon = this.element?.querySelector('#sync-icon');
       const icon = this.element?.querySelector('#sync-icon');
@@ -488,7 +488,7 @@ export class ShopDetailPage {
       if (text) text.textContent = 'Syncing...';
       if (text) text.textContent = 'Syncing...';
 
 
       try {
       try {
-        const response = await this.apiService.forceQdrantSync(this.shopId);
+        const response = await this.apiService.forceQdrantSync(this.siteId);
 
 
         if (response.success && response.data) {
         if (response.success && response.data) {
           this.toastService.success(
           this.toastService.success(
@@ -496,7 +496,7 @@ export class ShopDetailPage {
             `Syncing ${response.data.items_queued} items to Qdrant`
             `Syncing ${response.data.items_queued} items to Qdrant`
           );
           );
           // Reload the page after a short delay to show updated status
           // Reload the page after a short delay to show updated status
-          setTimeout(() => this.loadShopDetail(), 2000);
+          setTimeout(() => this.loadSiteDetail(), 2000);
         } else {
         } else {
           this.toastService.error('Sync Failed', response.error || 'Failed to start Qdrant sync');
           this.toastService.error('Sync Failed', response.error || 'Failed to start Qdrant sync');
         }
         }
@@ -510,22 +510,22 @@ export class ShopDetailPage {
       }
       }
     });
     });
 
 
-    // Delete shop
-    this.element.querySelector('#delete-shop')?.addEventListener('click', async () => {
-      const confirmed = confirm('Are you sure you want to delete this shop? This will remove all associated data and cannot be undone.');
+    // Delete site
+    this.element.querySelector('#delete-site')?.addEventListener('click', async () => {
+      const confirmed = confirm('Are you sure you want to delete this site? This will remove all associated data and cannot be undone.');
 
 
       if (confirmed) {
       if (confirmed) {
         try {
         try {
-          const response = await this.apiService.deleteShop(this.shopId);
+          const response = await this.apiService.deleteSite(this.siteId);
 
 
           if (response.success) {
           if (response.success) {
-            this.toastService.success('Shop Deleted', 'Shop and all data have been removed');
-            this.router.navigate('/shops');
+            this.toastService.success('Site Deleted', 'Site and all data have been removed');
+            this.router.navigate('/sites');
           } else {
           } else {
-            this.toastService.error('Delete Failed', response.error || 'Failed to delete shop');
+            this.toastService.error('Delete Failed', response.error || 'Failed to delete site');
           }
           }
         } catch (error) {
         } catch (error) {
-          this.toastService.error('Error', 'Failed to delete shop');
+          this.toastService.error('Error', 'Failed to delete site');
         }
         }
       }
       }
     });
     });
@@ -536,15 +536,15 @@ export class ShopDetailPage {
       const enabled = checkbox.checked;
       const enabled = checkbox.checked;
 
 
       try {
       try {
-        const response = await this.apiService.updateShopQdrant(this.shopId, enabled);
+        const response = await this.apiService.updateSiteQdrant(this.siteId, enabled);
 
 
         if (response.success) {
         if (response.success) {
           this.toastService.success(
           this.toastService.success(
             'Qdrant Updated',
             'Qdrant Updated',
-            `Vector search has been ${enabled ? 'enabled' : 'disabled'} for this shop`
+            `Vector search has been ${enabled ? 'enabled' : 'disabled'} for this site`
           );
           );
           // Reload the page to show updated status
           // Reload the page to show updated status
-          await this.loadShopDetail();
+          await this.loadSiteDetail();
         } else {
         } else {
           // Revert checkbox state on error
           // Revert checkbox state on error
           checkbox.checked = !enabled;
           checkbox.checked = !enabled;
@@ -560,13 +560,13 @@ export class ShopDetailPage {
     // Clear Qdrant errors
     // Clear Qdrant errors
     this.element.querySelector('#clear-qdrant-errors')?.addEventListener('click', async () => {
     this.element.querySelector('#clear-qdrant-errors')?.addEventListener('click', async () => {
       try {
       try {
-        const response = await this.apiService.clearShopQdrantErrors(this.shopId);
+        const response = await this.apiService.clearSiteQdrantErrors(this.siteId);
 
 
         if (response.success) {
         if (response.success) {
           this.toastService.success('Errors Cleared', 'Qdrant errors have been cleared');
           this.toastService.success('Errors Cleared', 'Qdrant errors have been cleared');
           // Clear errors from local state and re-render
           // Clear errors from local state and re-render
           this.qdrantErrors = [];
           this.qdrantErrors = [];
-          this.renderShopDetail();
+          this.renderSiteDetail();
         } else {
         } else {
           this.toastService.error('Clear Failed', response.error || 'Failed to clear Qdrant errors');
           this.toastService.error('Clear Failed', response.error || 'Failed to clear Qdrant errors');
         }
         }
@@ -577,10 +577,10 @@ export class ShopDetailPage {
 
 
     // Copy internal ID to clipboard
     // Copy internal ID to clipboard
     this.element.querySelector('#copy-internal-id')?.addEventListener('click', async () => {
     this.element.querySelector('#copy-internal-id')?.addEventListener('click', async () => {
-      if (!this.shopDetail) return;
+      if (!this.siteDetail) return;
 
 
       try {
       try {
-        await navigator.clipboard.writeText(this.shopDetail.shop.id);
+        await navigator.clipboard.writeText(this.siteDetail.site.id);
         this.toastService.success('Copied', 'Internal ID copied to clipboard');
         this.toastService.success('Copied', 'Internal ID copied to clipboard');
       } catch (error) {
       } catch (error) {
         this.toastService.error('Copy Failed', 'Failed to copy to clipboard');
         this.toastService.error('Copy Failed', 'Failed to copy to clipboard');
@@ -589,7 +589,7 @@ export class ShopDetailPage {
 
 
     // Save custom ID
     // Save custom ID
     this.element.querySelector('#save-custom-id')?.addEventListener('click', async () => {
     this.element.querySelector('#save-custom-id')?.addEventListener('click', async () => {
-      if (!this.shopDetail) return;
+      if (!this.siteDetail) return;
 
 
       const input = this.element?.querySelector('#custom-id-input') as HTMLInputElement;
       const input = this.element?.querySelector('#custom-id-input') as HTMLInputElement;
       if (!input) return;
       if (!input) return;
@@ -604,7 +604,7 @@ export class ShopDetailPage {
       }
       }
 
 
       // Warn if changing custom ID while Qdrant is enabled
       // Warn if changing custom ID while Qdrant is enabled
-      if (this.shopDetail.shop.qdrant_enabled && this.shopDetail.shop.custom_id && newCustomId !== this.shopDetail.shop.custom_id) {
+      if (this.siteDetail.site.qdrant_enabled && this.siteDetail.site.custom_id && newCustomId !== this.siteDetail.site.custom_id) {
         const confirmed = confirm(
         const confirmed = confirm(
           'Warning: Changing the custom ID while Qdrant is enabled may cause issues with existing collections. ' +
           'Warning: Changing the custom ID while Qdrant is enabled may cause issues with existing collections. ' +
           'It is recommended to disable Qdrant first. Do you want to continue?'
           'It is recommended to disable Qdrant first. Do you want to continue?'
@@ -613,8 +613,8 @@ export class ShopDetailPage {
       }
       }
 
 
       try {
       try {
-        const response = await this.apiService.updateShopCustomId(
-          this.shopId,
+        const response = await this.apiService.updateSiteCustomId(
+          this.siteId,
           newCustomId || null
           newCustomId || null
         );
         );
 
 
@@ -624,7 +624,7 @@ export class ShopDetailPage {
             newCustomId ? `Custom ID set to ${newCustomId}` : 'Custom ID removed'
             newCustomId ? `Custom ID set to ${newCustomId}` : 'Custom ID removed'
           );
           );
           // Reload the page to show updated data
           // Reload the page to show updated data
-          await this.loadShopDetail();
+          await this.loadSiteDetail();
         } else {
         } else {
           this.toastService.error('Update Failed', response.error || 'Failed to update custom ID');
           this.toastService.error('Update Failed', response.error || 'Failed to update custom ID');
         }
         }
@@ -635,10 +635,10 @@ export class ShopDetailPage {
 
 
     // Clear custom ID
     // Clear custom ID
     this.element.querySelector('#clear-custom-id')?.addEventListener('click', async () => {
     this.element.querySelector('#clear-custom-id')?.addEventListener('click', async () => {
-      if (!this.shopDetail) return;
+      if (!this.siteDetail) return;
 
 
       // Warn if clearing custom ID while Qdrant is enabled
       // Warn if clearing custom ID while Qdrant is enabled
-      if (this.shopDetail.shop.qdrant_enabled) {
+      if (this.siteDetail.site.qdrant_enabled) {
         const confirmed = confirm(
         const confirmed = confirm(
           'Warning: Removing the custom ID while Qdrant is enabled may cause issues with existing collections. ' +
           'Warning: Removing the custom ID while Qdrant is enabled may cause issues with existing collections. ' +
           'It is recommended to disable Qdrant first. Do you want to continue?'
           'It is recommended to disable Qdrant first. Do you want to continue?'
@@ -650,12 +650,12 @@ export class ShopDetailPage {
       if (!confirmClear) return;
       if (!confirmClear) return;
 
 
       try {
       try {
-        const response = await this.apiService.updateShopCustomId(this.shopId, null);
+        const response = await this.apiService.updateSiteCustomId(this.siteId, null);
 
 
         if (response.success) {
         if (response.success) {
           this.toastService.success('Custom ID Cleared', 'Custom ID has been removed');
           this.toastService.success('Custom ID Cleared', 'Custom ID has been removed');
           // Reload the page to show updated data
           // Reload the page to show updated data
-          await this.loadShopDetail();
+          await this.loadSiteDetail();
         } else {
         } else {
           this.toastService.error('Clear Failed', response.error || 'Failed to clear custom ID');
           this.toastService.error('Clear Failed', response.error || 'Failed to clear custom ID');
         }
         }

+ 109 - 109
web/src/components/pages/ShopsPage.ts → web/src/components/pages/SitesPage.ts

@@ -1,14 +1,14 @@
 import { ApiService } from '../../services/ApiService';
 import { ApiService } from '../../services/ApiService';
 import { ToastService } from '../../services/ToastService';
 import { ToastService } from '../../services/ToastService';
 import { Router } from '../../app/Router';
 import { Router } from '../../app/Router';
-import { ShopWithAnalytics, Shop } from '../../types';
+import { SiteWithAnalytics, Site } from '../../types';
 import { getIcon } from '../../utils/icons';
 import { getIcon } from '../../utils/icons';
-import { formatRelativeTime, getDomainFromUrl, getWebshopTypeInfo } from '../../utils/helpers';
+import { formatRelativeTime, getDomainFromUrl, getSiteTypeInfo } from '../../utils/helpers';
 
 
-export class ShopsPage {
+export class SitesPage {
   private element: HTMLElement | null = null;
   private element: HTMLElement | null = null;
-  private shops: ShopWithAnalytics[] = [];
-  private deletedShops: Shop[] = [];
+  private sites: SiteWithAnalytics[] = [];
+  private deletedSites: Site[] = [];
 
 
   constructor(
   constructor(
     private apiService: ApiService,
     private apiService: ApiService,
@@ -25,17 +25,17 @@ export class ShopsPage {
       <div class="md:flex md:items-center md:justify-between">
       <div class="md:flex md:items-center md:justify-between">
         <div class="flex-1 min-w-0">
         <div class="flex-1 min-w-0">
           <h2 class="text-2xl font-bold leading-7 text-gray-900 dark:text-white sm:text-3xl sm:truncate">
           <h2 class="text-2xl font-bold leading-7 text-gray-900 dark:text-white sm:text-3xl sm:truncate">
-            Shops
+            Sites
           </h2>
           </h2>
           <p class="mt-1 text-sm text-gray-500 dark:text-gray-400">
           <p class="mt-1 text-sm text-gray-500 dark:text-gray-400">
-            Manage and monitor your webshops
+            Manage and monitor your sites
           </p>
           </p>
         </div>
         </div>
         <div class="mt-4 flex md:mt-0 md:ml-4 space-x-3">
         <div class="mt-4 flex md:mt-0 md:ml-4 space-x-3">
           <button
           <button
             type="button"
             type="button"
             class="btn btn-secondary"
             class="btn btn-secondary"
-            id="refresh-shops"
+            id="refresh-sites"
           >
           >
             <div class="w-4 h-4 mr-2">
             <div class="w-4 h-4 mr-2">
               ${getIcon('refresh')}
               ${getIcon('refresh')}
@@ -45,44 +45,44 @@ export class ShopsPage {
           <button
           <button
             type="button"
             type="button"
             class="btn btn-primary"
             class="btn btn-primary"
-            id="add-shop-btn"
+            id="add-site-btn"
           >
           >
             <div class="w-4 h-4 mr-2">
             <div class="w-4 h-4 mr-2">
               ${getIcon('plus')}
               ${getIcon('plus')}
             </div>
             </div>
-            Add Shop
+            Add Site
           </button>
           </button>
         </div>
         </div>
       </div>
       </div>
 
 
-      <!-- Add Shop Modal -->
-      <div class="fixed inset-0 z-50 hidden" id="add-shop-modal">
+      <!-- Add Site Modal -->
+      <div class="fixed inset-0 z-50 hidden" id="add-site-modal">
         <div class="flex items-center justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
         <div class="flex items-center justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
           <div class="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity"></div>
           <div class="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity"></div>
 
 
           <div class="inline-block align-bottom bg-white dark:bg-gray-800 rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full">
           <div class="inline-block align-bottom bg-white dark:bg-gray-800 rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full">
-            <form id="add-shop-form">
+            <form id="add-site-form">
               <div class="bg-white dark:bg-gray-800 px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
               <div class="bg-white dark:bg-gray-800 px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
                 <div class="sm:flex sm:items-start">
                 <div class="sm:flex sm:items-start">
                   <div class="w-full">
                   <div class="w-full">
                     <h3 class="text-lg leading-6 font-medium text-gray-900 dark:text-white mb-4">
                     <h3 class="text-lg leading-6 font-medium text-gray-900 dark:text-white mb-4">
-                      Add New Shop
+                      Add New Site
                     </h3>
                     </h3>
                     <div class="space-y-4">
                     <div class="space-y-4">
                       <div>
                       <div>
-                        <label for="shop-url" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
-                          Shop URL
+                        <label for="site-url" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
+                          Site URL
                         </label>
                         </label>
                         <input
                         <input
                           type="url"
                           type="url"
-                          id="shop-url"
-                          name="shopUrl"
+                          id="site-url"
+                          name="siteUrl"
                           required
                           required
                           class="input mt-1"
                           class="input mt-1"
-                          placeholder="https://example-shop.com"
+                          placeholder="https://example.com"
                         >
                         >
                         <p class="mt-1 text-sm text-gray-500 dark:text-gray-400">
                         <p class="mt-1 text-sm text-gray-500 dark:text-gray-400">
-                          Enter the main URL of the webshop you want to scrape
+                          Enter the main URL of the site you want to scrape
                         </p>
                         </p>
                       </div>
                       </div>
                       <div>
                       <div>
@@ -109,9 +109,9 @@ export class ShopsPage {
                 <button
                 <button
                   type="submit"
                   type="submit"
                   class="btn btn-primary sm:ml-3 sm:w-auto"
                   class="btn btn-primary sm:ml-3 sm:w-auto"
-                  id="submit-shop"
+                  id="submit-site"
                 >
                 >
-                  <span id="submit-text">Add Shop</span>
+                  <span id="submit-text">Add Site</span>
                   <div class="w-4 h-4 ml-2 hidden" id="submit-spinner">
                   <div class="w-4 h-4 ml-2 hidden" id="submit-spinner">
                     <div class="spinner"></div>
                     <div class="spinner"></div>
                   </div>
                   </div>
@@ -119,7 +119,7 @@ export class ShopsPage {
                 <button
                 <button
                   type="button"
                   type="button"
                   class="btn btn-secondary mt-3 sm:mt-0 sm:w-auto"
                   class="btn btn-secondary mt-3 sm:mt-0 sm:w-auto"
-                  id="cancel-shop"
+                  id="cancel-site"
                 >
                 >
                   Cancel
                   Cancel
                 </button>
                 </button>
@@ -129,28 +129,28 @@ export class ShopsPage {
         </div>
         </div>
       </div>
       </div>
 
 
-      <!-- Shops Grid -->
-      <div id="shops-container">
+      <!-- Sites Grid -->
+      <div id="sites-container">
         <div class="flex items-center justify-center py-12">
         <div class="flex items-center justify-center py-12">
           <div class="w-8 h-8 spinner"></div>
           <div class="w-8 h-8 spinner"></div>
-          <span class="ml-3 text-gray-600 dark:text-gray-400">Loading shops...</span>
+          <span class="ml-3 text-gray-600 dark:text-gray-400">Loading sites...</span>
         </div>
         </div>
       </div>
       </div>
 
 
-      <!-- Deleted Shops Section -->
-      <div id="deleted-shops-section" class="hidden">
+      <!-- Deleted Sites Section -->
+      <div id="deleted-sites-section" class="hidden">
         <div class="border-t border-gray-200 dark:border-gray-700 my-8"></div>
         <div class="border-t border-gray-200 dark:border-gray-700 my-8"></div>
         <div class="flex items-center justify-between mb-4">
         <div class="flex items-center justify-between mb-4">
-          <h3 class="text-lg font-medium text-gray-900 dark:text-white">Deleted Shops</h3>
+          <h3 class="text-lg font-medium text-gray-900 dark:text-white">Deleted Sites</h3>
           <span class="text-sm text-gray-500 dark:text-gray-400">Pending permanent deletion</span>
           <span class="text-sm text-gray-500 dark:text-gray-400">Pending permanent deletion</span>
         </div>
         </div>
-        <div id="deleted-shops-container"></div>
+        <div id="deleted-sites-container"></div>
       </div>
       </div>
     `;
     `;
 
 
     this.bindEvents();
     this.bindEvents();
-    this.loadShops();
-    this.loadDeletedShops();
+    this.loadSites();
+    this.loadDeletedSites();
 
 
     return this.element;
     return this.element;
   }
   }
@@ -158,16 +158,16 @@ export class ShopsPage {
   private bindEvents(): void {
   private bindEvents(): void {
     if (!this.element) return;
     if (!this.element) return;
 
 
-    const addShopBtn = this.element.querySelector('#add-shop-btn');
-    const refreshBtn = this.element.querySelector('#refresh-shops');
-    const modal = this.element.querySelector('#add-shop-modal');
-    const form = this.element.querySelector('#add-shop-form') as HTMLFormElement;
-    const cancelBtn = this.element.querySelector('#cancel-shop');
+    const addSiteBtn = this.element.querySelector('#add-site-btn');
+    const refreshBtn = this.element.querySelector('#refresh-sites');
+    const modal = this.element.querySelector('#add-site-modal');
+    const form = this.element.querySelector('#add-site-form') as HTMLFormElement;
+    const cancelBtn = this.element.querySelector('#cancel-site');
 
 
     // Show modal
     // Show modal
-    addShopBtn?.addEventListener('click', () => {
+    addSiteBtn?.addEventListener('click', () => {
       modal?.classList.remove('hidden');
       modal?.classList.remove('hidden');
-      const urlInput = this.element?.querySelector('#shop-url') as HTMLInputElement;
+      const urlInput = this.element?.querySelector('#site-url') as HTMLInputElement;
       urlInput?.focus();
       urlInput?.focus();
     });
     });
 
 
@@ -188,17 +188,17 @@ export class ShopsPage {
 
 
     // Refresh
     // Refresh
     refreshBtn?.addEventListener('click', () => {
     refreshBtn?.addEventListener('click', () => {
-      this.loadShops();
+      this.loadSites();
     });
     });
 
 
     // Form submit
     // Form submit
     form?.addEventListener('submit', async (e) => {
     form?.addEventListener('submit', async (e) => {
       e.preventDefault();
       e.preventDefault();
       const formData = new FormData(form);
       const formData = new FormData(form);
-      const shopUrl = formData.get('shopUrl') as string;
+      const siteUrl = formData.get('siteUrl') as string;
       const customId = (formData.get('customId') as string)?.trim() || undefined;
       const customId = (formData.get('customId') as string)?.trim() || undefined;
 
 
-      if (!shopUrl) return;
+      if (!siteUrl) return;
 
 
       // Validate custom ID format if provided
       // Validate custom ID format if provided
       if (customId && !/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(customId)) {
       if (customId && !/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(customId)) {
@@ -206,7 +206,7 @@ export class ShopsPage {
         return;
         return;
       }
       }
 
 
-      const submitBtn = this.element?.querySelector('#submit-shop') as HTMLButtonElement;
+      const submitBtn = this.element?.querySelector('#submit-site') as HTMLButtonElement;
       const submitText = this.element?.querySelector('#submit-text');
       const submitText = this.element?.querySelector('#submit-text');
       const submitSpinner = this.element?.querySelector('#submit-spinner');
       const submitSpinner = this.element?.querySelector('#submit-spinner');
 
 
@@ -215,63 +215,63 @@ export class ShopsPage {
       submitSpinner?.classList.remove('hidden');
       submitSpinner?.classList.remove('hidden');
 
 
       try {
       try {
-        const response = await this.apiService.createJob(shopUrl, customId);
+        const response = await this.apiService.createJob(siteUrl, customId);
 
 
         if (response.success) {
         if (response.success) {
-          this.toastService.success('Shop Added', 'Shop scraping job has been started');
+          this.toastService.success('Site Added', 'Site scraping job has been started');
           hideModal();
           hideModal();
-          this.loadShops();
+          this.loadSites();
         } else {
         } else {
-          this.toastService.error('Add Failed', response.error || 'Failed to add shop');
+          this.toastService.error('Add Failed', response.error || 'Failed to add site');
         }
         }
       } catch (error) {
       } catch (error) {
-        this.toastService.error('Error', 'Failed to add shop');
+        this.toastService.error('Error', 'Failed to add site');
       } finally {
       } finally {
         submitBtn.disabled = false;
         submitBtn.disabled = false;
-        submitText!.textContent = 'Add Shop';
+        submitText!.textContent = 'Add Site';
         submitSpinner?.classList.add('hidden');
         submitSpinner?.classList.add('hidden');
       }
       }
     });
     });
   }
   }
 
 
-  private async loadShops(): Promise<void> {
-    const container = this.element?.querySelector('#shops-container');
+  private async loadSites(): Promise<void> {
+    const container = this.element?.querySelector('#sites-container');
     if (!container) return;
     if (!container) return;
 
 
     try {
     try {
-      const response = await this.apiService.getShops();
+      const response = await this.apiService.getSites();
 
 
       if (response.success && response.data) {
       if (response.success && response.data) {
-        // API returns { shops } directly, no data wrapper
-        this.shops = response.data.shops;
-        this.renderShops();
+        // API returns { sites } directly, no data wrapper
+        this.sites = response.data.sites;
+        this.renderSites();
       } else {
       } else {
-        this.toastService.error('Load Error', response.error || 'Failed to load shops');
+        this.toastService.error('Load Error', response.error || 'Failed to load sites');
       }
       }
     } catch (error) {
     } catch (error) {
-      this.toastService.error('Error', 'Failed to load shops');
+      this.toastService.error('Error', 'Failed to load sites');
     }
     }
   }
   }
 
 
-  private async loadDeletedShops(): Promise<void> {
+  private async loadDeletedSites(): Promise<void> {
     try {
     try {
-      const response = await this.apiService.getDeletedShops();
+      const response = await this.apiService.getDeletedSites();
 
 
       if (response.success && response.data) {
       if (response.success && response.data) {
-        this.deletedShops = response.data.shops;
-        this.renderDeletedShops();
+        this.deletedSites = response.data.sites;
+        this.renderDeletedSites();
       }
       }
     } catch (error) {
     } catch (error) {
-      // Silently fail - deleted shops are optional
-      console.error('Failed to load deleted shops', error);
+      // Silently fail - deleted sites are optional
+      console.error('Failed to load deleted sites', error);
     }
     }
   }
   }
 
 
-  private renderShops(): void {
-    const container = this.element?.querySelector('#shops-container');
+  private renderSites(): void {
+    const container = this.element?.querySelector('#sites-container');
     if (!container) return;
     if (!container) return;
 
 
-    if (this.shops.length === 0) {
+    if (this.sites.length === 0) {
       container.innerHTML = `
       container.innerHTML = `
         <div class="text-center py-12">
         <div class="text-center py-12">
           <div class="w-16 h-16 bg-gray-100 dark:bg-gray-700 rounded-lg flex items-center justify-center mx-auto mb-4">
           <div class="w-16 h-16 bg-gray-100 dark:bg-gray-700 rounded-lg flex items-center justify-center mx-auto mb-4">
@@ -279,15 +279,15 @@ export class ShopsPage {
               ${getIcon('shops')}
               ${getIcon('shops')}
             </div>
             </div>
           </div>
           </div>
-          <h3 class="text-lg font-medium text-gray-900 dark:text-white mb-2">No shops yet</h3>
+          <h3 class="text-lg font-medium text-gray-900 dark:text-white mb-2">No sites yet</h3>
           <p class="text-gray-500 dark:text-gray-400 mb-6">
           <p class="text-gray-500 dark:text-gray-400 mb-6">
-            Get started by adding your first webshop to scrape
+            Get started by adding your first site to scrape
           </p>
           </p>
-          <button class="btn btn-primary" onclick="document.getElementById('add-shop-btn').click()">
+          <button class="btn btn-primary" onclick="document.getElementById('add-site-btn').click()">
             <div class="w-4 h-4 mr-2">
             <div class="w-4 h-4 mr-2">
               ${getIcon('plus')}
               ${getIcon('plus')}
             </div>
             </div>
-            Add Your First Shop
+            Add Your First Site
           </button>
           </button>
         </div>
         </div>
       `;
       `;
@@ -296,29 +296,29 @@ export class ShopsPage {
 
 
     container.innerHTML = `
     container.innerHTML = `
       <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
       <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
-        ${this.shops.map(shop => this.renderShopCard(shop)).join('')}
+        ${this.sites.map(site => this.renderSiteCard(site)).join('')}
       </div>
       </div>
     `;
     `;
 
 
     // Add click handlers
     // Add click handlers
-    container.querySelectorAll('[data-shop-id]').forEach(element => {
+    container.querySelectorAll('[data-site-id]').forEach(element => {
       element.addEventListener('click', () => {
       element.addEventListener('click', () => {
-        const shopId = element.getAttribute('data-shop-id');
-        if (shopId) {
-          this.router.navigate(`/shops/${shopId}`);
+        const siteId = element.getAttribute('data-site-id');
+        if (siteId) {
+          this.router.navigate(`/sites/${siteId}`);
         }
         }
       });
       });
     });
     });
   }
   }
 
 
-  private renderShopCard(shop: ShopWithAnalytics): string {
-    const domain = getDomainFromUrl(shop.url);
-    const typeInfo = getWebshopTypeInfo(shop.webshop_type);
+  private renderSiteCard(site: SiteWithAnalytics): string {
+    const domain = getDomainFromUrl(site.url);
+    const typeInfo = getSiteTypeInfo(site.site_type);
 
 
     return `
     return `
       <div
       <div
         class="card hover:shadow-lg transition-shadow cursor-pointer"
         class="card hover:shadow-lg transition-shadow cursor-pointer"
-        data-shop-id="${shop.id}"
+        data-site-id="${site.id}"
       >
       >
         <div class="card-body">
         <div class="card-body">
           <div class="flex items-start justify-between">
           <div class="flex items-start justify-between">
@@ -343,34 +343,34 @@ export class ShopsPage {
                 <div class="flex items-center justify-between text-sm">
                 <div class="flex items-center justify-between text-sm">
                   <span class="text-gray-500 dark:text-gray-400">Total Scrapes</span>
                   <span class="text-gray-500 dark:text-gray-400">Total Scrapes</span>
                   <span class="font-medium text-gray-900 dark:text-white">
                   <span class="font-medium text-gray-900 dark:text-white">
-                    ${shop.analytics.total_scrapes}
+                    ${site.analytics.total_scrapes}
                   </span>
                   </span>
                 </div>
                 </div>
 
 
                 <div class="flex items-center justify-between text-sm">
                 <div class="flex items-center justify-between text-sm">
                   <span class="text-gray-500 dark:text-gray-400">URLs Found</span>
                   <span class="text-gray-500 dark:text-gray-400">URLs Found</span>
                   <span class="font-medium text-gray-900 dark:text-white">
                   <span class="font-medium text-gray-900 dark:text-white">
-                    ${shop.analytics.total_urls_found}
+                    ${site.analytics.total_urls_found}
                   </span>
                   </span>
                 </div>
                 </div>
 
 
                 <div class="flex items-center justify-between text-sm">
                 <div class="flex items-center justify-between text-sm">
                   <span class="text-gray-500 dark:text-gray-400">Last Scraped</span>
                   <span class="text-gray-500 dark:text-gray-400">Last Scraped</span>
                   <span class="font-medium text-gray-900 dark:text-white">
                   <span class="font-medium text-gray-900 dark:text-white">
-                    ${shop.analytics.last_scraped_at ? formatRelativeTime(shop.analytics.last_scraped_at) : 'Never'}
+                    ${site.analytics.last_scraped_at ? formatRelativeTime(site.analytics.last_scraped_at) : 'Never'}
                   </span>
                   </span>
                 </div>
                 </div>
 
 
-                ${shop.custom_id ? `
+                ${site.custom_id ? `
                 <div class="flex items-center justify-between text-sm">
                 <div class="flex items-center justify-between text-sm">
                   <span class="text-gray-500 dark:text-gray-400">Custom ID</span>
                   <span class="text-gray-500 dark:text-gray-400">Custom ID</span>
                   <div class="flex items-center space-x-1">
                   <div class="flex items-center space-x-1">
                     <span class="font-medium text-gray-900 dark:text-white font-mono text-xs">
                     <span class="font-medium text-gray-900 dark:text-white font-mono text-xs">
-                      ${shop.custom_id.substring(0, 8)}...
+                      ${site.custom_id.substring(0, 8)}...
                     </span>
                     </span>
                     <button
                     <button
                       class="text-gray-400 hover:text-gray-600 dark:hover:text-gray-300"
                       class="text-gray-400 hover:text-gray-600 dark:hover:text-gray-300"
-                      onclick="event.stopPropagation(); navigator.clipboard.writeText('${shop.custom_id}').then(() => {
+                      onclick="event.stopPropagation(); navigator.clipboard.writeText('${site.custom_id}').then(() => {
                         document.dispatchEvent(new CustomEvent('show-toast', {
                         document.dispatchEvent(new CustomEvent('show-toast', {
                           detail: { type: 'success', title: 'Copied!', message: 'Custom ID copied to clipboard' }
                           detail: { type: 'success', title: 'Copied!', message: 'Custom ID copied to clipboard' }
                         }));
                         }));
@@ -386,11 +386,11 @@ export class ShopsPage {
 
 
               <div class="mt-4 pt-4 border-t border-gray-200 dark:border-gray-700">
               <div class="mt-4 pt-4 border-t border-gray-200 dark:border-gray-700">
                 <div class="flex items-center justify-between">
                 <div class="flex items-center justify-between">
-                  <span class="badge ${shop.analytics.total_scrapes > 0 ? 'badge-success' : 'badge-gray'}">
-                    ${shop.analytics.total_scrapes > 0 ? 'Active' : 'New'}
+                  <span class="badge ${site.analytics.total_scrapes > 0 ? 'badge-success' : 'badge-gray'}">
+                    ${site.analytics.total_scrapes > 0 ? 'Active' : 'New'}
                   </span>
                   </span>
                   <div class="text-xs text-gray-500 dark:text-gray-400">
                   <div class="text-xs text-gray-500 dark:text-gray-400">
-                    Added ${formatRelativeTime(shop.created_at)}
+                    Added ${formatRelativeTime(site.created_at)}
                   </div>
                   </div>
                 </div>
                 </div>
               </div>
               </div>
@@ -401,12 +401,12 @@ export class ShopsPage {
     `;
     `;
   }
   }
 
 
-  private renderDeletedShops(): void {
-    const section = this.element?.querySelector('#deleted-shops-section');
-    const container = this.element?.querySelector('#deleted-shops-container');
+  private renderDeletedSites(): void {
+    const section = this.element?.querySelector('#deleted-sites-section');
+    const container = this.element?.querySelector('#deleted-sites-container');
     if (!section || !container) return;
     if (!section || !container) return;
 
 
-    if (this.deletedShops.length === 0) {
+    if (this.deletedSites.length === 0) {
       section.classList.add('hidden');
       section.classList.add('hidden');
       return;
       return;
     }
     }
@@ -420,23 +420,23 @@ export class ShopsPage {
           </div>
           </div>
           <div class="flex-1">
           <div class="flex-1">
             <p class="text-sm text-yellow-800 dark:text-yellow-300 mb-3">
             <p class="text-sm text-yellow-800 dark:text-yellow-300 mb-3">
-              ${this.deletedShops.length} shop${this.deletedShops.length !== 1 ? 's' : ''} marked for deletion. Data is preserved but hidden from API. Use force delete to permanently remove.
+              ${this.deletedSites.length} site${this.deletedSites.length !== 1 ? 's' : ''} marked for deletion. Data is preserved but hidden from API. Use force delete to permanently remove.
             </p>
             </p>
             <div class="space-y-2">
             <div class="space-y-2">
-              ${this.deletedShops.map(shop => `
+              ${this.deletedSites.map(site => `
                 <div class="flex items-center justify-between bg-white dark:bg-gray-800 rounded-lg p-3">
                 <div class="flex items-center justify-between bg-white dark:bg-gray-800 rounded-lg p-3">
                   <div class="flex-1 min-w-0">
                   <div class="flex-1 min-w-0">
                     <p class="text-sm font-medium text-gray-900 dark:text-white truncate">
                     <p class="text-sm font-medium text-gray-900 dark:text-white truncate">
-                      ${getDomainFromUrl(shop.url)}
+                      ${getDomainFromUrl(site.url)}
                     </p>
                     </p>
                     <p class="text-xs text-gray-500 dark:text-gray-400">
                     <p class="text-xs text-gray-500 dark:text-gray-400">
-                      Deleted ${formatRelativeTime(shop.deleted_at!)}
-                      ${shop.custom_id ? `• ID: ${shop.custom_id.substring(0, 8)}...` : ''}
+                      Deleted ${formatRelativeTime(site.deleted_at!)}
+                      ${site.custom_id ? `• ID: ${site.custom_id.substring(0, 8)}...` : ''}
                     </p>
                     </p>
                   </div>
                   </div>
                   <button
                   <button
                     class="btn btn-sm btn-danger ml-3"
                     class="btn btn-sm btn-danger ml-3"
-                    data-force-delete-id="${shop.id}"
+                    data-force-delete-id="${site.id}"
                   >
                   >
                     <div class="w-3 h-3 mr-1">${getIcon('delete')}</div>
                     <div class="w-3 h-3 mr-1">${getIcon('delete')}</div>
                     Force Delete
                     Force Delete
@@ -452,14 +452,14 @@ export class ShopsPage {
     // Add force delete handlers
     // Add force delete handlers
     container.querySelectorAll('[data-force-delete-id]').forEach(button => {
     container.querySelectorAll('[data-force-delete-id]').forEach(button => {
       button.addEventListener('click', async (e) => {
       button.addEventListener('click', async (e) => {
-        const shopId = (e.currentTarget as HTMLElement).getAttribute('data-force-delete-id');
-        if (!shopId) return;
+        const siteId = (e.currentTarget as HTMLElement).getAttribute('data-force-delete-id');
+        if (!siteId) return;
 
 
-        const shop = this.deletedShops.find(s => s.id === shopId);
-        if (!shop) return;
+        const site = this.deletedSites.find(s => s.id === siteId);
+        if (!site) return;
 
 
         const confirmed = confirm(
         const confirmed = confirm(
-          `Are you sure you want to permanently delete "${getDomainFromUrl(shop.url)}"?\n\n` +
+          `Are you sure you want to permanently delete "${getDomainFromUrl(site.url)}"?\n\n` +
           `This will:\n` +
           `This will:\n` +
           `- Remove all data from the database\n` +
           `- Remove all data from the database\n` +
           `- Queue Qdrant collections for cleanup\n` +
           `- Queue Qdrant collections for cleanup\n` +
@@ -469,18 +469,18 @@ export class ShopsPage {
         if (!confirmed) return;
         if (!confirmed) return;
 
 
         try {
         try {
-          const response = await this.apiService.forceDeleteShop(shopId);
+          const response = await this.apiService.forceDeleteSite(siteId);
 
 
           if (response.success) {
           if (response.success) {
-            this.toastService.success('Force Deleted', 'Shop and data permanently removed. Qdrant cleanup queued.');
-            this.loadDeletedShops();
+            this.toastService.success('Force Deleted', 'Site and data permanently removed. Qdrant cleanup queued.');
+            this.loadDeletedSites();
           } else {
           } else {
-            this.toastService.error('Delete Failed', response.error || 'Failed to force delete shop');
+            this.toastService.error('Delete Failed', response.error || 'Failed to force delete site');
           }
           }
         } catch (error) {
         } catch (error) {
-          this.toastService.error('Error', 'Failed to force delete shop');
+          this.toastService.error('Error', 'Failed to force delete site');
         }
         }
       });
       });
     });
     });
   }
   }
-}
+}

+ 62 - 62
web/src/components/pages/WebhooksPage.ts

@@ -1,19 +1,19 @@
 import { ApiService } from '../../services/ApiService';
 import { ApiService } from '../../services/ApiService';
 import { ToastService } from '../../services/ToastService';
 import { ToastService } from '../../services/ToastService';
 import { Router } from '../../app/Router';
 import { Router } from '../../app/Router';
-import { ShopWithAnalytics, Webhook, WebhookDelivery } from '../../types';
+import { SiteWithAnalytics, Webhook, WebhookDelivery } from '../../types';
 import { getIcon } from '../../utils/icons';
 import { getIcon } from '../../utils/icons';
 import { formatRelativeTime, getDomainFromUrl } from '../../utils/helpers';
 import { formatRelativeTime, getDomainFromUrl } from '../../utils/helpers';
 
 
-interface ShopWebhookData {
+interface SiteWebhookData {
   webhook: Webhook | null;
   webhook: Webhook | null;
   deliveries: WebhookDelivery[];
   deliveries: WebhookDelivery[];
 }
 }
 
 
 export class WebhooksPage {
 export class WebhooksPage {
   private element: HTMLElement | null = null;
   private element: HTMLElement | null = null;
-  private shops: ShopWithAnalytics[] = [];
-  private webhookData: Map<string, ShopWebhookData> = new Map();
+  private sites: SiteWithAnalytics[] = [];
+  private webhookData: Map<string, SiteWebhookData> = new Map();
   private eventsbound: boolean = false;
   private eventsbound: boolean = false;
 
 
   constructor(
   constructor(
@@ -34,7 +34,7 @@ export class WebhooksPage {
             Webhooks
             Webhooks
           </h2>
           </h2>
           <p class="mt-1 text-sm text-gray-500 dark:text-gray-400">
           <p class="mt-1 text-sm text-gray-500 dark:text-gray-400">
-            Configure webhook notifications for shop events
+            Configure webhook notifications for site events
           </p>
           </p>
         </div>
         </div>
         <div class="mt-4 flex md:mt-0 md:ml-4 space-x-3">
         <div class="mt-4 flex md:mt-0 md:ml-4 space-x-3">
@@ -56,14 +56,14 @@ export class WebhooksPage {
       <!-- Webhooks List -->
       <!-- Webhooks List -->
       <div class="card">
       <div class="card">
         <div class="card-header">
         <div class="card-header">
-          <h3 class="text-lg font-medium text-gray-900 dark:text-white">Shop Webhooks</h3>
-          <p class="text-sm text-gray-500 dark:text-gray-400">Configure webhook endpoints for each shop</p>
+          <h3 class="text-lg font-medium text-gray-900 dark:text-white">Site Webhooks</h3>
+          <p class="text-sm text-gray-500 dark:text-gray-400">Configure webhook endpoints for each site</p>
         </div>
         </div>
         <div class="card-body">
         <div class="card-body">
           <div id="webhooks-list">
           <div id="webhooks-list">
             <div class="flex items-center justify-center py-12">
             <div class="flex items-center justify-center py-12">
               <div class="w-8 h-8 spinner"></div>
               <div class="w-8 h-8 spinner"></div>
-              <span class="ml-3 text-gray-600 dark:text-gray-400">Loading shops...</span>
+              <span class="ml-3 text-gray-600 dark:text-gray-400">Loading sites...</span>
             </div>
             </div>
           </div>
           </div>
         </div>
         </div>
@@ -80,7 +80,7 @@ export class WebhooksPage {
               </button>
               </button>
             </div>
             </div>
             <form id="webhook-form">
             <form id="webhook-form">
-              <input type="hidden" id="webhook-shop-id" name="shopId" />
+              <input type="hidden" id="webhook-site-id" name="siteId" />
               <div class="mb-4">
               <div class="mb-4">
                 <label for="webhook-url" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
                 <label for="webhook-url" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
                   Webhook URL *
                   Webhook URL *
@@ -127,7 +127,7 @@ export class WebhooksPage {
     `;
     `;
 
 
     this.bindEvents();
     this.bindEvents();
-    this.loadShopsAndWebhooks();
+    this.loadSitesAndWebhooks();
 
 
     return this.element;
     return this.element;
   }
   }
@@ -138,7 +138,7 @@ export class WebhooksPage {
 
 
     // Refresh button
     // Refresh button
     this.element.querySelector('#refresh-webhooks')?.addEventListener('click', () => {
     this.element.querySelector('#refresh-webhooks')?.addEventListener('click', () => {
-      this.loadShopsAndWebhooks();
+      this.loadSitesAndWebhooks();
     });
     });
 
 
     // Modal events
     // Modal events
@@ -167,47 +167,47 @@ export class WebhooksPage {
     });
     });
   }
   }
 
 
-  private async loadShopsAndWebhooks(): Promise<void> {
+  private async loadSitesAndWebhooks(): Promise<void> {
     try {
     try {
-      const response = await this.apiService.getShops();
+      const response = await this.apiService.getSites();
 
 
       if (response.success && response.data) {
       if (response.success && response.data) {
-        this.shops = response.data.shops;
+        this.sites = response.data.sites;
 
 
-        // Load webhook data for each shop
+        // Load webhook data for each site
         await this.loadWebhookData();
         await this.loadWebhookData();
 
 
         this.renderStats();
         this.renderStats();
         this.renderWebhooksList();
         this.renderWebhooksList();
       } else {
       } else {
-        this.toastService.error('Load Error', response.error || 'Failed to load shops');
+        this.toastService.error('Load Error', response.error || 'Failed to load sites');
       }
       }
     } catch (error) {
     } catch (error) {
-      this.toastService.error('Error', 'Failed to load shops');
+      this.toastService.error('Error', 'Failed to load sites');
     }
     }
   }
   }
 
 
   private async loadWebhookData(): Promise<void> {
   private async loadWebhookData(): Promise<void> {
     this.webhookData.clear();
     this.webhookData.clear();
 
 
-    for (const shop of this.shops) {
+    for (const site of this.sites) {
       try {
       try {
-        const response = await this.apiService.getWebhook(shop.id);
+        const response = await this.apiService.getWebhook(site.id);
         if (response.success && response.data) {
         if (response.success && response.data) {
-          this.webhookData.set(shop.id, {
+          this.webhookData.set(site.id, {
             webhook: response.data.webhook,
             webhook: response.data.webhook,
             deliveries: response.data.deliveries
             deliveries: response.data.deliveries
           });
           });
         } else {
         } else {
           // No webhook configured - this is normal
           // No webhook configured - this is normal
-          this.webhookData.set(shop.id, {
+          this.webhookData.set(site.id, {
             webhook: null,
             webhook: null,
             deliveries: []
             deliveries: []
           });
           });
         }
         }
       } catch (error) {
       } catch (error) {
-        console.error(`Failed to load webhook for shop ${shop.id}:`, error);
-        this.webhookData.set(shop.id, {
+        console.error(`Failed to load webhook for site ${site.id}:`, error);
+        this.webhookData.set(site.id, {
           webhook: null,
           webhook: null,
           deliveries: []
           deliveries: []
         });
         });
@@ -219,7 +219,7 @@ export class WebhooksPage {
     const statsContainer = this.element?.querySelector('#webhook-stats');
     const statsContainer = this.element?.querySelector('#webhook-stats');
     if (!statsContainer) return;
     if (!statsContainer) return;
 
 
-    let totalShops = this.shops.length;
+    let totalSites = this.sites.length;
     let configuredCount = 0;
     let configuredCount = 0;
     let enabledCount = 0;
     let enabledCount = 0;
     let recentDeliveries = 0;
     let recentDeliveries = 0;
@@ -237,8 +237,8 @@ export class WebhooksPage {
     statsContainer.innerHTML = `
     statsContainer.innerHTML = `
       <div class="card">
       <div class="card">
         <div class="card-body text-center">
         <div class="card-body text-center">
-          <div class="text-2xl font-bold text-gray-900 dark:text-white">${totalShops}</div>
-          <div class="text-sm text-gray-500 dark:text-gray-400">Total Shops</div>
+          <div class="text-2xl font-bold text-gray-900 dark:text-white">${totalSites}</div>
+          <div class="text-sm text-gray-500 dark:text-gray-400">Total Sites</div>
         </div>
         </div>
       </div>
       </div>
       <div class="card">
       <div class="card">
@@ -266,14 +266,14 @@ export class WebhooksPage {
     const listContainer = this.element?.querySelector('#webhooks-list');
     const listContainer = this.element?.querySelector('#webhooks-list');
     if (!listContainer) return;
     if (!listContainer) return;
 
 
-    if (this.shops.length === 0) {
+    if (this.sites.length === 0) {
       listContainer.innerHTML = `
       listContainer.innerHTML = `
         <div class="text-center py-12">
         <div class="text-center py-12">
           <div class="w-16 h-16 bg-gray-100 dark:bg-gray-700 rounded-lg flex items-center justify-center mx-auto mb-4">
           <div class="w-16 h-16 bg-gray-100 dark:bg-gray-700 rounded-lg flex items-center justify-center mx-auto mb-4">
             <div class="w-8 h-8 text-gray-400">${getIcon('webhooks')}</div>
             <div class="w-8 h-8 text-gray-400">${getIcon('webhooks')}</div>
           </div>
           </div>
-          <h3 class="text-lg font-medium text-gray-900 dark:text-white mb-2">No shops yet</h3>
-          <p class="text-gray-500 dark:text-gray-400">Add shops first to configure webhooks</p>
+          <h3 class="text-lg font-medium text-gray-900 dark:text-white mb-2">No sites yet</h3>
+          <p class="text-gray-500 dark:text-gray-400">Add sites first to configure webhooks</p>
         </div>
         </div>
       `;
       `;
       return;
       return;
@@ -281,16 +281,16 @@ export class WebhooksPage {
 
 
     listContainer.innerHTML = `
     listContainer.innerHTML = `
       <div class="space-y-4">
       <div class="space-y-4">
-        ${this.shops.map(shop => this.renderWebhookCard(shop)).join('')}
+        ${this.sites.map(site => this.renderWebhookCard(site)).join('')}
       </div>
       </div>
     `;
     `;
 
 
     this.bindWebhookEvents();
     this.bindWebhookEvents();
   }
   }
 
 
-  private renderWebhookCard(shop: ShopWithAnalytics): string {
-    const domain = getDomainFromUrl(shop.url);
-    const data = this.webhookData.get(shop.id);
+  private renderWebhookCard(site: SiteWithAnalytics): string {
+    const domain = getDomainFromUrl(site.url);
+    const data = this.webhookData.get(site.id);
     const webhook = data?.webhook;
     const webhook = data?.webhook;
     const deliveries = data?.deliveries || [];
     const deliveries = data?.deliveries || [];
 
 
@@ -300,7 +300,7 @@ export class WebhooksPage {
     return `
     return `
       <div class="p-4 border border-gray-200 dark:border-gray-600 rounded-lg hover:shadow-md transition-shadow">
       <div class="p-4 border border-gray-200 dark:border-gray-600 rounded-lg hover:shadow-md transition-shadow">
         <div class="flex items-center justify-between mb-4">
         <div class="flex items-center justify-between mb-4">
-          <!-- Shop Info -->
+          <!-- Site Info -->
           <div class="flex items-center space-x-4 flex-1 min-w-0">
           <div class="flex items-center space-x-4 flex-1 min-w-0">
             <div class="flex-shrink-0">
             <div class="flex-shrink-0">
               <div class="w-12 h-12 bg-primary-100 dark:bg-primary-900 rounded-lg flex items-center justify-center">
               <div class="w-12 h-12 bg-primary-100 dark:bg-primary-900 rounded-lg flex items-center justify-center">
@@ -314,11 +314,11 @@ export class WebhooksPage {
                 ${domain}
                 ${domain}
               </h4>
               </h4>
               <p class="text-sm text-gray-500 dark:text-gray-400 truncate">
               <p class="text-sm text-gray-500 dark:text-gray-400 truncate">
-                ${shop.url}
+                ${site.url}
               </p>
               </p>
               <div class="mt-1 flex items-center space-x-4">
               <div class="mt-1 flex items-center space-x-4">
                 <span class="text-xs text-gray-500 dark:text-gray-400">
                 <span class="text-xs text-gray-500 dark:text-gray-400">
-                  ${shop.analytics.total_scrapes} scrapes
+                  ${site.analytics.total_scrapes} scrapes
                 </span>
                 </span>
               </div>
               </div>
             </div>
             </div>
@@ -359,7 +359,7 @@ export class WebhooksPage {
                   <input
                   <input
                     type="checkbox"
                     type="checkbox"
                     class="sr-only peer webhook-toggle"
                     class="sr-only peer webhook-toggle"
-                    data-shop-id="${shop.id}"
+                    data-site-id="${site.id}"
                     ${isEnabled ? 'checked' : ''}
                     ${isEnabled ? 'checked' : ''}
                   >
                   >
                   <div class="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-primary-300 dark:peer-focus:ring-primary-800 rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all dark:border-gray-600 peer-checked:bg-primary-600"></div>
                   <div class="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-primary-300 dark:peer-focus:ring-primary-800 rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all dark:border-gray-600 peer-checked:bg-primary-600"></div>
@@ -369,7 +369,7 @@ export class WebhooksPage {
                 <button
                 <button
                   type="button"
                   type="button"
                   class="btn btn-secondary btn-sm edit-webhook-btn"
                   class="btn btn-secondary btn-sm edit-webhook-btn"
-                  data-shop-id="${shop.id}"
+                  data-site-id="${site.id}"
                 >
                 >
                   <div class="w-4 h-4">${getIcon('edit')}</div>
                   <div class="w-4 h-4">${getIcon('edit')}</div>
                 </button>
                 </button>
@@ -378,7 +378,7 @@ export class WebhooksPage {
                 <button
                 <button
                   type="button"
                   type="button"
                   class="btn btn-danger btn-sm delete-webhook-btn"
                   class="btn btn-danger btn-sm delete-webhook-btn"
-                  data-shop-id="${shop.id}"
+                  data-site-id="${site.id}"
                 >
                 >
                   <div class="w-4 h-4">${getIcon('delete')}</div>
                   <div class="w-4 h-4">${getIcon('delete')}</div>
                 </button>
                 </button>
@@ -387,7 +387,7 @@ export class WebhooksPage {
                 <button
                 <button
                   type="button"
                   type="button"
                   class="btn btn-primary btn-sm add-webhook-btn"
                   class="btn btn-primary btn-sm add-webhook-btn"
-                  data-shop-id="${shop.id}"
+                  data-site-id="${site.id}"
                 >
                 >
                   <div class="w-4 h-4 mr-1">${getIcon('plus')}</div>
                   <div class="w-4 h-4 mr-1">${getIcon('plus')}</div>
                   Add Webhook
                   Add Webhook
@@ -432,24 +432,24 @@ export class WebhooksPage {
     // Add webhook buttons
     // Add webhook buttons
     this.element.querySelectorAll('.add-webhook-btn').forEach(btn => {
     this.element.querySelectorAll('.add-webhook-btn').forEach(btn => {
       btn.addEventListener('click', (e) => {
       btn.addEventListener('click', (e) => {
-        const shopId = (e.currentTarget as HTMLElement).getAttribute('data-shop-id');
-        if (shopId) this.showWebhookModal(shopId);
+        const siteId = (e.currentTarget as HTMLElement).getAttribute('data-site-id');
+        if (siteId) this.showWebhookModal(siteId);
       });
       });
     });
     });
 
 
     // Edit webhook buttons
     // Edit webhook buttons
     this.element.querySelectorAll('.edit-webhook-btn').forEach(btn => {
     this.element.querySelectorAll('.edit-webhook-btn').forEach(btn => {
       btn.addEventListener('click', (e) => {
       btn.addEventListener('click', (e) => {
-        const shopId = (e.currentTarget as HTMLElement).getAttribute('data-shop-id');
-        if (shopId) this.showWebhookModal(shopId, true);
+        const siteId = (e.currentTarget as HTMLElement).getAttribute('data-site-id');
+        if (siteId) this.showWebhookModal(siteId, true);
       });
       });
     });
     });
 
 
     // Delete webhook buttons
     // Delete webhook buttons
     this.element.querySelectorAll('.delete-webhook-btn').forEach(btn => {
     this.element.querySelectorAll('.delete-webhook-btn').forEach(btn => {
       btn.addEventListener('click', async (e) => {
       btn.addEventListener('click', async (e) => {
-        const shopId = (e.currentTarget as HTMLElement).getAttribute('data-shop-id');
-        if (shopId) await this.deleteWebhook(shopId);
+        const siteId = (e.currentTarget as HTMLElement).getAttribute('data-site-id');
+        if (siteId) await this.deleteWebhook(siteId);
       });
       });
     });
     });
 
 
@@ -457,15 +457,15 @@ export class WebhooksPage {
     this.element.querySelectorAll('.webhook-toggle').forEach(toggle => {
     this.element.querySelectorAll('.webhook-toggle').forEach(toggle => {
       toggle.addEventListener('change', async (e) => {
       toggle.addEventListener('change', async (e) => {
         const checkbox = e.target as HTMLInputElement;
         const checkbox = e.target as HTMLInputElement;
-        const shopId = checkbox.getAttribute('data-shop-id');
+        const siteId = checkbox.getAttribute('data-site-id');
 
 
-        if (!shopId) return;
+        if (!siteId) return;
 
 
         const enabled = checkbox.checked;
         const enabled = checkbox.checked;
         checkbox.disabled = true;
         checkbox.disabled = true;
 
 
         try {
         try {
-          const response = await this.apiService.updateWebhook(shopId, enabled);
+          const response = await this.apiService.updateWebhook(siteId, enabled);
 
 
           if (response.success) {
           if (response.success) {
             this.toastService.success(
             this.toastService.success(
@@ -486,18 +486,18 @@ export class WebhooksPage {
     });
     });
   }
   }
 
 
-  private showWebhookModal(shopId: string, isEdit: boolean = false): void {
+  private showWebhookModal(siteId: string, isEdit: boolean = false): void {
     const modal = this.element?.querySelector('#webhook-modal');
     const modal = this.element?.querySelector('#webhook-modal');
     const form = this.element?.querySelector('#webhook-form') as HTMLFormElement;
     const form = this.element?.querySelector('#webhook-form') as HTMLFormElement;
     const title = this.element?.querySelector('#modal-title');
     const title = this.element?.querySelector('#modal-title');
-    const shopIdInput = this.element?.querySelector('#webhook-shop-id') as HTMLInputElement;
+    const siteIdInput = this.element?.querySelector('#webhook-site-id') as HTMLInputElement;
     const urlInput = this.element?.querySelector('#webhook-url') as HTMLInputElement;
     const urlInput = this.element?.querySelector('#webhook-url') as HTMLInputElement;
     const secretInput = this.element?.querySelector('#webhook-secret') as HTMLInputElement;
     const secretInput = this.element?.querySelector('#webhook-secret') as HTMLInputElement;
 
 
-    if (!modal || !form || !shopIdInput) return;
+    if (!modal || !form || !siteIdInput) return;
 
 
-    const shop = this.shops.find(s => s.id === shopId);
-    const webhookData = this.webhookData.get(shopId);
+    const site = this.sites.find(s => s.id === siteId);
+    const webhookData = this.webhookData.get(siteId);
 
 
     if (title) {
     if (title) {
       title.textContent = isEdit ? 'Edit Webhook' : 'Add Webhook';
       title.textContent = isEdit ? 'Edit Webhook' : 'Add Webhook';
@@ -505,7 +505,7 @@ export class WebhooksPage {
 
 
     // Reset form
     // Reset form
     form.reset();
     form.reset();
-    shopIdInput.value = shopId;
+    siteIdInput.value = siteId;
 
 
     if (isEdit && webhookData?.webhook) {
     if (isEdit && webhookData?.webhook) {
       urlInput.value = webhookData.webhook.url;
       urlInput.value = webhookData.webhook.url;
@@ -526,7 +526,7 @@ export class WebhooksPage {
     if (!form) return;
     if (!form) return;
 
 
     const formData = new FormData(form);
     const formData = new FormData(form);
-    const shopId = formData.get('shopId') as string;
+    const siteId = formData.get('siteId') as string;
     const url = formData.get('url') as string;
     const url = formData.get('url') as string;
     const secret = formData.get('secret') as string;
     const secret = formData.get('secret') as string;
 
 
@@ -536,7 +536,7 @@ export class WebhooksPage {
     saveSpinner?.classList.remove('hidden');
     saveSpinner?.classList.remove('hidden');
 
 
     try {
     try {
-      const response = await this.apiService.createWebhook(shopId, {
+      const response = await this.apiService.createWebhook(siteId, {
         url,
         url,
         secret: secret || undefined
         secret: secret || undefined
       });
       });
@@ -562,18 +562,18 @@ export class WebhooksPage {
     }
     }
   }
   }
 
 
-  private async deleteWebhook(shopId: string): Promise<void> {
-    const shop = this.shops.find(s => s.id === shopId);
-    if (!shop) return;
+  private async deleteWebhook(siteId: string): Promise<void> {
+    const site = this.sites.find(s => s.id === siteId);
+    if (!site) return;
 
 
     const confirmed = confirm(
     const confirmed = confirm(
-      `Are you sure you want to delete the webhook for ${getDomainFromUrl(shop.url)}? This cannot be undone.`
+      `Are you sure you want to delete the webhook for ${getDomainFromUrl(site.url)}? This cannot be undone.`
     );
     );
 
 
     if (!confirmed) return;
     if (!confirmed) return;
 
 
     try {
     try {
-      const response = await this.apiService.deleteWebhook(shopId);
+      const response = await this.apiService.deleteWebhook(siteId);
 
 
       if (response.success) {
       if (response.success) {
         this.toastService.success('Webhook Deleted', 'Webhook removed successfully');
         this.toastService.success('Webhook Deleted', 'Webhook removed successfully');

+ 71 - 71
web/src/services/ApiService.ts

@@ -1,16 +1,16 @@
 import {
 import {
-  Shop,
-  ShopWithAnalytics,
-  ShopDetail,
+  Site,
+  SiteWithAnalytics,
+  SiteDetail,
   Job,
   Job,
   QueueStats,
   QueueStats,
-  ShopContent,
+  SiteContent,
   ScrapeHistory,
   ScrapeHistory,
   Webhook,
   Webhook,
   WebhookDelivery,
   WebhookDelivery,
   CustomUrl,
   CustomUrl,
   ContentFilters,
   ContentFilters,
-  ShopResultsResponse,
+  SiteResultsResponse,
   ApiResponse,
   ApiResponse,
   QdrantEmbedding,
   QdrantEmbedding,
   QdrantError,
   QdrantError,
@@ -76,8 +76,8 @@ export class ApiService {
     return this.request(`/api/jobs/${jobId}`);
     return this.request(`/api/jobs/${jobId}`);
   }
   }
 
 
-  async createJob(shopUrl: string, customId?: string): Promise<ApiResponse<{ job_id: string; message: string }>> {
-    const body: { url: string; custom_id?: string } = { url: shopUrl };
+  async createJob(siteUrl: string, customId?: string): Promise<ApiResponse<{ job_id: string; message: string }>> {
+    const body: { url: string; custom_id?: string } = { url: siteUrl };
     if (customId) {
     if (customId) {
       body.custom_id = customId;
       body.custom_id = customId;
     }
     }
@@ -88,48 +88,48 @@ export class ApiService {
     });
     });
   }
   }
 
 
-  // Shops
-  async getShops(): Promise<ApiResponse<{ shops: ShopWithAnalytics[] }>> {
-    const response = await this.request<{ shops: ShopWithAnalytics[] }>('/api/shops');
-    // API returns { shops } directly, no wrapper
+  // Sites
+  async getSites(): Promise<ApiResponse<{ sites: SiteWithAnalytics[] }>> {
+    const response = await this.request<{ sites: SiteWithAnalytics[] }>('/api/sites');
+    // API returns { sites } directly, no wrapper
     return response;
     return response;
   }
   }
 
 
-  async getShop(shopId: string): Promise<ApiResponse<ShopDetail>> {
-    return this.request(`/api/shops/${shopId}`);
+  async getSite(siteId: string): Promise<ApiResponse<SiteDetail>> {
+    return this.request(`/api/sites/${siteId}`);
   }
   }
 
 
-  async deleteShop(shopId: string): Promise<ApiResponse<{ message: string }>> {
-    return this.request(`/api/shops/${shopId}`, {
+  async deleteSite(siteId: string): Promise<ApiResponse<{ message: string }>> {
+    return this.request(`/api/sites/${siteId}`, {
       method: 'DELETE',
       method: 'DELETE',
     });
     });
   }
   }
 
 
-  async getDeletedShops(): Promise<ApiResponse<{ shops: Shop[] }>> {
-    return this.request('/api/shops/deleted');
+  async getDeletedSites(): Promise<ApiResponse<{ sites: Site[] }>> {
+    return this.request('/api/sites/deleted');
   }
   }
 
 
-  async forceDeleteShop(shopId: string): Promise<ApiResponse<{ message: string }>> {
-    return this.request(`/api/shops/${shopId}/force`, {
+  async forceDeleteSite(siteId: string): Promise<ApiResponse<{ message: string }>> {
+    return this.request(`/api/sites/${siteId}/force`, {
       method: 'DELETE',
       method: 'DELETE',
     });
     });
   }
   }
 
 
-  async updateShopCustomId(
-    shopId: string,
+  async updateSiteCustomId(
+    siteId: string,
     customId: string | null
     customId: string | null
-  ): Promise<ApiResponse<{ shop_id: string; custom_id: string | null; message: string }>> {
-    return this.request(`/api/shops/${shopId}/custom-id`, {
+  ): Promise<ApiResponse<{ site_id: string; custom_id: string | null; message: string }>> {
+    return this.request(`/api/sites/${siteId}/custom-id`, {
       method: 'PATCH',
       method: 'PATCH',
       body: JSON.stringify({ custom_id: customId }),
       body: JSON.stringify({ custom_id: customId }),
     });
     });
   }
   }
 
 
-  // Shop Results
-  async getShopResults(
-    shopId: string,
+  // Site Results
+  async getSiteResults(
+    siteId: string,
     filters: ContentFilters = {}
     filters: ContentFilters = {}
-  ): Promise<ApiResponse<ShopResultsResponse>> {
+  ): Promise<ApiResponse<SiteResultsResponse>> {
     const params = new URLSearchParams();
     const params = new URLSearchParams();
 
 
     if (filters.limit) params.append('limit', filters.limit.toString());
     if (filters.limit) params.append('limit', filters.limit.toString());
@@ -139,97 +139,97 @@ export class ApiService {
     if (filters.content_type) params.append('content_type', filters.content_type);
     if (filters.content_type) params.append('content_type', filters.content_type);
 
 
     const query = params.toString();
     const query = params.toString();
-    const url = `/api/shops/${shopId}/results${query ? `?${query}` : ''}`;
+    const url = `/api/sites/${siteId}/results${query ? `?${query}` : ''}`;
 
 
     return this.request(url);
     return this.request(url);
   }
   }
 
 
   // Schedule Management
   // Schedule Management
-  async updateShopSchedule(
-    shopId: string,
+  async updateSiteSchedule(
+    siteId: string,
     enabled: boolean
     enabled: boolean
   ): Promise<ApiResponse<{ message: string }>> {
   ): Promise<ApiResponse<{ message: string }>> {
-    return this.request(`/api/shops/${shopId}/schedule`, {
+    return this.request(`/api/sites/${siteId}/schedule`, {
       method: 'PATCH',
       method: 'PATCH',
       body: JSON.stringify({ enabled }),
       body: JSON.stringify({ enabled }),
     });
     });
   }
   }
 
 
   // Webhooks
   // Webhooks
-  async getWebhook(shopId: string): Promise<ApiResponse<{
+  async getWebhook(siteId: string): Promise<ApiResponse<{
     webhook: Webhook | null;
     webhook: Webhook | null;
     deliveries: WebhookDelivery[];
     deliveries: WebhookDelivery[];
   }>> {
   }>> {
-    return this.request(`/api/shops/${shopId}/webhooks`);
+    return this.request(`/api/sites/${siteId}/webhooks`);
   }
   }
 
 
   async createWebhook(
   async createWebhook(
-    shopId: string,
+    siteId: string,
     webhookData: { url: string; secret?: string }
     webhookData: { url: string; secret?: string }
   ): Promise<ApiResponse<Webhook>> {
   ): Promise<ApiResponse<Webhook>> {
-    return this.request(`/api/shops/${shopId}/webhooks`, {
+    return this.request(`/api/sites/${siteId}/webhooks`, {
       method: 'POST',
       method: 'POST',
       body: JSON.stringify(webhookData),
       body: JSON.stringify(webhookData),
     });
     });
   }
   }
 
 
   async updateWebhook(
   async updateWebhook(
-    shopId: string,
+    siteId: string,
     enabled: boolean
     enabled: boolean
   ): Promise<ApiResponse<{ message: string }>> {
   ): Promise<ApiResponse<{ message: string }>> {
-    return this.request(`/api/shops/${shopId}/webhooks`, {
+    return this.request(`/api/sites/${siteId}/webhooks`, {
       method: 'PATCH',
       method: 'PATCH',
       body: JSON.stringify({ enabled }),
       body: JSON.stringify({ enabled }),
     });
     });
   }
   }
 
 
-  async deleteWebhook(shopId: string): Promise<ApiResponse<{ message: string }>> {
-    return this.request(`/api/shops/${shopId}/webhooks`, {
+  async deleteWebhook(siteId: string): Promise<ApiResponse<{ message: string }>> {
+    return this.request(`/api/sites/${siteId}/webhooks`, {
       method: 'DELETE',
       method: 'DELETE',
     });
     });
   }
   }
 
 
   // Custom URLs
   // Custom URLs
-  async getCustomUrls(shopId: string): Promise<ApiResponse<{ custom_urls: CustomUrl[] }>> {
-    return this.request(`/api/shops/${shopId}/custom-urls`);
+  async getCustomUrls(siteId: string): Promise<ApiResponse<{ custom_urls: CustomUrl[] }>> {
+    return this.request(`/api/sites/${siteId}/custom-urls`);
   }
   }
 
 
   async addCustomUrl(
   async addCustomUrl(
-    shopId: string,
+    siteId: string,
     urlData: { url: string; content_type: 'shipping' | 'contacts' | 'terms' | 'faq' }
     urlData: { url: string; content_type: 'shipping' | 'contacts' | 'terms' | 'faq' }
   ): Promise<ApiResponse<CustomUrl>> {
   ): Promise<ApiResponse<CustomUrl>> {
-    return this.request(`/api/shops/${shopId}/custom-urls`, {
+    return this.request(`/api/sites/${siteId}/custom-urls`, {
       method: 'POST',
       method: 'POST',
       body: JSON.stringify(urlData),
       body: JSON.stringify(urlData),
     });
     });
   }
   }
 
 
   async updateCustomUrl(
   async updateCustomUrl(
-    shopId: string,
+    siteId: string,
     customUrlId: string,
     customUrlId: string,
     enabled: boolean
     enabled: boolean
   ): Promise<ApiResponse<{ message: string }>> {
   ): Promise<ApiResponse<{ message: string }>> {
-    return this.request(`/api/shops/${shopId}/custom-urls/${customUrlId}`, {
+    return this.request(`/api/sites/${siteId}/custom-urls/${customUrlId}`, {
       method: 'PATCH',
       method: 'PATCH',
       body: JSON.stringify({ enabled }),
       body: JSON.stringify({ enabled }),
     });
     });
   }
   }
 
 
   async deleteCustomUrl(
   async deleteCustomUrl(
-    shopId: string,
+    siteId: string,
     customUrlId: string
     customUrlId: string
   ): Promise<ApiResponse<{ message: string }>> {
   ): Promise<ApiResponse<{ message: string }>> {
-    return this.request(`/api/shops/${shopId}/custom-urls/${customUrlId}`, {
+    return this.request(`/api/sites/${siteId}/custom-urls/${customUrlId}`, {
       method: 'DELETE',
       method: 'DELETE',
     });
     });
   }
   }
 
 
   // Qdrant Management
   // Qdrant Management
-  async updateShopQdrant(
-    shopId: string,
+  async updateSiteQdrant(
+    siteId: string,
     enabled: boolean
     enabled: boolean
-  ): Promise<ApiResponse<{ shop_id: string; qdrant_enabled: boolean; message: string }>> {
-    return this.request(`/api/shops/${shopId}/qdrant`, {
+  ): Promise<ApiResponse<{ site_id: string; qdrant_enabled: boolean; message: string }>> {
+    return this.request(`/api/sites/${siteId}/qdrant`, {
       method: 'PATCH',
       method: 'PATCH',
       body: JSON.stringify({ enabled }),
       body: JSON.stringify({ enabled }),
     });
     });
@@ -243,25 +243,25 @@ export class ApiService {
     return this.request('/api/qdrant/health');
     return this.request('/api/qdrant/health');
   }
   }
 
 
-  async getShopQdrantInfo(shopId: string): Promise<ApiResponse<{
-    shop: Shop;
+  async getSiteQdrantInfo(siteId: string): Promise<ApiResponse<{
+    site: Site;
     embeddings: QdrantEmbedding[];
     embeddings: QdrantEmbedding[];
     errors: QdrantError[];
     errors: QdrantError[];
     collections: QdrantCollection[];
     collections: QdrantCollection[];
   }>> {
   }>> {
-    return this.request(`/api/qdrant/shops/${shopId}`);
+    return this.request(`/api/qdrant/sites/${siteId}`);
   }
   }
 
 
-  async getShopQdrantEmbeddings(shopId: string): Promise<ApiResponse<{ embeddings: QdrantEmbedding[] }>> {
-    return this.request(`/api/qdrant/shops/${shopId}/embeddings`);
+  async getSiteQdrantEmbeddings(siteId: string): Promise<ApiResponse<{ embeddings: QdrantEmbedding[] }>> {
+    return this.request(`/api/qdrant/sites/${siteId}/embeddings`);
   }
   }
 
 
-  async getShopQdrantErrors(shopId: string): Promise<ApiResponse<{ errors: QdrantError[] }>> {
-    return this.request(`/api/qdrant/shops/${shopId}/errors`);
+  async getSiteQdrantErrors(siteId: string): Promise<ApiResponse<{ errors: QdrantError[] }>> {
+    return this.request(`/api/qdrant/sites/${siteId}/errors`);
   }
   }
 
 
-  async clearShopQdrantErrors(shopId: string): Promise<ApiResponse<{ message: string }>> {
-    return this.request(`/api/qdrant/shops/${shopId}/errors`, {
+  async clearSiteQdrantErrors(siteId: string): Promise<ApiResponse<{ message: string }>> {
+    return this.request(`/api/qdrant/sites/${siteId}/errors`, {
       method: 'DELETE',
       method: 'DELETE',
     });
     });
   }
   }
@@ -278,14 +278,14 @@ export class ApiService {
     });
     });
   }
   }
 
 
-  async scheduleShopQdrantDeletion(shopId: string): Promise<ApiResponse<{ message: string; scheduled_at: string }>> {
-    return this.request(`/api/qdrant/shops/${shopId}/schedule-deletion`, {
+  async scheduleSiteQdrantDeletion(siteId: string): Promise<ApiResponse<{ message: string; scheduled_at: string }>> {
+    return this.request(`/api/qdrant/sites/${siteId}/schedule-deletion`, {
       method: 'POST',
       method: 'POST',
     });
     });
   }
   }
 
 
-  async forceQdrantSync(shopId: string): Promise<ApiResponse<{ message: string; items_queued: number; shop_id: string }>> {
-    return this.request(`/api/shops/${shopId}/qdrant/sync`, {
+  async forceQdrantSync(siteId: string): Promise<ApiResponse<{ message: string; items_queued: number; site_id: string }>> {
+    return this.request(`/api/sites/${siteId}/qdrant/sync`, {
       method: 'POST',
       method: 'POST',
     });
     });
   }
   }
@@ -295,8 +295,8 @@ export class ApiService {
     return this.request('/api/mcp/stats');
     return this.request('/api/mcp/stats');
   }
   }
 
 
-  async getShopMcpLogs(
-    shopId: string,
+  async getSiteMcpLogs(
+    siteId: string,
     filters: { limit?: number; success?: boolean; tool_name?: string } = {}
     filters: { limit?: number; success?: boolean; tool_name?: string } = {}
   ): Promise<ApiResponse<{ logs: McpLog[] }>> {
   ): Promise<ApiResponse<{ logs: McpLog[] }>> {
     const params = new URLSearchParams();
     const params = new URLSearchParams();
@@ -305,12 +305,12 @@ export class ApiService {
     if (filters.tool_name) params.append('tool_name', filters.tool_name);
     if (filters.tool_name) params.append('tool_name', filters.tool_name);
 
 
     const query = params.toString();
     const query = params.toString();
-    const url = `/api/mcp/shops/${shopId}/logs${query ? `?${query}` : ''}`;
+    const url = `/api/mcp/sites/${siteId}/logs${query ? `?${query}` : ''}`;
     return this.request(url);
     return this.request(url);
   }
   }
 
 
-  async clearShopMcpLogs(shopId: string): Promise<ApiResponse<{ message: string }>> {
-    return this.request(`/api/mcp/shops/${shopId}/logs`, {
+  async clearSiteMcpLogs(siteId: string): Promise<ApiResponse<{ message: string }>> {
+    return this.request(`/api/mcp/sites/${siteId}/logs`, {
       method: 'DELETE',
       method: 'DELETE',
     });
     });
   }
   }
@@ -320,7 +320,7 @@ export class ApiService {
     successful_calls: number;
     successful_calls: number;
     failed_calls: number;
     failed_calls: number;
     average_response_time: number;
     average_response_time: number;
-    shops_using_mcp: number;
+    sites_using_mcp: number;
     top_tools: Array<{ tool_name: string; call_count: number }>;
     top_tools: Array<{ tool_name: string; call_count: number }>;
     recent_activity: McpLog[];
     recent_activity: McpLog[];
   }>> {
   }>> {
@@ -384,4 +384,4 @@ export class ApiService {
       };
       };
     }
     }
   }
   }
-}
+}

+ 33 - 33
web/src/types/index.ts

@@ -1,17 +1,17 @@
 // API Types (matching the backend)
 // API Types (matching the backend)
-export interface Shop {
+export interface Site {
   id: string;
   id: string;
   custom_id: string | null;
   custom_id: string | null;
   url: string;
   url: string;
   sitemap_url?: string;
   sitemap_url?: string;
-  webshop_type: 'shopify' | 'woocommerce' | 'shoprenter' | string;
+  site_type: 'shopify' | 'woocommerce' | 'shoprenter' | string;
   qdrant_enabled: boolean;
   qdrant_enabled: boolean;
   deleted_at: string | null;
   deleted_at: string | null;
   created_at: string;
   created_at: string;
   updated_at: string;
   updated_at: string;
 }
 }
 
 
-export interface ShopAnalytics {
+export interface SiteAnalytics {
   total_scrapes: number;
   total_scrapes: number;
   last_scraped_at?: string;
   last_scraped_at?: string;
   next_scrape_at?: string;
   next_scrape_at?: string;
@@ -20,20 +20,20 @@ export interface ShopAnalytics {
   average_page_scrape_time: number;
   average_page_scrape_time: number;
 }
 }
 
 
-export interface ShopWithAnalytics extends Shop {
-  analytics: ShopAnalytics;
+export interface SiteWithAnalytics extends Site {
+  analytics: SiteAnalytics;
 }
 }
 
 
 export interface ContentMetadata {
 export interface ContentMetadata {
-  shipping_informations: ShopContent[];
-  contacts: ShopContent[];
-  terms_of_conditions: ShopContent[];
-  faq: ShopContent[];
+  shipping_informations: SiteContent[];
+  contacts: SiteContent[];
+  terms_of_conditions: SiteContent[];
+  faq: SiteContent[];
 }
 }
 
 
-export interface ShopContent {
+export interface SiteContent {
   id: string;
   id: string;
-  shop_id: string;
+  site_id: string;
   content_type: 'shipping' | 'contacts' | 'terms' | 'faq';
   content_type: 'shipping' | 'contacts' | 'terms' | 'faq';
   url: string;
   url: string;
   content: string;
   content: string;
@@ -46,7 +46,7 @@ export interface ShopContent {
 
 
 export interface ScrapeHistory {
 export interface ScrapeHistory {
   id: string;
   id: string;
-  shop_id: string;
+  site_id: string;
   job_id: string;
   job_id: string;
   started_at: string;
   started_at: string;
   completed_at?: string;
   completed_at?: string;
@@ -58,7 +58,7 @@ export interface ScrapeHistory {
 
 
 export interface ScheduledJob {
 export interface ScheduledJob {
   id: string;
   id: string;
-  shop_id: string;
+  site_id: string;
   next_run_at: string;
   next_run_at: string;
   frequency?: string;
   frequency?: string;
   last_modified?: string;
   last_modified?: string;
@@ -69,7 +69,7 @@ export interface ScheduledJob {
 
 
 export interface Webhook {
 export interface Webhook {
   id: string;
   id: string;
-  shop_id: string;
+  site_id: string;
   url: string;
   url: string;
   enabled: boolean;
   enabled: boolean;
   secret?: string;
   secret?: string;
@@ -90,7 +90,7 @@ export interface WebhookDelivery {
 
 
 export interface CustomUrl {
 export interface CustomUrl {
   id: string;
   id: string;
-  shop_id: string;
+  site_id: string;
   url: string;
   url: string;
   content_type: 'shipping' | 'contacts' | 'terms' | 'faq';
   content_type: 'shipping' | 'contacts' | 'terms' | 'faq';
   enabled: boolean;
   enabled: boolean;
@@ -99,15 +99,15 @@ export interface CustomUrl {
 
 
 export interface Job {
 export interface Job {
   job_id: string;
   job_id: string;
-  shop_id?: string;
+  site_id?: string;
   sitemap_url?: string;
   sitemap_url?: string;
   status: 'pending' | 'processing' | 'completed' | 'failed';
   status: 'pending' | 'processing' | 'completed' | 'failed';
   created_at: string;
   created_at: string;
   updated_at?: string;
   updated_at?: string;
   error?: string;
   error?: string;
   result?: {
   result?: {
-    shop: Shop;
-    analytics: ShopAnalytics;
+    site: Site;
+    analytics: SiteAnalytics;
     content_metadata: ContentMetadata;
     content_metadata: ContentMetadata;
     scrape_history: ScrapeHistory[];
     scrape_history: ScrapeHistory[];
     scheduled_jobs: ScheduledJob[];
     scheduled_jobs: ScheduledJob[];
@@ -122,9 +122,9 @@ export interface QueueStats {
   failed: number;
   failed: number;
 }
 }
 
 
-export interface ShopDetail {
-  shop: Shop;
-  analytics: ShopAnalytics;
+export interface SiteDetail {
+  site: Site;
+  analytics: SiteAnalytics;
   content_metadata: ContentMetadata;
   content_metadata: ContentMetadata;
   scrape_history: ScrapeHistory[];
   scrape_history: ScrapeHistory[];
   scheduled_jobs: ScheduledJob[];
   scheduled_jobs: ScheduledJob[];
@@ -161,8 +161,8 @@ export interface ContentFilters extends PaginationParams {
   content_type?: 'shipping' | 'contacts' | 'terms' | 'faq';
   content_type?: 'shipping' | 'contacts' | 'terms' | 'faq';
 }
 }
 
 
-export interface ShopResultsResponse {
-  shop_id: string;
+export interface SiteResultsResponse {
+  site_id: string;
   filters: {
   filters: {
     limit: number;
     limit: number;
     date_from: string | null;
     date_from: string | null;
@@ -170,10 +170,10 @@ export interface ShopResultsResponse {
     content_type: string | null;
     content_type: string | null;
   };
   };
   results: {
   results: {
-    shipping_informations: ShopContent[];
-    contacts: ShopContent[];
-    terms_of_conditions: ShopContent[];
-    faq: ShopContent[];
+    shipping_informations: SiteContent[];
+    contacts: SiteContent[];
+    terms_of_conditions: SiteContent[];
+    faq: SiteContent[];
   };
   };
   total_count?: number; // Total count for pagination
   total_count?: number; // Total count for pagination
 }
 }
@@ -197,7 +197,7 @@ export type NavigationItem = {
 // Qdrant Types
 // Qdrant Types
 export interface QdrantEmbedding {
 export interface QdrantEmbedding {
   id: string;
   id: string;
-  shop_content_id: string;
+  site_content_id: string;
   collection_name: string;
   collection_name: string;
   point_id: string;
   point_id: string;
   embedding_status: 'pending' | 'completed' | 'failed';
   embedding_status: 'pending' | 'completed' | 'failed';
@@ -207,7 +207,7 @@ export interface QdrantEmbedding {
 
 
 export interface QdrantError {
 export interface QdrantError {
   id: string;
   id: string;
-  shop_id: string;
+  site_id: string;
   error_type: 'connection' | 'embedding' | 'search' | 'collection';
   error_type: 'connection' | 'embedding' | 'search' | 'collection';
   error_message: string;
   error_message: string;
   metadata: any;
   metadata: any;
@@ -237,7 +237,7 @@ export interface QdrantSearchResult {
   id: string;
   id: string;
   score: number;
   score: number;
   payload: {
   payload: {
-    shop_id: string;
+    site_id: string;
     content_id: string;
     content_id: string;
     content_type: 'shipping' | 'contacts' | 'terms' | 'faq';
     content_type: 'shipping' | 'contacts' | 'terms' | 'faq';
     url: string;
     url: string;
@@ -250,7 +250,7 @@ export interface QdrantSearchResult {
 export interface QdrantStats {
 export interface QdrantStats {
   total_collections: number;
   total_collections: number;
   total_vectors: number;
   total_vectors: number;
-  enabled_shops: number;
+  enabled_sites: number;
   recent_embeddings: number;
   recent_embeddings: number;
   embedding_queue_size: number;
   embedding_queue_size: number;
 }
 }
@@ -258,7 +258,7 @@ export interface QdrantStats {
 // MCP Types
 // MCP Types
 export interface McpLog {
 export interface McpLog {
   id: string;
   id: string;
-  shop_id: string;
+  site_id: string;
   tool_name: string;
   tool_name: string;
   query: string;
   query: string;
   response_time_ms: number;
   response_time_ms: number;
@@ -275,4 +275,4 @@ export interface McpStats {
   average_response_time: number;
   average_response_time: number;
   top_tools: Array<{ tool_name: string; call_count: number }>;
   top_tools: Array<{ tool_name: string; call_count: number }>;
   recent_activity: McpLog[];
   recent_activity: McpLog[];
-}
+}

+ 2 - 2
web/src/utils/helpers.ts

@@ -194,9 +194,9 @@ export function getContentTypeLabel(type: string): string {
 }
 }
 
 
 /**
 /**
- * Get webshop type label and logo
+ * Get site type label and logo
  */
  */
-export function getWebshopTypeInfo(type: string): { label: string; logo?: string } {
+export function getSiteTypeInfo(type: string): { label: string; logo?: string } {
   switch (type.toLowerCase()) {
   switch (type.toLowerCase()) {
     case 'shopify':
     case 'shopify':
       return { label: 'Shopify' };
       return { label: 'Shopify' };