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:
Semih
2026-05-24 00:11:05 +03:00
parent 565ad5af59
commit fdce3f6bd0
22 changed files with 1856 additions and 1 deletions

View File

@@ -18,6 +18,7 @@ import {
LayoutDashboardIcon,
LightbulbIcon,
LogOutIcon,
PenLineIcon,
ScrollTextIcon,
Settings2Icon,
SlidersHorizontalIcon,
@@ -94,6 +95,17 @@ export function CommandPalette({ projects }: { projects: ProjectLite[] }) {
<CommandSeparator />
<CommandGroup heading="Content">
<CommandItem keywords={["content","icerik","konu","kuyruk","queue"]} onSelect={() => go("/content")}>
<PenLineIcon /> İçerik kuyruğu
</CommandItem>
<CommandItem keywords={["content","cost","maliyet","spend"]} onSelect={() => go("/content/costs")}>
<CoinsIcon /> İçerik maliyeti
</CommandItem>
</CommandGroup>
<CommandSeparator />
<CommandGroup heading="Projects">
{projects.map((p) => (
<CommandItem