feat(content): Phase 8 content generation (Faz A+B) for Sase.tr
Hybrid content automation pilot: generation + review + drafts live in the panel (reusing the insight pipeline's DeepSeek client, prompt_templates versioning, cost_ledger and budget_settings); publishing/distribution will go through n8n (Faz C, not built). Channels: blog, LinkedIn, X, Instagram. Topic sourcing is automatic (LLM-generated ideas). Approval model: drafts sit in the panel for manual review/edit/publish. Faz A (worker): - ContentTopic / ContentDraft Prisma models (content_topics, content_drafts) - content-prompts.ts: 5 seed prompts (topic ideas[pro] + blog[pro] + linkedin/x/instagram[flash]), Turkish B2B automotive tone, per-channel JSON schemas - content-budget.ts: separate budget envelope (sums only content_* spend) - content-topics job (auto idea gen, backlog-capped, title dedupe) + content-generate job (queued topic -> one draft per channel) - content-pipeline scheduler (separate BullMQ queue, topics@*/8h, generate@*/10min), wired into index.ts; seeded via seed-runtime - content budget settings (caps + content_paused kill switch); seed default content_paused=true for a safe first deploy Faz B (web): - /content (queue + auto/manual triggers + manual topic form), /content/t/[id] (per-channel draft cards: preview, JSON edits, approve/reject), /content/costs (content-only spend) - server actions (audit-logged), manual trigger API routes, contentQueue(), nav + Cmd+K entries - content caps surfaced on /insights/settings/budgets + whitelisted Both packages typecheck. Schema applies on deploy (web start runs prisma db push). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -364,6 +364,71 @@ model EvalRun {
|
||||
@@map("eval_runs")
|
||||
}
|
||||
|
||||
// ---------- Phase 8a: Content generation ----------
|
||||
|
||||
// A topic/brief for content generation. Either auto-generated by the
|
||||
// content-topics job (LLM idea generation) or entered manually. One topic
|
||||
// fans out into one ContentDraft per selected channel.
|
||||
model ContentTopic {
|
||||
id String @id @default(cuid())
|
||||
projectKey String
|
||||
title String
|
||||
brief String @db.Text
|
||||
angle String? @db.Text
|
||||
channels String[] // ["blog","linkedin","x","instagram"]
|
||||
keywords String[]
|
||||
/// queued | generating | drafted | archived
|
||||
status String @default("queued")
|
||||
/// auto | manual
|
||||
source String @default("auto")
|
||||
fingerprint String? // dedupe near-identical auto topics
|
||||
sourcePromptTag String?
|
||||
sourcePromptVersion Int?
|
||||
sourceModel String?
|
||||
sourceCostUsd Float @default(0)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
drafts ContentDraft[]
|
||||
|
||||
@@index([projectKey, status])
|
||||
@@index([fingerprint])
|
||||
@@map("content_topics")
|
||||
}
|
||||
|
||||
// One generated piece of content for a single channel. Lives as a draft in
|
||||
// the panel; founder reviews/edits, then publishes via the n8n webhook
|
||||
// (Phase 8c). bodyJson holds the channel-specific generated structure;
|
||||
// founderEdits holds any human overrides applied before publish.
|
||||
model ContentDraft {
|
||||
id String @id @default(cuid())
|
||||
topicId String
|
||||
projectKey String
|
||||
/// blog | linkedin | x | instagram
|
||||
channel String
|
||||
/// draft | approved | publishing | published | failed | rejected
|
||||
status String @default("draft")
|
||||
bodyJson Json
|
||||
founderEdits Json?
|
||||
publishedUrl String?
|
||||
n8nExecutionId String?
|
||||
publishError String?
|
||||
sourcePromptTag String
|
||||
sourcePromptVersion Int
|
||||
sourceModel String
|
||||
sourceCostUsd Float @default(0)
|
||||
publishedAt DateTime?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
topic ContentTopic @relation(fields: [topicId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@index([projectKey, status])
|
||||
@@index([topicId])
|
||||
@@index([channel, status])
|
||||
@@map("content_drafts")
|
||||
}
|
||||
|
||||
// ---------- Phase 7a: Sase user-management ----------
|
||||
|
||||
// Founder-only notes pinned to a Sase user. Stored panel-side (KVKK minimize:
|
||||
|
||||
Reference in New Issue
Block a user