From 4a00b3b900d75e6c90f2773a7a650e28bd151684 Mon Sep 17 00:00:00 2001 From: DaKheera47 Date: Sun, 14 Dec 2025 19:12:58 +0000 Subject: [PATCH] source being extracted --- orchestrator/src/client/components/JobCard.tsx | 9 ++++++++- orchestrator/src/server/db/migrate.ts | 15 +++++++++++++++ orchestrator/src/server/db/schema.ts | 1 + orchestrator/src/server/repositories/jobs.ts | 2 ++ orchestrator/src/server/services/crawler.ts | 1 + orchestrator/src/shared/types.ts | 5 +++++ 6 files changed, 32 insertions(+), 1 deletion(-) diff --git a/orchestrator/src/client/components/JobCard.tsx b/orchestrator/src/client/components/JobCard.tsx index 185136d..1391430 100644 --- a/orchestrator/src/client/components/JobCard.tsx +++ b/orchestrator/src/client/components/JobCard.tsx @@ -16,6 +16,7 @@ import { XCircle, } from "lucide-react"; +import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"; import type { Job } from "../../shared/types"; @@ -52,6 +53,10 @@ export const JobCard: React.FC = ({ onProcess, isProcessing, }) => { + const sourceLabel: Record = { + gradcracker: "Gradcracker", + }; + const hasPdf = !!job.pdfPath; const canApply = job.status === "ready"; const canProcess = job.status === "discovered"; @@ -72,6 +77,9 @@ export const JobCard: React.FC = ({
+ + {sourceLabel[job.source]} +
@@ -181,4 +189,3 @@ export const JobCard: React.FC = ({ ); }; - diff --git a/orchestrator/src/server/db/migrate.ts b/orchestrator/src/server/db/migrate.ts index a9b47c7..87dfc44 100644 --- a/orchestrator/src/server/db/migrate.ts +++ b/orchestrator/src/server/db/migrate.ts @@ -25,6 +25,7 @@ const sqlite = new Database(DB_PATH); const migrations = [ `CREATE TABLE IF NOT EXISTS jobs ( id TEXT PRIMARY KEY, + source TEXT NOT NULL DEFAULT 'gradcracker', title TEXT NOT NULL, employer TEXT NOT NULL, employer_url TEXT, @@ -60,6 +61,10 @@ const migrations = [ error_message TEXT )`, + // Add source column for existing databases (safe to skip if already present) + `ALTER TABLE jobs ADD COLUMN source TEXT NOT NULL DEFAULT 'gradcracker'`, + `UPDATE jobs SET source = 'gradcracker' WHERE source IS NULL OR source = ''`, + `CREATE INDEX IF NOT EXISTS idx_jobs_status ON jobs(status)`, `CREATE INDEX IF NOT EXISTS idx_jobs_discovered_at ON jobs(discovered_at)`, `CREATE INDEX IF NOT EXISTS idx_pipeline_runs_started_at ON pipeline_runs(started_at)`, @@ -72,6 +77,16 @@ for (const migration of migrations) { sqlite.exec(migration); console.log('✅ Migration applied'); } catch (error) { + const message = error instanceof Error ? error.message : String(error); + const isDuplicateSourceColumn = + migration.includes('ALTER TABLE jobs ADD COLUMN source') && + message.toLowerCase().includes('duplicate column name'); + + if (isDuplicateSourceColumn) { + console.log('â†Šī¸ Migration skipped (source column already exists)'); + continue; + } + console.error('❌ Migration failed:', error); process.exit(1); } diff --git a/orchestrator/src/server/db/schema.ts b/orchestrator/src/server/db/schema.ts index 42784a8..9cadb93 100644 --- a/orchestrator/src/server/db/schema.ts +++ b/orchestrator/src/server/db/schema.ts @@ -9,6 +9,7 @@ export const jobs = sqliteTable('jobs', { id: text('id').primaryKey(), // From crawler + source: text('source', { enum: ['gradcracker'] }).notNull().default('gradcracker'), title: text('title').notNull(), employer: text('employer').notNull(), employerUrl: text('employer_url'), diff --git a/orchestrator/src/server/repositories/jobs.ts b/orchestrator/src/server/repositories/jobs.ts index 19a3461..4b6863e 100644 --- a/orchestrator/src/server/repositories/jobs.ts +++ b/orchestrator/src/server/repositories/jobs.ts @@ -60,6 +60,7 @@ export async function createJob(input: CreateJobInput): Promise { await db.insert(jobs).values({ id, + source: input.source, title: input.title, employer: input.employer, employerUrl: input.employerUrl ?? null, @@ -171,6 +172,7 @@ export async function getJobsForProcessing(limit: number = 10): Promise { function mapRowToJob(row: typeof jobs.$inferSelect): Job { return { id: row.id, + source: row.source as Job['source'], title: row.title, employer: row.employer, employerUrl: row.employerUrl, diff --git a/orchestrator/src/server/services/crawler.ts b/orchestrator/src/server/services/crawler.ts index c654dae..7d07f4e 100644 --- a/orchestrator/src/server/services/crawler.ts +++ b/orchestrator/src/server/services/crawler.ts @@ -144,6 +144,7 @@ async function readCrawledJobs(): Promise { // Map crawler output to our job input format jobs.push({ + source: 'gradcracker', title: data.title || 'Unknown Title', employer: data.employer || 'Unknown Employer', employerUrl: data.employerUrl, diff --git a/orchestrator/src/shared/types.ts b/orchestrator/src/shared/types.ts index f6cd0a0..503d649 100644 --- a/orchestrator/src/shared/types.ts +++ b/orchestrator/src/shared/types.ts @@ -10,10 +10,14 @@ export type JobStatus = | 'rejected' // User rejected this job | 'expired'; // Deadline passed +export type JobSource = + | 'gradcracker'; + export interface Job { id: string; // From crawler + source: JobSource; title: string; employer: string; employerUrl: string | null; @@ -44,6 +48,7 @@ export interface Job { } export interface CreateJobInput { + source: JobSource; title: string; employer: string; employerUrl?: string;