AirTech Hub
A job board built specifically for aviation, where listings are aggregated from across the industry and parsed into structured, filterable data.
- Role
- Solo developer
- Year
- 2026
- Stack
- Next.js · TypeScript · Prisma

Aviation hiring is scattered across airline career pages, MRO sites, recruiter feeds and generic job boards that have no idea what an EASA Part 66 B1.1 licence is. AirTech Hub aggregates those listings and models the domain properly, with sectors, role types, aircraft types and licence requirements as first-class filterable fields rather than free text buried in a description.
Listings arrive through several paths: Adzuna and RSS ingestors, airline-specific ingestors, recruiter-submitted posts, and a discovery crawler driven by Google Custom Search and Serper. Jobs are deduplicated on a source and external-id unique constraint. It is Next.js 14 with Prisma over PostgreSQL; Supabase handles auth and stores CVs and licence documents. Job alerts match new listings against saved role, sector and keyword preferences and go out as HTML email through Resend, fire-and-forget so a mail failure never breaks an ingest.
Turning arbitrary scraped text into a structured job is a four-stage pipeline. A cheap keyword classifier scores the text first, and only text scoring above a threshold is sent to Groq for LLM extraction, so the expensive call is gated by the free one. A regex extractor always runs and fills gaps, and a validator merges both sources into a confidence-scored result.
Engineering notes
A cheap classifier gates the expensive model
A keyword scorer runs first and only text that looks like a job posting reaches the LLM. The regex extractor runs unconditionally as a fallback, so extraction still degrades gracefully when no LLM key is configured.
Two models for two latency budgets
Live search uses an 8B instant model for its speed and high token-per-minute ceiling, while the background discovery cron uses a 70B model for accuracy. Interactive search completes in roughly 700 to 1200ms by skipping the database entirely and extracting straight from search snippets.
Revalidating the token on every request, deliberately
The middleware calls the Supabase getUser() rather than the cheaper getSession(), because only getUser() re-validates the token server-side. Admin and recruiter route prefixes are soft-gated in middleware and re-checked in the API, so a spoofed role claim in user metadata gets nowhere.