import { Injectable, NotFoundException } from '@nestjs/common'; import { and, desc, eq } from 'drizzle-orm'; import { db } from '../db/client'; import { savedSegments } from '../db/schema'; import { AuditService } from '../audit/audit.service'; import { OutboxService } from '../events/outbox.service'; import { IntelligenceService } from '../intelligence/intelligence.service'; import type { AuthenticatedSession } from '../auth/tenant.guard'; import type { CreateSegmentDto } from './dto'; @Injectable() export class SegmentsService { constructor( private readonly audit: AuditService, private readonly intelligence: IntelligenceService, private readonly outbox: OutboxService, ) {} async list(session: AuthenticatedSession) { return db.query.savedSegments.findMany({ where: eq(savedSegments.tenantId, session.tenantId), orderBy: desc(savedSegments.createdAt), }); } async create(session: AuthenticatedSession, dto: CreateSegmentDto) { return this.outbox.withTransaction(async (tx) => { const [row] = await tx .insert(savedSegments) .values({ tenantId: session.tenantId, createdByUserId: session.userId, name: dto.name, query: dto.query, resultLimit: dto.resultLimit, }) .returning(); await this.audit.record(tx, { tenantId: session.tenantId, actorId: session.userId, action: 'segment.created', resource: `segment:${row.id}`, }); await this.outbox.record(tx, { tenantId: session.tenantId, workspaceId: session.workspaceId, actorId: session.userId, eventType: 'segment.created', aggregateType: 'segment', subjectId: row.id, correlationId: session.correlationId, payload: { name: row.name }, }); return row; }); } /** Re-ruleaza cautarea salvata contra intelligence-api si intoarce rezultate proaspete. */ async run(session: AuthenticatedSession, id: string) { const segment = await this.getById(session, id); const results = await this.intelligence.searchCompanies(segment.query, segment.resultLimit); return { segment, ...results }; } async remove(session: AuthenticatedSession, id: string) { const segment = await this.getById(session, id); await this.outbox.withTransaction(async (tx) => { await tx.delete(savedSegments).where(eq(savedSegments.id, segment.id)); await this.audit.record(tx, { tenantId: session.tenantId, actorId: session.userId, action: 'segment.deleted', resource: `segment:${id}`, }); await this.outbox.record(tx, { tenantId: session.tenantId, workspaceId: session.workspaceId, actorId: session.userId, eventType: 'segment.deleted', aggregateType: 'segment', subjectId: id, correlationId: session.correlationId, payload: {}, }); }); return { deleted: true }; } private async getById(session: AuthenticatedSession, id: string) { const segment = await db.query.savedSegments.findFirst({ where: and(eq(savedSegments.id, id), eq(savedSegments.tenantId, session.tenantId)), }); if (!segment) { throw new NotFoundException('Segment not found'); } return segment; } }