-- ===================================================== -- Add dispensary slug/state to crawl_schedule_status view -- ===================================================== -- Enables proper linking from scheduler to dispensary detail page -- which uses route /dispensaries/:state/:city/:slug DROP VIEW IF EXISTS crawl_schedule_status; CREATE OR REPLACE VIEW crawl_schedule_status AS SELECT s.id AS store_id, s.name AS store_name, s.slug AS store_slug, s.timezone, s.active, s.scrape_enabled, s.last_scraped_at, -- Dispensary info (master record) s.dispensary_id, d.name AS dispensary_name, d.company_name AS dispensary_company, d.city AS dispensary_city, d.state AS dispensary_state, d.slug AS dispensary_slug, d.address AS dispensary_address, d.menu_url AS dispensary_menu_url, -- Provider intelligence from dispensary (if linked) d.product_provider, d.product_confidence, d.product_crawler_mode, -- Schedule settings (use store override or global) COALESCE(scs.enabled, TRUE) AS schedule_enabled, COALESCE(scs.interval_hours, cs_global.interval_hours, 4) AS interval_hours, COALESCE(scs.daily_special_enabled, TRUE) AS daily_special_enabled, COALESCE(scs.daily_special_time, '00:01'::TIME) AS daily_special_time, COALESCE(scs.priority, 0) AS priority, -- Orchestrator status scs.last_status, scs.last_summary, scs.last_run_at AS schedule_last_run, scs.last_error, -- Next scheduled run calculation CASE WHEN s.last_scraped_at IS NULL THEN NOW() ELSE s.last_scraped_at + (COALESCE(scs.interval_hours, cs_global.interval_hours, 4) || ' hours')::INTERVAL END AS next_scheduled_run, -- Latest job info cj.id AS latest_job_id, cj.status AS latest_job_status, cj.job_type AS latest_job_type, cj.trigger_type AS latest_job_trigger, cj.started_at AS latest_job_started, cj.completed_at AS latest_job_completed, cj.products_found AS latest_products_found, cj.products_new AS latest_products_new, cj.products_updated AS latest_products_updated, cj.error_message AS latest_job_error FROM stores s LEFT JOIN dispensaries d ON d.id = s.dispensary_id LEFT JOIN store_crawl_schedule scs ON scs.store_id = s.id LEFT JOIN crawler_schedule cs_global ON cs_global.schedule_type = 'global_interval' LEFT JOIN LATERAL ( SELECT * FROM crawl_jobs cj2 WHERE cj2.store_id = s.id ORDER BY cj2.created_at DESC LIMIT 1 ) cj ON TRUE WHERE s.active = TRUE; -- Grant permissions GRANT SELECT ON crawl_schedule_status TO dutchie;