From fc5ab43ac71b5a8ff739d36b626db5243ca19f03 Mon Sep 17 00:00:00 2001
From: Philipp Nowinski <mail@pno.dev>
Date: Tue, 19 May 2026 17:48:06 +0200
Subject: [PATCH 1/3] fix: fix session

---
 src/db/mutations/attachments.ts |  6 +++---
 src/db/mutations/comments.ts    |  4 ++--
 src/db/mutations/labels.ts      | 10 +++++-----
 src/db/mutations/projects.ts    |  8 ++++----
 src/db/mutations/sprints.ts     |  8 ++++----
 src/db/mutations/statuses.ts    | 10 +++++-----
 src/db/mutations/sub-tasks.ts   | 12 ++++++------
 src/db/mutations/tasks.ts       | 14 +++++++-------
 src/db/queries/attachments.ts   |  4 ++--
 src/db/queries/bundles.ts       | 10 +++++-----
 src/db/queries/comments.ts      |  4 ++--
 src/db/queries/labels.ts        |  6 +++---
 src/db/queries/projects.ts      |  6 +++---
 src/db/queries/sprints.ts       |  6 +++---
 src/db/queries/statuses.ts      |  6 +++---
 src/db/queries/tasks.ts         |  8 ++++----
 src/db/queries/users.ts         |  4 ++--
 src/lib/auth-functions.ts       | 21 ++++++---------------
 src/lib/session.ts              | 21 +++++++++++++++++++++
 19 files changed, 90 insertions(+), 78 deletions(-)
 create mode 100644 src/lib/session.ts

diff --git a/src/db/mutations/attachments.ts b/src/db/mutations/attachments.ts
index f860c05..e693347 100644
--- a/src/db/mutations/attachments.ts
+++ b/src/db/mutations/attachments.ts
@@ -4,7 +4,7 @@ import {
   CreateAttachment,
   insertAttachmentValidator,
 } from "../schema";
-import { requireSession } from "~/lib/auth-functions";
+import { requireSessionFromRequest } from "~/lib/session";
 import { db } from "..";
 import { v7 as uuid } from "uuid";
 import { getOwningIdentity } from "~/lib/utils";
