X-Hiring ่ๅ V2EXใ็ต้ธญ็คพๅบไธ่ฐๅจๆไบบ็ไบ่็ฝๆ่ไฟกๆฏ๏ผๅนถไฝฟ็จ Cloudflare Workers AI ็ๆ่ไฝๆ่ฆใ
- ๅคๆบ่ๅ - ๆๅ V2EXใ็ต้ธญ็คพๅบไธ่ฐๅจๆไบบ็ๅ ฌๅผๆ่ไฟกๆฏ
- AI ๆ่ฆ - ไฝฟ็จ Workers AI ๆๅ่ไฝๆ ้ขใๆ่ฆๅๅฏ้็ๅฐ็นใๅฒไฝใ่ช่ตใๅนด่ชใๆงๅซๅๅญฆๅๅญๆฎต
- ๆ่็ญ้ - ๆฏๆๅ ณ้ฎ่ฏใๆฅๆใ็ปๆๅ่ไฝๅญๆฎตๅ่ถๅฟ็ญ้
- ็ธๅ ณ่ไฝ - ๆ นๆฎ่ง่ๅๆ ็ญพๆจ่็ธไผผ่ไฝ
- RSS - ๆไพ
/feed.xml่ฎข้ ๏ผๅนถไฝฟ็จ Cloudflare KV ็ผๅญ - Cloudflare Runtime - D1ใKVใQueuesใCronใWorkers AI ๅ AI Gateway ๅ จ้จ่ฟ่กๅจ Worker ๆถๆ
| Category | Technology |
|---|---|
| Frontend | React 19, TanStack Start (SSR), TanStack Router |
| Styling | Tailwind CSS v4, shadcn/ui (base-nova) |
| API Layer | oRPC (end-to-end type-safe RPC) |
| Database | Cloudflare D1 + Drizzle ORM |
| Authentication | Better Auth (ๅฏ้้ฎ็ฎฑ/OAuth่ฝๅ) |
| Caching | Cloudflare KV |
| Scheduling | Cron Triggers + Cloudflare Queues |
| AI | Workers AI (@cf/openai/gpt-oss-120b) + AI Gateway + Vercel AI SDK structured output |
| Deployment | Cloudflare Workers + Wrangler |
| Code Quality | Biome + Ultracite |
| Package Manager | pnpm (monorepo workspaces) |
x-hiring/
โโโ apps/
โ โโโ web/ # Full-stack application (port 3002)
โ โโโ src/
โ โโโ routes/ # File-based routing
โ โ โโโ (app)/ # Recruitment pages
โ โ โโโ api/ # Health, ingestion, auth and RPC handlers
โ โโโ components/
โ โ โโโ ui/ # shadcn/ui components
โ โ โโโ shared/ # Shared components
โ โ โโโ features/ # Feature-specific components
โ โโโ lib/ # Utilities (auth-client, utils)
โ โโโ hooks/ # Custom React hooks
โ โโโ stores/ # State management
โ
โโโ packages/
โ โโโ api/ # oRPC entrypoints + routers/services
โ โ โโโ src/
โ โ โโโ routers/ # Thin route handlers for app and auth APIs
โ โ โโโ services/ # Recruitment domain business logic
โ โ โโโ lib/ # Shared server utilities
โ โโโ auth/ # Better Auth configuration
โ โโโ db/ # Drizzle database schema
โ โโโ email/ # React Email templates
โ โโโ common/ # Shared types and validations
- Node.js 24+
- pnpm 10+
- Cloudflare account (for remote D1 / Workers deploy)
- Clone the repository and install dependencies:
git clone <repository-url> x-hiring
cd x-hiring
pnpm install- Configure local Worker secrets:
cp apps/web/.dev.vars.example apps/web/.dev.varsEdit apps/web/.dev.vars with your values (see Environment Variables below).
For local TanStack Start + Cloudflare development, this is the preferred config source.
apps/web/.env is now only a legacy fallback for plain Node-based tooling.
- Configure D1 in
apps/web/wrangler.toml:
- Local development uses the checked-in
env.developmentD1 binding together with.wrangler/state. - Before running against a real Cloudflare database, replace
database_idwith your actual D1 database ID. - Keep the binding name as
DB, because the app and auth layer resolve D1 from that binding.
- Initialize the local D1 schema:
pnpm run db:generate
pnpm run db:migrateOptional seed data:
pnpm run db:seeddb:seed will reset the local D1 sample tables before inserting fresh demo data.
Start the development server:
pnpm run devVisit http://localhost:3002
# Development
pnpm run dev # Start all apps (runs local D1 migrations, then vite dev with CLOUDFLARE_ENV=development)
pnpm run dev:web # Start web app only
# Type Checking
pnpm run check-types # Check TypeScript types across all packages
# Code Quality
pnpm run check # Vite+ / Oxlint checks
vp fmt # Format with Oxfmt
vp lint --fix # Auto-fix lint issues
# Database
pnpm run db:generate # Generate migration files
pnpm run db:migrate # Alias of local D1 migration
pnpm run db:migrate:local # Apply migrations to local D1 (development env)
pnpm run db:migrate:remote # Apply migrations to remote D1 (development env)
pnpm run db:migrate:production # Apply migrations to production D1
pnpm run db:seed # Reset and seed local D1 with sample data
pnpm run cf-typegen # Generate Wrangler/Cloudflare runtime types from development env- Use
apps/web/.dev.varsfor local Worker development withvite dev/ Wrangler bindings. - Keep non-secret runtime defaults in
apps/web/wrangler.toml. apps/web/.envis only a fallback for plain Node-based tooling.- In the Cloudflare runtime, server-side code reads Worker bindings/env first.
- Only variables prefixed with
VITE_are exposed to the browser. Never put secrets inVITE_variables.
| Variable | Required | Description | Notes |
|---|---|---|---|
CORS_ORIGIN |
Yes | Allowed origin for auth and API requests | Set to your app URL in production (e.g. https://your-domain.com). |
BETTER_AUTH_URL |
Yes | Base URL used by Better Auth for redirects and emails | Should match the public URL of the app. |
- D1 is configured through the
DBbinding inapps/web/wrangler.toml, not throughDATABASE_URL. - Local D1 state is persisted in
apps/web/.wrangler/stateafter running migrations. - Local development uses the
developmentenvironment in Wrangler config. - Replace the placeholder
database_idvalues in Wrangler config before applying remote migrations or deploying.
| Variable | Required | Description | Notes |
|---|---|---|---|
BETTER_AUTH_SECRET |
Yes | Token signing secret | Generate with pnpm dlx @better-auth/cli@latest secret and keep it private. |
GITHUB_CLIENT_ID |
Optional | GitHub OAuth client ID | Needed for GitHub login. |
GITHUB_CLIENT_SECRET |
Optional | GitHub OAuth client secret | Needed for GitHub login; keep secret. |
GOOGLE_CLIENT_ID |
Optional | Google OAuth client ID | Needed for Google login. |
GOOGLE_CLIENT_SECRET |
Optional | Google OAuth client secret | Needed for Google login; keep secret. |
app.job.*: job listing, detail, related-job and RSS data servicesauth.*: authentication-related endpoints retained by the Worker API
| Variable | Required | Description | Notes |
|---|---|---|---|
INGESTION_TRIGGER_SECRET |
Optional | Secret for the protected manual ingestion trigger | Send as Authorization: Bearer ...; Cron and Queue execution do not use this HTTP secret. |
AI_JOB_MODEL |
Yes | Workers AI model used for job analysis | Current default is @cf/openai/gpt-oss-120b; override for a lower-latency model when needed. |
AI_GATEWAY_ID |
Yes | AI Gateway identifier | Used for caching and observability of AI requests. |
pnpm run buildBuild output is located at apps/web/dist/ (client/ for static assets, server/ for the server bundle).
This project is configured for Cloudflare Workers + D1 through the checked-in apps/web/wrangler.toml.
pnpm run build- Create real D1 databases in Cloudflare and set the
database_idvalues inapps/web/wrangler.toml. - Apply the schema to the remote D1 database:
pnpm run db:migrate:production- Set production secrets with Wrangler, for example:
cd apps/web
wrangler secret put BETTER_AUTH_SECRET
wrangler secret put INGESTION_TRIGGER_SECRET- Deploy the app:
pnpm run deployWrangler will deploy the Worker plus the built client assets from apps/web/dist/.