From f2733c6e72259e46019995765b21ae6b12789df3 Mon Sep 17 00:00:00 2001 From: admin-valentin Date: Fri, 31 Jul 2026 10:45:01 +0000 Subject: [PATCH] feat(observations): add observations.service --- src/observations/observations.service.ts | 47 ++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 src/observations/observations.service.ts diff --git a/src/observations/observations.service.ts b/src/observations/observations.service.ts new file mode 100644 index 0000000..125f50e --- /dev/null +++ b/src/observations/observations.service.ts @@ -0,0 +1,47 @@ +import { Injectable } from '@nestjs/common'; +import { and, desc, eq } from 'drizzle-orm'; +import { db } from '../db/client'; +import { observations } from '../db/schema'; +import { AuditService } from '../audit/audit.service'; +import type { AuthenticatedSession } from '../auth/tenant.guard'; +import type { CreateObservationDto } from './dto'; + +@Injectable() +export class ObservationsService { + constructor(private readonly audit: AuditService) {} + + async list(session: AuthenticatedSession, subjectType?: string, subjectId?: string) { + return db.query.observations.findMany({ + where: and( + eq(observations.tenantId, session.tenantId), + ...(subjectType ? [eq(observations.subjectType, subjectType)] : []), + ...(subjectId ? [eq(observations.subjectId, subjectId)] : []), + ), + orderBy: desc(observations.observedAt), + }); + } + + async create(session: AuthenticatedSession, dto: CreateObservationDto) { + const [row] = await db + .insert(observations) + .values({ + tenantId: session.tenantId, + subjectType: dto.subjectType, + subjectId: dto.subjectId, + metric: dto.metric, + value: dto.value, + unit: dto.unit, + source: dto.source, + observedAt: dto.observedAt ? new Date(dto.observedAt) : new Date(), + confidence: dto.confidence !== undefined ? String(dto.confidence) : undefined, + }) + .returning(); + await this.audit.record(null, { + tenantId: session.tenantId, + actorId: session.userId, + action: 'observation.created', + resource: `observation:${row.id}:${dto.subjectType}/${dto.subjectId}`, + }); + return row; + } +}