# 01 — Architecture

## Directory layout

```
/var/www/html/Searchmercials/
├── .git/                       # Version history
├── .gitignore
├── 64.250.180.23               # SSL wildcard cert generation script (shell)
├── fixlinks.sh                 # Symlink sync between httpdocs/ and httpsdocs/
├── ypbackfill_feed_data        # 1-byte marker / cron stub
├── ypbackfill_feed_data.txt    # Instructions for YouPortal data-sync
├── ypbackfill_feed_data.curl   # Empty placeholder
├── Documentation/              # This documentation (blocked at web layer)
│   └── an/                     # Empty — historically unused
├── affiliates/                 # Per-brand cobrand webroots + iDevAffiliate vendor app (262 MB)
│   ├── affiliate/              # iDevAffiliate v4.0 (iDevDirect.com, 2001–2005) — full vendor product
│   ├── searchmercials_com/     # Searchmercials.com cobrand (34 MB) — has own SDBA copy + duplicate videoads/
│   ├── searchtube_com/         # SearchTube.com cobrand (62 MB)
│   ├── wwbn_com/               # WWBN.com cobrand (27 MB) — exposes phpinfo.php, xdebug/, webgrind/
│   ├── newspaperrevenues_com/, avideo_com/, arism_tv/, vendor_directory/, ibusiness_directory/
│   ├── jobslistings_app/, searchppv_com/, searchads_tv/, fingersearch_com/, pooptube_com/
│   ├── ccsllconline/, wwbn_tv/, *_mobi/, searchmercials_com_old/ ...
│   └── SpryAssets/, components/, connections/, dandelion/, help/, responsive/, stylesheet/, wideadmin/, ...   # shared assets
├── data/                       # Shared config + templates + Hyperseek data (59 MB)
│   ├── config.inc, config.inc.save, config_bu_9-23.inc, global.config.{save,backup}   # global PHP config arrays
│   ├── config/                 # Per-cobrand .inc/.config files (arism, avideo, searchmercials_com, wwbn_com, ...)
│   ├── custom/                 # Include fragments: ACCOUNTINFO.inc, VIDEOFRAME.inc, NETWORKS.inc, ...
│   ├── templates/              # Per-cobrand .txt render templates (~35 brand folders)
│   ├── hyperseek/              # GeoIP binaries, dated CSV/tab exports, bids/hyperseek import files, recent.log
│   ├── sql/schemas/            # Historical .patch.done migrations (renametables.patch.done created iweb_ prefix)
│   ├── bids/                   # Advertiser bid spreadsheets (.xls)
│   ├── transaction.log         # Plaintext Authorize.net deposit log
│   ├── badwords.txt, financial-report.xls, notes.txt, hscats.sql, tempcats.sql
├── httpdocs/                   # Primary webroot (HTTP)
│   ├── index.php               # Main dispatcher
│   ├── admin.php               # Admin interface gateway
│   ├── r.php                   # Click redirect + logger
│   ├── joe.php                 # Dev/test YP API probe (legacy)
│   ├── ip_zip.php              # GeoIP ZIP lookup endpoint
│   ├── account/                # Advertiser account dashboard
│   ├── advertisers/            # Advertiser portal
│   ├── publishers/             # Publisher platform
│   ├── pages/                  # Static pages (about/privacy/tos/etc.)
│   ├── support/                # Support ticket UI + FAQs
│   ├── auth/                   # Login + session machinery
│   │   └── classes/sdba/       # Custom mysqli ORM + DB creds
│   ├── search/                 # dsX framework (Hyperseek core)
│   │   ├── dsX/                # Table defs, record classes, addons
│   │   ├── Player/             # Video player assets
│   │   └── ... results.php, accounts.php, api.php, ...
│   ├── classes_new/            # Vendor libs (minibots bot detector)
│   ├── maxmind/                # GeoIP binary DBs + PHP wrapper
│   ├── inc/                    # Legacy MySQL ordering + RSS feeds
│   ├── includes/               # Near-empty (symlink target?)
│   ├── files/                  # User-uploaded assets
│   ├── images/                 # Static images
│   └── submissions/            # User submissions (156 MB — media)
└── httpsdocs/                  # Secondary webroot (HTTPS)
    ├── index.php, admin.php, r.php, search.php, receive-payment.php
    ├── accounts.php, settings.php
    ├── templates/              # HTML templates (bidding_manager.htm, payment.htm)
    ├── validation/             # dhtmlxSuite26 + form validation
    ├── stylesheet/, images1/
    └── *_old/                  # Legacy snapshots
```

## Two webroots, one codebase

