From f2c3258b53dcc39c516221e7cadccfb91eea8692 Mon Sep 17 00:00:00 2001 From: saravanakumardb1 Date: Mon, 6 Apr 2026 10:45:03 -0700 Subject: [PATCH] =?UTF-8?q?fix(backend):=20review=20fixes=20=E2=80=94=20pe?= =?UTF-8?q?rsist=20requiresApproval,=20shutdown=20hook,=20productId=20chec?= =?UTF-8?q?k,=20GET=20by=20ID?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - repository.ts: persist requiresApproval field in createPromptTemplate (was silently dropped) - server.ts: register onClose hook to call stopSchedulerLoop() on graceful shutdown - scheduler.ts: add productId check in webhook trigger note lookup - scheduler.ts: add GET /prompt-schedules/:id and GET /prompt-webhooks/:id endpoints --- backend/src/modules/note-prompts/repository.ts | 1 + backend/src/modules/note-prompts/scheduler.ts | 18 +++++++++++++++++- backend/src/server.ts | 3 ++- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/backend/src/modules/note-prompts/repository.ts b/backend/src/modules/note-prompts/repository.ts index 8fa64cc..dec657c 100644 --- a/backend/src/modules/note-prompts/repository.ts +++ b/backend/src/modules/note-prompts/repository.ts @@ -40,6 +40,7 @@ export async function createPromptTemplate( outputType: input.outputType ?? 'new_note', category: input.category ?? 'transform', isBuiltin: false, + requiresApproval: input.requiresApproval ?? false, model: input.model, temperature: input.temperature, maxTokens: input.maxTokens, diff --git a/backend/src/modules/note-prompts/scheduler.ts b/backend/src/modules/note-prompts/scheduler.ts index f6b76b8..ffc50df 100644 --- a/backend/src/modules/note-prompts/scheduler.ts +++ b/backend/src/modules/note-prompts/scheduler.ts @@ -272,6 +272,14 @@ export async function promptSchedulerRoutes(app: FastifyInstance): Promise return doc; }); + app.get('/prompt-schedules/:id', async (req) => { + const userId = getUserId(req); + const { id } = req.params as { id: string }; + const doc = await scheduleCollection().findById(id, userId); + if (!doc || doc.userId !== userId) throw new NotFoundError('Schedule not found'); + return doc; + }); + app.patch('/prompt-schedules/:id', async (req) => { const userId = getUserId(req); const { id } = req.params as { id: string }; @@ -332,6 +340,14 @@ export async function promptSchedulerRoutes(app: FastifyInstance): Promise return doc; }); + app.get('/prompt-webhooks/:id', async (req) => { + const userId = getUserId(req); + const { id } = req.params as { id: string }; + const doc = await webhookCollection().findById(id, userId); + if (!doc || doc.userId !== userId) throw new NotFoundError('Webhook not found'); + return doc; + }); + app.patch('/prompt-webhooks/:id', async (req) => { const userId = getUserId(req); const { id } = req.params as { id: string }; @@ -369,7 +385,7 @@ export async function promptSchedulerRoutes(app: FastifyInstance): Promise if (!template) throw new NotFoundError('Associated template not found'); const note = await noteRepo.getNote(input.noteId, input.workspaceId); - if (!note || note.userId !== userId) throw new NotFoundError('Note not found'); + if (!note || note.userId !== userId || note.productId !== PRODUCT_ID) throw new NotFoundError('Note not found'); const noteBody = stripHtmlForEmbedding(note.body ?? ''); const result = await executePrompt(template, { diff --git a/backend/src/server.ts b/backend/src/server.ts index 1e2a33c..3ba71b8 100644 --- a/backend/src/server.ts +++ b/backend/src/server.ts @@ -10,7 +10,7 @@ import { noteTaskRoutes } from './modules/note-tasks/routes.js'; import { savedViewRoutes } from './modules/saved-views/routes.js'; import { workspaceRoutes } from './modules/workspaces/routes.js'; import { notePromptRoutes } from './modules/note-prompts/routes.js'; -import { promptSchedulerRoutes, startSchedulerLoop } from './modules/note-prompts/scheduler.js'; +import { promptSchedulerRoutes, startSchedulerLoop, stopSchedulerLoop } from './modules/note-prompts/scheduler.js'; import { initCosmosIfNeeded } from './lib/cosmos-init.js'; import { initEncryption } from './lib/field-encrypt.js'; import { initDatastore } from './lib/datastore.js'; @@ -68,6 +68,7 @@ await registerApiPlugin(promptSchedulerRoutes); // ── Start scheduler loop (F25) ──────────────────────────────────── startSchedulerLoop(); +app.addHook('onClose', async () => { stopSchedulerLoop(); }); // ── Public read-only share (no auth) ─────────────────────────────── app.get('/api/public/note-shares/:token', async (req, reply) => {