# ARCHITECTURE

Backend: Laravel 10 (PHP 8.3), MySQL, Queue (DB), Cron (schedule:run)
Telegram: defstudio/telegraph
Admin: Filament + spatie/permission
Payments: shetabit/payment (Zarinpal)
AI: OpenAI Responses + file_search (Vector Stores)
    Threads per module: store:true + previous_response_id
    VS_MAIN for all bots; VS_IG for Instagram module
Ads: majidapi (bama latest/search/details, divar scraper) + Smart Multi-Page Search

Layers:

- Services/AI: LlmProvider (interface), OpenAiProvider (responses)
- Services/Ads: AdsNormalizer, OpportunityScorer (-15% city median → fallback -10%), CityMedianService, Deduper
- Jobs: BamaSearchJob (Smart Multi-Page + Fallback), DivarScrapeJob (City-Specific URLs), ScoreOpportunitiesJob
- Controllers: TelegramWebhookController, PaymentsController, AIController
- Filament Resources: Users, Menu, Prompts, VectorStores, VectorFiles, Opportunities, FeaturedAds, ScrapeProfiles, LegalFiles, Checklists, Payments, Settings, Analytics

## Smart Search Architecture

### BamaSearchJob Flow
1. **Smart Search Phase**:
   - Multi-page search (up to 15 pages)
   - City detection from `detail.location` field
   - Filter ads by detected city vs target city
   - Stop when minimum results (5) found
   - Rate limiting: 0.5s delay between requests

2. **Fallback Search Phase**:
   - Activates if < 3 city-specific ads found
   - Search additional 5 pages
   - Store all ads with requested `city_id` (override actual location)

3. **City Detection**:
   - Extract city from location text ("تهران / کلاهدوز" → "تهران")
   - Match against `cities` table (exact, alias, partial)
   - Support 20+ major cities with fallback patterns

### DivarScrapeJob Flow (City-Specific URLs)
1. **URL Construction**:
   - Build city-specific Divar URLs (`https://divar.ir/s/tehran/car`)
   - Map city slugs to city names (tehran → تهران)
   - Support 50+ cities with comprehensive mapping

2. **HTML Parsing**:
   - Parse Divar HTML cards using stable CSS selectors
   - Extract: title, price, mileage, location, links
   - Filter out navigation and non-car content
   - Convert Persian digits to English

3. **Data Processing**:
   - Extract external_code from ad URL slug
   - Parse price from title text (handle Rials/Tomans)
   - Extract year from title (1300-1450 range)
   - Map to normalized format with city_id

### Data Flow
```
Telegram Request → BamaSearchJob → MajidAPI (multi-page) → City Filter → ads_raw
                    ↓
                   DivarScrapeJob → MajidAPI (city URL) → HTML Parse → ads_raw
                                                           ↓
ScoreOpportunitiesJob → Normalize → Dedup → Median → Score → opportunities
                                                           ↓
TelegramWebhookController → Filter by city_id/source → Display Results
```

### Configuration
- Smart search settings in `config/ads.php`
- Configurable page limits, delays, thresholds
- City detection patterns and fallback rules
