feat: Platform isolation, Evomi geo-targeting, proxy management

Platform isolation:
- Rename handlers to {task}-{platform}.ts convention
- Deprecate -curl variants (now _deprecated-*)
- Platform-based routing in task-worker.ts
- Add Jane platform handlers and client

Evomi geo-targeting:
- Add dynamic proxy URL builder with state/city targeting
- Session stickiness per worker per state (30 min)
- Fallback to static proxy table when API unavailable
- Add proxy tracking columns to worker_tasks

Proxy management:
- New /proxies admin page for visibility
- Track proxy_ip, proxy_geo, proxy_source per task
- Show active sessions and task history

Validation filtering:
- Filter by validated stores (platform_dispensary_id + menu_url)
- Mark incomplete stores as deprecated
- Update all dashboard/stats queries

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Kelly
2025-12-13 15:16:48 -07:00
parent 59e0e45f8f
commit c215d11a84
31 changed files with 2698 additions and 129 deletions

View File

@@ -982,19 +982,24 @@ router.get('/stats', async (_req: Request, res: Response) => {
GROUP BY stage
`);
// Dispensaries by stage
// Dispensaries by stage (only validated stores)
const { rows: dispensaryStats } = await pool.query(`
SELECT stage, COUNT(*) as count
FROM dispensaries
WHERE crawl_enabled = true
WHERE platform_dispensary_id IS NOT NULL
AND menu_url IS NOT NULL
AND (stage IS NULL OR stage != 'deprecated')
GROUP BY stage
`);
// By state for dispensaries
// By state for dispensaries (only validated stores)
const { rows: byState } = await pool.query(`
SELECT state, stage, COUNT(*) as count
FROM dispensaries
WHERE crawl_enabled = true AND state IS NOT NULL
WHERE state IS NOT NULL
AND platform_dispensary_id IS NOT NULL
AND menu_url IS NOT NULL
AND (stage IS NULL OR stage != 'deprecated')
GROUP BY state, stage
ORDER BY state, stage
`);