From 939d503f3a6712208c72c4c7531d0b15e4f5e727 Mon Sep 17 00:00:00 2001 From: Roberto Musso Date: Thu, 19 Feb 2026 17:05:06 +0100 Subject: [PATCH] =?UTF-8?q?feat:=20US-008=20=E2=80=94=20Checkpoint=20and?= =?UTF-8?q?=20Note=20tRPC=20procedures=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 | 89 +++++++++++++++++++++++++++++++++++----- 1 file changed, 79 insertions(+), 10 deletions(-) diff --git a/src/main/router/index.ts b/src/main/router/index.ts index 8858319..0a7dd94 100644 --- a/src/main/router/index.ts +++ b/src/main/router/index.ts @@ -3,7 +3,7 @@ import { z } from 'zod'; import { eq, asc, inArray, and, or, like, sql } from 'drizzle-orm'; import { alias } from 'drizzle-orm/sqlite-core'; import { getDb } from '../db'; -import { clients, projects, tasks } from '../db/schema'; +import { clients, projects, tasks, checkpoints, notes } from '../db/schema'; import { getStore } from '../store'; const t = initTRPC.create(); @@ -295,7 +295,11 @@ const tasksRouter = router({ const checkpointsRouter = router({ list: publicProcedure .input(z.object({ projectId: z.string().optional() }).optional()) - .query(() => []), + .query(({ input }) => { + const where = input?.projectId !== undefined ? eq(checkpoints.projectId, input.projectId) : undefined; + return getDb().select().from(checkpoints).where(where).orderBy(asc(checkpoints.date)).all(); + }), + create: publicProcedure .input(z.object({ projectId: z.string(), @@ -304,7 +308,21 @@ const checkpointsRouter = router({ isAiSuggested: z.number().optional(), isApproved: z.number().optional(), })) - .mutation(() => null), + .mutation(({ input }) => { + const id = crypto.randomUUID(); + const now = Date.now(); + getDb().insert(checkpoints).values({ + id, + projectId: input.projectId, + title: input.title, + date: input.date, + isAiSuggested: input.isAiSuggested ?? 0, + isApproved: input.isApproved ?? 0, + createdAt: now, + }).run(); + return { id }; + }), + update: publicProcedure .input(z.object({ id: z.string(), @@ -312,28 +330,79 @@ const checkpointsRouter = router({ date: z.number().optional(), isApproved: z.number().optional(), })) - .mutation(() => null), + .mutation(({ input }) => { + const set: Partial<{ title: string; date: number; isApproved: number }> = {}; + if (input.title !== undefined) set.title = input.title; + if (input.date !== undefined) set.date = input.date; + if (input.isApproved !== undefined) set.isApproved = input.isApproved; + if (Object.keys(set).length > 0) { + getDb().update(checkpoints).set(set).where(eq(checkpoints.id, input.id)).run(); + } + return null; + }), + delete: publicProcedure .input(z.object({ id: z.string() })) - .mutation(() => null), + .mutation(({ input }) => { + getDb().delete(checkpoints).where(eq(checkpoints.id, input.id)).run(); + return { success: true as const }; + }), }); const notesRouter = router({ list: publicProcedure .input(z.object({ projectId: z.string().optional() }).optional()) - .query(() => []), + .query(({ input }) => { + const where = input?.projectId !== undefined ? eq(notes.projectId, input.projectId) : undefined; + return getDb() + .select({ id: notes.id, projectId: notes.projectId, title: notes.title, createdAt: notes.createdAt, updatedAt: notes.updatedAt }) + .from(notes) + .where(where) + .orderBy(asc(notes.createdAt)) + .all(); + }), + get: publicProcedure .input(z.object({ id: z.string() })) - .query(() => null), + .query(({ input }) => { + const result = getDb().select().from(notes).where(eq(notes.id, input.id)).all(); + return result[0] ?? null; + }), + create: publicProcedure .input(z.object({ title: z.string(), content: z.string(), projectId: z.string().optional() })) - .mutation(() => null), + .mutation(({ input }) => { + const id = crypto.randomUUID(); + const now = Date.now(); + getDb().insert(notes).values({ + id, + title: input.title, + content: input.content, + projectId: input.projectId ?? null, + createdAt: now, + updatedAt: now, + }).run(); + return { id }; + }), + update: publicProcedure .input(z.object({ id: z.string(), title: z.string().optional(), content: z.string().optional() })) - .mutation(() => null), + .mutation(({ input }) => { + const set: Partial<{ title: string; content: string; updatedAt: number }> = {}; + if (input.title !== undefined) set.title = input.title; + if (input.content !== undefined) set.content = input.content; + // Always update updatedAt + set.updatedAt = Date.now(); + getDb().update(notes).set(set).where(eq(notes.id, input.id)).run(); + return null; + }), + delete: publicProcedure .input(z.object({ id: z.string() })) - .mutation(() => null), + .mutation(({ input }) => { + getDb().delete(notes).where(eq(notes.id, input.id)).run(); + return { success: true as const }; + }), }); const settingsRouter = router({