feat(schema): declare user relation on verification tokens

Keys have always referenced their owner by a bare user_id string with no
declared relation, so the database could not enforce integrity and no
query could join keys to users. This adds the litellm_user_table
relation on LiteLLM_VerificationToken (FK on user_id, ON DELETE SET
NULL, matching the table's existing budget, organization and project
FKs) and a keys back-relation on LiteLLM_UserTable.

The migration first nulls user_ids pointing at users that no longer
exist; the constraint cannot be added over them, and SET NULL would have
produced the same rows had it existed when those users were deleted. The
user-delete endpoint already deletes the user's keys itself, so the FK
changes no runtime behavior; it formalizes the link and unlocks
relation queries and joins for future work
This commit is contained in:
ryan-crabbe-berri 2026-07-27 11:28:32 -07:00
parent 10cd4288b6
commit c0d0ecf198
3 changed files with 19 additions and 0 deletions

View file

@ -0,0 +1,15 @@
-- Null out user_ids that reference users that no longer exist; the foreign key
-- below cannot be added over them, and ON DELETE SET NULL would have produced
-- the same rows had the constraint existed when those users were deleted
UPDATE "LiteLLM_VerificationToken" vt
SET "user_id" = NULL
WHERE vt."user_id" IS NOT NULL
AND NOT EXISTS (SELECT 1 FROM "LiteLLM_UserTable" u WHERE u."user_id" = vt."user_id");
-- AddForeignKey
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'LiteLLM_VerificationToken_user_id_fkey') THEN
ALTER TABLE "LiteLLM_VerificationToken" ADD CONSTRAINT "LiteLLM_VerificationToken_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "LiteLLM_UserTable"("user_id") ON DELETE SET NULL ON UPDATE CASCADE;
END IF;
END $$;

View file

@ -265,6 +265,7 @@ model LiteLLM_UserTable {
invitations_updated LiteLLM_InvitationLink[] @relation("UpdatedBy")
invitations_user LiteLLM_InvitationLink[] @relation("UserId")
object_permission LiteLLM_ObjectPermissionTable? @relation(fields: [object_permission_id], references: [object_permission_id])
keys LiteLLM_VerificationToken[]
}
model LiteLLM_ObjectPermissionTable {
@ -462,6 +463,7 @@ model LiteLLM_VerificationToken {
litellm_budget_table LiteLLM_BudgetTable? @relation(fields: [budget_id], references: [budget_id])
litellm_organization_table LiteLLM_OrganizationTable? @relation(fields: [organization_id], references: [organization_id])
litellm_project_table LiteLLM_ProjectTable? @relation(fields: [project_id], references: [project_id])
litellm_user_table LiteLLM_UserTable? @relation(fields: [user_id], references: [user_id])
object_permission LiteLLM_ObjectPermissionTable? @relation(fields: [object_permission_id], references: [object_permission_id])
jwt_key_mappings LiteLLM_JWTKeyMapping[]

View file

@ -265,6 +265,7 @@ model LiteLLM_UserTable {
invitations_updated LiteLLM_InvitationLink[] @relation("UpdatedBy")
invitations_user LiteLLM_InvitationLink[] @relation("UserId")
object_permission LiteLLM_ObjectPermissionTable? @relation(fields: [object_permission_id], references: [object_permission_id])
keys LiteLLM_VerificationToken[]
}
model LiteLLM_ObjectPermissionTable {
@ -462,6 +463,7 @@ model LiteLLM_VerificationToken {
litellm_budget_table LiteLLM_BudgetTable? @relation(fields: [budget_id], references: [budget_id])
litellm_organization_table LiteLLM_OrganizationTable? @relation(fields: [organization_id], references: [organization_id])
litellm_project_table LiteLLM_ProjectTable? @relation(fields: [project_id], references: [project_id])
litellm_user_table LiteLLM_UserTable? @relation(fields: [user_id], references: [user_id])
object_permission LiteLLM_ObjectPermissionTable? @relation(fields: [object_permission_id], references: [object_permission_id])
jwt_key_mappings LiteLLM_JWTKeyMapping[]