diff --git a/apps/web/src/features/applications/components/import-applications-sheet.tsx b/apps/web/src/features/applications/components/import-applications-sheet.tsx
index 9d47aac81..e3afe814a 100644
--- a/apps/web/src/features/applications/components/import-applications-sheet.tsx
+++ b/apps/web/src/features/applications/components/import-applications-sheet.tsx
@@ -22,7 +22,7 @@ import { applicationsListQueryKey } from "../queries";
const MAX_IMPORT = 500;
const SAMPLE =
- "Company,Role,Stage,Location,Salary,Source,Tags\nStripe,Frontend Engineer,applied,Remote,$180k,LinkedIn,remote;react";
+ "Company,Role,Stage,Stage Date,Location,Salary,Source,Tags\nStripe,Frontend Engineer,applied,2026-07-01,Remote,$180k,LinkedIn,remote;react";
type Props = {
open: boolean;
@@ -74,7 +74,8 @@ export function ImportApplicationsSheet({ open, onOpenChange }: Props) {
- Paste rows or upload a .csv. We map columns like Company, Role, Stage, Salary, Source and Tags.
+ Paste rows or upload a .csv. We map columns like Company, Role, Stage, Stage Date, Salary, Source and
+ Tags.
diff --git a/apps/web/src/features/applications/components/insights-view.tsx b/apps/web/src/features/applications/components/insights-view.tsx
index 3d4774807..e98ea5d69 100644
--- a/apps/web/src/features/applications/components/insights-view.tsx
+++ b/apps/web/src/features/applications/components/insights-view.tsx
@@ -1,3 +1,4 @@
+import type { ApplicationTimelineEntry } from "@reactive-resume/schema/applications/data";
import type { Application } from "../types";
import { t } from "@lingui/core/macro";
import { Trans } from "@lingui/react/macro";
@@ -9,13 +10,20 @@ import { Button } from "@reactive-resume/ui/components/button";
import { orpc } from "@/libs/orpc/client";
import { computeInsights, computeTimeline } from "../insights";
+const byNewest = (a: ApplicationTimelineEntry, b: ApplicationTimelineEntry) =>
+ new Date(b.at).getTime() - new Date(a.at).getTime();
+
+const appliedDate = (app: Application) =>
+ [...app.activity].sort(byNewest).find((entry) => entry.type === "stage" && entry.stage === "applied")?.at ??
+ app.appliedAt;
+
export function ApplicationInsights({ applications }: { applications: Application[] }) {
const { data } = useQuery(orpc.applications.stats.queryOptions({}));
// Weekly application velocity — derived from the already-loaded list, matching the stats
// population (archived excluded), so no extra endpoint is needed.
const timeline = useMemo(
- () => computeTimeline(applications.filter((app) => !app.archived).map((app) => new Date(app.appliedAt))),
+ () => computeTimeline(applications.filter((app) => !app.archived).map((app) => new Date(appliedDate(app)))),
[applications],
);
const maxWeek = Math.max(1, ...timeline.map((bucket) => bucket.count));
diff --git a/apps/web/src/features/applications/components/table-view.tsx b/apps/web/src/features/applications/components/table-view.tsx
index f618d19df..8f07ae36b 100644
--- a/apps/web/src/features/applications/components/table-view.tsx
+++ b/apps/web/src/features/applications/components/table-view.tsx
@@ -1,3 +1,4 @@
+import type { ApplicationStatus, ApplicationTimelineEntry } from "@reactive-resume/schema/applications/data";
import type { Application } from "../types";
import { t } from "@lingui/core/macro";
import { Trans } from "@lingui/react/macro";
@@ -26,6 +27,12 @@ import { ApplicationActionsMenu } from "./application-actions-menu";
const PAGE_SIZE = 25;
const stageOf = (status: string) => STAGES.find((s) => s.value === status);
+const byNewest = (a: ApplicationTimelineEntry, b: ApplicationTimelineEntry) =>
+ new Date(b.at).getTime() - new Date(a.at).getTime();
+const latestStageDate = (activity: ApplicationTimelineEntry[], status: ApplicationStatus) =>
+ [...activity].sort(byNewest).find((entry) => entry.type === "stage" && entry.stage === status)?.at;
+const formatDate = (value: Date | string) =>
+ new Date(value).toLocaleDateString(undefined, { month: "numeric", day: "numeric", timeZone: "UTC", year: "numeric" });
type Props = {
applications: Application[];
@@ -265,7 +272,7 @@ export function ApplicationTable({ applications, onOpen, onEdit }: Props) {
{app.source || "—"} |
- {new Date(app.appliedAt).toLocaleDateString()}
+ {formatDate(latestStageDate(app.activity, "applied") ?? app.appliedAt)}
|
diff --git a/apps/web/src/features/applications/csv.test.ts b/apps/web/src/features/applications/csv.test.ts
index 95b873ccd..e1794adc8 100644
--- a/apps/web/src/features/applications/csv.test.ts
+++ b/apps/web/src/features/applications/csv.test.ts
@@ -26,24 +26,30 @@ describe("parseCsv", () => {
describe("mapCsvToApplications", () => {
it("maps aliased headers and coerces status/tags", () => {
- const csv = 'Company,Job Title,Stage,Salary,Tags\nStripe,Frontend,Interview,$180k,"remote;react"';
+ const csv =
+ 'Company,Job Title,Stage,Stage Date,Salary,Tags\nStripe,Frontend,Interview,2026-07-01,$180k,"remote;react"';
const { rows, recognized } = mapCsvToApplications(parseCsv(csv));
expect(rows).toHaveLength(1);
expect(rows[0]).toMatchObject({
company: "Stripe",
role: "Frontend",
status: "interview",
+ stageEnteredAt: "2026-07-01",
salary: "$180k",
tags: ["remote", "react"],
});
- expect(recognized).toEqual(expect.arrayContaining(["company", "role", "status", "salary", "tags"]));
+ expect(recognized).toEqual(
+ expect.arrayContaining(["company", "role", "status", "stageEnteredAt", "salary", "tags"]),
+ );
});
it("skips rows missing company or role and drops invalid status", () => {
- const csv = "company,role,status\nStripe,Eng,bogus\n,NoCompany,applied\nAcme,,saved";
+ const csv =
+ "company,role,status,stage date\nStripe,Eng,bogus,2026-99-99\n,NoCompany,applied,2026-07-01\nAcme,,saved,2026-07-01";
const { rows, skipped } = mapCsvToApplications(parseCsv(csv));
expect(rows).toHaveLength(1);
expect(rows[0]?.status).toBeUndefined(); // "bogus" dropped
+ expect(rows[0]?.stageEnteredAt).toBeUndefined(); // invalid date dropped
expect(skipped).toBe(2);
});
});
diff --git a/apps/web/src/features/applications/csv.ts b/apps/web/src/features/applications/csv.ts
index bf6d41e37..2df8422ce 100644
--- a/apps/web/src/features/applications/csv.ts
+++ b/apps/web/src/features/applications/csv.ts
@@ -61,9 +61,17 @@ type ParsedApplication = {
source?: string;
notes?: string;
sourceUrl?: string;
+ stageEnteredAt?: string;
tags?: string[];
};
+function dateOnly(value: string) {
+ if (!/^\d{4}-\d{2}-\d{2}$/.test(value)) return undefined;
+ const [year, month, day] = value.split("-").map(Number);
+ const date = new Date(Date.UTC(year ?? 0, (month ?? 1) - 1, day ?? 0));
+ return date.toISOString().slice(0, 10) === value ? value : undefined;
+}
+
// Header aliases → canonical field. Matched case-insensitively after trimming.
const HEADER_ALIASES: Record = {
company: "company",
@@ -75,6 +83,9 @@ const HEADER_ALIASES: Record = {
"job title": "role",
status: "status",
stage: "status",
+ "applied date": "stageEnteredAt",
+ "stage date": "stageEnteredAt",
+ "stage entered at": "stageEnteredAt",
location: "location",
salary: "salary",
"salary range": "salary",
@@ -123,6 +134,8 @@ export function mapCsvToApplications(table: string[][]): CsvMapResult {
else if (field === "status") {
const parsed = applicationStatusSchema.safeParse(value.toLowerCase());
if (parsed.success) record.status = parsed.data;
+ } else if (field === "stageEnteredAt") {
+ record.stageEnteredAt = dateOnly(value);
} else record[field] = value as never;
});
diff --git a/migrations/20260708210217_wonderful_captain_midlands/migration.sql b/migrations/20260708210217_wonderful_captain_midlands/migration.sql
new file mode 100644
index 000000000..0d274d0f6
--- /dev/null
+++ b/migrations/20260708210217_wonderful_captain_midlands/migration.sql
@@ -0,0 +1,116 @@
+WITH entries AS (
+ SELECT
+ a.id AS application_id,
+ entry.value AS entry,
+ entry.ordinality,
+ coalesce(nullif(entry.value ->> 'id', ''), md5(a.id || ':' || entry.ordinality::text)) AS entry_id,
+ coalesce(nullif(entry.value ->> 'at', ''), a.applied_at::text, a.created_at::text, now()::text) AS entry_at,
+ lower(coalesce(entry.value ->> 'text', '')) AS entry_text
+ FROM "application" a
+ CROSS JOIN LATERAL jsonb_array_elements(
+ CASE WHEN jsonb_typeof(a.activity) = 'array' THEN a.activity ELSE '[]'::jsonb END
+ ) WITH ORDINALITY AS entry(value, ordinality)
+),
+normalized AS (
+ SELECT
+ application_id,
+ ordinality,
+ CASE
+ WHEN entry ->> 'type' = 'stage'
+ AND entry ->> 'stage' IN ('saved', 'applied', 'screening', 'interview', 'offer', 'rejected') THEN
+ jsonb_build_object('id', entry_id, 'type', 'stage', 'stage', entry ->> 'stage', 'at', entry_at)
+ WHEN entry ->> 'type' IN ('created', 'stage')
+ AND CASE
+ WHEN entry_text LIKE '%screening%' THEN 'screening'
+ WHEN entry_text LIKE '%interview%' THEN 'interview'
+ WHEN entry_text LIKE '%offer%' THEN 'offer'
+ WHEN entry_text LIKE '%rejected%' THEN 'rejected'
+ WHEN entry_text LIKE '%applied%' THEN 'applied'
+ WHEN entry_text LIKE '%saved%' THEN 'saved'
+ END IS NOT NULL THEN
+ jsonb_build_object(
+ 'id', entry_id,
+ 'type', 'stage',
+ 'stage', CASE
+ WHEN entry_text LIKE '%screening%' THEN 'screening'
+ WHEN entry_text LIKE '%interview%' THEN 'interview'
+ WHEN entry_text LIKE '%offer%' THEN 'offer'
+ WHEN entry_text LIKE '%rejected%' THEN 'rejected'
+ WHEN entry_text LIKE '%applied%' THEN 'applied'
+ WHEN entry_text LIKE '%saved%' THEN 'saved'
+ END,
+ 'at', entry_at
+ )
+ ELSE
+ jsonb_build_object(
+ 'id', entry_id,
+ 'type', 'note',
+ 'text', coalesce(nullif(btrim(entry ->> 'text'), ''), 'Imported timeline entry'),
+ 'at', entry_at
+ )
+ END AS normalized_entry
+ FROM entries
+),
+grouped AS (
+ SELECT application_id, jsonb_agg(normalized_entry ORDER BY ordinality) AS activity
+ FROM normalized
+ GROUP BY application_id
+)
+UPDATE "application" a
+SET activity = grouped.activity
+FROM grouped
+WHERE a.id = grouped.application_id;
+--> statement-breakpoint
+UPDATE "application"
+SET activity = jsonb_build_array(
+ jsonb_build_object(
+ 'id', md5(id || ':stage'),
+ 'type', 'stage',
+ 'stage', status,
+ 'at', coalesce(applied_at::text, created_at::text, now()::text)
+ )
+)
+WHERE jsonb_typeof(activity) IS DISTINCT FROM 'array' OR activity = '[]'::jsonb;
+--> statement-breakpoint
+WITH stage_stats AS (
+ SELECT
+ a.id AS application_id,
+ max((entry.value ->> 'at')::timestamptz) FILTER (WHERE entry.value ->> 'type' = 'stage') AS latest_stage_at,
+ max((entry.value ->> 'at')::timestamptz) FILTER (
+ WHERE entry.value ->> 'type' = 'stage' AND entry.value ->> 'stage' = a.status
+ ) AS current_stage_at
+ FROM "application" a
+ CROSS JOIN LATERAL jsonb_array_elements(
+ CASE WHEN jsonb_typeof(a.activity) = 'array' THEN a.activity ELSE '[]'::jsonb END
+ ) AS entry(value)
+ GROUP BY a.id
+),
+anchors AS (
+ SELECT
+ a.id,
+ a.status,
+ greatest(
+ coalesce(stage_stats.latest_stage_at, a.applied_at, a.created_at, now()),
+ coalesce(a.applied_at, a.created_at, now())
+ ) AS anchor_at,
+ stage_stats.latest_stage_at,
+ stage_stats.current_stage_at
+ FROM "application" a
+ LEFT JOIN stage_stats ON stage_stats.application_id = a.id
+ WHERE jsonb_typeof(a.activity) = 'array'
+)
+UPDATE "application" a
+SET activity = a.activity || jsonb_build_array(
+ jsonb_build_object(
+ 'id', md5(a.id || ':stage:' || a.status || ':anchor'),
+ 'type', 'stage',
+ 'stage', a.status,
+ 'at', anchors.anchor_at::text
+ )
+)
+FROM anchors
+WHERE a.id = anchors.id
+ AND (
+ anchors.current_stage_at IS NULL
+ OR (anchors.latest_stage_at IS NOT NULL AND anchors.current_stage_at < anchors.latest_stage_at)
+ );
diff --git a/migrations/20260708210217_wonderful_captain_midlands/snapshot.json b/migrations/20260708210217_wonderful_captain_midlands/snapshot.json
new file mode 100644
index 000000000..77278a10b
--- /dev/null
+++ b/migrations/20260708210217_wonderful_captain_midlands/snapshot.json
@@ -0,0 +1,5558 @@
+{
+ "id": "35a5af6c-909f-43d0-a206-9b71ad20d8e7",
+ "prevIds": ["8bb888e0-1e3e-4f20-ac7f-e5591f5037ca"],
+ "version": "8",
+ "dialect": "postgres",
+ "ddl": [
+ {
+ "isRlsEnabled": false,
+ "name": "agent_actions",
+ "entityType": "tables",
+ "schema": "public"
+ },
+ {
+ "isRlsEnabled": false,
+ "name": "agent_attachments",
+ "entityType": "tables",
+ "schema": "public"
+ },
+ {
+ "isRlsEnabled": false,
+ "name": "agent_messages",
+ "entityType": "tables",
+ "schema": "public"
+ },
+ {
+ "isRlsEnabled": false,
+ "name": "agent_threads",
+ "entityType": "tables",
+ "schema": "public"
+ },
+ {
+ "isRlsEnabled": false,
+ "name": "ai_providers",
+ "entityType": "tables",
+ "schema": "public"
+ },
+ {
+ "isRlsEnabled": false,
+ "name": "application",
+ "entityType": "tables",
+ "schema": "public"
+ },
+ {
+ "isRlsEnabled": false,
+ "name": "account",
+ "entityType": "tables",
+ "schema": "public"
+ },
+ {
+ "isRlsEnabled": false,
+ "name": "apikey",
+ "entityType": "tables",
+ "schema": "public"
+ },
+ {
+ "isRlsEnabled": false,
+ "name": "jwks",
+ "entityType": "tables",
+ "schema": "public"
+ },
+ {
+ "isRlsEnabled": false,
+ "name": "oauth_access_token",
+ "entityType": "tables",
+ "schema": "public"
+ },
+ {
+ "isRlsEnabled": false,
+ "name": "oauth_client",
+ "entityType": "tables",
+ "schema": "public"
+ },
+ {
+ "isRlsEnabled": false,
+ "name": "oauth_consent",
+ "entityType": "tables",
+ "schema": "public"
+ },
+ {
+ "isRlsEnabled": false,
+ "name": "oauth_refresh_token",
+ "entityType": "tables",
+ "schema": "public"
+ },
+ {
+ "isRlsEnabled": false,
+ "name": "passkey",
+ "entityType": "tables",
+ "schema": "public"
+ },
+ {
+ "isRlsEnabled": false,
+ "name": "session",
+ "entityType": "tables",
+ "schema": "public"
+ },
+ {
+ "isRlsEnabled": false,
+ "name": "two_factor",
+ "entityType": "tables",
+ "schema": "public"
+ },
+ {
+ "isRlsEnabled": false,
+ "name": "user",
+ "entityType": "tables",
+ "schema": "public"
+ },
+ {
+ "isRlsEnabled": false,
+ "name": "verification",
+ "entityType": "tables",
+ "schema": "public"
+ },
+ {
+ "isRlsEnabled": false,
+ "name": "resume",
+ "entityType": "tables",
+ "schema": "public"
+ },
+ {
+ "isRlsEnabled": false,
+ "name": "resume_analysis",
+ "entityType": "tables",
+ "schema": "public"
+ },
+ {
+ "isRlsEnabled": false,
+ "name": "resume_statistics",
+ "entityType": "tables",
+ "schema": "public"
+ },
+ {
+ "isRlsEnabled": false,
+ "name": "resume_statistics_daily",
+ "entityType": "tables",
+ "schema": "public"
+ },
+ {
+ "isRlsEnabled": false,
+ "name": "resume_version",
+ "entityType": "tables",
+ "schema": "public"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "agent_actions"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "user_id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "agent_actions"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "thread_id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "agent_actions"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "message_id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "agent_actions"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "resume_id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "agent_actions"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "kind",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "agent_actions"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "'applied'",
+ "generated": null,
+ "identity": null,
+ "name": "status",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "agent_actions"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "title",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "agent_actions"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "summary",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "agent_actions"
+ },
+ {
+ "type": "jsonb",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "operations",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "agent_actions"
+ },
+ {
+ "type": "jsonb",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "snapshot_data",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "agent_actions"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "base_updated_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "agent_actions"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "applied_updated_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "agent_actions"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "reverted_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "agent_actions"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "revert_message",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "agent_actions"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "now()",
+ "generated": null,
+ "identity": null,
+ "name": "created_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "agent_actions"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "now()",
+ "generated": null,
+ "identity": null,
+ "name": "updated_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "agent_actions"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "agent_attachments"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "user_id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "agent_attachments"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "thread_id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "agent_attachments"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "message_id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "agent_attachments"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "storage_key",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "agent_attachments"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "filename",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "agent_attachments"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "media_type",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "agent_attachments"
+ },
+ {
+ "type": "integer",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "size",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "agent_attachments"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "now()",
+ "generated": null,
+ "identity": null,
+ "name": "created_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "agent_attachments"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "agent_messages"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "user_id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "agent_messages"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "thread_id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "agent_messages"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "role",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "agent_messages"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "'completed'",
+ "generated": null,
+ "identity": null,
+ "name": "status",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "agent_messages"
+ },
+ {
+ "type": "integer",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "sequence",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "agent_messages"
+ },
+ {
+ "type": "jsonb",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "ui_message",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "agent_messages"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "error",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "agent_messages"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "now()",
+ "generated": null,
+ "identity": null,
+ "name": "created_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "agent_messages"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "now()",
+ "generated": null,
+ "identity": null,
+ "name": "updated_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "agent_messages"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "agent_threads"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "user_id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "agent_threads"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "ai_provider_id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "agent_threads"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "source_resume_id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "agent_threads"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "working_resume_id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "agent_threads"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "title",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "agent_threads"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "'active'",
+ "generated": null,
+ "identity": null,
+ "name": "status",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "agent_threads"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "active_run_id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "agent_threads"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "active_stream_id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "agent_threads"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "active_run_started_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "agent_threads"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "now()",
+ "generated": null,
+ "identity": null,
+ "name": "last_message_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "agent_threads"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "archived_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "agent_threads"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "deleted_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "agent_threads"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "now()",
+ "generated": null,
+ "identity": null,
+ "name": "created_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "agent_threads"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "now()",
+ "generated": null,
+ "identity": null,
+ "name": "updated_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "agent_threads"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "ai_providers"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "user_id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "ai_providers"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "label",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "ai_providers"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "provider",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "ai_providers"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "model",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "ai_providers"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "base_url",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "ai_providers"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "encrypted_api_key",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "ai_providers"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "api_key_salt",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "ai_providers"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "api_key_hash",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "ai_providers"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "api_key_preview",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "ai_providers"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "'untested'",
+ "generated": null,
+ "identity": null,
+ "name": "test_status",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "ai_providers"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "test_error",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "ai_providers"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "last_tested_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "ai_providers"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "last_used_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "ai_providers"
+ },
+ {
+ "type": "boolean",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "false",
+ "generated": null,
+ "identity": null,
+ "name": "enabled",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "ai_providers"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "now()",
+ "generated": null,
+ "identity": null,
+ "name": "created_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "ai_providers"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "now()",
+ "generated": null,
+ "identity": null,
+ "name": "updated_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "ai_providers"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "application"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "user_id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "application"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "company",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "application"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "role",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "application"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "location",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "application"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "salary",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "application"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "'saved'",
+ "generated": null,
+ "identity": null,
+ "name": "status",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "application"
+ },
+ {
+ "type": "boolean",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "false",
+ "generated": null,
+ "identity": null,
+ "name": "archived",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "application"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "resume_id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "application"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "source",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "application"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 1,
+ "default": "'{}'",
+ "generated": null,
+ "identity": null,
+ "name": "tags",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "application"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "source_url",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "application"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "job_description",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "application"
+ },
+ {
+ "type": "integer",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "match_score",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "application"
+ },
+ {
+ "type": "jsonb",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "ai_metadata",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "application"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "notes",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "application"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "resume_file_url",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "application"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "resume_file_name",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "application"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "cover_letter_url",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "application"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "cover_letter_name",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "application"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "follow_up_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "application"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "follow_up_note",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "application"
+ },
+ {
+ "type": "jsonb",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "'[]'",
+ "generated": null,
+ "identity": null,
+ "name": "contacts",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "application"
+ },
+ {
+ "type": "jsonb",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "'[]'",
+ "generated": null,
+ "identity": null,
+ "name": "activity",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "application"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "now()",
+ "generated": null,
+ "identity": null,
+ "name": "applied_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "application"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "now()",
+ "generated": null,
+ "identity": null,
+ "name": "created_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "application"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "now()",
+ "generated": null,
+ "identity": null,
+ "name": "updated_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "application"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "account"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "account_id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "account"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "'credential'",
+ "generated": null,
+ "identity": null,
+ "name": "provider_id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "account"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "user_id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "account"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "scope",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "account"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "id_token",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "account"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "password",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "account"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "access_token",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "account"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "refresh_token",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "account"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "access_token_expires_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "account"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "refresh_token_expires_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "account"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "now()",
+ "generated": null,
+ "identity": null,
+ "name": "created_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "account"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "now()",
+ "generated": null,
+ "identity": null,
+ "name": "updated_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "account"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "apikey"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "name",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "apikey"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "start",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "apikey"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "prefix",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "apikey"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "key",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "apikey"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "'default'",
+ "generated": null,
+ "identity": null,
+ "name": "config_id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "apikey"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "reference_id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "apikey"
+ },
+ {
+ "type": "integer",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "refill_interval",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "apikey"
+ },
+ {
+ "type": "integer",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "refill_amount",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "apikey"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "last_refill_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "apikey"
+ },
+ {
+ "type": "boolean",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "true",
+ "generated": null,
+ "identity": null,
+ "name": "enabled",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "apikey"
+ },
+ {
+ "type": "boolean",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "false",
+ "generated": null,
+ "identity": null,
+ "name": "rate_limit_enabled",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "apikey"
+ },
+ {
+ "type": "integer",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": "86400000",
+ "generated": null,
+ "identity": null,
+ "name": "rate_limit_time_window",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "apikey"
+ },
+ {
+ "type": "integer",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": "10",
+ "generated": null,
+ "identity": null,
+ "name": "rate_limit_max",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "apikey"
+ },
+ {
+ "type": "integer",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "0",
+ "generated": null,
+ "identity": null,
+ "name": "request_count",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "apikey"
+ },
+ {
+ "type": "integer",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "remaining",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "apikey"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "last_request",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "apikey"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "expires_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "apikey"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "now()",
+ "generated": null,
+ "identity": null,
+ "name": "created_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "apikey"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "now()",
+ "generated": null,
+ "identity": null,
+ "name": "updated_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "apikey"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "permissions",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "apikey"
+ },
+ {
+ "type": "jsonb",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "metadata",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "apikey"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "jwks"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "public_key",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "jwks"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "private_key",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "jwks"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "now()",
+ "generated": null,
+ "identity": null,
+ "name": "created_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "jwks"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "expires_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "jwks"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "oauth_access_token"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "token",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "oauth_access_token"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "client_id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "oauth_access_token"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "session_id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "oauth_access_token"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "user_id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "oauth_access_token"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "reference_id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "oauth_access_token"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "refresh_id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "oauth_access_token"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "expires_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "oauth_access_token"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": "now()",
+ "generated": null,
+ "identity": null,
+ "name": "created_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "oauth_access_token"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 1,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "scopes",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "oauth_access_token"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "oauth_client"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "client_id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "oauth_client"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "client_secret",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "oauth_client"
+ },
+ {
+ "type": "boolean",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": "false",
+ "generated": null,
+ "identity": null,
+ "name": "disabled",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "oauth_client"
+ },
+ {
+ "type": "boolean",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "skip_consent",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "oauth_client"
+ },
+ {
+ "type": "boolean",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "enable_end_session",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "oauth_client"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "subject_type",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "oauth_client"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 1,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "scopes",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "oauth_client"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "user_id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "oauth_client"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": "now()",
+ "generated": null,
+ "identity": null,
+ "name": "created_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "oauth_client"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": "now()",
+ "generated": null,
+ "identity": null,
+ "name": "updated_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "oauth_client"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "name",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "oauth_client"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "uri",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "oauth_client"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "icon",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "oauth_client"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 1,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "contacts",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "oauth_client"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "tos",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "oauth_client"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "policy",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "oauth_client"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "software_id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "oauth_client"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "software_version",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "oauth_client"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "software_statement",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "oauth_client"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 1,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "redirect_uris",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "oauth_client"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 1,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "post_logout_redirect_uris",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "oauth_client"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "token_endpoint_auth_method",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "oauth_client"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 1,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "grant_types",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "oauth_client"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 1,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "response_types",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "oauth_client"
+ },
+ {
+ "type": "boolean",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "public",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "oauth_client"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "type",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "oauth_client"
+ },
+ {
+ "type": "boolean",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "require_pkce",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "oauth_client"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "reference_id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "oauth_client"
+ },
+ {
+ "type": "jsonb",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "metadata",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "oauth_client"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "oauth_consent"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "client_id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "oauth_consent"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "user_id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "oauth_consent"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "reference_id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "oauth_consent"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 1,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "scopes",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "oauth_consent"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": "now()",
+ "generated": null,
+ "identity": null,
+ "name": "created_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "oauth_consent"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": "now()",
+ "generated": null,
+ "identity": null,
+ "name": "updated_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "oauth_consent"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "oauth_refresh_token"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "token",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "oauth_refresh_token"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "client_id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "oauth_refresh_token"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "session_id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "oauth_refresh_token"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "user_id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "oauth_refresh_token"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "reference_id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "oauth_refresh_token"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "expires_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "oauth_refresh_token"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": "now()",
+ "generated": null,
+ "identity": null,
+ "name": "created_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "oauth_refresh_token"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "revoked",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "oauth_refresh_token"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "auth_time",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "oauth_refresh_token"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 1,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "scopes",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "oauth_refresh_token"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "passkey"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "name",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "passkey"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "aaguid",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "passkey"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "public_key",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "passkey"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "credential_id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "passkey"
+ },
+ {
+ "type": "integer",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "counter",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "passkey"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "device_type",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "passkey"
+ },
+ {
+ "type": "boolean",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "false",
+ "generated": null,
+ "identity": null,
+ "name": "backed_up",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "passkey"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "transports",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "passkey"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "user_id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "passkey"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "now()",
+ "generated": null,
+ "identity": null,
+ "name": "created_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "passkey"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "now()",
+ "generated": null,
+ "identity": null,
+ "name": "updated_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "passkey"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "session"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "token",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "session"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "ip_address",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "session"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "user_agent",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "session"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "impersonated_by",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "session"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "user_id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "session"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "expires_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "session"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "now()",
+ "generated": null,
+ "identity": null,
+ "name": "created_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "session"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "now()",
+ "generated": null,
+ "identity": null,
+ "name": "updated_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "session"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "two_factor"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "user_id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "two_factor"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "secret",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "two_factor"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "backup_codes",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "two_factor"
+ },
+ {
+ "type": "boolean",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "true",
+ "generated": null,
+ "identity": null,
+ "name": "verified",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "two_factor"
+ },
+ {
+ "type": "integer",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": "0",
+ "generated": null,
+ "identity": null,
+ "name": "failed_verification_count",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "two_factor"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "locked_until",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "two_factor"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "now()",
+ "generated": null,
+ "identity": null,
+ "name": "created_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "two_factor"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "now()",
+ "generated": null,
+ "identity": null,
+ "name": "updated_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "two_factor"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "user"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "image",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "user"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "name",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "user"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "email",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "user"
+ },
+ {
+ "type": "boolean",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "false",
+ "generated": null,
+ "identity": null,
+ "name": "email_verified",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "user"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "username",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "user"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "display_username",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "user"
+ },
+ {
+ "type": "boolean",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "false",
+ "generated": null,
+ "identity": null,
+ "name": "two_factor_enabled",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "user"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "last_active_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "user"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": "'user'",
+ "generated": null,
+ "identity": null,
+ "name": "role",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "user"
+ },
+ {
+ "type": "boolean",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": "false",
+ "generated": null,
+ "identity": null,
+ "name": "banned",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "user"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "ban_reason",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "user"
+ },
+ {
+ "type": "timestamp(6) with time zone",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "ban_expires",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "user"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "now()",
+ "generated": null,
+ "identity": null,
+ "name": "created_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "user"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "now()",
+ "generated": null,
+ "identity": null,
+ "name": "updated_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "user"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "verification"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "identifier",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "verification"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "value",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "verification"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "expires_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "verification"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "now()",
+ "generated": null,
+ "identity": null,
+ "name": "created_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "verification"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "now()",
+ "generated": null,
+ "identity": null,
+ "name": "updated_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "verification"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "resume"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "name",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "resume"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "slug",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "resume"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 1,
+ "default": "'{}'",
+ "generated": null,
+ "identity": null,
+ "name": "tags",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "resume"
+ },
+ {
+ "type": "boolean",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "false",
+ "generated": null,
+ "identity": null,
+ "name": "is_public",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "resume"
+ },
+ {
+ "type": "boolean",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "false",
+ "generated": null,
+ "identity": null,
+ "name": "is_locked",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "resume"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "password",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "resume"
+ },
+ {
+ "type": "jsonb",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "data",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "resume"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "user_id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "resume"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "now()",
+ "generated": null,
+ "identity": null,
+ "name": "created_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "resume"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "now()",
+ "generated": null,
+ "identity": null,
+ "name": "updated_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "resume"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "resume_analysis"
+ },
+ {
+ "type": "jsonb",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "analysis",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "resume_analysis"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "resume_id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "resume_analysis"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "now()",
+ "generated": null,
+ "identity": null,
+ "name": "created_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "resume_analysis"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "now()",
+ "generated": null,
+ "identity": null,
+ "name": "updated_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "resume_analysis"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "resume_statistics"
+ },
+ {
+ "type": "integer",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "0",
+ "generated": null,
+ "identity": null,
+ "name": "views",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "resume_statistics"
+ },
+ {
+ "type": "integer",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "0",
+ "generated": null,
+ "identity": null,
+ "name": "downloads",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "resume_statistics"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "last_viewed_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "resume_statistics"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": false,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "last_downloaded_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "resume_statistics"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "resume_id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "resume_statistics"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "now()",
+ "generated": null,
+ "identity": null,
+ "name": "created_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "resume_statistics"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "now()",
+ "generated": null,
+ "identity": null,
+ "name": "updated_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "resume_statistics"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "resume_statistics_daily"
+ },
+ {
+ "type": "date",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "date",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "resume_statistics_daily"
+ },
+ {
+ "type": "integer",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "0",
+ "generated": null,
+ "identity": null,
+ "name": "views",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "resume_statistics_daily"
+ },
+ {
+ "type": "integer",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "0",
+ "generated": null,
+ "identity": null,
+ "name": "downloads",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "resume_statistics_daily"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "resume_id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "resume_statistics_daily"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "now()",
+ "generated": null,
+ "identity": null,
+ "name": "created_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "resume_statistics_daily"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "now()",
+ "generated": null,
+ "identity": null,
+ "name": "updated_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "resume_statistics_daily"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "resume_version"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "resume_id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "resume_version"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "user_id",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "resume_version"
+ },
+ {
+ "type": "jsonb",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "data",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "resume_version"
+ },
+ {
+ "type": "text",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": null,
+ "generated": null,
+ "identity": null,
+ "name": "label",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "resume_version"
+ },
+ {
+ "type": "timestamp with time zone",
+ "typeSchema": null,
+ "notNull": true,
+ "dimensions": 0,
+ "default": "now()",
+ "generated": null,
+ "identity": null,
+ "name": "created_at",
+ "entityType": "columns",
+ "schema": "public",
+ "table": "resume_version"
+ },
+ {
+ "nameExplicit": false,
+ "columns": [
+ {
+ "value": "thread_id",
+ "isExpression": false,
+ "asc": true,
+ "nullsFirst": false,
+ "opclass": null
+ },
+ {
+ "value": "created_at",
+ "isExpression": false,
+ "asc": false,
+ "nullsFirst": false,
+ "opclass": null
+ }
+ ],
+ "isUnique": false,
+ "where": null,
+ "with": "",
+ "method": "btree",
+ "concurrently": false,
+ "name": "agent_actions_thread_id_created_at_index",
+ "entityType": "indexes",
+ "schema": "public",
+ "table": "agent_actions"
+ },
+ {
+ "nameExplicit": false,
+ "columns": [
+ {
+ "value": "resume_id",
+ "isExpression": false,
+ "asc": true,
+ "nullsFirst": false,
+ "opclass": null
+ }
+ ],
+ "isUnique": false,
+ "where": null,
+ "with": "",
+ "method": "btree",
+ "concurrently": false,
+ "name": "agent_actions_resume_id_index",
+ "entityType": "indexes",
+ "schema": "public",
+ "table": "agent_actions"
+ },
+ {
+ "nameExplicit": false,
+ "columns": [
+ {
+ "value": "message_id",
+ "isExpression": false,
+ "asc": true,
+ "nullsFirst": false,
+ "opclass": null
+ }
+ ],
+ "isUnique": false,
+ "where": null,
+ "with": "",
+ "method": "btree",
+ "concurrently": false,
+ "name": "agent_actions_message_id_index",
+ "entityType": "indexes",
+ "schema": "public",
+ "table": "agent_actions"
+ },
+ {
+ "nameExplicit": false,
+ "columns": [
+ {
+ "value": "thread_id",
+ "isExpression": false,
+ "asc": true,
+ "nullsFirst": false,
+ "opclass": null
+ }
+ ],
+ "isUnique": false,
+ "where": null,
+ "with": "",
+ "method": "btree",
+ "concurrently": false,
+ "name": "agent_attachments_thread_id_index",
+ "entityType": "indexes",
+ "schema": "public",
+ "table": "agent_attachments"
+ },
+ {
+ "nameExplicit": false,
+ "columns": [
+ {
+ "value": "message_id",
+ "isExpression": false,
+ "asc": true,
+ "nullsFirst": false,
+ "opclass": null
+ }
+ ],
+ "isUnique": false,
+ "where": null,
+ "with": "",
+ "method": "btree",
+ "concurrently": false,
+ "name": "agent_attachments_message_id_index",
+ "entityType": "indexes",
+ "schema": "public",
+ "table": "agent_attachments"
+ },
+ {
+ "nameExplicit": false,
+ "columns": [
+ {
+ "value": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nullsFirst": false,
+ "opclass": null
+ }
+ ],
+ "isUnique": false,
+ "where": null,
+ "with": "",
+ "method": "btree",
+ "concurrently": false,
+ "name": "agent_attachments_user_id_index",
+ "entityType": "indexes",
+ "schema": "public",
+ "table": "agent_attachments"
+ },
+ {
+ "nameExplicit": false,
+ "columns": [
+ {
+ "value": "thread_id",
+ "isExpression": false,
+ "asc": true,
+ "nullsFirst": false,
+ "opclass": null
+ },
+ {
+ "value": "sequence",
+ "isExpression": false,
+ "asc": true,
+ "nullsFirst": false,
+ "opclass": null
+ }
+ ],
+ "isUnique": true,
+ "where": null,
+ "with": "",
+ "method": "btree",
+ "concurrently": false,
+ "name": "agent_messages_thread_id_sequence_index",
+ "entityType": "indexes",
+ "schema": "public",
+ "table": "agent_messages"
+ },
+ {
+ "nameExplicit": false,
+ "columns": [
+ {
+ "value": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nullsFirst": false,
+ "opclass": null
+ },
+ {
+ "value": "created_at",
+ "isExpression": false,
+ "asc": false,
+ "nullsFirst": false,
+ "opclass": null
+ }
+ ],
+ "isUnique": false,
+ "where": null,
+ "with": "",
+ "method": "btree",
+ "concurrently": false,
+ "name": "agent_messages_user_id_created_at_index",
+ "entityType": "indexes",
+ "schema": "public",
+ "table": "agent_messages"
+ },
+ {
+ "nameExplicit": false,
+ "columns": [
+ {
+ "value": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nullsFirst": false,
+ "opclass": null
+ },
+ {
+ "value": "status",
+ "isExpression": false,
+ "asc": true,
+ "nullsFirst": false,
+ "opclass": null
+ },
+ {
+ "value": "last_message_at",
+ "isExpression": false,
+ "asc": false,
+ "nullsFirst": false,
+ "opclass": null
+ }
+ ],
+ "isUnique": false,
+ "where": null,
+ "with": "",
+ "method": "btree",
+ "concurrently": false,
+ "name": "agent_threads_user_id_status_last_message_at_index",
+ "entityType": "indexes",
+ "schema": "public",
+ "table": "agent_threads"
+ },
+ {
+ "nameExplicit": false,
+ "columns": [
+ {
+ "value": "working_resume_id",
+ "isExpression": false,
+ "asc": true,
+ "nullsFirst": false,
+ "opclass": null
+ }
+ ],
+ "isUnique": false,
+ "where": null,
+ "with": "",
+ "method": "btree",
+ "concurrently": false,
+ "name": "agent_threads_working_resume_id_index",
+ "entityType": "indexes",
+ "schema": "public",
+ "table": "agent_threads"
+ },
+ {
+ "nameExplicit": false,
+ "columns": [
+ {
+ "value": "ai_provider_id",
+ "isExpression": false,
+ "asc": true,
+ "nullsFirst": false,
+ "opclass": null
+ }
+ ],
+ "isUnique": false,
+ "where": null,
+ "with": "",
+ "method": "btree",
+ "concurrently": false,
+ "name": "agent_threads_ai_provider_id_index",
+ "entityType": "indexes",
+ "schema": "public",
+ "table": "agent_threads"
+ },
+ {
+ "nameExplicit": true,
+ "columns": [
+ {
+ "value": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nullsFirst": false,
+ "opclass": null
+ },
+ {
+ "value": "working_resume_id",
+ "isExpression": false,
+ "asc": true,
+ "nullsFirst": false,
+ "opclass": null
+ },
+ {
+ "value": "source_resume_id",
+ "isExpression": false,
+ "asc": true,
+ "nullsFirst": false,
+ "opclass": null
+ }
+ ],
+ "isUnique": true,
+ "where": "\"status\" = 'active' and \"deleted_at\" is null",
+ "with": "",
+ "method": "btree",
+ "concurrently": false,
+ "name": "agent_threads_active_in_place_unique",
+ "entityType": "indexes",
+ "schema": "public",
+ "table": "agent_threads"
+ },
+ {
+ "nameExplicit": false,
+ "columns": [
+ {
+ "value": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nullsFirst": false,
+ "opclass": null
+ },
+ {
+ "value": "enabled",
+ "isExpression": false,
+ "asc": true,
+ "nullsFirst": false,
+ "opclass": null
+ }
+ ],
+ "isUnique": false,
+ "where": null,
+ "with": "",
+ "method": "btree",
+ "concurrently": false,
+ "name": "ai_providers_user_id_enabled_index",
+ "entityType": "indexes",
+ "schema": "public",
+ "table": "ai_providers"
+ },
+ {
+ "nameExplicit": false,
+ "columns": [
+ {
+ "value": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nullsFirst": false,
+ "opclass": null
+ },
+ {
+ "value": "last_used_at",
+ "isExpression": false,
+ "asc": false,
+ "nullsFirst": false,
+ "opclass": null
+ }
+ ],
+ "isUnique": false,
+ "where": null,
+ "with": "",
+ "method": "btree",
+ "concurrently": false,
+ "name": "ai_providers_user_id_last_used_at_index",
+ "entityType": "indexes",
+ "schema": "public",
+ "table": "ai_providers"
+ },
+ {
+ "nameExplicit": false,
+ "columns": [
+ {
+ "value": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nullsFirst": false,
+ "opclass": null
+ },
+ {
+ "value": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nullsFirst": false,
+ "opclass": null
+ }
+ ],
+ "isUnique": false,
+ "where": null,
+ "with": "",
+ "method": "btree",
+ "concurrently": false,
+ "name": "ai_providers_user_id_created_at_index",
+ "entityType": "indexes",
+ "schema": "public",
+ "table": "ai_providers"
+ },
+ {
+ "nameExplicit": false,
+ "columns": [
+ {
+ "value": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nullsFirst": false,
+ "opclass": null
+ }
+ ],
+ "isUnique": false,
+ "where": null,
+ "with": "",
+ "method": "btree",
+ "concurrently": false,
+ "name": "application_user_id_index",
+ "entityType": "indexes",
+ "schema": "public",
+ "table": "application"
+ },
+ {
+ "nameExplicit": false,
+ "columns": [
+ {
+ "value": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nullsFirst": false,
+ "opclass": null
+ },
+ {
+ "value": "updated_at",
+ "isExpression": false,
+ "asc": false,
+ "nullsFirst": false,
+ "opclass": null
+ }
+ ],
+ "isUnique": false,
+ "where": null,
+ "with": "",
+ "method": "btree",
+ "concurrently": false,
+ "name": "application_user_id_updated_at_index",
+ "entityType": "indexes",
+ "schema": "public",
+ "table": "application"
+ },
+ {
+ "nameExplicit": false,
+ "columns": [
+ {
+ "value": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nullsFirst": false,
+ "opclass": null
+ }
+ ],
+ "isUnique": false,
+ "where": null,
+ "with": "",
+ "method": "btree",
+ "concurrently": false,
+ "name": "account_user_id_index",
+ "entityType": "indexes",
+ "schema": "public",
+ "table": "account"
+ },
+ {
+ "nameExplicit": false,
+ "columns": [
+ {
+ "value": "reference_id",
+ "isExpression": false,
+ "asc": true,
+ "nullsFirst": false,
+ "opclass": null
+ }
+ ],
+ "isUnique": false,
+ "where": null,
+ "with": "",
+ "method": "btree",
+ "concurrently": false,
+ "name": "apikey_user_id_index",
+ "entityType": "indexes",
+ "schema": "public",
+ "table": "apikey"
+ },
+ {
+ "nameExplicit": false,
+ "columns": [
+ {
+ "value": "key",
+ "isExpression": false,
+ "asc": true,
+ "nullsFirst": false,
+ "opclass": null
+ }
+ ],
+ "isUnique": false,
+ "where": null,
+ "with": "",
+ "method": "btree",
+ "concurrently": false,
+ "name": "apikey_key_index",
+ "entityType": "indexes",
+ "schema": "public",
+ "table": "apikey"
+ },
+ {
+ "nameExplicit": false,
+ "columns": [
+ {
+ "value": "config_id",
+ "isExpression": false,
+ "asc": true,
+ "nullsFirst": false,
+ "opclass": null
+ }
+ ],
+ "isUnique": false,
+ "where": null,
+ "with": "",
+ "method": "btree",
+ "concurrently": false,
+ "name": "apikey_config_id_index",
+ "entityType": "indexes",
+ "schema": "public",
+ "table": "apikey"
+ },
+ {
+ "nameExplicit": false,
+ "columns": [
+ {
+ "value": "enabled",
+ "isExpression": false,
+ "asc": true,
+ "nullsFirst": false,
+ "opclass": null
+ },
+ {
+ "value": "reference_id",
+ "isExpression": false,
+ "asc": true,
+ "nullsFirst": false,
+ "opclass": null
+ }
+ ],
+ "isUnique": false,
+ "where": null,
+ "with": "",
+ "method": "btree",
+ "concurrently": false,
+ "name": "apikey_enabled_user_id_index",
+ "entityType": "indexes",
+ "schema": "public",
+ "table": "apikey"
+ },
+ {
+ "nameExplicit": false,
+ "columns": [
+ {
+ "value": "token",
+ "isExpression": false,
+ "asc": true,
+ "nullsFirst": false,
+ "opclass": null
+ }
+ ],
+ "isUnique": false,
+ "where": null,
+ "with": "",
+ "method": "btree",
+ "concurrently": false,
+ "name": "oauth_access_token_token_index",
+ "entityType": "indexes",
+ "schema": "public",
+ "table": "oauth_access_token"
+ },
+ {
+ "nameExplicit": false,
+ "columns": [
+ {
+ "value": "client_id",
+ "isExpression": false,
+ "asc": true,
+ "nullsFirst": false,
+ "opclass": null
+ }
+ ],
+ "isUnique": false,
+ "where": null,
+ "with": "",
+ "method": "btree",
+ "concurrently": false,
+ "name": "oauth_client_client_id_index",
+ "entityType": "indexes",
+ "schema": "public",
+ "table": "oauth_client"
+ },
+ {
+ "nameExplicit": false,
+ "columns": [
+ {
+ "value": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nullsFirst": false,
+ "opclass": null
+ },
+ {
+ "value": "client_id",
+ "isExpression": false,
+ "asc": true,
+ "nullsFirst": false,
+ "opclass": null
+ }
+ ],
+ "isUnique": false,
+ "where": null,
+ "with": "",
+ "method": "btree",
+ "concurrently": false,
+ "name": "oauth_consent_user_id_client_id_index",
+ "entityType": "indexes",
+ "schema": "public",
+ "table": "oauth_consent"
+ },
+ {
+ "nameExplicit": false,
+ "columns": [
+ {
+ "value": "token",
+ "isExpression": false,
+ "asc": true,
+ "nullsFirst": false,
+ "opclass": null
+ }
+ ],
+ "isUnique": false,
+ "where": null,
+ "with": "",
+ "method": "btree",
+ "concurrently": false,
+ "name": "oauth_refresh_token_token_index",
+ "entityType": "indexes",
+ "schema": "public",
+ "table": "oauth_refresh_token"
+ },
+ {
+ "nameExplicit": false,
+ "columns": [
+ {
+ "value": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nullsFirst": false,
+ "opclass": null
+ }
+ ],
+ "isUnique": false,
+ "where": null,
+ "with": "",
+ "method": "btree",
+ "concurrently": false,
+ "name": "passkey_user_id_index",
+ "entityType": "indexes",
+ "schema": "public",
+ "table": "passkey"
+ },
+ {
+ "nameExplicit": false,
+ "columns": [
+ {
+ "value": "token",
+ "isExpression": false,
+ "asc": true,
+ "nullsFirst": false,
+ "opclass": null
+ },
+ {
+ "value": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nullsFirst": false,
+ "opclass": null
+ }
+ ],
+ "isUnique": false,
+ "where": null,
+ "with": "",
+ "method": "btree",
+ "concurrently": false,
+ "name": "session_token_user_id_index",
+ "entityType": "indexes",
+ "schema": "public",
+ "table": "session"
+ },
+ {
+ "nameExplicit": false,
+ "columns": [
+ {
+ "value": "expires_at",
+ "isExpression": false,
+ "asc": true,
+ "nullsFirst": false,
+ "opclass": null
+ }
+ ],
+ "isUnique": false,
+ "where": null,
+ "with": "",
+ "method": "btree",
+ "concurrently": false,
+ "name": "session_expires_at_index",
+ "entityType": "indexes",
+ "schema": "public",
+ "table": "session"
+ },
+ {
+ "nameExplicit": false,
+ "columns": [
+ {
+ "value": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nullsFirst": false,
+ "opclass": null
+ }
+ ],
+ "isUnique": false,
+ "where": null,
+ "with": "",
+ "method": "btree",
+ "concurrently": false,
+ "name": "two_factor_user_id_index",
+ "entityType": "indexes",
+ "schema": "public",
+ "table": "two_factor"
+ },
+ {
+ "nameExplicit": false,
+ "columns": [
+ {
+ "value": "secret",
+ "isExpression": false,
+ "asc": true,
+ "nullsFirst": false,
+ "opclass": null
+ }
+ ],
+ "isUnique": false,
+ "where": null,
+ "with": "",
+ "method": "btree",
+ "concurrently": false,
+ "name": "two_factor_secret_index",
+ "entityType": "indexes",
+ "schema": "public",
+ "table": "two_factor"
+ },
+ {
+ "nameExplicit": false,
+ "columns": [
+ {
+ "value": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nullsFirst": false,
+ "opclass": null
+ }
+ ],
+ "isUnique": false,
+ "where": null,
+ "with": "",
+ "method": "btree",
+ "concurrently": false,
+ "name": "user_created_at_index",
+ "entityType": "indexes",
+ "schema": "public",
+ "table": "user"
+ },
+ {
+ "nameExplicit": true,
+ "columns": [
+ {
+ "value": "lower(\"email\")",
+ "isExpression": true,
+ "asc": true,
+ "nullsFirst": false,
+ "opclass": null
+ }
+ ],
+ "isUnique": true,
+ "where": null,
+ "with": "",
+ "method": "btree",
+ "concurrently": false,
+ "name": "user_email_lower_unique_idx",
+ "entityType": "indexes",
+ "schema": "public",
+ "table": "user"
+ },
+ {
+ "nameExplicit": false,
+ "columns": [
+ {
+ "value": "identifier",
+ "isExpression": false,
+ "asc": true,
+ "nullsFirst": false,
+ "opclass": null
+ }
+ ],
+ "isUnique": false,
+ "where": null,
+ "with": "",
+ "method": "btree",
+ "concurrently": false,
+ "name": "verification_identifier_index",
+ "entityType": "indexes",
+ "schema": "public",
+ "table": "verification"
+ },
+ {
+ "nameExplicit": false,
+ "columns": [
+ {
+ "value": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nullsFirst": false,
+ "opclass": null
+ }
+ ],
+ "isUnique": false,
+ "where": null,
+ "with": "",
+ "method": "btree",
+ "concurrently": false,
+ "name": "resume_user_id_index",
+ "entityType": "indexes",
+ "schema": "public",
+ "table": "resume"
+ },
+ {
+ "nameExplicit": false,
+ "columns": [
+ {
+ "value": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nullsFirst": false,
+ "opclass": null
+ }
+ ],
+ "isUnique": false,
+ "where": null,
+ "with": "",
+ "method": "btree",
+ "concurrently": false,
+ "name": "resume_created_at_index",
+ "entityType": "indexes",
+ "schema": "public",
+ "table": "resume"
+ },
+ {
+ "nameExplicit": false,
+ "columns": [
+ {
+ "value": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nullsFirst": false,
+ "opclass": null
+ },
+ {
+ "value": "updated_at",
+ "isExpression": false,
+ "asc": false,
+ "nullsFirst": false,
+ "opclass": null
+ }
+ ],
+ "isUnique": false,
+ "where": null,
+ "with": "",
+ "method": "btree",
+ "concurrently": false,
+ "name": "resume_user_id_updated_at_index",
+ "entityType": "indexes",
+ "schema": "public",
+ "table": "resume"
+ },
+ {
+ "nameExplicit": false,
+ "columns": [
+ {
+ "value": "is_public",
+ "isExpression": false,
+ "asc": true,
+ "nullsFirst": false,
+ "opclass": null
+ },
+ {
+ "value": "slug",
+ "isExpression": false,
+ "asc": true,
+ "nullsFirst": false,
+ "opclass": null
+ },
+ {
+ "value": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nullsFirst": false,
+ "opclass": null
+ }
+ ],
+ "isUnique": false,
+ "where": null,
+ "with": "",
+ "method": "btree",
+ "concurrently": false,
+ "name": "resume_is_public_slug_user_id_index",
+ "entityType": "indexes",
+ "schema": "public",
+ "table": "resume"
+ },
+ {
+ "nameExplicit": false,
+ "columns": [
+ {
+ "value": "resume_id",
+ "isExpression": false,
+ "asc": true,
+ "nullsFirst": false,
+ "opclass": null
+ }
+ ],
+ "isUnique": false,
+ "where": null,
+ "with": "",
+ "method": "btree",
+ "concurrently": false,
+ "name": "resume_analysis_resume_id_index",
+ "entityType": "indexes",
+ "schema": "public",
+ "table": "resume_analysis"
+ },
+ {
+ "nameExplicit": false,
+ "columns": [
+ {
+ "value": "resume_id",
+ "isExpression": false,
+ "asc": true,
+ "nullsFirst": false,
+ "opclass": null
+ },
+ {
+ "value": "date",
+ "isExpression": false,
+ "asc": false,
+ "nullsFirst": false,
+ "opclass": null
+ }
+ ],
+ "isUnique": false,
+ "where": null,
+ "with": "",
+ "method": "btree",
+ "concurrently": false,
+ "name": "resume_statistics_daily_resume_id_date_index",
+ "entityType": "indexes",
+ "schema": "public",
+ "table": "resume_statistics_daily"
+ },
+ {
+ "nameExplicit": false,
+ "columns": [
+ {
+ "value": "resume_id",
+ "isExpression": false,
+ "asc": true,
+ "nullsFirst": false,
+ "opclass": null
+ },
+ {
+ "value": "created_at",
+ "isExpression": false,
+ "asc": false,
+ "nullsFirst": false,
+ "opclass": null
+ }
+ ],
+ "isUnique": false,
+ "where": null,
+ "with": "",
+ "method": "btree",
+ "concurrently": false,
+ "name": "resume_version_resume_id_created_at_index",
+ "entityType": "indexes",
+ "schema": "public",
+ "table": "resume_version"
+ },
+ {
+ "nameExplicit": false,
+ "columns": ["user_id"],
+ "schemaTo": "public",
+ "tableTo": "user",
+ "columnsTo": ["id"],
+ "onUpdate": "NO ACTION",
+ "onDelete": "CASCADE",
+ "name": "agent_actions_user_id_user_id_fkey",
+ "entityType": "fks",
+ "schema": "public",
+ "table": "agent_actions"
+ },
+ {
+ "nameExplicit": false,
+ "columns": ["thread_id"],
+ "schemaTo": "public",
+ "tableTo": "agent_threads",
+ "columnsTo": ["id"],
+ "onUpdate": "NO ACTION",
+ "onDelete": "CASCADE",
+ "name": "agent_actions_thread_id_agent_threads_id_fkey",
+ "entityType": "fks",
+ "schema": "public",
+ "table": "agent_actions"
+ },
+ {
+ "nameExplicit": false,
+ "columns": ["message_id"],
+ "schemaTo": "public",
+ "tableTo": "agent_messages",
+ "columnsTo": ["id"],
+ "onUpdate": "NO ACTION",
+ "onDelete": "SET NULL",
+ "name": "agent_actions_message_id_agent_messages_id_fkey",
+ "entityType": "fks",
+ "schema": "public",
+ "table": "agent_actions"
+ },
+ {
+ "nameExplicit": false,
+ "columns": ["resume_id"],
+ "schemaTo": "public",
+ "tableTo": "resume",
+ "columnsTo": ["id"],
+ "onUpdate": "NO ACTION",
+ "onDelete": "SET NULL",
+ "name": "agent_actions_resume_id_resume_id_fkey",
+ "entityType": "fks",
+ "schema": "public",
+ "table": "agent_actions"
+ },
+ {
+ "nameExplicit": false,
+ "columns": ["user_id"],
+ "schemaTo": "public",
+ "tableTo": "user",
+ "columnsTo": ["id"],
+ "onUpdate": "NO ACTION",
+ "onDelete": "CASCADE",
+ "name": "agent_attachments_user_id_user_id_fkey",
+ "entityType": "fks",
+ "schema": "public",
+ "table": "agent_attachments"
+ },
+ {
+ "nameExplicit": false,
+ "columns": ["thread_id"],
+ "schemaTo": "public",
+ "tableTo": "agent_threads",
+ "columnsTo": ["id"],
+ "onUpdate": "NO ACTION",
+ "onDelete": "CASCADE",
+ "name": "agent_attachments_thread_id_agent_threads_id_fkey",
+ "entityType": "fks",
+ "schema": "public",
+ "table": "agent_attachments"
+ },
+ {
+ "nameExplicit": false,
+ "columns": ["message_id"],
+ "schemaTo": "public",
+ "tableTo": "agent_messages",
+ "columnsTo": ["id"],
+ "onUpdate": "NO ACTION",
+ "onDelete": "SET NULL",
+ "name": "agent_attachments_message_id_agent_messages_id_fkey",
+ "entityType": "fks",
+ "schema": "public",
+ "table": "agent_attachments"
+ },
+ {
+ "nameExplicit": false,
+ "columns": ["user_id"],
+ "schemaTo": "public",
+ "tableTo": "user",
+ "columnsTo": ["id"],
+ "onUpdate": "NO ACTION",
+ "onDelete": "CASCADE",
+ "name": "agent_messages_user_id_user_id_fkey",
+ "entityType": "fks",
+ "schema": "public",
+ "table": "agent_messages"
+ },
+ {
+ "nameExplicit": false,
+ "columns": ["thread_id"],
+ "schemaTo": "public",
+ "tableTo": "agent_threads",
+ "columnsTo": ["id"],
+ "onUpdate": "NO ACTION",
+ "onDelete": "CASCADE",
+ "name": "agent_messages_thread_id_agent_threads_id_fkey",
+ "entityType": "fks",
+ "schema": "public",
+ "table": "agent_messages"
+ },
+ {
+ "nameExplicit": false,
+ "columns": ["user_id"],
+ "schemaTo": "public",
+ "tableTo": "user",
+ "columnsTo": ["id"],
+ "onUpdate": "NO ACTION",
+ "onDelete": "CASCADE",
+ "name": "agent_threads_user_id_user_id_fkey",
+ "entityType": "fks",
+ "schema": "public",
+ "table": "agent_threads"
+ },
+ {
+ "nameExplicit": false,
+ "columns": ["ai_provider_id"],
+ "schemaTo": "public",
+ "tableTo": "ai_providers",
+ "columnsTo": ["id"],
+ "onUpdate": "NO ACTION",
+ "onDelete": "SET NULL",
+ "name": "agent_threads_ai_provider_id_ai_providers_id_fkey",
+ "entityType": "fks",
+ "schema": "public",
+ "table": "agent_threads"
+ },
+ {
+ "nameExplicit": false,
+ "columns": ["source_resume_id"],
+ "schemaTo": "public",
+ "tableTo": "resume",
+ "columnsTo": ["id"],
+ "onUpdate": "NO ACTION",
+ "onDelete": "SET NULL",
+ "name": "agent_threads_source_resume_id_resume_id_fkey",
+ "entityType": "fks",
+ "schema": "public",
+ "table": "agent_threads"
+ },
+ {
+ "nameExplicit": false,
+ "columns": ["working_resume_id"],
+ "schemaTo": "public",
+ "tableTo": "resume",
+ "columnsTo": ["id"],
+ "onUpdate": "NO ACTION",
+ "onDelete": "SET NULL",
+ "name": "agent_threads_working_resume_id_resume_id_fkey",
+ "entityType": "fks",
+ "schema": "public",
+ "table": "agent_threads"
+ },
+ {
+ "nameExplicit": false,
+ "columns": ["user_id"],
+ "schemaTo": "public",
+ "tableTo": "user",
+ "columnsTo": ["id"],
+ "onUpdate": "NO ACTION",
+ "onDelete": "CASCADE",
+ "name": "ai_providers_user_id_user_id_fkey",
+ "entityType": "fks",
+ "schema": "public",
+ "table": "ai_providers"
+ },
+ {
+ "nameExplicit": false,
+ "columns": ["user_id"],
+ "schemaTo": "public",
+ "tableTo": "user",
+ "columnsTo": ["id"],
+ "onUpdate": "NO ACTION",
+ "onDelete": "CASCADE",
+ "name": "application_user_id_user_id_fkey",
+ "entityType": "fks",
+ "schema": "public",
+ "table": "application"
+ },
+ {
+ "nameExplicit": false,
+ "columns": ["resume_id"],
+ "schemaTo": "public",
+ "tableTo": "resume",
+ "columnsTo": ["id"],
+ "onUpdate": "NO ACTION",
+ "onDelete": "SET NULL",
+ "name": "application_resume_id_resume_id_fkey",
+ "entityType": "fks",
+ "schema": "public",
+ "table": "application"
+ },
+ {
+ "nameExplicit": false,
+ "columns": ["user_id"],
+ "schemaTo": "public",
+ "tableTo": "user",
+ "columnsTo": ["id"],
+ "onUpdate": "NO ACTION",
+ "onDelete": "CASCADE",
+ "name": "account_user_id_user_id_fkey",
+ "entityType": "fks",
+ "schema": "public",
+ "table": "account"
+ },
+ {
+ "nameExplicit": false,
+ "columns": ["reference_id"],
+ "schemaTo": "public",
+ "tableTo": "user",
+ "columnsTo": ["id"],
+ "onUpdate": "NO ACTION",
+ "onDelete": "CASCADE",
+ "name": "apikey_user_id_user_id_fkey",
+ "entityType": "fks",
+ "schema": "public",
+ "table": "apikey"
+ },
+ {
+ "nameExplicit": false,
+ "columns": ["client_id"],
+ "schemaTo": "public",
+ "tableTo": "oauth_client",
+ "columnsTo": ["client_id"],
+ "onUpdate": "NO ACTION",
+ "onDelete": "CASCADE",
+ "name": "oauth_access_token_client_id_oauth_client_client_id_fkey",
+ "entityType": "fks",
+ "schema": "public",
+ "table": "oauth_access_token"
+ },
+ {
+ "nameExplicit": false,
+ "columns": ["session_id"],
+ "schemaTo": "public",
+ "tableTo": "session",
+ "columnsTo": ["id"],
+ "onUpdate": "NO ACTION",
+ "onDelete": "SET NULL",
+ "name": "oauth_access_token_session_id_session_id_fkey",
+ "entityType": "fks",
+ "schema": "public",
+ "table": "oauth_access_token"
+ },
+ {
+ "nameExplicit": false,
+ "columns": ["user_id"],
+ "schemaTo": "public",
+ "tableTo": "user",
+ "columnsTo": ["id"],
+ "onUpdate": "NO ACTION",
+ "onDelete": "CASCADE",
+ "name": "oauth_access_token_user_id_user_id_fkey",
+ "entityType": "fks",
+ "schema": "public",
+ "table": "oauth_access_token"
+ },
+ {
+ "nameExplicit": false,
+ "columns": ["refresh_id"],
+ "schemaTo": "public",
+ "tableTo": "oauth_refresh_token",
+ "columnsTo": ["id"],
+ "onUpdate": "NO ACTION",
+ "onDelete": "CASCADE",
+ "name": "oauth_access_token_refresh_id_oauth_refresh_token_id_fkey",
+ "entityType": "fks",
+ "schema": "public",
+ "table": "oauth_access_token"
+ },
+ {
+ "nameExplicit": false,
+ "columns": ["user_id"],
+ "schemaTo": "public",
+ "tableTo": "user",
+ "columnsTo": ["id"],
+ "onUpdate": "NO ACTION",
+ "onDelete": "CASCADE",
+ "name": "oauth_client_user_id_user_id_fkey",
+ "entityType": "fks",
+ "schema": "public",
+ "table": "oauth_client"
+ },
+ {
+ "nameExplicit": false,
+ "columns": ["client_id"],
+ "schemaTo": "public",
+ "tableTo": "oauth_client",
+ "columnsTo": ["client_id"],
+ "onUpdate": "NO ACTION",
+ "onDelete": "CASCADE",
+ "name": "oauth_consent_client_id_oauth_client_client_id_fkey",
+ "entityType": "fks",
+ "schema": "public",
+ "table": "oauth_consent"
+ },
+ {
+ "nameExplicit": false,
+ "columns": ["user_id"],
+ "schemaTo": "public",
+ "tableTo": "user",
+ "columnsTo": ["id"],
+ "onUpdate": "NO ACTION",
+ "onDelete": "CASCADE",
+ "name": "oauth_consent_user_id_user_id_fkey",
+ "entityType": "fks",
+ "schema": "public",
+ "table": "oauth_consent"
+ },
+ {
+ "nameExplicit": false,
+ "columns": ["client_id"],
+ "schemaTo": "public",
+ "tableTo": "oauth_client",
+ "columnsTo": ["client_id"],
+ "onUpdate": "NO ACTION",
+ "onDelete": "CASCADE",
+ "name": "oauth_refresh_token_client_id_oauth_client_client_id_fkey",
+ "entityType": "fks",
+ "schema": "public",
+ "table": "oauth_refresh_token"
+ },
+ {
+ "nameExplicit": false,
+ "columns": ["session_id"],
+ "schemaTo": "public",
+ "tableTo": "session",
+ "columnsTo": ["id"],
+ "onUpdate": "NO ACTION",
+ "onDelete": "SET NULL",
+ "name": "oauth_refresh_token_session_id_session_id_fkey",
+ "entityType": "fks",
+ "schema": "public",
+ "table": "oauth_refresh_token"
+ },
+ {
+ "nameExplicit": false,
+ "columns": ["user_id"],
+ "schemaTo": "public",
+ "tableTo": "user",
+ "columnsTo": ["id"],
+ "onUpdate": "NO ACTION",
+ "onDelete": "CASCADE",
+ "name": "oauth_refresh_token_user_id_user_id_fkey",
+ "entityType": "fks",
+ "schema": "public",
+ "table": "oauth_refresh_token"
+ },
+ {
+ "nameExplicit": false,
+ "columns": ["user_id"],
+ "schemaTo": "public",
+ "tableTo": "user",
+ "columnsTo": ["id"],
+ "onUpdate": "NO ACTION",
+ "onDelete": "CASCADE",
+ "name": "passkey_user_id_user_id_fkey",
+ "entityType": "fks",
+ "schema": "public",
+ "table": "passkey"
+ },
+ {
+ "nameExplicit": false,
+ "columns": ["user_id"],
+ "schemaTo": "public",
+ "tableTo": "user",
+ "columnsTo": ["id"],
+ "onUpdate": "NO ACTION",
+ "onDelete": "CASCADE",
+ "name": "session_user_id_user_id_fkey",
+ "entityType": "fks",
+ "schema": "public",
+ "table": "session"
+ },
+ {
+ "nameExplicit": false,
+ "columns": ["user_id"],
+ "schemaTo": "public",
+ "tableTo": "user",
+ "columnsTo": ["id"],
+ "onUpdate": "NO ACTION",
+ "onDelete": "CASCADE",
+ "name": "two_factor_user_id_user_id_fkey",
+ "entityType": "fks",
+ "schema": "public",
+ "table": "two_factor"
+ },
+ {
+ "nameExplicit": false,
+ "columns": ["user_id"],
+ "schemaTo": "public",
+ "tableTo": "user",
+ "columnsTo": ["id"],
+ "onUpdate": "NO ACTION",
+ "onDelete": "CASCADE",
+ "name": "resume_user_id_user_id_fkey",
+ "entityType": "fks",
+ "schema": "public",
+ "table": "resume"
+ },
+ {
+ "nameExplicit": false,
+ "columns": ["resume_id"],
+ "schemaTo": "public",
+ "tableTo": "resume",
+ "columnsTo": ["id"],
+ "onUpdate": "NO ACTION",
+ "onDelete": "CASCADE",
+ "name": "resume_analysis_resume_id_resume_id_fkey",
+ "entityType": "fks",
+ "schema": "public",
+ "table": "resume_analysis"
+ },
+ {
+ "nameExplicit": false,
+ "columns": ["resume_id"],
+ "schemaTo": "public",
+ "tableTo": "resume",
+ "columnsTo": ["id"],
+ "onUpdate": "NO ACTION",
+ "onDelete": "CASCADE",
+ "name": "resume_statistics_resume_id_resume_id_fkey",
+ "entityType": "fks",
+ "schema": "public",
+ "table": "resume_statistics"
+ },
+ {
+ "nameExplicit": false,
+ "columns": ["resume_id"],
+ "schemaTo": "public",
+ "tableTo": "resume",
+ "columnsTo": ["id"],
+ "onUpdate": "NO ACTION",
+ "onDelete": "CASCADE",
+ "name": "resume_statistics_daily_resume_id_resume_id_fkey",
+ "entityType": "fks",
+ "schema": "public",
+ "table": "resume_statistics_daily"
+ },
+ {
+ "nameExplicit": false,
+ "columns": ["resume_id"],
+ "schemaTo": "public",
+ "tableTo": "resume",
+ "columnsTo": ["id"],
+ "onUpdate": "NO ACTION",
+ "onDelete": "CASCADE",
+ "name": "resume_version_resume_id_resume_id_fkey",
+ "entityType": "fks",
+ "schema": "public",
+ "table": "resume_version"
+ },
+ {
+ "nameExplicit": false,
+ "columns": ["user_id"],
+ "schemaTo": "public",
+ "tableTo": "user",
+ "columnsTo": ["id"],
+ "onUpdate": "NO ACTION",
+ "onDelete": "CASCADE",
+ "name": "resume_version_user_id_user_id_fkey",
+ "entityType": "fks",
+ "schema": "public",
+ "table": "resume_version"
+ },
+ {
+ "columns": ["id"],
+ "nameExplicit": false,
+ "name": "agent_actions_pkey",
+ "schema": "public",
+ "table": "agent_actions",
+ "entityType": "pks"
+ },
+ {
+ "columns": ["id"],
+ "nameExplicit": false,
+ "name": "agent_attachments_pkey",
+ "schema": "public",
+ "table": "agent_attachments",
+ "entityType": "pks"
+ },
+ {
+ "columns": ["id"],
+ "nameExplicit": false,
+ "name": "agent_messages_pkey",
+ "schema": "public",
+ "table": "agent_messages",
+ "entityType": "pks"
+ },
+ {
+ "columns": ["id"],
+ "nameExplicit": false,
+ "name": "agent_threads_pkey",
+ "schema": "public",
+ "table": "agent_threads",
+ "entityType": "pks"
+ },
+ {
+ "columns": ["id"],
+ "nameExplicit": false,
+ "name": "ai_providers_pkey",
+ "schema": "public",
+ "table": "ai_providers",
+ "entityType": "pks"
+ },
+ {
+ "columns": ["id"],
+ "nameExplicit": false,
+ "name": "application_pkey",
+ "schema": "public",
+ "table": "application",
+ "entityType": "pks"
+ },
+ {
+ "columns": ["id"],
+ "nameExplicit": false,
+ "name": "account_pkey",
+ "schema": "public",
+ "table": "account",
+ "entityType": "pks"
+ },
+ {
+ "columns": ["id"],
+ "nameExplicit": false,
+ "name": "apikey_pkey",
+ "schema": "public",
+ "table": "apikey",
+ "entityType": "pks"
+ },
+ {
+ "columns": ["id"],
+ "nameExplicit": false,
+ "name": "jwks_pkey",
+ "schema": "public",
+ "table": "jwks",
+ "entityType": "pks"
+ },
+ {
+ "columns": ["id"],
+ "nameExplicit": false,
+ "name": "oauth_access_token_pkey",
+ "schema": "public",
+ "table": "oauth_access_token",
+ "entityType": "pks"
+ },
+ {
+ "columns": ["id"],
+ "nameExplicit": false,
+ "name": "oauth_client_pkey",
+ "schema": "public",
+ "table": "oauth_client",
+ "entityType": "pks"
+ },
+ {
+ "columns": ["id"],
+ "nameExplicit": false,
+ "name": "oauth_consent_pkey",
+ "schema": "public",
+ "table": "oauth_consent",
+ "entityType": "pks"
+ },
+ {
+ "columns": ["id"],
+ "nameExplicit": false,
+ "name": "oauth_refresh_token_pkey",
+ "schema": "public",
+ "table": "oauth_refresh_token",
+ "entityType": "pks"
+ },
+ {
+ "columns": ["id"],
+ "nameExplicit": false,
+ "name": "passkey_pkey",
+ "schema": "public",
+ "table": "passkey",
+ "entityType": "pks"
+ },
+ {
+ "columns": ["id"],
+ "nameExplicit": false,
+ "name": "session_pkey",
+ "schema": "public",
+ "table": "session",
+ "entityType": "pks"
+ },
+ {
+ "columns": ["id"],
+ "nameExplicit": false,
+ "name": "two_factor_pkey",
+ "schema": "public",
+ "table": "two_factor",
+ "entityType": "pks"
+ },
+ {
+ "columns": ["id"],
+ "nameExplicit": false,
+ "name": "user_pkey",
+ "schema": "public",
+ "table": "user",
+ "entityType": "pks"
+ },
+ {
+ "columns": ["id"],
+ "nameExplicit": false,
+ "name": "verification_pkey",
+ "schema": "public",
+ "table": "verification",
+ "entityType": "pks"
+ },
+ {
+ "columns": ["id"],
+ "nameExplicit": false,
+ "name": "resume_pkey",
+ "schema": "public",
+ "table": "resume",
+ "entityType": "pks"
+ },
+ {
+ "columns": ["id"],
+ "nameExplicit": false,
+ "name": "resume_analysis_pkey",
+ "schema": "public",
+ "table": "resume_analysis",
+ "entityType": "pks"
+ },
+ {
+ "columns": ["id"],
+ "nameExplicit": false,
+ "name": "resume_statistics_pkey",
+ "schema": "public",
+ "table": "resume_statistics",
+ "entityType": "pks"
+ },
+ {
+ "columns": ["id"],
+ "nameExplicit": false,
+ "name": "resume_statistics_daily_pkey",
+ "schema": "public",
+ "table": "resume_statistics_daily",
+ "entityType": "pks"
+ },
+ {
+ "columns": ["id"],
+ "nameExplicit": false,
+ "name": "resume_version_pkey",
+ "schema": "public",
+ "table": "resume_version",
+ "entityType": "pks"
+ },
+ {
+ "nameExplicit": false,
+ "columns": ["slug", "user_id"],
+ "nullsNotDistinct": false,
+ "name": "resume_slug_user_id_unique",
+ "entityType": "uniques",
+ "schema": "public",
+ "table": "resume"
+ },
+ {
+ "nameExplicit": false,
+ "columns": ["resume_id", "date"],
+ "nullsNotDistinct": false,
+ "name": "resume_statistics_daily_resume_id_date_unique",
+ "entityType": "uniques",
+ "schema": "public",
+ "table": "resume_statistics_daily"
+ },
+ {
+ "nameExplicit": false,
+ "columns": ["token"],
+ "nullsNotDistinct": false,
+ "name": "oauth_access_token_token_key",
+ "schema": "public",
+ "table": "oauth_access_token",
+ "entityType": "uniques"
+ },
+ {
+ "nameExplicit": false,
+ "columns": ["client_id"],
+ "nullsNotDistinct": false,
+ "name": "oauth_client_client_id_key",
+ "schema": "public",
+ "table": "oauth_client",
+ "entityType": "uniques"
+ },
+ {
+ "nameExplicit": false,
+ "columns": ["token"],
+ "nullsNotDistinct": false,
+ "name": "session_token_key",
+ "schema": "public",
+ "table": "session",
+ "entityType": "uniques"
+ },
+ {
+ "nameExplicit": false,
+ "columns": ["email"],
+ "nullsNotDistinct": false,
+ "name": "user_email_key",
+ "schema": "public",
+ "table": "user",
+ "entityType": "uniques"
+ },
+ {
+ "nameExplicit": false,
+ "columns": ["username"],
+ "nullsNotDistinct": false,
+ "name": "user_username_key",
+ "schema": "public",
+ "table": "user",
+ "entityType": "uniques"
+ },
+ {
+ "nameExplicit": false,
+ "columns": ["display_username"],
+ "nullsNotDistinct": false,
+ "name": "user_display_username_key",
+ "schema": "public",
+ "table": "user",
+ "entityType": "uniques"
+ },
+ {
+ "nameExplicit": false,
+ "columns": ["identifier"],
+ "nullsNotDistinct": false,
+ "name": "verification_identifier_key",
+ "schema": "public",
+ "table": "verification",
+ "entityType": "uniques"
+ },
+ {
+ "nameExplicit": false,
+ "columns": ["resume_id"],
+ "nullsNotDistinct": false,
+ "name": "resume_analysis_resume_id_key",
+ "schema": "public",
+ "table": "resume_analysis",
+ "entityType": "uniques"
+ },
+ {
+ "nameExplicit": false,
+ "columns": ["resume_id"],
+ "nullsNotDistinct": false,
+ "name": "resume_statistics_resume_id_key",
+ "schema": "public",
+ "table": "resume_statistics",
+ "entityType": "uniques"
+ }
+ ],
+ "renames": []
+}
diff --git a/packages/api/src/dto/application.ts b/packages/api/src/dto/application.ts
index 9f9e26255..2e544d943 100644
--- a/packages/api/src/dto/application.ts
+++ b/packages/api/src/dto/application.ts
@@ -2,9 +2,9 @@ import { createSelectSchema } from "drizzle-zod";
import z from "zod";
import * as schema from "@reactive-resume/db/schema";
import {
- activityEventSchema,
aiMetadataSchema,
applicationStatusSchema,
+ applicationTimelineEntrySchema,
contactSchema,
} from "@reactive-resume/schema/applications/data";
@@ -12,6 +12,7 @@ const MAX_APPLICATION_JOB_DESCRIPTION_CHARS = 20_000;
const MAX_APPLICATION_DOCUMENT_BYTES = 10 * 1024 * 1024;
const applicationDocumentKindSchema = z.enum(["resume", "cover-letter"]);
+const timelineDateSchema = z.string().regex(/^\d{4}-\d{2}-\d{2}$/, "Date must use YYYY-MM-DD format.");
const applicationDocumentFileSchema = z
.file()
@@ -61,7 +62,7 @@ const applicationSchema = createSelectSchema(schema.application, {
followUpNote: z.string().trim().nullable(),
tags: z.array(z.string()),
contacts: z.array(contactSchema),
- activity: z.array(activityEventSchema),
+ activity: z.array(applicationTimelineEntrySchema),
appliedAt: z.date(),
createdAt: z.date(),
updatedAt: z.date(),
@@ -94,6 +95,7 @@ const createInputSchema = editableSchema.partial().extend({
company: applicationSchema.shape.company,
role: applicationSchema.shape.role,
status: applicationStatusSchema.optional(),
+ stageEnteredAt: timelineDateSchema.optional(),
});
export const applicationDto = {
@@ -150,7 +152,24 @@ export const applicationDto = {
},
addNote: {
- input: z.object({ id: z.string(), text: z.string().trim().min(1) }),
+ input: z.object({ id: z.string(), text: z.string().trim().min(1), date: timelineDateSchema.optional() }),
+ output: applicationSchema.omit({ userId: true }),
+ },
+
+ updateTimelineEntry: {
+ input: z
+ .object({
+ id: z.string(),
+ entryId: z.string(),
+ date: timelineDateSchema.optional(),
+ text: z.string().trim().min(1).optional(),
+ })
+ .refine((value) => value.date !== undefined || value.text !== undefined, "Provide date or text to update."),
+ output: applicationSchema.omit({ userId: true }),
+ },
+
+ deleteTimelineEntry: {
+ input: z.object({ id: z.string(), entryId: z.string() }),
output: applicationSchema.omit({ userId: true }),
},
diff --git a/packages/api/src/features/applications/crud.ts b/packages/api/src/features/applications/crud.ts
index d6d475ff7..f880f859a 100644
--- a/packages/api/src/features/applications/crud.ts
+++ b/packages/api/src/features/applications/crud.ts
@@ -171,7 +171,42 @@ export const crudRouter = {
.use(resumeMutationRateLimit)
.output(applicationDto.addNote.output)
.handler(async ({ input, context }) => {
- return applicationService.addNote({ id: input.id, userId: context.user.id, text: input.text });
+ return applicationService.addNote({ id: input.id, userId: context.user.id, text: input.text, date: input.date });
+ }),
+
+ updateTimelineEntry: protectedProcedure
+ .route({
+ method: "PUT",
+ path: "/applications/{id}/timeline/{entryId}",
+ tags: ["Applications"],
+ operationId: "updateApplicationTimelineEntry",
+ summary: "Update a timeline entry",
+ description: "Updates a timeline entry date, or note text for note entries. Requires authentication.",
+ successDescription: "The updated application.",
+ })
+ .input(applicationDto.updateTimelineEntry.input)
+ .use(resumeMutationRateLimit)
+ .output(applicationDto.updateTimelineEntry.output)
+ .handler(async ({ input, context }) => {
+ return applicationService.updateTimelineEntry({ ...input, userId: context.user.id });
+ }),
+
+ deleteTimelineEntry: protectedProcedure
+ .route({
+ method: "DELETE",
+ path: "/applications/{id}/timeline/{entryId}",
+ tags: ["Applications"],
+ operationId: "deleteApplicationTimelineEntry",
+ summary: "Delete a timeline entry",
+ description:
+ "Deletes a note or older stage entry. The current stage entry cannot be deleted. Requires authentication.",
+ successDescription: "The updated application.",
+ })
+ .input(applicationDto.deleteTimelineEntry.input)
+ .use(resumeMutationRateLimit)
+ .output(applicationDto.deleteTimelineEntry.output)
+ .handler(async ({ input, context }) => {
+ return applicationService.deleteTimelineEntry({ ...input, userId: context.user.id });
}),
delete: protectedProcedure
diff --git a/packages/api/src/features/applications/router.ts b/packages/api/src/features/applications/router.ts
index 8807ef77a..e78455ab6 100644
--- a/packages/api/src/features/applications/router.ts
+++ b/packages/api/src/features/applications/router.ts
@@ -10,6 +10,8 @@ export const applicationsRouter = {
attachDocument: crudRouter.attachDocument,
removeDocument: crudRouter.removeDocument,
addNote: crudRouter.addNote,
+ updateTimelineEntry: crudRouter.updateTimelineEntry,
+ deleteTimelineEntry: crudRouter.deleteTimelineEntry,
delete: crudRouter.delete,
bulkUpdate: crudRouter.bulkUpdate,
bulkDelete: crudRouter.bulkDelete,
diff --git a/packages/api/src/features/applications/service.test.ts b/packages/api/src/features/applications/service.test.ts
index f8224becc..52d6282da 100644
--- a/packages/api/src/features/applications/service.test.ts
+++ b/packages/api/src/features/applications/service.test.ts
@@ -6,6 +6,8 @@ const dbMock = vi.hoisted(() => ({
insert: vi.fn(),
update: vi.fn(),
delete: vi.fn(),
+ execute: vi.fn(),
+ transaction: vi.fn(),
}));
const resumeGetByIdMock = vi.hoisted(() => vi.fn());
const storageDeleteMock = vi.hoisted(() => vi.fn());
@@ -17,6 +19,8 @@ vi.mock("@reactive-resume/db/schema", () => ({
id: "id",
userId: "user_id",
status: "status",
+ activity: "activity",
+ appliedAt: "applied_at",
updatedAt: "updated_at",
resumeFileUrl: "resume_file_url",
coverLetterUrl: "cover_letter_url",
@@ -48,7 +52,9 @@ const existing = {
company: "Stripe",
role: "Engineer",
status: "saved" as const,
- activity: [{ id: "e0", type: "created" as const, text: "Added to Saved", at: new Date() }],
+ activity: [{ id: "e0", type: "stage" as const, stage: "saved" as const, at: new Date("2026-07-01T12:00:00.000Z") }],
+ appliedAt: new Date("2026-07-01T12:00:00.000Z"),
+ createdAt: new Date("2026-07-01T12:00:00.000Z"),
resumeFileUrl: "http://localhost:3000/api/uploads/user-1/pictures/resume.pdf",
coverLetterUrl: "/api/uploads/user-1/pictures/cover.pdf",
};
@@ -71,6 +77,9 @@ beforeEach(() => {
dbMock.insert.mockReset();
dbMock.update.mockReset();
dbMock.delete.mockReset();
+ dbMock.execute.mockReset();
+ dbMock.transaction.mockReset();
+ dbMock.transaction.mockImplementation((callback) => callback(dbMock));
resumeGetByIdMock.mockReset();
storageDeleteMock.mockReset();
uploadFileMock.mockReset();
@@ -84,15 +93,22 @@ beforeEach(() => {
});
describe("applicationService.create", () => {
- it("seeds a 'created' activity event", async () => {
+ it("seeds an initial stage timeline entry with the chosen date", async () => {
const values = vi.fn(() => Promise.resolve());
dbMock.insert.mockReturnValue({ values });
- await applicationService.create({ userId: "user-1", company: "Stripe", role: "Engineer", status: "applied" });
+ await applicationService.create({
+ userId: "user-1",
+ company: "Stripe",
+ role: "Engineer",
+ status: "applied",
+ stageEnteredAt: "2026-07-10",
+ } as never);
- const [[inserted]] = values.mock.calls as unknown as [[{ activity: { type: string }[] }]];
+ const [[inserted]] = values.mock.calls as unknown as [[{ activity: { type: string; stage: string; at: Date }[] }]];
expect(inserted.activity).toHaveLength(1);
- expect(inserted.activity.at(0)?.type).toBe("created");
+ expect(inserted.activity.at(0)).toMatchObject({ type: "stage", stage: "applied" });
+ expect(inserted.activity.at(0)?.at.toISOString()).toBe("2026-07-10T12:00:00.000Z");
});
it("checks linked resume ownership before inserting", async () => {
@@ -118,12 +134,17 @@ describe("applicationService.update", () => {
return set;
};
- it("appends a 'stage' event when the status changes", async () => {
+ const appendedEvent = (activity: { values: unknown[] }) => {
+ const value = activity.values.find((item) => typeof item === "string" && item.includes('"type":"stage"'));
+ return JSON.parse(String(value))[0] as { type: string; stage: string };
+ };
+
+ it("appends a typed stage timeline entry when the status changes", async () => {
const set = captureSet();
await applicationService.update({ id: "app-1", userId: "user-1", status: "applied" });
- const [[arg]] = set.mock.calls as unknown as [[{ activity: unknown }]];
- expect(arg.activity).toBeDefined();
+ const [[arg]] = set.mock.calls as unknown as [[{ activity: { values: unknown[] } }]];
+ expect(appendedEvent(arg.activity)).toMatchObject({ type: "stage", stage: "applied" });
});
it("does not rewrite activity when the status is unchanged", async () => {
@@ -142,6 +163,221 @@ describe("applicationService.update", () => {
});
});
+describe("applicationService timeline entries", () => {
+ const captureSet = (returning = [{ ...existing }]) => {
+ const set = vi.fn(() => ({ where: () => ({ returning: () => Promise.resolve(returning) }) }));
+ dbMock.update.mockReturnValue({ set });
+ return set;
+ };
+
+ it("adds dated note timeline entries", async () => {
+ const set = captureSet();
+
+ await applicationService.addNote({
+ id: "app-1",
+ userId: "user-1",
+ text: "Recruiter replied",
+ date: "2026-07-12",
+ } as never);
+
+ const [[arg]] = set.mock.calls as unknown as [[{ activity: { values: unknown[] } }]];
+ const value = arg.activity.values.find((item) => typeof item === "string" && item.includes('"type":"note"'));
+ const [entry] = JSON.parse(String(value)) as [{ type: string; text: string; at: string }];
+ expect(entry).toMatchObject({ type: "note", text: "Recruiter replied" });
+ expect(new Date(entry.at).toISOString()).toBe("2026-07-12T12:00:00.000Z");
+ });
+
+ it("rejects invalid calendar dates instead of letting Date overflow", async () => {
+ await expect(
+ applicationService.addNote({
+ id: "app-1",
+ userId: "user-1",
+ text: "Impossible date",
+ date: "2026-99-99",
+ } as never),
+ ).rejects.toMatchObject({ code: "BAD_REQUEST" });
+ });
+
+ it("updates note text and timeline dates", async () => {
+ const activity = [
+ { id: "stage-1", type: "stage" as const, stage: "saved" as const, at: new Date("2026-07-01T09:30:00.000Z") },
+ { id: "note-1", type: "note" as const, text: "Old note", at: new Date("2026-07-02T15:45:00.000Z") },
+ ];
+ setSelectResults([{ ...existing, activity }]);
+ const set = captureSet();
+
+ await (
+ applicationService as unknown as {
+ updateTimelineEntry: (input: {
+ id: string;
+ userId: string;
+ entryId: string;
+ date?: string;
+ text?: string;
+ }) => Promise;
+ }
+ ).updateTimelineEntry({
+ id: "app-1",
+ userId: "user-1",
+ entryId: "note-1",
+ date: "2026-07-10",
+ text: "Updated note",
+ });
+
+ const [[arg]] = set.mock.calls as unknown as [[{ activity: typeof activity }]];
+ expect(arg.activity.find((entry) => entry.id === "note-1")).toMatchObject({
+ text: "Updated note",
+ at: new Date("2026-07-10T15:45:00.000Z"),
+ });
+ expect(dbMock.transaction).toHaveBeenCalled();
+ expect(dbMock.execute).toHaveBeenCalled();
+ });
+
+ it("normalizes JSONB date strings when editing timeline dates", async () => {
+ const activity = [
+ { id: "stage-1", type: "stage" as const, stage: "saved" as const, at: "2026-07-01T09:30:00.000Z" },
+ ];
+ setSelectResults([{ ...existing, activity }]);
+ const set = captureSet();
+
+ await (
+ applicationService as unknown as {
+ updateTimelineEntry: (input: { id: string; userId: string; entryId: string; date: string }) => Promise;
+ }
+ ).updateTimelineEntry({
+ id: "app-1",
+ userId: "user-1",
+ entryId: "stage-1",
+ date: "2026-07-05",
+ });
+
+ const [[arg]] = set.mock.calls as unknown as [[{ activity: { id: string; at: Date }[] }]];
+ expect(arg.activity.find((entry) => entry.id === "stage-1")?.at.toISOString()).toBe("2026-07-05T09:30:00.000Z");
+ });
+
+ it("allows notes to be newer than the current-stage anchor", async () => {
+ const activity = [
+ { id: "stage-1", type: "stage" as const, stage: "saved" as const, at: new Date("2026-07-01T12:00:00.000Z") },
+ { id: "note-1", type: "note" as const, text: "Followed up", at: new Date("2026-07-10T12:00:00.000Z") },
+ ];
+ setSelectResults([{ ...existing, activity }]);
+ const set = captureSet();
+
+ await (
+ applicationService as unknown as {
+ updateTimelineEntry: (input: { id: string; userId: string; entryId: string; date: string }) => Promise;
+ }
+ ).updateTimelineEntry({ id: "app-1", userId: "user-1", entryId: "stage-1", date: "2026-07-02" });
+
+ const [[arg]] = set.mock.calls as unknown as [[{ activity: { id: string; at: Date }[] }]];
+ expect(arg.activity.find((entry) => entry.id === "stage-1")?.at.toISOString()).toBe("2026-07-02T12:00:00.000Z");
+ });
+
+ it("blocks moving the current-stage anchor older than another stage", async () => {
+ setSelectResults([
+ {
+ ...existing,
+ status: "screening",
+ activity: [
+ {
+ id: "stage-1",
+ type: "stage" as const,
+ stage: "applied" as const,
+ at: new Date("2026-07-03T12:00:00.000Z"),
+ },
+ {
+ id: "stage-2",
+ type: "stage" as const,
+ stage: "screening" as const,
+ at: new Date("2026-07-04T12:00:00.000Z"),
+ },
+ ],
+ },
+ ]);
+
+ await expect(
+ (
+ applicationService as unknown as {
+ updateTimelineEntry: (input: {
+ id: string;
+ userId: string;
+ entryId: string;
+ date: string;
+ }) => Promise;
+ }
+ ).updateTimelineEntry({ id: "app-1", userId: "user-1", entryId: "stage-2", date: "2026-07-01" }),
+ ).rejects.toMatchObject({ code: "BAD_REQUEST" });
+ });
+
+ it("blocks deleting the current-stage anchor", async () => {
+ setSelectResults([
+ {
+ ...existing,
+ status: "screening",
+ activity: [
+ {
+ id: "stage-1",
+ type: "stage" as const,
+ stage: "applied" as const,
+ at: new Date("2026-07-01T12:00:00.000Z"),
+ },
+ {
+ id: "stage-2",
+ type: "stage" as const,
+ stage: "screening" as const,
+ at: new Date("2026-07-03T12:00:00.000Z"),
+ },
+ ],
+ },
+ ]);
+
+ await expect(
+ (
+ applicationService as unknown as {
+ deleteTimelineEntry: (input: { id: string; userId: string; entryId: string }) => Promise;
+ }
+ ).deleteTimelineEntry({ id: "app-1", userId: "user-1", entryId: "stage-2" }),
+ ).rejects.toMatchObject({ code: "BAD_REQUEST" });
+ expect(dbMock.transaction).toHaveBeenCalled();
+ expect(dbMock.execute).toHaveBeenCalled();
+ });
+
+ it("deletes older stage entries", async () => {
+ setSelectResults([
+ {
+ ...existing,
+ status: "screening",
+ activity: [
+ {
+ id: "stage-1",
+ type: "stage" as const,
+ stage: "applied" as const,
+ at: new Date("2026-07-01T12:00:00.000Z"),
+ },
+ {
+ id: "stage-2",
+ type: "stage" as const,
+ stage: "screening" as const,
+ at: new Date("2026-07-03T12:00:00.000Z"),
+ },
+ ],
+ },
+ ]);
+ const set = captureSet();
+
+ await (
+ applicationService as unknown as {
+ deleteTimelineEntry: (input: { id: string; userId: string; entryId: string }) => Promise;
+ }
+ ).deleteTimelineEntry({ id: "app-1", userId: "user-1", entryId: "stage-1" });
+
+ const [[arg]] = set.mock.calls as unknown as [[{ activity: { id: string }[] }]];
+ expect(arg.activity).toEqual([
+ { id: "stage-2", type: "stage", stage: "screening", at: new Date("2026-07-03T12:00:00.000Z") },
+ ]);
+ });
+});
+
describe("applicationService.delete", () => {
it("deletes owned uploaded attachments after deleting the application", async () => {
dbMock.delete.mockReturnValue({
diff --git a/packages/api/src/features/applications/service.ts b/packages/api/src/features/applications/service.ts
index ea03b4037..5ac1f9361 100644
--- a/packages/api/src/features/applications/service.ts
+++ b/packages/api/src/features/applications/service.ts
@@ -1,18 +1,87 @@
-import type { ActivityEvent, AiMetadata, ApplicationStatus, Contact } from "@reactive-resume/schema/applications/data";
+import type {
+ AiMetadata,
+ ApplicationStatus,
+ ApplicationTimelineEntry,
+ Contact,
+} from "@reactive-resume/schema/applications/data";
import type { ApplicationDocumentKind } from "../../dto/application";
import { ORPCError } from "@orpc/client";
import { and, arrayContains, desc, eq, inArray, sql } from "drizzle-orm";
import { db } from "@reactive-resume/db/client";
import * as schema from "@reactive-resume/db/schema";
-import { STAGES } from "@reactive-resume/schema/applications/data";
import { generateId } from "@reactive-resume/utils/string";
import { resumeService } from "../resume/service";
import { getStorageService, uploadFile } from "../storage/service";
-const stageLabel = (status: ApplicationStatus) => STAGES.find((s) => s.value === status)?.label ?? status;
+function timelineDate(value: Date | string): Date {
+ return value instanceof Date ? value : new Date(value);
+}
-function activityEvent(type: ActivityEvent["type"], text: string): ActivityEvent {
- return { id: generateId(), type, text, at: new Date() };
+function atFromDateString(date: string, existing?: Date | string): Date {
+ const [year, month, day] = date.split("-").map(Number);
+ if (!year || !month || !day) throw new ORPCError("BAD_REQUEST", { message: "Date must use YYYY-MM-DD format." });
+
+ const existingDate = existing ? timelineDate(existing) : undefined;
+
+ const parsed = new Date(
+ Date.UTC(
+ year,
+ month - 1,
+ day,
+ existingDate?.getUTCHours() ?? 12,
+ existingDate?.getUTCMinutes() ?? 0,
+ existingDate?.getUTCSeconds() ?? 0,
+ existingDate?.getUTCMilliseconds() ?? 0,
+ ),
+ );
+ if (timelineDay(parsed) !== date) throw new ORPCError("BAD_REQUEST", { message: "Date must use YYYY-MM-DD format." });
+
+ return parsed;
+}
+
+function stageEntry(stage: ApplicationStatus, date?: string): ApplicationTimelineEntry {
+ return { id: generateId(), type: "stage", stage, at: date ? atFromDateString(date) : new Date() };
+}
+
+function noteEntry(text: string, date?: string): ApplicationTimelineEntry {
+ return { id: generateId(), type: "note", text, at: date ? atFromDateString(date) : new Date() };
+}
+
+function byNewest(a: ApplicationTimelineEntry, b: ApplicationTimelineEntry) {
+ return new Date(b.at).getTime() - new Date(a.at).getTime();
+}
+
+function timelineDay(value: Date | string) {
+ return timelineDate(value).toISOString().slice(0, 10);
+}
+
+function sortTimeline(activity: ApplicationTimelineEntry[]): ApplicationTimelineEntry[] {
+ return [...activity].sort(byNewest);
+}
+
+function currentStageAnchor(activity: ApplicationTimelineEntry[], status: ApplicationStatus) {
+ return sortTimeline(activity).find((entry) => entry.type === "stage" && entry.stage === status);
+}
+
+function assertCurrentStageAnchorLatest(activity: ApplicationTimelineEntry[], status: ApplicationStatus) {
+ const anchor = currentStageAnchor(activity, status);
+ if (!anchor)
+ throw new ORPCError("BAD_REQUEST", { message: "Application timeline is missing its current stage entry." });
+
+ const anchorDay = timelineDay(anchor.at);
+ const newerStage = activity.some((entry) => entry.type === "stage" && timelineDay(entry.at) > anchorDay);
+ if (newerStage) {
+ throw new ORPCError("BAD_REQUEST", {
+ message: "Current stage date cannot be older than another stage entry.",
+ });
+ }
+}
+
+function appliedAtFromTimeline(activity: ApplicationTimelineEntry[], fallback: Date): Date {
+ const sorted = sortTimeline(activity);
+ const applied = sorted.find((entry) => entry.type === "stage" && entry.stage === "applied");
+ const fallbackEntry = sorted.at(-1);
+ return applied ? timelineDate(applied.at) : fallbackEntry ? timelineDate(fallbackEntry.at) : fallback;
}
// Editable fields shared by create/update. Kept explicit so Drizzle's typed insert/update
@@ -124,9 +193,9 @@ function documentFields(kind: ApplicationDocumentKind) {
} as const);
}
-const stripUserId = (row: T) => {
+const stripUserId = (row: T) => {
const { userId: _userId, ...rest } = row;
- return rest;
+ return rest.activity ? { ...rest, activity: sortTimeline(rest.activity) } : rest;
};
export const applicationService = {
@@ -151,18 +220,27 @@ export const applicationService = {
},
create: async (
- input: EditableFields & { userId: string; company: string; role: string; status?: ApplicationStatus | undefined },
+ input: EditableFields & {
+ userId: string;
+ company: string;
+ role: string;
+ status?: ApplicationStatus | undefined;
+ stageEnteredAt?: string | undefined;
+ },
) => {
- const { userId, status, ...fields } = input;
+ const { userId, status, stageEnteredAt, ...fields } = input;
const id = generateId();
+ const initialStatus = status ?? "saved";
+ const activity = [stageEntry(initialStatus, stageEnteredAt)];
await assertOwnedResume(userId, fields.resumeId);
await db.insert(schema.application).values({
id,
userId,
- status: status ?? "saved",
- activity: [activityEvent("created", `Added to ${stageLabel(status ?? "saved")}`)],
+ status: initialStatus,
+ activity,
+ appliedAt: appliedAtFromTimeline(activity, new Date()),
...fields,
});
@@ -171,7 +249,12 @@ export const applicationService = {
importMany: async (input: {
userId: string;
- items: (EditableFields & { company: string; role: string; status?: ApplicationStatus | undefined })[];
+ items: (EditableFields & {
+ company: string;
+ role: string;
+ status?: ApplicationStatus | undefined;
+ stageEnteredAt?: string | undefined;
+ })[];
}) => {
if (input.items.length === 0) return { imported: 0 };
@@ -180,13 +263,18 @@ export const applicationService = {
input.items.map((item) => item.resumeId),
);
- const values = input.items.map(({ status, ...fields }) => ({
- id: generateId(),
- userId: input.userId,
- status: status ?? ("saved" as ApplicationStatus),
- activity: [activityEvent("created", `Added to ${stageLabel(status ?? "saved")}`)],
- ...fields,
- }));
+ const values = input.items.map(({ status, stageEnteredAt, ...fields }) => {
+ const initialStatus = status ?? ("saved" as ApplicationStatus);
+ const activity = [stageEntry(initialStatus, stageEnteredAt)];
+ return {
+ id: generateId(),
+ userId: input.userId,
+ status: initialStatus,
+ activity,
+ appliedAt: appliedAtFromTimeline(activity, new Date()),
+ ...fields,
+ };
+ });
const rows = await db.insert(schema.application).values(values).returning({ id: schema.application.id });
return { imported: rows.length };
@@ -205,12 +293,19 @@ export const applicationService = {
const { id, userId, status, archived, ...fields } = input;
await assertOwnedResume(userId, fields.resumeId);
+ const statusEntry = status !== undefined ? stageEntry(status) : undefined;
// Append in SQL so concurrent notes/stage events are not overwritten by a stale array.
const activityExpr =
- status !== undefined
+ statusEntry !== undefined
? sql`case when ${schema.application.status} <> ${status}
- then ${schema.application.activity} || ${JSON.stringify([activityEvent("stage", `Moved to ${stageLabel(status)}`)])}::jsonb
- else ${schema.application.activity} end`
+ then ${schema.application.activity} || ${JSON.stringify([statusEntry])}::jsonb
+ else ${schema.application.activity} end`
+ : undefined;
+ const appliedAtExpr =
+ statusEntry !== undefined && status === "applied"
+ ? sql`case when ${schema.application.status} <> ${status}
+ then ${statusEntry.at}
+ else ${schema.application.appliedAt} end`
: undefined;
const [updated] = await db
@@ -218,6 +313,7 @@ export const applicationService = {
.set({
...fields,
...(status !== undefined ? { status } : {}),
+ ...(appliedAtExpr ? { appliedAt: appliedAtExpr } : {}),
...(archived !== undefined ? { archived } : {}),
...(activityExpr ? { activity: activityExpr } : {}),
})
@@ -313,10 +409,10 @@ export const applicationService = {
return stripUserId(updated);
},
- addNote: async (input: { id: string; userId: string; text: string }) => {
+ addNote: async (input: { id: string; userId: string; text: string; date?: string | undefined }) => {
// Append in a single statement (activity || [event]) so concurrent notes can't drop each
// other via read-then-write; ownership is enforced by the WHERE clause.
- const event = activityEvent("note", input.text);
+ const event = noteEntry(input.text, input.date);
const [updated] = await db
.update(schema.application)
.set({ activity: sql`${schema.application.activity} || ${JSON.stringify([event])}::jsonb` })
@@ -327,6 +423,96 @@ export const applicationService = {
return stripUserId(updated);
},
+ updateTimelineEntry: async (input: {
+ id: string;
+ userId: string;
+ entryId: string;
+ date?: string | undefined;
+ text?: string | undefined;
+ }) => {
+ return db.transaction(async (tx) => {
+ await tx.execute(sql`
+ select 1 from ${schema.application}
+ where ${schema.application.id} = ${input.id} and ${schema.application.userId} = ${input.userId}
+ for update
+ `);
+
+ const [existing] = await tx
+ .select()
+ .from(schema.application)
+ .where(and(eq(schema.application.id, input.id), eq(schema.application.userId, input.userId)));
+ if (!existing) throw new ORPCError("NOT_FOUND");
+
+ const activity = existing.activity.map((entry) => {
+ if (entry.id !== input.entryId) return entry;
+
+ if (entry.type === "stage" && input.text !== undefined) {
+ throw new ORPCError("BAD_REQUEST", { message: "Stage timeline text is derived and cannot be edited." });
+ }
+
+ return {
+ ...entry,
+ ...(input.date !== undefined ? { at: atFromDateString(input.date, entry.at) } : {}),
+ ...(entry.type === "note" && input.text !== undefined ? { text: input.text } : {}),
+ };
+ });
+
+ if (!activity.some((entry) => entry.id === input.entryId)) throw new ORPCError("NOT_FOUND");
+ assertCurrentStageAnchorLatest(activity, existing.status);
+
+ const [updated] = await tx
+ .update(schema.application)
+ .set({
+ activity,
+ appliedAt: appliedAtFromTimeline(activity, existing.appliedAt),
+ })
+ .where(and(eq(schema.application.id, input.id), eq(schema.application.userId, input.userId)))
+ .returning();
+
+ if (!updated) throw new ORPCError("NOT_FOUND");
+ return stripUserId(updated);
+ });
+ },
+
+ deleteTimelineEntry: async (input: { id: string; userId: string; entryId: string }) => {
+ return db.transaction(async (tx) => {
+ await tx.execute(sql`
+ select 1 from ${schema.application}
+ where ${schema.application.id} = ${input.id} and ${schema.application.userId} = ${input.userId}
+ for update
+ `);
+
+ const [existing] = await tx
+ .select()
+ .from(schema.application)
+ .where(and(eq(schema.application.id, input.id), eq(schema.application.userId, input.userId)));
+ if (!existing) throw new ORPCError("NOT_FOUND");
+
+ const entry = existing.activity.find((item) => item.id === input.entryId);
+ if (!entry) throw new ORPCError("NOT_FOUND");
+
+ const anchor = currentStageAnchor(existing.activity, existing.status);
+ if (entry.type === "stage" && anchor?.id === entry.id) {
+ throw new ORPCError("BAD_REQUEST", { message: "The current stage timeline entry cannot be deleted." });
+ }
+
+ const activity = existing.activity.filter((item) => item.id !== input.entryId);
+ assertCurrentStageAnchorLatest(activity, existing.status);
+
+ const [updated] = await tx
+ .update(schema.application)
+ .set({
+ activity,
+ appliedAt: appliedAtFromTimeline(activity, existing.appliedAt),
+ })
+ .where(and(eq(schema.application.id, input.id), eq(schema.application.userId, input.userId)))
+ .returning();
+
+ if (!updated) throw new ORPCError("NOT_FOUND");
+ return stripUserId(updated);
+ });
+ },
+
delete: async (input: { id: string; userId: string }) => {
const existing = await requireOwned(input.id, input.userId);
const result = await db
@@ -359,17 +545,25 @@ export const applicationService = {
// Stage moves must log a timeline event on every row that actually changed — mirror the
// single-item update path. Append the event only where the current status differs.
+ const statusEntry = input.status !== undefined ? stageEntry(input.status) : undefined;
const activityExpr =
- input.status !== undefined
+ statusEntry !== undefined
? sql`case when ${schema.application.status} <> ${input.status}
- then ${schema.application.activity} || ${JSON.stringify([activityEvent("stage", `Moved to ${stageLabel(input.status)}`)])}::jsonb
- else ${schema.application.activity} end`
+ then ${schema.application.activity} || ${JSON.stringify([statusEntry])}::jsonb
+ else ${schema.application.activity} end`
+ : undefined;
+ const appliedAtExpr =
+ statusEntry !== undefined && input.status === "applied"
+ ? sql`case when ${schema.application.status} <> ${input.status}
+ then ${statusEntry.at}
+ else ${schema.application.appliedAt} end`
: undefined;
const rows = await db
.update(schema.application)
.set({
...(input.status !== undefined ? { status: input.status } : {}),
+ ...(appliedAtExpr ? { appliedAt: appliedAtExpr } : {}),
...(activityExpr ? { activity: activityExpr } : {}),
...(input.archived !== undefined ? { archived: input.archived } : {}),
...(tagsExpr ? { tags: tagsExpr } : {}),
diff --git a/packages/db/src/schema/applications.ts b/packages/db/src/schema/applications.ts
index 04094ca84..0d907139f 100644
--- a/packages/db/src/schema/applications.ts
+++ b/packages/db/src/schema/applications.ts
@@ -1,4 +1,9 @@
-import type { ActivityEvent, AiMetadata, ApplicationStatus, Contact } from "@reactive-resume/schema/applications/data";
+import type {
+ AiMetadata,
+ ApplicationStatus,
+ ApplicationTimelineEntry,
+ Contact,
+} from "@reactive-resume/schema/applications/data";
import * as pg from "drizzle-orm/pg-core";
import { generateId } from "@reactive-resume/utils/string";
import { user } from "./auth";
@@ -47,7 +52,7 @@ export const application = pg.pgTable(
followUpAt: pg.timestamp("follow_up_at", { withTimezone: true }),
followUpNote: pg.text("follow_up_note"),
contacts: pg.jsonb("contacts").notNull().$type().default([]),
- activity: pg.jsonb("activity").notNull().$type().default([]),
+ activity: pg.jsonb("activity").notNull().$type().default([]),
appliedAt: pg.timestamp("applied_at", { withTimezone: true }).notNull().defaultNow(),
createdAt: pg.timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
updatedAt: pg
diff --git a/packages/mcp/src/mcp-tool-names.ts b/packages/mcp/src/mcp-tool-names.ts
index 7f00ae886..a1fc916be 100644
--- a/packages/mcp/src/mcp-tool-names.ts
+++ b/packages/mcp/src/mcp-tool-names.ts
@@ -21,6 +21,8 @@ export const MCP_TOOL_NAME = {
createApplication: "create_application",
updateApplication: "update_application",
addApplicationNote: "add_application_note",
+ updateApplicationTimelineEntry: "update_application_timeline_entry",
+ deleteApplicationTimelineEntry: "delete_application_timeline_entry",
deleteApplication: "delete_application",
bulkUpdateApplications: "bulk_update_applications",
bulkDeleteApplications: "bulk_delete_applications",
diff --git a/packages/mcp/src/tool-annotations.ts b/packages/mcp/src/tool-annotations.ts
index 5f3be0514..6ba065b8b 100644
--- a/packages/mcp/src/tool-annotations.ts
+++ b/packages/mcp/src/tool-annotations.ts
@@ -64,6 +64,8 @@ export const TOOL_ANNOTATIONS: Record =
[MCP_TOOL_NAME.createApplication]: WRITE_NON_IDEMPOTENT,
[MCP_TOOL_NAME.updateApplication]: WRITE_IDEMPOTENT,
[MCP_TOOL_NAME.addApplicationNote]: WRITE_NON_IDEMPOTENT,
+ [MCP_TOOL_NAME.updateApplicationTimelineEntry]: WRITE_IDEMPOTENT,
+ [MCP_TOOL_NAME.deleteApplicationTimelineEntry]: WRITE_DESTRUCTIVE,
[MCP_TOOL_NAME.deleteApplication]: WRITE_DESTRUCTIVE,
[MCP_TOOL_NAME.bulkUpdateApplications]: WRITE_IDEMPOTENT,
[MCP_TOOL_NAME.bulkDeleteApplications]: WRITE_DESTRUCTIVE,
diff --git a/packages/mcp/src/tool-meta.ts b/packages/mcp/src/tool-meta.ts
index 70616deea..a2d642b9b 100644
--- a/packages/mcp/src/tool-meta.ts
+++ b/packages/mcp/src/tool-meta.ts
@@ -16,7 +16,9 @@ const applicationIdSchema = z
.string()
.min(1)
.describe(`Application ID. Use \`${T.listApplications}\` to find valid IDs.`);
+const applicationTimelineEntryIdSchema = z.string().min(1).describe("Timeline entry ID from an application response.");
const applicationDocumentKindSchema = z.enum(["resume", "cover-letter"]);
+const timelineDateSchema = z.string().regex(/^\d{4}-\d{2}-\d{2}$/, "Date must use YYYY-MM-DD format.");
const httpUrlSchema = z
.string()
.trim()
@@ -67,6 +69,7 @@ const createApplicationSchema = z
...applicationMutableFieldsSchema,
company: z.string().min(1).describe("Company name."),
role: z.string().min(1).describe("Role or job title."),
+ stageEnteredAt: timelineDateSchema.optional().describe("Initial stage date in YYYY-MM-DD format."),
})
.strict();
@@ -343,9 +346,32 @@ export const TOOL_META = {
[T.addApplicationNote]: {
title: "Add Application Note",
description: "Append a free-text note to an application's timeline.",
- inputSchema: z.object({ id: applicationIdSchema, text: z.string().min(1) }),
+ inputSchema: z.object({
+ id: applicationIdSchema,
+ text: z.string().min(1),
+ date: timelineDateSchema.optional().describe("Optional note date in YYYY-MM-DD format."),
+ }),
annotations: TOOL_ANNOTATIONS[T.addApplicationNote],
},
+ [T.updateApplicationTimelineEntry]: {
+ title: "Update Application Timeline Entry",
+ description: "Update a timeline entry date, or note text for note entries.",
+ inputSchema: z
+ .object({
+ id: applicationIdSchema,
+ entryId: applicationTimelineEntryIdSchema,
+ date: timelineDateSchema.optional().describe("Replacement row date in YYYY-MM-DD format."),
+ text: z.string().min(1).optional().describe("Replacement note text. Only note entries can change text."),
+ })
+ .refine((value) => value.date !== undefined || value.text !== undefined, "Provide date or text to update."),
+ annotations: TOOL_ANNOTATIONS[T.updateApplicationTimelineEntry],
+ },
+ [T.deleteApplicationTimelineEntry]: {
+ title: "Delete Application Timeline Entry",
+ description: "Delete a note or older stage entry. The current stage entry cannot be deleted.",
+ inputSchema: z.object({ id: applicationIdSchema, entryId: applicationTimelineEntryIdSchema }),
+ annotations: TOOL_ANNOTATIONS[T.deleteApplicationTimelineEntry],
+ },
[T.deleteApplication]: {
title: "Delete Application",
description: "Permanently delete one job application and its owned uploaded documents.",
diff --git a/packages/mcp/src/tools.test.ts b/packages/mcp/src/tools.test.ts
index a0e4a8204..550f2ab1b 100644
--- a/packages/mcp/src/tools.test.ts
+++ b/packages/mcp/src/tools.test.ts
@@ -71,6 +71,8 @@ const clientMock = {
create: vi.fn(),
update: vi.fn(),
addNote: vi.fn(),
+ updateTimelineEntry: vi.fn(),
+ deleteTimelineEntry: vi.fn(),
delete: vi.fn(),
bulkUpdate: vi.fn(),
bulkDelete: vi.fn(),
@@ -185,6 +187,51 @@ describe("registerTools", () => {
});
});
+ it("adds dated application notes through the router client", async () => {
+ clientMock.applications.addNote.mockResolvedValueOnce({ id: "app-1", company: "Acme" });
+ const { server, registered } = makeFakeServer();
+ registerTools(server as never, clientMock as never, new Headers());
+
+ const tool = registered.find((item) => item.name === "add_application_note")!;
+ await tool.handler({ id: "app-1", text: "Recruiter replied", date: "2026-07-12" });
+
+ expect(clientMock.applications.addNote).toHaveBeenCalledWith({
+ id: "app-1",
+ text: "Recruiter replied",
+ date: "2026-07-12",
+ });
+ });
+
+ it("updates application timeline entries through the router client", async () => {
+ clientMock.applications.updateTimelineEntry.mockResolvedValueOnce({ id: "app-1", company: "Acme" });
+ const { server, registered } = makeFakeServer();
+ registerTools(server as never, clientMock as never, new Headers());
+
+ const tool = registered.find((item) => item.name === "update_application_timeline_entry")!;
+ await tool.handler({ id: "app-1", entryId: "entry-1", date: "2026-07-13", text: "Updated note" });
+
+ expect(clientMock.applications.updateTimelineEntry).toHaveBeenCalledWith({
+ id: "app-1",
+ entryId: "entry-1",
+ date: "2026-07-13",
+ text: "Updated note",
+ });
+ });
+
+ it("deletes application timeline entries through the router client", async () => {
+ clientMock.applications.deleteTimelineEntry.mockResolvedValueOnce({ id: "app-1", company: "Acme" });
+ const { server, registered } = makeFakeServer();
+ registerTools(server as never, clientMock as never, new Headers());
+
+ const tool = registered.find((item) => item.name === "delete_application_timeline_entry")!;
+ await tool.handler({ id: "app-1", entryId: "entry-1" });
+
+ expect(clientMock.applications.deleteTimelineEntry).toHaveBeenCalledWith({
+ id: "app-1",
+ entryId: "entry-1",
+ });
+ });
+
it("imports applications with followUpAt coerced to Date and null preserved", async () => {
clientMock.applications.import.mockResolvedValueOnce({ imported: 2 });
const { server, registered } = makeFakeServer();
diff --git a/packages/mcp/src/tools.ts b/packages/mcp/src/tools.ts
index 613ae9c8b..6f206a828 100644
--- a/packages/mcp/src/tools.ts
+++ b/packages/mcp/src/tools.ts
@@ -410,11 +410,33 @@ export function registerTools(server: McpServer, client: RouterClient {
- return json(await client.applications.addNote({ id, text: noteText }));
+ withErrorHandling(
+ "adding application note",
+ async ({ id, text: noteText, date }: { id: string; text: string; date?: string | undefined }) => {
+ return json(await client.applications.addNote({ id, text: noteText, date }));
+ },
+ ),
+ );
+
+ server.registerTool(
+ T.updateApplicationTimelineEntry,
+ TOOL_META[T.updateApplicationTimelineEntry],
+ withErrorHandling("updating application timeline entry", async (params) => {
+ return json(await client.applications.updateTimelineEntry(params as never));
}),
);
+ server.registerTool(
+ T.deleteApplicationTimelineEntry,
+ TOOL_META[T.deleteApplicationTimelineEntry],
+ withErrorHandling(
+ "deleting application timeline entry",
+ async ({ id, entryId }: { id: string; entryId: string }) => {
+ return json(await client.applications.deleteTimelineEntry({ id, entryId }));
+ },
+ ),
+ );
+
server.registerTool(
T.deleteApplication,
TOOL_META[T.deleteApplication],
diff --git a/packages/schema/src/applications/data.ts b/packages/schema/src/applications/data.ts
index bb3fa739b..9e863a000 100644
--- a/packages/schema/src/applications/data.ts
+++ b/packages/schema/src/applications/data.ts
@@ -26,16 +26,24 @@ export const contactSchema = z.object({
export type Contact = z.infer;
-// Timeline events: `stage` entries are auto-appended when an application moves; `note`
-// entries are added manually from the detail panel.
-export const activityEventSchema = z.object({
+const timelineBaseSchema = z.object({
id: z.string().min(1),
- type: z.enum(["stage", "note", "created"]),
- text: z.string().trim().min(1),
at: z.coerce.date(),
});
-export type ActivityEvent = z.infer;
+export const applicationTimelineEntrySchema = z.discriminatedUnion("type", [
+ timelineBaseSchema.extend({
+ type: z.literal("stage"),
+ stage: applicationStatusSchema,
+ }),
+ timelineBaseSchema.extend({
+ type: z.literal("note"),
+ text: z.string().trim().min(1),
+ }),
+]);
+
+export type ApplicationTimelineEntry = z.infer;
+export type ActivityEvent = ApplicationTimelineEntry;
// Reserved for AI enrichment output (autofill / match-score). Free-form so the shape can
// evolve without a migration. See the AI roadmap in the applications feature.
diff --git a/tests/e2e/specs/applications-tracker.spec.ts b/tests/e2e/specs/applications-tracker.spec.ts
index c3cd15e79..cf994e53c 100644
--- a/tests/e2e/specs/applications-tracker.spec.ts
+++ b/tests/e2e/specs/applications-tracker.spec.ts
@@ -39,9 +39,9 @@ test("adds an application and logs stage changes and notes", async ({ authPage:
await expect(detail.getByText(company)).toBeVisible();
await detail.getByRole("button", { name: "Move to Applied" }).click();
await expect(detail.getByRole("button", { name: "Move to Screening" })).toBeVisible();
- await expect(detail.getByText("Moved to Applied")).toBeVisible();
+ await expect(detail.locator('[data-timeline-entry="stage"][data-stage="applied"]')).toBeVisible();
- await detail.getByPlaceholder("Add a note or log activity…").fill(note);
+ await detail.locator("[data-timeline-note-input]").fill(note);
await detail.getByRole("button", { name: "Add", exact: true }).click();
await expect(detail.getByText(note)).toBeVisible();
});
|