@@ -19,7 +19,7 @@ import { UTApi } from "uploadthing/server";
 const createAttachment = createServerFn({ method: "POST" })
   .inputValidator(insertAttachmentValidator)
   .handler(async ({ data }) => {
-    const session = await requireSession();
+    const session = await requireSessionFromRequest();
 
     await db.insert(attachments).values({
       ...data,
@@ -59,7 +59,7 @@ export function useCreateAttachmentMutation() {
 export const deleteAttachment = createServerFn({ method: "POST" })
   .inputValidator(z.object({ id: z.string() }))
   .handler(async ({ data }) => {
-    const session = await requireSession();
+    const session = await requireSessionFromRequest();
 
     const attachment = await db.query.attachments.findFirst({
       where: (model, { eq, and }) =>
diff --git a/src/db/mutations/comments.ts b/src/db/mutations/comments.ts
index 6d9c26b..371e7d7 100644
--- a/src/db/mutations/comments.ts
+++ b/src/db/mutations/comments.ts
@@ -1,6 +1,6 @@
 import { createServerFn, useServerFn } from "@tanstack/react-start";
 import { comments, CreateComment, insertCommentValidator } from "../schema";
-import { requireSession } from "~/lib/auth-functions";
+import { requireSessionFromRequest } from "~/lib/session";
 import { db } from "..";
 import { v7 as uuid } from "uuid";
 import { getOwningIdentity } from "~/lib/utils";
@@ -12,7 +12,7 @@ import { sync } from "./sync";
 const createComment = createServerFn({ method: "POST" })
   .inputValidator(insertCommentValidator)
   .handler(async ({ data }) => {
-    const session = await requireSession();
+    const session = await requireSessionFromRequest();
 
     await db.insert(comments).values({
       ...data,
diff --git a/src/db/mutations/labels.ts b/src/db/mutations/labels.ts
index 0c98321..67c6bee 100644
--- a/src/db/mutations/labels.ts
+++ b/src/db/mutations/labels.ts
@@ -15,13 +15,13 @@ import { useQueryClient } from "@tanstack/react-query";
 import { useCallback } from "react";
 import { and, eq } from "drizzle-orm";
 import { getOwningIdentity } from "~/lib/utils";
-import { requireSession } from "~/lib/auth-functions";
+import { requireSessionFromRequest } from "~/lib/session";
 import { sync } from "./sync";
 
 const createLabel = createServerFn({ method: "POST" })
   .inputValidator(insertLabelValidator)
   .handler(async ({ data }) => {
-    const session = await requireSession();
+    const session = await requireSessionFromRequest();
     await db.insert(labels).values({
       ...data,
       id: uuid(),
@@ -58,7 +58,7 @@ export function useCreateLabelMutation() {
 const updateLabel = createServerFn({ method: "POST" })
   .inputValidator(updateLabelValidator)
   .handler(async ({ data }) => {
-    const session = await requireSession();
+    const session = await requireSessionFromRequest();
 
     await db
       .update(labels)
@@ -101,7 +101,7 @@ export function useUpdateLabelMutation() {
 const updateMultipleLabels = createServerFn({ method: "POST" })
   .inputValidator(updateMultipleLabelsValidator)
   .handler(async ({ data }) => {
-    const session = await requireSession();
+    const session = await requireSessionFromRequest();
 
     await Promise.all(
       data.map(async (entry) => {
@@ -165,7 +165,7 @@ export function useUpdateMultipleLabelsMutation() {
 const deleteLabel = createServerFn({ method: "POST" })
   .inputValidator(z.object({ id: z.string() }))
   .handler(async ({ data }) => {
-    const session = await requireSession();
+    const session = await requireSessionFromRequest();
 
     await db
       .delete(labels)
diff --git a/src/db/mutations/projects.ts b/src/db/mutations/projects.ts
index c384e37..64c8b1a 100644
--- a/src/db/mutations/projects.ts
+++ b/src/db/mutations/projects.ts
@@ -10,7 +10,7 @@ import {
   UpdateProject,
   updateProjectValidator,
 } from "../schema";
-import { requireSession } from "~/lib/auth-functions";
+import { requireSessionFromRequest } from "~/lib/session";
 import { db } from "..";
 import { v7 as uuid } from "uuid";
 import { getOwningIdentity } from "~/lib/utils";
@@ -24,7 +24,7 @@ import z from "zod";
 const createProject = createServerFn({ method: "POST" })
   .inputValidator(insertProjectValidator)
   .handler(async ({ data }) => {
-    const session = await requireSession();
+    const session = await requireSessionFromRequest();
 
     await db.insert(projects).values({
       ...data,
@@ -59,7 +59,7 @@ export function useCreateProjectMutation() {
 const updateProject = createServerFn({ method: "POST" })
   .inputValidator(updateProjectValidator)
   .handler(async ({ data }) => {
-    const session = await requireSession();
+    const session = await requireSessionFromRequest();
 
     await db
       .update(projects)
@@ -101,7 +101,7 @@ export function useUpdateProjectMutation() {
 const deleteProject = createServerFn({ method: "POST" })
   .inputValidator(z.object({ id: z.string() }))
   .handler(async ({ data }) => {
-    const session = await requireSession();
+    const session = await requireSessionFromRequest();
 
     await db
       .delete(tasks)
diff --git a/src/db/mutations/sprints.ts b/src/db/mutations/sprints.ts
index 6c4d331..14369d0 100644
--- a/src/db/mutations/sprints.ts
+++ b/src/db/mutations/sprints.ts
@@ -7,7 +7,7 @@ import {
   UpdateSprint,
   updateSprintValidator,
 } from "../schema";
-import { requireSession } from "~/lib/auth-functions";
+import { requireSessionFromRequest } from "~/lib/session";
 import { db } from "..";
 import { getOwningIdentity } from "~/lib/utils";
 import { v7 as uuid } from "uuid";
@@ -21,7 +21,7 @@ import { z } from "zod";
 const createSprint = createServerFn({ method: "POST" })
   .inputValidator(insertSprintValidator)
   .handler(async ({ data }) => {
-    const session = await requireSession();
+    const session = await requireSessionFromRequest();
 
     await db.insert(sprints).values({
       ...data,
@@ -56,7 +56,7 @@ export function useCreateSprintMutation() {
 const updateSprint = createServerFn({ method: "POST" })
   .inputValidator(updateSprintValidator)
   .handler(async ({ data }) => {
-    const session = await requireSession();
+    const session = await requireSessionFromRequest();
 
     await db
       .update(sprints)
@@ -96,7 +96,7 @@ export function useUpdateSprintMutation() {
 export const deleteSprint = createServerFn({ method: "POST" })
   .inputValidator(z.object({ sprintId: z.string() }))
   .handler(async ({ data: { sprintId } }) => {
-    const session = await requireSession();
+    const session = await requireSessionFromRequest();
 
     // remove all tasks from the sprint
     await db
diff --git a/src/db/mutations/statuses.ts b/src/db/mutations/statuses.ts
index ba66ff9..0b8ade4 100644
--- a/src/db/mutations/statuses.ts
+++ b/src/db/mutations/statuses.ts
@@ -15,14 +15,14 @@ import { useRouter } from "@tanstack/react-router";
 import { useQueryClient } from "@tanstack/react-query";
 import { useCallback } from "react";
 import { and, eq } from "drizzle-orm";
-import { requireSession } from "~/lib/auth-functions";
+import { requireSessionFromRequest } from "~/lib/session";
 import { getOwningIdentity } from "~/lib/utils";
 import { sync } from "./sync";
 
 const createStatus = createServerFn({ method: "POST" })
   .inputValidator(insertStatusValidator)
   .handler(async ({ data }) => {
-    const session = await requireSession();
+    const session = await requireSessionFromRequest();
 
     await db.insert(statuses).values({
       ...data,
@@ -60,7 +60,7 @@ export function useCreateStatusMutation() {
 const updateStatus = createServerFn({ method: "POST" })
   .inputValidator(updateStatusValidator)
   .handler(async ({ data }) => {
-    const session = await requireSession();
+    const session = await requireSessionFromRequest();
 
     await db
       .update(statuses)
@@ -105,7 +105,7 @@ export function useUpdateStatusMutation() {
 const updateMultipleStatuses = createServerFn({ method: "POST" })
   .inputValidator(updateMultipleStatusesValidator)
   .handler(async ({ data }) => {
-    const session = await requireSession();
+    const session = await requireSessionFromRequest();
 
     await Promise.all(
       data.map(async (entry) => {
@@ -169,7 +169,7 @@ export function useUpdateMultipleStatusesMutation() {
 const deleteStatus = createServerFn({ method: "POST" })
   .inputValidator(z.object({ id: z.string() }))
   .handler(async ({ data }) => {
-    const session = await requireSession();
+    const session = await requireSessionFromRequest();
 
     await db
       .update(tasks)
diff --git a/src/db/mutations/sub-tasks.ts b/src/db/mutations/sub-tasks.ts
index d977bbe..35648e0 100644
--- a/src/db/mutations/sub-tasks.ts
+++ b/src/db/mutations/sub-tasks.ts
@@ -8,7 +8,7 @@ import {
   UpdateSubTask,
   updateSubTaskValidator,
 } from "../schema";
-import { requireSession } from "~/lib/auth-functions";
+import { requireSessionFromRequest } from "~/lib/session";
 import { db } from "..";
 import { v7 as uuid } from "uuid";
 import { getOwningIdentity } from "~/lib/utils";
@@ -22,7 +22,7 @@ import z from "zod";
 const createSubTask = createServerFn({ method: "POST" })
   .inputValidator(insertSubTaskValidator)
   .handler(async ({ data }) => {
-    const session = await requireSession();
+    const session = await requireSessionFromRequest();
 
     await db.insert(subTasks).values({
       ...data,
@@ -57,7 +57,7 @@ export function useCreateSubTaskMutation() {
 const updateSubTask = createServerFn({ method: "POST" })
   .inputValidator(updateSubTaskValidator)
   .handler(async ({ data }) => {
-    const session = await requireSession();
+    const session = await requireSessionFromRequest();
 
     await db
       .update(subTasks)
@@ -121,7 +121,7 @@ export function useUpdateSubTaskMutation() {
 const deleteSubTask = createServerFn({ method: "POST" })
   .inputValidator(z.object({ id: z.string() }))
   .handler(async ({ data }) => {
-    const session = await requireSession();
+    const session = await requireSessionFromRequest();
 
     const subTask = await db.query.subTasks.findFirst({
       where(fields, operators) {
@@ -176,7 +176,7 @@ const unassignSubTask = createServerFn({ method: "POST" })
     })
   )
   .handler(async ({ data }) => {
-    const session = await requireSession();
+    const session = await requireSessionFromRequest();
     const subTask = await db.query.subTasks.findFirst({
       where(fields, operators) {
         return operators.and(
@@ -226,7 +226,7 @@ const assignSubTask = createServerFn({ method: "POST" })
     })
   )
   .handler(async ({ data }) => {
-    const session = await requireSession();
+    const session = await requireSessionFromRequest();
     const subTask = await db.query.subTasks.findFirst({
       where(fields, operators) {
         return operators.and(
diff --git a/src/db/mutations/tasks.ts b/src/db/mutations/tasks.ts
index 29179fc..01e00e7 100644
--- a/src/db/mutations/tasks.ts
+++ b/src/db/mutations/tasks.ts
@@ -20,7 +20,7 @@ import { useQueryClient } from "@tanstack/react-query";
 import { useCallback } from "react";
 import { and, eq, inArray } from "drizzle-orm";
 import z from "zod";
-import { requireSession } from "~/lib/auth-functions";
+import { requireSessionFromRequest } from "~/lib/session";
 import { getOwningIdentity } from "~/lib/utils";
 import { sync } from "./sync";
 import { deleteAttachment } from "./attachments";
@@ -54,7 +54,7 @@ function getTaskListQueryKeys(
 const createTask = createServerFn({ method: "POST" })
   .inputValidator(insertTaskValidator)
   .handler(async ({ data }) => {
-    const session = await requireSession();
+    const session = await requireSessionFromRequest();
 
     const newTask = {
       id: uuid(),
@@ -109,7 +109,7 @@ const assignTask = createServerFn({ method: "POST" })
     })
   )
   .handler(async ({ data }) => {
-    const session = await requireSession();
+    const session = await requireSessionFromRequest();
     const owner = getOwningIdentity(session);
 
     const task = await db.query.tasks.findFirst({
@@ -153,7 +153,7 @@ const unassignTask = createServerFn({ method: "POST" })
     })
   )
   .handler(async ({ data }) => {
-    const session = await requireSession();
+    const session = await requireSessionFromRequest();
     const owner = getOwningIdentity(session);
 
     const task = await db.query.tasks.findFirst({
@@ -231,7 +231,7 @@ const updateTask = createServerFn({ method: "POST" })
   .inputValidator(updateTaskValidator)
   .handler(async ({ data }) => {
     try {
-      const session = await requireSession();
+      const session = await requireSessionFromRequest();
       const { id, ...updates } = data;
 
       const setValues = Object.fromEntries(
@@ -321,7 +321,7 @@ export function useUpdateTaskMutation() {
 const deleteTask = createServerFn({ method: "POST" })
   .inputValidator(z.object({ id: z.string() }))
   .handler(async ({ data }) => {
-    const session = await requireSession();
+    const session = await requireSessionFromRequest();
     const task = await db.query.tasks.findFirst({
       with: {
         attachments: true,
@@ -374,7 +374,7 @@ const setLabelsForTask = createServerFn({ method: "POST" })
     })
   )
   .handler(async ({ data }) => {
-    const session = await requireSession();
+    const session = await requireSessionFromRequest();
     const owner = getOwningIdentity(session);
 
     const task = await db.query.tasks.findFirst({
diff --git a/src/db/queries/attachments.ts b/src/db/queries/attachments.ts
index 0abc4ef..89a4adf 100644
--- a/src/db/queries/attachments.ts
+++ b/src/db/queries/attachments.ts
@@ -1,4 +1,4 @@
-import { requireSession } from "~/lib/auth-functions";
+import { requireSessionFromRequest } from "~/lib/session";
 import { createServerFn } from "@tanstack/react-start";
 import { db } from "..";
 import { getOwningIdentity } from "~/lib/utils";
@@ -12,7 +12,7 @@ const fetchAttachmentsForTask = createServerFn({ method: "GET" })
       return [];
     }
     console.info(`Fetching attachments for... ${data}`);
-    const session = await requireSession();
+    const session = await requireSessionFromRequest();
     return await db.query.attachments.findMany({
       where: (model, { eq, and }) =>
         and(eq(model.owner, getOwningIdentity(session)), eq(model.taskId, data)),
diff --git a/src/db/queries/bundles.ts b/src/db/queries/bundles.ts
index 709285e..0f5ccb2 100644
--- a/src/db/queries/bundles.ts
+++ b/src/db/queries/bundles.ts
@@ -6,7 +6,7 @@ import { getCommentsForTask } from "~/db/queries/comments";
 import type { AppUser } from "~/db/queries/users";
 import { getUsersForSession } from "~/db/queries/users";
 import type { Label, Project, Sprint, Status, TaskWithRelations } from "~/db/schema";
-import { requireSession } from "~/lib/auth-functions";
+import { requireSessionFromRequest } from "~/lib/session";
 import { getOwningIdentity } from "~/lib/utils";
 
 export type ProjectBoardBundle = {
@@ -48,7 +48,7 @@ export const fetchProjectBoardBundle = createServerFn({ method: "GET" })
     async ({
       data: { projectId },
     }): Promise<ProjectBoardBundle> => {
-      const session = await requireSession();
+      const session = await requireSessionFromRequest();
       const owner = getOwningIdentity(session);
 
       const [project, rawTasks, statuses, users] = await Promise.all([
@@ -85,7 +85,7 @@ export const fetchSprintBoardBundle = createServerFn({ method: "GET" })
     async ({
       data: { sprintId },
     }): Promise<SprintBoardBundle> => {
-      const session = await requireSession();
+      const session = await requireSessionFromRequest();
       const owner = getOwningIdentity(session);
 
       const [sprint, rawTasks, statuses, users] = await Promise.all([
@@ -120,7 +120,7 @@ export const fetchTaskPageBundle = createServerFn({ method: "GET" })
     async ({
       data: { taskId },
     }): Promise<TaskPageBundle> => {
-      const session = await requireSession();
+      const session = await requireSessionFromRequest();
       const owner = getOwningIdentity(session);
 
       const [taskRow, comments, labels, statuses] = await Promise.all([
@@ -171,7 +171,7 @@ export const fetchTaskPageBundle = createServerFn({ method: "GET" })
 
 export const fetchSidebarBundle = createServerFn({ method: "GET" }).handler(
   async (): Promise<SidebarBundle> => {
-    const session = await requireSession();
+    const session = await requireSessionFromRequest();
     const owner = getOwningIdentity(session);
 
     const [projects, sprints] = await Promise.all([
diff --git a/src/db/queries/comments.ts b/src/db/queries/comments.ts
index 598b312..ae403a5 100644
--- a/src/db/queries/comments.ts
+++ b/src/db/queries/comments.ts
@@ -1,4 +1,4 @@
-import { requireSession } from "~/lib/auth-functions";
+import { requireSessionFromRequest } from "~/lib/session";
 import { createServerFn } from "@tanstack/react-start";
 import { db } from "..";
 import { formatUserName, getOwningIdentity } from "~/lib/utils";
@@ -58,7 +58,7 @@ const fetchCommentsForTask = createServerFn({ method: "GET" })
       return [];
     }
 
-    const session = await requireSession();
+    const session = await requireSessionFromRequest();
     return getCommentsForTask(getOwningIdentity(session), data);
   });
 
diff --git a/src/db/queries/labels.ts b/src/db/queries/labels.ts
index c03e877..0194168 100644
--- a/src/db/queries/labels.ts
+++ b/src/db/queries/labels.ts
@@ -3,14 +3,14 @@ import { createServerFn } from "@tanstack/react-start";
 import { db } from "~/db";
 import { labels, labelsToTasks } from "~/db/schema";
 import { asc, eq, sql } from "drizzle-orm";
-import { requireSession } from "~/lib/auth-functions";
+import { requireSessionFromRequest } from "~/lib/session";
 import { getOwningIdentity } from "~/lib/utils";
 import { useEventSource } from "~/hooks/use-event-source";
 
 export const fetchLabels = createServerFn({ method: "GET" }).handler(
   async () => {
     console.info("Fetching labels...");
-    const session = await requireSession();
+    const session = await requireSessionFromRequest();
     return await db.query.labels.findMany({
       where: (model, { eq }) => eq(model.owner, getOwningIdentity(session)),
       orderBy: (fields, { asc }) => [asc(fields.order)],
@@ -46,7 +46,7 @@ export const fetchLabelsWithTaskCounts = createServerFn({
   method: "GET",
 }).handler(async () => {
   console.info("Fetching labels with task counts...");
-  const session = await requireSession();
+  const session = await requireSessionFromRequest();
   const labelsWithCounts = await db
     .select({
       id: labels.id,
diff --git a/src/db/queries/projects.ts b/src/db/queries/projects.ts
index 6a7d5dc..f9d6303 100644
--- a/src/db/queries/projects.ts
+++ b/src/db/queries/projects.ts
@@ -1,13 +1,13 @@
 import { queryOptions, useSuspenseQuery } from "@tanstack/react-query";
 import { createServerFn } from "@tanstack/react-start";
 import { db } from "~/db";
-import { requireSession } from "~/lib/auth-functions";
+import { requireSessionFromRequest } from "~/lib/session";
 import { getOwningIdentity } from "~/lib/utils";
 import { useEventSource } from "~/hooks/use-event-source";
 
 const fetchProjects = createServerFn({ method: "GET" }).handler(async () => {
   console.info("Fetching projects...");
-  const session = await requireSession();
+  const session = await requireSessionFromRequest();
   return await db.query.projects.findMany({
     where: (model, { eq }) => eq(model.owner, getOwningIdentity(session)),
   });
@@ -40,7 +40,7 @@ const fetchProject = createServerFn({ method: "GET" })
   .inputValidator((d: { projectId: string }) => d)
   .handler(async ({ data: { projectId } }) => {
     console.info("Fetching project...");
-    const session = await requireSession();
+    const session = await requireSessionFromRequest();
     return await db.query.projects.findFirst({
       where: (model, { eq, and }) =>
         and(eq(model.id, projectId), eq(model.owner, getOwningIdentity(session))),
diff --git a/src/db/queries/sprints.ts b/src/db/queries/sprints.ts
index 0e1a04c..e057a73 100644
--- a/src/db/queries/sprints.ts
+++ b/src/db/queries/sprints.ts
@@ -1,13 +1,13 @@
 import { queryOptions, useSuspenseQuery } from "@tanstack/react-query";
 import { createServerFn } from "@tanstack/react-start";
 import { db } from "~/db";
-import { requireSession } from "~/lib/auth-functions";
+import { requireSessionFromRequest } from "~/lib/session";
 import { getOwningIdentity } from "~/lib/utils";
 import { useEventSource } from "~/hooks/use-event-source";
 
 const fetchSprints = createServerFn({ method: "GET" }).handler(async () => {
   console.info("Fetching sprints...");
-  const session = await requireSession();
+  const session = await requireSessionFromRequest();
 
   return await db.query.sprints.findMany({
     where: (model, { eq }) => eq(model.owner, getOwningIdentity(session)),
@@ -42,7 +42,7 @@ const fetchSprint = createServerFn({ method: "GET" })
   .inputValidator((d: { sprintId: string }) => d)
   .handler(async ({ data: { sprintId } }) => {
     console.info("Fetching sprint...");
-    const session = await requireSession();
+    const session = await requireSessionFromRequest();
 
     return await db.query.sprints.findFirst({
       where: (model, { eq, and }) =>
diff --git a/src/db/queries/statuses.ts b/src/db/queries/statuses.ts
index e744bb8..ddb346f 100644
--- a/src/db/queries/statuses.ts
+++ b/src/db/queries/statuses.ts
@@ -3,14 +3,14 @@ import { createServerFn } from "@tanstack/react-start";
 import { db } from "~/db";
 import { statuses, tasks } from "~/db/schema";
 import { asc, eq, sql } from "drizzle-orm";
-import { requireSession } from "~/lib/auth-functions";
+import { requireSessionFromRequest } from "~/lib/session";
 import { getOwningIdentity } from "~/lib/utils";
 import { useEventSource } from "~/hooks/use-event-source";
 
 export const fetchStatuses = createServerFn({ method: "GET" }).handler(
   async () => {
     console.info("Fetching statuses...");
-    const session = await requireSession();
+    const session = await requireSessionFromRequest();
 
     return await db.query.statuses.findMany({
       where: (model, { eq }) => eq(model.owner, getOwningIdentity(session)),
@@ -47,7 +47,7 @@ export const fetchStatusesWithTaskCounts = createServerFn({
   method: "GET",
 }).handler(async () => {
   console.info("Fetching statuses with task counts...");
-  const session = await requireSession();
+  const session = await requireSessionFromRequest();
 
   const statusesWithCounts = await db
     .select({
diff --git a/src/db/queries/tasks.ts b/src/db/queries/tasks.ts
index be9d3e7..6c7b1f8 100644
--- a/src/db/queries/tasks.ts
+++ b/src/db/queries/tasks.ts
@@ -2,7 +2,7 @@ import { queryOptions, useSuspenseQuery } from "@tanstack/react-query";
 import { createServerFn } from "@tanstack/react-start";
 import { db } from "~/db";
 import { Project, TaskWithRelations } from "../schema";
-import { requireSession } from "~/lib/auth-functions";
+import { requireSessionFromRequest } from "~/lib/session";
 import { getOwningIdentity } from "~/lib/utils";
 import { useEventSource } from "~/hooks/use-event-source";
 
@@ -108,7 +108,7 @@ export function mapTaskWithRelations(task: TaskDetailRow): TaskWithRelations {
 const fetchTasks = createServerFn({ method: "GET" })
   .inputValidator((d: { projectId: string }) => d)
   .handler(async ({ data: { projectId } }): Promise<TaskWithRelations[]> => {
-    const session = await requireSession();
+    const session = await requireSessionFromRequest();
 
     const rawTasks = await db.query.tasks.findMany({
       with: boardTaskRelationsForProject,
@@ -148,7 +148,7 @@ export const useTasksQuery = (projectId: string) => {
 const fetchTasksForSprint = createServerFn({ method: "GET" })
   .inputValidator((d: { sprintId: string }) => d)
   .handler(async ({ data: { sprintId } }): Promise<TaskWithRelations[]> => {
-    const session = await requireSession();
+    const session = await requireSessionFromRequest();
 
     const rawTasks = await db.query.tasks.findMany({
       with: boardTaskRelationsForSprint,
@@ -188,7 +188,7 @@ export const useTasksForSprintQuery = (sprintId: string) => {
 export const fetchTask = createServerFn({ method: "GET" })
   .inputValidator((d: string) => d)
   .handler(async ({ data }): Promise<TaskWithRelations | null> => {
-    const session = await requireSession();
+    const session = await requireSessionFromRequest();
     const task = await db.query.tasks.findFirst({
       where(fields, operators) {
         return operators.and(
diff --git a/src/db/queries/users.ts b/src/db/queries/users.ts
index 2d05c04..0ec2cb0 100644
--- a/src/db/queries/users.ts
+++ b/src/db/queries/users.ts
@@ -1,4 +1,4 @@
-import { requireSession } from "~/lib/auth-functions";
+import { requireSessionFromRequest } from "~/lib/session";
 import { queryOptions, useSuspenseQuery } from "@tanstack/react-query";
 import { createServerFn } from "@tanstack/react-start";
 import { eq } from "drizzle-orm";
@@ -55,7 +55,7 @@ export async function getUsersForSession(
 
 const fetchAllUsers = createServerFn({ method: "GET" }).handler(
   async (): Promise<AppUser[]> => {
-    const session = await requireSession();
+    const session = await requireSessionFromRequest();
     return getUsersForSession(session);
   }
 );
diff --git a/src/lib/auth-functions.ts b/src/lib/auth-functions.ts
index d029e66..05104f8 100644
--- a/src/lib/auth-functions.ts
+++ b/src/lib/auth-functions.ts
@@ -1,24 +1,15 @@
 import { createServerFn } from "@tanstack/react-start";
-import { getRequestHeaders } from "@tanstack/react-start/server";
-import { redirect } from "@tanstack/react-router";
-import { auth } from "~/lib/auth";
+import {
+  getSessionFromRequest,
+  requireSessionFromRequest,
+} from "~/lib/session";
 
 export const getSession = createServerFn({ method: "GET" }).handler(async () => {
-  return auth.api.getSession({
-    headers: getRequestHeaders(),
-  });
+  return getSessionFromRequest();
 });
 
 export const requireSession = createServerFn({ method: "GET" }).handler(
   async () => {
-    const session = await auth.api.getSession({
-      headers: getRequestHeaders(),
-    });
-
-    if (!session) {
-      throw redirect({ to: "/sign-in/$" });
-    }
-
-    return session;
+    return requireSessionFromRequest();
   }
 );
diff --git a/src/lib/session.ts b/src/lib/session.ts
new file mode 100644
index 0000000..14a8399
--- /dev/null
+++ b/src/lib/session.ts
@@ -0,0 +1,21 @@
+import { redirect } from "@tanstack/react-router";
+import { getRequestHeaders } from "@tanstack/react-start/server";
+import { auth } from "~/lib/auth";
+
+/** Read the session in server handlers (loaders, server functions, API routes). */
+export async function getSessionFromRequest() {
+  return auth.api.getSession({
+    headers: getRequestHeaders(),
+  });
+}
+
+/** Like getSessionFromRequest but redirects unauthenticated users to sign-in. */
+export async function requireSessionFromRequest() {
+  const session = await getSessionFromRequest();
+
+  if (!session) {
+    throw redirect({ to: "/sign-in/$" });
+  }
+
+  return session;
+}

From f49708d249fc7dfb707b27a5a17bb69c522140c6 Mon Sep 17 00:00:00 2001
From: Philipp Nowinski <mail@pno.dev>
Date: Tue, 19 May 2026 17:55:19 +0200
Subject: [PATCH 2/3] fix: address coderabbit findings

---
 src/db/mutations/attachments.ts | 46 ++++++++++++++++++---------------
 src/db/mutations/sub-tasks.ts   |  4 ++-
 src/db/mutations/tasks.ts       |  5 ++--
 3 files changed, 31 insertions(+), 24 deletions(-)

diff --git a/src/db/mutations/attachments.ts b/src/db/mutations/attachments.ts
index e693347..4057414 100644
--- a/src/db/mutations/attachments.ts
+++ b/src/db/mutations/attachments.ts
@@ -56,31 +56,35 @@ export function useCreateAttachmentMutation() {
   );
 }
 
+export async function deleteAttachmentForOwner(
+  owner: string,
+  attachmentId: string
+) {
+  const attachment = await db.query.attachments.findFirst({
+    where: (model, { eq, and }) =>
+      and(eq(model.id, attachmentId), eq(model.owner, owner)),
+  });
+  if (!attachment) return;
+
+  const utapi = new UTApi();
+  utapi.deleteFiles([attachment.providerFileId]);
+  await db
+    .delete(attachments)
+    .where(
+      and(eq(attachments.id, attachmentId), eq(attachments.owner, owner))
+    );
+
+  await sync(`attachment-update-${attachmentId}`, { data: { id: attachmentId } });
+  await sync(`task-update-${attachment.taskId}`, { data: { id: attachmentId } });
+
+  return { id: attachmentId, taskId: attachment.taskId };
+}
+
 export const deleteAttachment = createServerFn({ method: "POST" })
   .inputValidator(z.object({ id: z.string() }))
   .handler(async ({ data }) => {
     const session = await requireSessionFromRequest();
-
-    const attachment = await db.query.attachments.findFirst({
-      where: (model, { eq, and }) =>
-        and(eq(model.id, data.id), eq(model.owner, getOwningIdentity(session))),
-    });
-    if (!attachment) return;
-    const utapi = new UTApi();
-    utapi.deleteFiles([attachment?.providerFileId]);
-    await db
-      .delete(attachments)
-      .where(
-        and(
-          eq(attachments.id, data.id),
-          eq(attachments.owner, getOwningIdentity(session))
-        )
-      );
-
-    await sync(`attachment-update-${data.id}`, { data });
-    await sync(`task-update-${attachment?.taskId}`, { data });
-
-    return { id: data.id, taskId: attachment?.taskId };
+    return deleteAttachmentForOwner(getOwningIdentity(session), data.id);
   });
 
 export function useDeleteAttachmentMutation() {
diff --git a/src/db/mutations/sub-tasks.ts b/src/db/mutations/sub-tasks.ts
index 35648e0..4ea1712 100644
--- a/src/db/mutations/sub-tasks.ts
+++ b/src/db/mutations/sub-tasks.ts
@@ -131,6 +131,8 @@ const deleteSubTask = createServerFn({ method: "POST" })
         );
       },
     });
+    if (!subTask) return;
+
     await db
       .delete(subTasks)
       .where(
@@ -140,7 +142,7 @@ const deleteSubTask = createServerFn({ method: "POST" })
         )
       );
 
-    await sync(`task-update-${data.id}`, { data });
+    await sync(`task-update-${subTask.taskId}`, { data });
     return subTask;
   });
 
diff --git a/src/db/mutations/tasks.ts b/src/db/mutations/tasks.ts
index 01e00e7..7eda95a 100644
--- a/src/db/mutations/tasks.ts
+++ b/src/db/mutations/tasks.ts
@@ -23,7 +23,7 @@ import z from "zod";
 import { requireSessionFromRequest } from "~/lib/session";
 import { getOwningIdentity } from "~/lib/utils";
 import { sync } from "./sync";
-import { deleteAttachment } from "./attachments";
+import { deleteAttachmentForOwner } from "./attachments";
 import type { QueryClient, QueryKey } from "@tanstack/react-query";
 import { toast } from "sonner";
 
@@ -330,9 +330,10 @@ const deleteTask = createServerFn({ method: "POST" })
         and(eq(model.id, data.id), eq(model.owner, getOwningIdentity(session))),
     });
     if (!task) return;
+    const owner = getOwningIdentity(session);
     await Promise.all(
       task.attachments.map((attachment) =>
-        deleteAttachment({ data: { id: attachment.id } })
+        deleteAttachmentForOwner(owner, attachment.id)
       )
     );
     await db

From 2e0ed3bdd35e77378217c1f58a9b388d222a9594 Mon Sep 17 00:00:00 2001
From: Philipp Nowinski <mail@pno.dev>
Date: Tue, 19 May 2026 18:01:23 +0200
Subject: [PATCH 3/3] fix: address coderabbit findings

---
 src/db/mutations/attachments.ts | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/src/db/mutations/attachments.ts b/src/db/mutations/attachments.ts
index 4057414..ff8d47d 100644
--- a/src/db/mutations/attachments.ts
+++ b/src/db/mutations/attachments.ts
@@ -67,7 +67,11 @@ export async function deleteAttachmentForOwner(
   if (!attachment) return;
 
   const utapi = new UTApi();
-  utapi.deleteFiles([attachment.providerFileId]);
+  const deleteResult = await utapi.deleteFiles([attachment.providerFileId]);
+  if (!deleteResult.success) {
+    throw new Error("Failed to delete attachment file from storage");
+  }
+
   await db
     .delete(attachments)
     .where(
