Platform Adapters
Each job platform is implemented as an adapter behind the JobSearchService trait.
Trait Definition
#![allow(unused)]
fn main() {
#[async_trait]
pub trait JobSearchService: Send + Sync {
fn platform(&self) -> Platform;
async fn search(&self, criteria: &SearchCriteria) -> Result<Vec<Job>, DomainError>;
async fn fetch_details(&self, job: &Job) -> Result<Job, DomainError>;
}
}
Adapter Architecture
graph LR
subgraph kairos-core
Trait[JobSearchService trait]
end
subgraph kairos-platform
Seek[SeekClient]
Indeed[IndeedClient]
LinkedIn[LinkedInClient]
RL[RateLimiter]
HC[PlatformHttpClient]
end
Seek --> Trait
Indeed --> Trait
LinkedIn --> Trait
Seek --> HC
Indeed --> HC
LinkedIn --> HC
HC --> RL
Shared Infrastructure
RateLimiter
Enforces randomized delays between requests:
- Seek: 2-5s
- Indeed: 3-8s (more aggressive anti-bot)
- LinkedIn: 2-6s
PlatformHttpClient
Wraps reqwest::Client with:
- Rate limiting
- User-Agent rotation (pool of realistic browser UAs)
- Retry with exponential backoff (3 attempts)
- Configurable proxy support
Seek.com.au
Method: reqwest + scraper (HTTP + HTML parsing)
flowchart LR
Search[Search URL] --> HTTP[reqwest GET]
HTTP --> HTML[HTML Response]
HTML --> Parse["scraper: extract JSON"]
Parse --> Struct[SeekJobListing]
Struct --> Map[Map to Job entity]
- Server-side rendered with job data embedded as JSON in HTML
- Pagination: 20 results per page
- Key selector:
<script type="application/json">tag
Indeed AU
Method: chromiumoxide (headless Chrome via CDP)
flowchart LR
Search[Search URL] --> Chrome[chromiumoxide]
Chrome --> Wait[Wait for render]
Wait --> DOM[Extract from DOM]
DOM --> Parse[Parse listings]
Parse --> Map[Map to Job entity]
- Requires JavaScript rendering (Cloudflare protection)
- Anti-detection: disable automation flags, randomized viewport, human-like scrolling
- Slower (~5-10s per page)
Method: reqwest + scraper (public job listings)
- Public job search pages, no login required
- Fallback: if blocked (403/429), suggests user browse manually
- Jobs can be added by pasting URL
Adding a New Platform
- Create module under
kairos-platform/src/ - Implement
JobSearchServicetrait - Add variant to
Platformenum inkairos-core - Register adapter in
kairos-apidependency injection
No existing code needs to change.