import { Router } from 'express'; import { authMiddleware } from '../auth/middleware'; import { query as azQuery } from '../dutchie-az/db/connection'; const router = Router(); router.use(authMiddleware); // Get dashboard stats - uses consolidated dutchie-az DB // OPTIMIZED: Combined 4 sequential queries into 1 using CTEs router.get('/stats', async (req, res) => { try { // All stats in a single query using CTEs const result = await azQuery(` WITH dispensary_stats AS ( SELECT COUNT(*) as total, COUNT(*) FILTER (WHERE menu_type IS NOT NULL AND menu_type != 'unknown') as active, COUNT(*) FILTER (WHERE platform_dispensary_id IS NOT NULL) as with_platform_id, COUNT(*) FILTER (WHERE menu_url IS NOT NULL) as with_menu_url, MIN(last_crawled_at) as oldest_crawl, MAX(last_crawled_at) as latest_crawl FROM dispensaries ), product_stats AS ( SELECT COUNT(*) as total, COUNT(*) FILTER (WHERE stock_status = 'in_stock') as in_stock, COUNT(*) FILTER (WHERE primary_image_url IS NOT NULL) as with_images, COUNT(DISTINCT brand_name) FILTER (WHERE brand_name IS NOT NULL AND brand_name != '') as unique_brands, COUNT(DISTINCT dispensary_id) as dispensaries_with_products, COUNT(*) FILTER (WHERE created_at >= NOW() - INTERVAL '24 hours') as new_products_24h FROM dutchie_products ) SELECT ds.total as store_total, ds.active as store_active, ds.with_platform_id as store_with_platform_id, ds.with_menu_url as store_with_menu_url, ds.oldest_crawl, ds.latest_crawl, ps.total as product_total, ps.in_stock as product_in_stock, ps.with_images as product_with_images, ps.unique_brands as product_unique_brands, ps.dispensaries_with_products, ps.new_products_24h FROM dispensary_stats ds, product_stats ps `); const stats = result.rows[0] || {}; const storeStats = { total: stats.store_total, active: stats.store_active, with_platform_id: stats.store_with_platform_id, with_menu_url: stats.store_with_menu_url, oldest_crawl: stats.oldest_crawl, latest_crawl: stats.latest_crawl }; const productStats = { total: stats.product_total, in_stock: stats.product_in_stock, with_images: stats.product_with_images, unique_brands: stats.product_unique_brands, dispensaries_with_products: stats.dispensaries_with_products }; res.json({ stores: { total: parseInt(storeStats.total) || 0, active: parseInt(storeStats.active) || 0, with_menu_url: parseInt(storeStats.with_menu_url) || 0, with_platform_id: parseInt(storeStats.with_platform_id) || 0, oldest_crawl: storeStats.oldest_crawl, latest_crawl: storeStats.latest_crawl }, products: { total: parseInt(productStats.total) || 0, in_stock: parseInt(productStats.in_stock) || 0, with_images: parseInt(productStats.with_images) || 0, unique_brands: parseInt(productStats.unique_brands) || 0, dispensaries_with_products: parseInt(productStats.dispensaries_with_products) || 0 }, brands: { total: parseInt(productStats.unique_brands) || 0 // Same as unique_brands from product stats }, campaigns: { total: 0, active: 0 }, // Legacy - no longer used clicks: { clicks_24h: 0 }, // Legacy - no longer used recent: { new_products_24h: parseInt(stats.new_products_24h) || 0 } }); } catch (error) { console.error('Error fetching dashboard stats:', error); res.status(500).json({ error: 'Failed to fetch dashboard stats' }); } }); // Get recent activity - from consolidated dutchie-az DB router.get('/activity', async (req, res) => { try { const { limit = 20 } = req.query; // Recent crawls from dispensaries (with product counts from dutchie_products) const scrapesResult = await azQuery(` SELECT d.name, d.last_crawled_at as last_scraped_at, d.product_count FROM dispensaries d WHERE d.last_crawled_at IS NOT NULL ORDER BY d.last_crawled_at DESC LIMIT $1 `, [limit]); // Recent products from dutchie_products const productsResult = await azQuery(` SELECT p.name, 0 as price, p.brand_name as brand, p.thc as thc_percentage, p.cbd as cbd_percentage, d.name as store_name, p.created_at as first_seen_at FROM dutchie_products p JOIN dispensaries d ON p.dispensary_id = d.id ORDER BY p.created_at DESC LIMIT $1 `, [limit]); res.json({ recent_scrapes: scrapesResult.rows, recent_products: productsResult.rows }); } catch (error) { console.error('Error fetching dashboard activity:', error); res.status(500).json({ error: 'Failed to fetch dashboard activity' }); } }); export default router;