- Drop @supabase/supabase-js entirely; add drizzle-orm + postgres (porsager) driver - New packages/db: schema (pgSchema ordinarthur_os), client factory, migrate runner, drizzle-kit config - SQL migrations: 0000_init (pgcrypto + schema), 0001_jobs (jobs + job_search_criteria, no RLS) - Rewrite apps/api db module with DI symbols DB/DB_HANDLE + @InjectDb() decorator - Rewrite jobs.service.ts with Drizzle queries (upsert via onConflictDoUpdate, arrayOverlaps for stack filter) - Replace SUPABASE_* env vars with DATABASE_URL in env config + .env.example - Add docker-compose.yml (Postgres 16-alpine, dev only) - Add deploy/k8s/postgres.yaml (StatefulSet + PVC), migrate.job.yaml, updated secrets.template.yaml - Update all docs (README, PLAN, ARCHITECTURE, CLAUDE.md, AGENTS.md, packages/db/README.md) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
52 lines
1.9 KiB
SQL
52 lines
1.9 KiB
SQL
-- 0001_jobs.sql — Phase 1
|
|
-- Tables jobs + job_search_criteria.
|
|
|
|
CREATE TABLE IF NOT EXISTS "ordinarthur_os"."jobs" (
|
|
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
|
"source" text NOT NULL,
|
|
"source_url" text NOT NULL,
|
|
"title" text NOT NULL,
|
|
"company" text,
|
|
"description" text,
|
|
"location" text,
|
|
"remote_type" text,
|
|
"salary_min" integer,
|
|
"salary_max" integer,
|
|
"stack" text[] DEFAULT '{}'::text[] NOT NULL,
|
|
"apply_url" text,
|
|
"first_seen_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
"last_seen_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
"archived" boolean DEFAULT false NOT NULL,
|
|
"starred" boolean DEFAULT false NOT NULL,
|
|
"applied_at" timestamp with time zone,
|
|
"notes" text,
|
|
CONSTRAINT "jobs_source_url_unique" UNIQUE("source_url"),
|
|
CONSTRAINT "jobs_remote_type_check"
|
|
CHECK ("remote_type" IS NULL OR "remote_type" IN ('remote','hybrid','onsite'))
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS "jobs_last_seen_idx"
|
|
ON "ordinarthur_os"."jobs" ("last_seen_at" DESC);
|
|
CREATE INDEX IF NOT EXISTS "jobs_archived_idx"
|
|
ON "ordinarthur_os"."jobs" ("archived");
|
|
CREATE INDEX IF NOT EXISTS "jobs_remote_type_idx"
|
|
ON "ordinarthur_os"."jobs" ("remote_type");
|
|
CREATE INDEX IF NOT EXISTS "jobs_stack_gin"
|
|
ON "ordinarthur_os"."jobs" USING gin ("stack");
|
|
|
|
CREATE TABLE IF NOT EXISTS "ordinarthur_os"."job_search_criteria" (
|
|
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
|
"name" text,
|
|
"titles" text[] DEFAULT '{}'::text[] NOT NULL,
|
|
"locations" text[] DEFAULT '{}'::text[] NOT NULL,
|
|
"stack" text[] DEFAULT '{}'::text[] NOT NULL,
|
|
"remote_types" text[] DEFAULT '{}'::text[] NOT NULL,
|
|
"salary_min" integer,
|
|
"active" boolean DEFAULT true NOT NULL,
|
|
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS "job_criteria_active_idx"
|
|
ON "ordinarthur_os"."job_search_criteria" ("active");
|