diff --git a/backend/src/db/schema.ts b/backend/src/db/schema.ts index c70dc8a..913ba7f 100644 --- a/backend/src/db/schema.ts +++ b/backend/src/db/schema.ts @@ -3,7 +3,6 @@ import { uuid, text, integer, - serial, timestamp, jsonb, pgEnum, @@ -41,7 +40,7 @@ export interface ProgressNote { export const tasks = pgTable("tasks", { id: uuid("id").defaultRandom().primaryKey(), - taskNumber: serial("task_number").notNull(), + taskNumber: integer("task_number"), title: text("title").notNull(), description: text("description"), source: taskSourceEnum("source").notNull().default("donovan"), diff --git a/backend/src/index.ts b/backend/src/index.ts index 7c0ecc2..a6ff7b3 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -2,9 +2,38 @@ import { Elysia } from "elysia"; import { cors } from "@elysiajs/cors"; import { taskRoutes } from "./routes/tasks"; import { auth } from "./lib/auth"; +import { db } from "./db"; +import { tasks } from "./db/schema"; +import { isNull, asc, sql } from "drizzle-orm"; const PORT = process.env.PORT || 3100; +// Backfill task numbers for existing tasks that don't have one +async function backfillTaskNumbers() { + const unnumbered = await db + .select() + .from(tasks) + .where(isNull(tasks.taskNumber)) + .orderBy(asc(tasks.createdAt)); + + if (unnumbered.length === 0) return; + + const maxNum = await db + .select({ max: sql`COALESCE(MAX(${tasks.taskNumber}), 0)` }) + .from(tasks); + let next = (maxNum[0]?.max ?? 0) + 1; + + for (const task of unnumbered) { + await db + .update(tasks) + .set({ taskNumber: next++ }) + .where(sql`${tasks.id} = ${task.id}`); + } + console.log(`Backfilled ${unnumbered.length} task numbers (${next - unnumbered.length} to ${next - 1})`); +} + +backfillTaskNumbers().catch(console.error); + const app = new Elysia() .use( cors({ diff --git a/backend/src/routes/tasks.ts b/backend/src/routes/tasks.ts index 3330e30..f2adfec 100644 --- a/backend/src/routes/tasks.ts +++ b/backend/src/routes/tasks.ts @@ -119,6 +119,12 @@ export const taskRoutes = new Elysia({ prefix: "/api/tasks" }) const maxPos = await db .select({ max: sql`COALESCE(MAX(${tasks.position}), 0)` }) .from(tasks); + // Get next task number + const maxNum = await db + .select({ max: sql`COALESCE(MAX(${tasks.taskNumber}), 0)` }) + .from(tasks); + const nextNumber = (maxNum[0]?.max ?? 0) + 1; + const newTask = await db .insert(tasks) .values({ @@ -128,6 +134,7 @@ export const taskRoutes = new Elysia({ prefix: "/api/tasks" }) status: body.status || "queued", priority: body.priority || "medium", position: (maxPos[0]?.max ?? 0) + 1, + taskNumber: nextNumber, progressNotes: [], }) .returning();