From fa1fd2b9f53dd4b88c565aac38ea577c1e9f720e Mon Sep 17 00:00:00 2001 From: Roberto Musso Date: Thu, 19 Feb 2026 16:58:46 +0100 Subject: [PATCH] =?UTF-8?q?feat:=20US-006=20=E2=80=94=20Project=20tRPC=20p?= =?UTF-8?q?rocedures=20(CRUD)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 4.6 --- src/main/router/index.ts | 58 +++++++++++++++++++++++++++++++++++----- 1 file changed, 51 insertions(+), 7 deletions(-) diff --git a/src/main/router/index.ts b/src/main/router/index.ts index f1f8de6..f85ac3f 100644 --- a/src/main/router/index.ts +++ b/src/main/router/index.ts @@ -1,6 +1,6 @@ import { initTRPC } from '@trpc/server'; import { z } from 'zod'; -import { eq, asc, inArray } from 'drizzle-orm'; +import { eq, asc, inArray, and } from 'drizzle-orm'; import { getDb } from '../db'; import { clients, projects, tasks } from '../db/schema'; import { getStore } from '../store'; @@ -101,14 +101,40 @@ const clientsRouter = router({ const projectsRouter = router({ list: publicProcedure .input(z.object({ clientId: z.string().optional(), includeArchived: z.boolean().optional() }).optional()) - .query(() => []), - listAll: publicProcedure.query(() => [] as Array<{ id: string; name: string }>), + .query(({ input }) => { + const where = and( + input?.clientId !== undefined ? eq(projects.clientId, input.clientId) : undefined, + !input?.includeArchived ? eq(projects.status, 'active') : undefined, + ); + return getDb().select().from(projects).where(where).orderBy(asc(projects.name)).all(); + }), + + listAll: publicProcedure.query(() => { + return getDb().select({ id: projects.id, name: projects.name }).from(projects).orderBy(asc(projects.name)).all(); + }), + get: publicProcedure .input(z.object({ id: z.string() })) - .query(() => null), + .query(({ input }) => { + const result = getDb().select().from(projects).where(eq(projects.id, input.id)).all(); + return result[0] ?? null; + }), + create: publicProcedure .input(z.object({ name: z.string(), clientId: z.string().optional() })) - .mutation(() => null), + .mutation(({ input }) => { + const id = crypto.randomUUID(); + const now = Date.now(); + getDb().insert(projects).values({ + id, + name: input.name, + clientId: input.clientId ?? null, + status: 'active', + createdAt: now, + }).run(); + return { id }; + }), + update: publicProcedure .input(z.object({ id: z.string(), @@ -117,10 +143,28 @@ const projectsRouter = router({ status: z.enum(['active', 'archived']).optional(), aiSummary: z.string().optional(), })) - .mutation(() => null), + .mutation(({ input }) => { + const set: Partial<{ name: string; clientId: string | null; status: 'active' | 'archived'; aiSummary: string | null }> = {}; + if (input.name !== undefined) set.name = input.name; + if (input.clientId !== undefined) set.clientId = input.clientId; + if (input.status !== undefined) set.status = input.status; + if (input.aiSummary !== undefined) set.aiSummary = input.aiSummary; + if (Object.keys(set).length > 0) { + getDb().update(projects).set(set).where(eq(projects.id, input.id)).run(); + } + return null; + }), + delete: publicProcedure .input(z.object({ id: z.string() })) - .mutation(() => null), + .mutation(({ input }) => { + const db = getDb(); + // Null out projectId on tasks belonging to this project + db.update(tasks).set({ projectId: null }).where(eq(tasks.projectId, input.id)).run(); + // Delete the project + db.delete(projects).where(eq(projects.id, input.id)).run(); + return { success: true as const }; + }), }); const tasksRouter = router({