Envoy's job search reads public ATS board APIs (Greenhouse, Lever, Ashby, Workable, Recruitee). SmartRecruiters is another common ATS with a public postings API, and the JobSource.SmartRecruiters enum value already exists, so this is a well-scoped "follow the existing pattern" task.
What to do
- Add src/Envoy.Discovery/Sources/SmartRecruitersSource.cs implementing IAtsBoardSource, following the shape of GreenhouseSource and LeverSource.
- Public endpoint: https://api.smartrecruiters.com/v1/companies/{companyIdentifier}/postings (public postings, no auth). Paginated with limit and offset.
- Map each posting to a JobPosting (title, location, company, url, posted date, RawSourceId). Use the shared Envoy.Discovery.Internal helpers (Json, HtmlText, DateParsing, Naming) like the other sources do.
- Plain GET, short timeout, no scraping, no auth. Stay within the read-public-data-only rule.
- Register it in ServiceRegistration (AddEnvoyDiscovery) so JobDiscoveryService picks it up.
- Add a SmartRecruiters entry (a real public company token) to the seed boards (SeedBoards.cs, seed-boards.json) so it works out of the box.
- Add tests in Envoy.Discovery.Tests with a stubbed HttpClient (see the existing AtsSourceTests and StubHttpMessageHandler). No real network calls.
Acceptance criteria
A bit more involved than the signal issues, but a clean copy-the-pattern task.
Envoy's job search reads public ATS board APIs (Greenhouse, Lever, Ashby, Workable, Recruitee). SmartRecruiters is another common ATS with a public postings API, and the JobSource.SmartRecruiters enum value already exists, so this is a well-scoped "follow the existing pattern" task.
What to do
Acceptance criteria
A bit more involved than the signal issues, but a clean copy-the-pattern task.