From 79ac0bb1d6bf1622acb392a8af33f1d0a682ba60 Mon Sep 17 00:00:00 2001 From: saravanakumardb1 Date: Sat, 18 Apr 2026 18:09:04 -0700 Subject: [PATCH] feat(backend): Phase C.1-C.2 wire domain events from timer + routine repositories to webhook dispatch --- backend/src/modules/routines/repository.ts | 10 +++++++++- backend/src/modules/timers/repository.ts | 14 ++++++++++++-- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/backend/src/modules/routines/repository.ts b/backend/src/modules/routines/repository.ts index 120017e..766d49f 100644 --- a/backend/src/modules/routines/repository.ts +++ b/backend/src/modules/routines/repository.ts @@ -6,6 +6,7 @@ import { getCollection } from '../../lib/datastore.js'; import { getEncryptor, isEncryptedField } from '../../lib/field-encrypt.js'; +import { getEventBus } from '../../lib/event-bus.js'; import type { RoutineDoc, RoutineQuery, BatchUpsertRoutinesResult } from './types.js'; import type { FilterMap } from '@bytelyst/datastore'; @@ -126,7 +127,14 @@ export async function updateRoutine( }; const encrypted = await encryptRoutineFields(merged); const doc = await collection().upsert(encrypted); - return { doc: await decryptRoutineFields(doc), conflict: false }; + const decrypted = await decryptRoutineFields(doc); + if (decrypted.status === 'active' && existing.status !== 'active') { + getEventBus().emit('routine.started', { routineId: decrypted.id, userId: decrypted.userId, name: decrypted.name }); + } + if (decrypted.status === 'completed' && existing.status !== 'completed') { + getEventBus().emit('routine.completed', { routineId: decrypted.id, userId: decrypted.userId, name: decrypted.name }); + } + return { doc: decrypted, conflict: false }; } catch { return { doc: null, conflict: false }; } diff --git a/backend/src/modules/timers/repository.ts b/backend/src/modules/timers/repository.ts index 31685d3..95a9cdc 100644 --- a/backend/src/modules/timers/repository.ts +++ b/backend/src/modules/timers/repository.ts @@ -6,6 +6,7 @@ import { getCollection } from '../../lib/datastore.js'; import { getEncryptor, isEncryptedField } from '../../lib/field-encrypt.js'; +import { getEventBus } from '../../lib/event-bus.js'; import type { TimerDoc, TimerQuery, BatchUpsertResult } from './types.js'; import type { FilterMap } from '@bytelyst/datastore'; @@ -75,7 +76,9 @@ export async function getTimer(id: string, userId: string): Promise { const encrypted = await encryptTimerFields(doc); const created = await collection().create(encrypted); - return decryptTimerFields(created); + const decrypted = await decryptTimerFields(created); + getEventBus().emit('timer.created', { timerId: decrypted.id, userId: decrypted.userId, label: decrypted.label }); + return decrypted; } export async function updateTimer( @@ -102,7 +105,14 @@ export async function updateTimer( }; const encrypted = await encryptTimerFields(merged); const doc = await collection().upsert(encrypted); - return { doc: await decryptTimerFields(doc), conflict: false }; + const decrypted = await decryptTimerFields(doc); + if (decrypted.state === 'fired' && existing.state !== 'fired') { + getEventBus().emit('timer.fired', { timerId: decrypted.id, userId: decrypted.userId, label: decrypted.label }); + } + if (decrypted.state === 'completed' && existing.state !== 'completed') { + getEventBus().emit('timer.completed', { timerId: decrypted.id, userId: decrypted.userId, label: decrypted.label }); + } + return { doc: decrypted, conflict: false }; } catch { return { doc: null, conflict: false }; }