`httpdocs/` and `httpsdocs/` are **not** two separate apps. The `fixlinks.sh` script (119 lines) creates symlinks so the HTTPS root shares the same backend resources (`search/`, `dandelion/`, `responsive/`). The distinction is protocol context only:

- **`httpdocs/`**: browsing, search, advertiser/publisher dashboards
- **`httpsdocs/`**: account login, payment processing, sensitive operations

Apache serves each via the appropriate vhost. Files that genuinely diverge between the two (e.g., `receive-payment.php`, `settings.php`) live only in `httpsdocs/`.

## Multi-brand webroots under `affiliates/`

In addition to the two primary webroots, each per-brand domain points at a **separate vhost root** under `affiliates/`. These are not symlinks of `httpdocs/`; they are independent (but heavily overlapping) copies that share the dsX engine through their own `search/`, `inc/`, `template/` trees and pull per-brand config from `data/config/<brand>.inc` + templates from `data/templates/<brand>/`. The iDevAffiliate v4.0 product under `affiliates/affiliate/` is an entirely separate sibling application with its own DB tables (`idevaff_*`). Detailed breakdown in [13-affiliates-and-data.md](13-affiliates-and-data.md).

## Entry-point matrix

| Path | File | LOC | Role |
|------|------|-----|------|
| `/` | `httpdocs/index.php` | 12 KB | Main dispatcher; loads dsX, initializes GeoIP constants, serves search UI |
| `/admin.php` | `httpdocs/admin.php` | 5.3 KB | Admin gateway; sets `$IS_ADVERTISER=1` flag |
| `/r.php` | `httpdocs/r.php` | 11 KB | Click redirect + log writer |
| `/ip_zip.php` | `httpdocs/ip_zip.php` | 674 B | `geoip_record_by_name()` → postal code JSON |
| `/joe.php` | `httpdocs/joe.php` | 1.1 KB | Yellow Pages API probe — **dev artifact, should be deleted** |
| `/advertisers/` | `httpdocs/advertisers/index.php` | 6 KB | Advertiser portal |
| `/publishers/` | `httpdocs/publishers/index.php` | 5.4 KB | Publisher platform |
| `/search/results.php` | `httpdocs/search/results.php` | — | Search-results renderer |
| `/account/` | `httpdocs/account/index.php` | 5.9 KB | Account dashboard |
| `/pages/?page=X` | `httpdocs/pages/index.php` | 11 KB | Static-page router |
| HTTPS `/receive-payment.php` | `httpsdocs/receive-payment.php` | 16 KB | PayPal/Auth.net callback |
| HTTPS `/accounts.php` | `httpsdocs/accounts.php` | 5 KB | Account management form |

## Routing model

**There is no router / front controller.** Every URL maps directly to a filesystem path via Apache's DirectoryIndex. `.htaccess` at `httpdocs/.htaccess` is minimal — only commented-out error directives, **no `RewriteRule`s**. Branching within each entry point is procedural: `if(isset($_GET['page']))` style.

## Request flow (typical search)

```
GET /?q=plumber&loc=30022
  └→ httpdocs/index.php
       ├─ session_start()
       ├─ include search/dsX/dsX.inc
       ├─ constants loaded (MAXMIND paths, DB creds via auth/classes/sdba/dbconnect.php)
       ├─ $include_dir = "/var/www/html/searchmercials/httpdocs/search"
       └─ dispatch → search/results.php
             ├─ iSQL query against iweb_hyperseek_links
             ├─ GeoIP filter (maxmind DB) against $_SERVER['REMOTE_ADDR']
             ├─ render via dsX PageTemplate.inc + SubTemplate.inc
             └─ each result link wraps /r.php?id=<listing_id>&url=<dest>

User clicks result
  └→ GET /r.php?id=123&url=https://example.com
        ├─ INSERT INTO iweb_jh_click_log
        ├─ UPDATE iweb_accounts (bid debit)
        └─ 302 → destination
```

## Framework layers

From top (newest) to bottom (oldest):

1. **SDBA** (`auth/classes/sdba/sdba.php`) — modern-ish mysqli ORM; used by `auth/`, `account/`, `advertisers/`
2. **dsX / Hyperseek** (`search/dsX/`) — original XML-template framework, Record classes (Listing.inc, Account.inc, CategoryNavigator.inc), iSQL query builder
3. **Raw `mysql_*`** (`inc/order.php`, `inc/sitemap.php`) — pre-PHP-5.4 procedural database access, will fatal on PHP 7+

Co-existence of three generations of DB access makes cross-cutting changes (e.g., PHP 8 migration) intrinsically painful.
