2026-05-01 02:54:42 +02:00
|
|
|
-- AI usage tracking for companies and job seekers
|
|
|
|
|
-- Supports per-day rate limiting for AI generation features
|
|
|
|
|
|
|
|
|
|
BEGIN;
|
|
|
|
|
|
|
|
|
|
-- Track AI usage per company per day
|
|
|
|
|
CREATE TABLE IF NOT EXISTS company_ai_usage (
|
|
|
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
|
|
|
company_id UUID NOT NULL REFERENCES company_profiles(id) ON DELETE CASCADE,
|
|
|
|
|
usage_date DATE NOT NULL DEFAULT CURRENT_DATE,
|
|
|
|
|
generations_used INTEGER NOT NULL DEFAULT 0,
|
|
|
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
|
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
|
|
|
UNIQUE(company_id, usage_date)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
-- Track AI usage per job seeker per day
|
|
|
|
|
CREATE TABLE IF NOT EXISTS job_seeker_ai_usage (
|
|
|
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
|
|
|
job_seeker_id UUID NOT NULL REFERENCES job_seeker_profiles(id) ON DELETE CASCADE,
|
|
|
|
|
usage_date DATE NOT NULL DEFAULT CURRENT_DATE,
|
|
|
|
|
generations_used INTEGER NOT NULL DEFAULT 0,
|
|
|
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
|
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
|
|
|
UNIQUE(job_seeker_id, usage_date)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
-- Indexes for fast lookups
|
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_company_ai_usage_company_date ON company_ai_usage(company_id, usage_date);
|
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_job_seeker_ai_usage_seeker_date ON job_seeker_ai_usage(job_seeker_id, usage_date);
|
|
|
|
|
|
fix: three more already-deployed migrations unconditionally ALTERed tables that were never created
Following the reference_numbers fix, audited every active (non .skip)
migration for the same failure shape — ALTER/CREATE TRIGGER against
lead_requests, tracecoin_wallets, tracecoin_ledger, or job_applications
without ever creating them — since this codebase has a repeated pattern
of table-creation migrations getting silently disabled (renamed .skip)
after the code that depends on them was already written. Found three
more, ALL already pushed to origin, meaning they've likely been
breaking the migration chain since the date each was deployed:
- 20260317195000_profession_specific_profiles.up.sql (Mar 17) — ALTERs
lead_requests twice. Earliest failure point found for the lead_requests
chain. Now self-creates a minimal lead_requests table first (no FK to
`leads`, which isn't created until June 10 — well after this migration).
- 20260318233000_tracecoin_ledger_immutable.up.sql (Mar 18) — creates
immutability triggers ON tracecoin_ledger, assuming it exists. Now
self-creates tracecoin_wallets/tracecoin_ledger first, matching the
column names (transaction_type/reference_type) the Rust code actually
uses — the only schema that ever existed for these tables (in a
disabled .skip migration) used stale names (type/reason).
- 20260425000000_ai_usage.up.sql (Apr 25) — ALTERs job_applications
inside a BEGIN/COMMIT block, so this failure was also rolling back
company_ai_usage/job_seeker_ai_usage creation in the same file. Now
self-creates job_applications first.
Each later migration that also touches these tables (this session's
customer/job-seeker/lead_requests fixes) now uses ADD COLUMN IF NOT
EXISTS instead of assuming its own CREATE TABLE ran, so the schema
converges to the same end state regardless of which migration actually
created the table first.
Every touched migration uses IF NOT EXISTS / idempotent guards
throughout, so this is safe to apply whether or not any of these tables
already exist in the real database.
2026-07-21 02:18:23 +05:30
|
|
|
-- job_applications was never created by any active migration until now
|
|
|
|
|
-- (only referenced, never defined — see crates/db/src/models/application.rs)
|
|
|
|
|
-- so this ALTER always failed and — since the whole file runs in one
|
|
|
|
|
-- transaction — rolled back company_ai_usage/job_seeker_ai_usage above too.
|
|
|
|
|
-- Self-create a minimal version; the later migration that fully owns this
|
|
|
|
|
-- table (20260721000000_fix_job_seeker_profile_and_applications.up.sql)
|
|
|
|
|
-- converges the rest of the columns via ADD COLUMN IF NOT EXISTS.
|
|
|
|
|
CREATE TABLE IF NOT EXISTS job_applications (
|
|
|
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
|
|
|
job_id UUID NOT NULL REFERENCES jobs(id) ON DELETE CASCADE,
|
|
|
|
|
applicant_user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
|
|
|
cover_note TEXT,
|
|
|
|
|
status VARCHAR(50) NOT NULL DEFAULT 'APPLIED',
|
|
|
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
|
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
|
|
|
UNIQUE(job_id, applicant_user_id)
|
|
|
|
|
);
|
|
|
|
|
|
2026-05-01 02:54:42 +02:00
|
|
|
-- Add applied_via_ai flag to job_applications for AI auto-apply tracking
|
|
|
|
|
ALTER TABLE job_applications ADD COLUMN IF NOT EXISTS applied_via_ai BOOLEAN DEFAULT false;
|
|
|
|
|
|
|
|
|
|
-- Add ai_pack field to job_seeker_profiles for quick lookup (cached from pricing_packages)
|
|
|
|
|
ALTER TABLE job_seeker_profiles ADD COLUMN IF NOT EXISTS has_ai_pack BOOLEAN DEFAULT false;
|
|
|
|
|
|
|
|
|
|
COMMIT;
|