Full Documentation
Comprehensive developer and design documentation for InkHive.
InkHive — Documentation
Table of contents
- Purpose & problem solved
- Quick overview (no repo steps)
- System design & architecture
- Detailed agents & workflows
- Data model (Convex) — examples
- API reference (detailed)
- AI prompts & generation details
- Security & auth model
- Environment variables & deployment checklist
- Testing, observability & runbook
- Alternatives & comparison tables
- Contributing & code map
- Related links
Purpose & problem solved
InkHive addresses the common marketing problem of scaling high-quality, cross-channel content from a single idea. It automates generation, organizes drafts, and provides a reliable publishing pipeline so teams can:
- Produce a publish-ready blog post, SEO metadata, social posts, and newsletter copy from one seed idea.
- Track progress and edits in a realtime UI.
- Publish reliably with retries and per-platform error reporting.
Who benefits:
- Content marketers needing consistency across channels.
- Agencies producing many variations from limited briefs.
- Startups automating content workflows with auditability.
Quick overview (no repo steps)
This section summarizes how components interact without repo-level onboarding commands.
- User creates a content project in the UI (topic or article text).
- The frontend writes a
contentProjectsdocument into Convex and triggers a durable Inngest workflowcontent/generate. - Inngest's
contentPipelineorchestrates AI generation (blog → social/email/SEO) and writes outputs back to Convex. - UI subscribes to Convex and shows per-job progress and generated drafts.
- When the user requests publish, the frontend triggers
content/publish, and Inngest runspublishContentto publish in parallel to chosen platforms.
System design & architecture
High-level components:
- Frontend: Next.js (app router) — UI, Clerk auth, minimal server routes for uploads and triggering Inngest.
- Realtime data & transactional API: Convex — holds
contentProjects, job statuses, errors, published history. - Orchestration: Inngest — durable, observable execution for multi-step AI tasks and parallel publishing.
- AI engine: Google Generative AI — used in Inngest steps to generate natural language artifacts.
- Integrations: Resend (email), and social publishers under
lib/publish/.
Design rationale:
- Convex for fast real-time UX and simple serverless data model with indexes.
- Inngest for complex background orchestration: retries, step-wise logging, parallelism, and observability.
Sequence diagram (conceptual):
- [UI] -> (Convex.createProject) -> [Convex]
- [UI] -> (POST /api/trigger-inngest) -> [Next API] -> (inngest.send)
- [Inngest] -> (contentPipeline) -> [AI steps] -> (Convex.save*) -> [Convex]
- [UI] subscribe -> [Convex] updates
- [UI] publish -> (POST /api/trigger-inngest publish) -> [Inngest.publishContent] -> [Platforms]
Note: Replace sequence diagram with an SVG in
public/architecture.svgfor visual docs.
Detailed agents & workflows
This section documents each Inngest function, its triggers, inputs, outputs, and failure semantics.
contentPipeline (inngest/functions/content-pipeline.ts)
- Trigger: event
content/generate - Configuration: retries = 3, optimizeParallelism = true
- Responsibilities:
- Mark
contentProjects.status = "generating" - Run
generateBlogPost(must complete first because downstream agents consume the blog output) - In parallel run
generateSocialPosts,generateEmailNewsletter,generateSeoMetadata - On completion, set
status = "completed" - On any error, call
api.contentProjects.recordErrorwith step and stack trace
- Mark
Inputs (event.data):
- projectId: string
- inputType: "topic" | "article"
- inputContent: string
Primary outputs (Convex mutations called):
- updateProjectStatus(projectId, status)
- saveBlogPost(projectId, title, content, excerpt, readingTime)
- saveSocialPosts(projectId, twitter, linkedin, facebook, instagram, medium)
- saveEmailNewsletter(projectId, subjectLines..., htmlContent, plainText)
- saveSeoMetadata(projectId, title, description, keywords, slug)
Failure handling:
- Each step wrapped in
step.runwith automatic retry semantics. - If the blog generation fails, pipeline records error and stops dependent step execution.
- Parallel step failures are recorded per-job; pipeline still tries to complete other jobs.
publishContent (inngest/functions/publish-content.ts)
- Trigger: event
content/publish - Responsibilities:
- Fetch project snapshot from Convex (getProjectById)
- For each requested platform run publisher (parallel)
- Update per-platform publish status via
updatePublishStatus - Return consolidated results and record per-platform errors
Failure handling:
- Retries configured at function level
onFailurelogs exhausted retries for observability- Publishing continues for other platforms if one platform fails
Data model (Convex) — examples
Table: contentProjects (see convex/schema.ts)
Example document (abridged):
{
"_id": "proj_abc123",
"userId": "user_xyz",
"inputType": "topic",
"inputContent": "How AI improves conversion",
"status": "completed",
"jobStatus": {
"blogPost": "completed",
"socialPosts": "completed",
"emailNewsletter": "completed",
"seoMetadata": "completed"
},
"blogPost": {
"title": "How AI Improves Conversion",
"content": "# Intro\n...markdown content...",
"excerpt": "AI boosts conversion by...",
"readingTime": 6,
"isEdited": false
},
"socialPosts": {
"twitter": { "text": "AI can boost conversion...", "status": "draft" }
},
"createdAt": 1680000000000,
"updatedAt": 1680000100000
}Indexes used:
- by_user (userId)
- by_status (status)
- by_created_at (createdAt)
Guidelines:
- Use indexes for queries in Convex; avoid filter() usage.
- Keep large collections as separate tables (no unbounded arrays inside documents).
API reference (detailed)
This section lists public HTTP endpoints and the Convex API surface used by the frontend.
POST /api/trigger-inngest
Trigger generation for a project.
Request body
{
"projectId": "proj_abc123",
"inputType": "topic",
"inputContent": "Single idea to expand"
}Successful response
{
"success": true,
"projectId": "proj_abc123"
}Error response (example)
{
"error": "Failed to trigger content generation"
}Internal Convex functions (examples of usage from frontend):
- api.contentProjects.createProject (mutation) — creates a new content project (auth required)
- api.contentProjects.getUserProjects (query) — list projects for current user
- api.contentProjects.getProject (query) — get single project (auth required)
- api.contentProjects.updateBlogPost / updateSocialPost / updateEmailNewsletter (mutations) — user edits
Request/response patterns for Convex calls are typed in convex/_generated and executed via Convex client.
POST /api/upload
- Accepts: multipart/form-data
file - Returns:
{ url: string } - Implementation note: currently returns data URL placeholder; replace with signed URL uploads to stable storage (Vercel Blob, S3, etc.)
AI prompts & generation details
This section documents the high-level prompt engineering and expected outputs for each agent. Keep prompts in inngest/steps/ai-generation/* and version them when updated.
General guidance:
- Use deterministic system prompt elements for style (tone, length, audience).
- Request structured output (markdown for blog, JSON for metadata) to simplify parsing.
- Include examples in the prompt to reduce hallucinations.
Example blog-generation prompt (conceptual):
System: You are a professional marketing copywriter. Produce a long-form blog post in Markdown with title, subheadings, and conclusion. Target audience: B2B SaaS marketers. Tone: authoritative but friendly.
User: Topic: "How AI improves conversion"
Output: JSON with keys: title, content(markdown), excerpt(<=150 chars), readingTime (minutes)Example social-post prompt (derived from blog):
Create platform-specific short posts for Twitter (X), LinkedIn, and Instagram captions using the blog title and excerpt. Limit Twitter to 280 characters, LinkedIn to 600, Instagram caption to 2200. Provide optional image prompt.SEO metadata prompt (structured JSON):
Return a slug (URL-friendly), meta title <= 60 chars, meta description 150-160 chars, and 5 keywords as array.Prompt versioning:
- Keep prompt text in source files and add a comment with a short changelog when altering behavior.
Cost & safety:
- Log token usage per step (optional) and set sensible max tokens for long-form content.
- Add moderation checks if exposing content to public channels.
Security & auth model
Auth providers:
- Clerk (frontend) — issues JWTs used by Convex auth.config.ts for server-side identity.
Convex security patterns:
- UI-facing mutations must derive identity server-side using
ctx.auth.getUserIdentity(). - Avoid accepting userId arguments for authorization — always use server-derived identity.
- Inngest jobs call Convex queries/mutations without a user token; the security model relies on unguessable
projectIdand server-side validation where necessary.
Sensitive data handling:
- Never store API keys or secrets in the repo. Use environment variables or secret manager.
- When publishing to third-party platforms, encrypt keys in your deployment platform and rotate regularly.
Operational security:
- Log errors and redact PII before sending logs to external systems.
Environment variables & deployment checklist
Minimum environment variables (example):
- NEXT_PUBLIC_CONVEX_URL — Convex deployment URL
- CLERK_JWT_ISSUER_DOMAIN — Clerk OIDC issuer domain
- GOOGLE_API_KEY (or equivalent) — Generative AI credentials
- RESEND_API_KEY — email sending
- SOCIAL_TWITTER_TOKEN, SOCIAL_LINKEDIN_TOKEN, SOCIAL_FACEBOOK_TOKEN, etc.
- INNGEST_API_KEY (if using hosted Inngest)
Deployment checklist:
- Configure Convex deployment and set NEXT_PUBLIC_CONVEX_URL.
- Provision Inngest (hosted or self-host) and set API keys.
- Add platform credentials (Twitter, LinkedIn, Resend) in deployment secrets.
- Add monitoring & alerting for Inngest failures and Convex function errors.
Testing, observability & runbook
Testing:
- Add Convex unit tests using convex-test + vitest for core mutations and queries.
- Add integration tests for Inngest functions by mocking Convex responses (or spinning a test Convex instance).
Logs & monitoring:
- Inngest step logs give step-level visibility. Aggregate with a logging backend (Datadog, Logflare).
- Record job-level errors in Convex via
recordErrorfor historic analysis.
Runbook (high-level):
- If pipeline fails for many projects, check Inngest dashboard for failing steps.
- Query Convex
contentProjectsfor documents withstatus: failedand inspecterrorfield. - For publishing failures, inspect per-platform
errorfields incontentProjects.socialPostsandemailNewsletter. - Rotate credentials if a platform starts returning auth errors.
Contributing & code map
Primary folders:
- app/ — Next.js app components and pages
- components/ — shared UI
- convex/ — schema.ts and server functions (queries/mutations)
- inngest/ — client.ts, functions/, steps/
- lib/publish/ — platform-specific publishing logic
- public/ — static assets and suggested SVG diagrams
How to add a new AI step:
- Create an
inngest/steps/ai-generation/<your-step>.tswith prompt and helper parsing. - Wire the step into
contentPipelineor a new Inngest function. - Add Convex mutation to persist results.
- Add tests and log token usage.
Related links
- Convex docs: https://convex.dev/docs
- Inngest docs: https://www.inngest.com/docs
- Google Generative AI: https://developers.google.com/generative-ai
- Clerk docs: https://docs.clerk.com
- Resend docs: https://resend.com/docs
If you want, next actions I can take:
- Insert real prompt text from
inngest/steps/ai-generationinto this file and version them. - Generate a visual architecture SVG and add it to
public/. - Create a detailed runbook (incident playbook) with exact commands and queries for on-call.