530f81416a
Replaces the Redis-over-Tailscale handoff with a far simpler HTTP surface on the existing public API — no Redis client, Tailscale, or firewall changes needed on the dev side. - GET /ai/stream — SSE feed of every ingested message, reads the internal Redis stream; resumes from Last-Event-ID on reconnect (no missed messages); heartbeats keep the connection warm through proxies - POST /ai/drafts — writeback: creates a ContentDraft (PENDING_REVIEW) that shows up in the admin /admin/drafts review UI - AiStreamGuard — static bearer token auth (AI_STREAM_TOKEN), accepts header or ?token= query for browser EventSource - Remove Tailscale sidecar + public Redis port; Redis stays internal-only Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
25 lines
490 B
TypeScript
25 lines
490 B
TypeScript
import { IsString, IsIn, IsOptional, IsNumber, IsObject, Min, Max } from 'class-validator';
|
|
import { DraftType } from '@prisma/client';
|
|
|
|
const DRAFT_TYPES: DraftType[] = ['EVENT', 'SEVA_TASK', 'FAQ_ITEM'];
|
|
|
|
export class CreateDraftDto {
|
|
@IsString()
|
|
tenantId!: string;
|
|
|
|
@IsString()
|
|
sourceMessageId!: string;
|
|
|
|
@IsIn(DRAFT_TYPES)
|
|
type!: DraftType;
|
|
|
|
@IsObject()
|
|
proposedJson!: Record<string, unknown>;
|
|
|
|
@IsOptional()
|
|
@IsNumber()
|
|
@Min(0)
|
|
@Max(1)
|
|
confidence?: number;
|
|
}
|