From 925ce11a064e1366aef0dba406bcfed8f08f25fa Mon Sep 17 00:00:00 2001 From: admin-valentin Date: Sat, 1 Aug 2026 12:32:04 +0000 Subject: [PATCH] feat(CC-054): add @Public ingest endpoint with X-Ingest-Key auth --- .../financial-intelligence.controller.ts | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/financial-intelligence/financial-intelligence.controller.ts b/src/financial-intelligence/financial-intelligence.controller.ts index 640f2c8..d786d96 100644 --- a/src/financial-intelligence/financial-intelligence.controller.ts +++ b/src/financial-intelligence/financial-intelligence.controller.ts @@ -1,14 +1,14 @@ -import { Body, Controller, Get, Post, Query } from '@nestjs/common'; +import { Body, Controller, Get, Headers, Post, Query, UnauthorizedException } from '@nestjs/common'; import { desc, isNull, or, eq, and, gte } from 'drizzle-orm'; import { CurrentSession } from '../auth/session.decorator'; import type { AuthenticatedSession } from '../auth/tenant.guard'; +import { Public } from '../auth/public.decorator'; import { db } from '../db/client'; import { financialSignals } from '../db/schema'; import { IngestSignalsDto } from './dto'; @Controller('financial-intelligence') export class FinancialIntelligenceController { - /** GET /v1/financial-intelligence/signals — semnale active pentru tenant */ @Get('signals') async signals( @CurrentSession() session: AuthenticatedSession, @@ -33,16 +33,20 @@ export class FinancialIntelligenceController { }); } - /** POST /v1/financial-intelligence/ingest — webhook pentru n8n */ + /** POST /v1/financial-intelligence/ingest — n8n webhook, semnat cu X-Ingest-Key */ + @Public() @Post('ingest') async ingest( - @CurrentSession() session: AuthenticatedSession, + @Headers('x-ingest-key') ingestKey: string | undefined, @Body() dto: IngestSignalsDto, ) { - if (!dto.signals || dto.signals.length === 0) { - return { ingested: 0 }; + const expected = process.env.INGEST_SECRET; + if (expected && ingestKey !== expected) { + throw new UnauthorizedException('Invalid ingest key'); } + if (!dto.signals || dto.signals.length === 0) return { ingested: 0 }; + const rows = dto.signals.map((s) => ({ tenantId: dto.tenantId ?? null, category: s.category ?? 'macro',