83 lines
4.0 KiB
SQL
83 lines
4.0 KiB
SQL
-- ============================================================================
|
|
-- Frontend reconciliation gaps
|
|
--
|
|
-- Three columns the frontend reads or writes but migration 000001 had no place
|
|
-- for. All three were found by sweeping runtime write paths, not just seed data.
|
|
--
|
|
-- ── 1. job_applications.interview_id ──────────────────────────────────────
|
|
--
|
|
-- WRITE components/krow/AIInterviewModal.jsx:180
|
|
-- PATCH {status:'interview', interview_id, ai_score} — reachable from
|
|
-- admin/CandidateProfile.jsx, admin/Candidates.jsx, PositionDetail.jsx
|
|
-- READ components/krow/CandidateExpandedDetails.jsx:41,142
|
|
-- via CandidateCard.jsx ← admin/Candidates.jsx, PositionDetail.jsx
|
|
-- SEED 5 of 24 applications in src/api/seed.js carry it
|
|
--
|
|
-- Deliberately NOT a foreign key. `app_devon` references `int_devon`, for which
|
|
-- no AIInterview record exists in the seed; a REFERENCES constraint would
|
|
-- either fail the seed or force that value to NULL, and nulling it would be
|
|
-- silently transforming source data. The column is a soft reference, which is
|
|
-- also how the frontend treats it — every read is a truthiness check, never a
|
|
-- lookup.
|
|
-- ============================================================================
|
|
|
|
SET search_path = public;
|
|
|
|
ALTER TABLE public.job_applications
|
|
ADD COLUMN interview_id uuid;
|
|
|
|
COMMENT ON COLUMN public.job_applications.interview_id IS
|
|
'Soft reference to ai_interviews.id. Intentionally unconstrained: seed data '
|
|
'contains a dangling reference, and the frontend only ever tests it for '
|
|
'presence.';
|
|
|
|
CREATE INDEX job_applications_interview_idx
|
|
ON public.job_applications (interview_id)
|
|
WHERE interview_id IS NOT NULL;
|
|
|
|
|
|
-- ── 2. courses.training_outline ───────────────────────────────────────────
|
|
--
|
|
-- WRITE components/forge/AddSkillTraining.jsx:103 ← pages/University.jsx
|
|
-- (mounted at /admin/university)
|
|
-- READ components/forge/challengeMeta.js:139, ai-assistant/insights.js:177,
|
|
-- ai-assistant/capabilities/admin.js:1547, lib/skills/actions.js:369
|
|
-- SEED 0 of 40 courses carry it — the Forge authoring flow writes it, and
|
|
-- every shipped course predates that flow.
|
|
--
|
|
-- text[] rather than jsonb: the writer is
|
|
-- `form.outline.map((s) => s.trim()).filter(Boolean)`, a plain list of strings,
|
|
-- and every reader guards with Array.isArray then filters. This matches the
|
|
-- shape of completion_criteria and verification_criteria on the same table.
|
|
|
|
ALTER TABLE public.courses
|
|
ADD COLUMN training_outline text[] NOT NULL DEFAULT '{}';
|
|
|
|
COMMENT ON COLUMN public.courses.training_outline IS
|
|
'Ordered written training steps, authored through the Forge flow. Empty for '
|
|
'every course that predates it.';
|
|
|
|
|
|
-- ── 3. worker_profiles.score_breakdown ────────────────────────────────────
|
|
--
|
|
-- WRITE lib/krowScore.js:64 recalcProfilePatch() → spread into the profile
|
|
-- patch at lib/krowHooks.js:682, the live challenge-submission path
|
|
-- reached through CourseDetail.jsx.
|
|
-- READ No reader consumes it *from a profile*: every score_breakdown reader
|
|
-- in the frontend works on a job application. The column exists so the
|
|
-- write lands rather than being silently discarded.
|
|
--
|
|
-- jsonb, mirroring job_applications.score_breakdown, which holds the output of
|
|
-- the same scoring engine.
|
|
|
|
ALTER TABLE public.worker_profiles
|
|
ADD COLUMN score_breakdown jsonb NOT NULL DEFAULT '{}'::jsonb;
|
|
|
|
ALTER TABLE public.worker_profiles
|
|
ADD CONSTRAINT worker_profiles_score_breakdown_object
|
|
CHECK (jsonb_typeof(score_breakdown) = 'object');
|
|
|
|
COMMENT ON COLUMN public.worker_profiles.score_breakdown IS
|
|
'Per-dimension KROW score detail from recalcProfilePatch(). Written by the '
|
|
'challenge flow; no frontend reader consumes it from a profile yet.';
|