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; } }