Coming soon

See how OmniChan is
built.

We’re documenting the system behind OmniChan — what we’ve shipped, what’s in build, and how each capability is verified.

Back to OmniChan

23recorded

decisions

49dated

milestones ahead

86/170

features shipped

3860/3863

tests passing

170 capabilities tracked

86 Shipped44 In Build40 Planned

gate

Push a change through it

The gate is the product’s spine, so here it is working. Choose who proposes, send it to the queue, and decide. The audit log fills in as you go — and the one control that would skip it does nothing, because in the API that transition does not exist.

1 · Who is proposing?

The change

Cut bids on 6 losing keywords (−£310/mo)

Run run_8f2a · 4 steps · £0.004 · full diff attached

2 · The queue

Nothing waiting. Send a change to see the gate work.

3 · Audit log

Append-only. Every row carries the actor that caused it.

studio

Where the creative lives

Marketing runs on pictures, so two of these features are about handling them properly: one library every channel draws from, and a pipeline that turns a single upload into every size an ad platform demands.

F-033

Media library

upload once, tag, reuse — thumbnails and transcodes on the way in

F-055

Ad asset pipeline

one upload, the five sizes Google Ads asks for

The uploaded source image
source

ss26-af1-pastel.jpg

1800×1800 · 261 KB · uploaded once

Focal point
  • Landscape1200×628

    Search · Display · PMax

  • Square1200×1200

    Display · Discover

  • Portrait960×1200

    PMax · Demand Gen

  • Logo strip1200×300

    Responsive Search

  • Story1080×1920

    Demand Gen vertical

Generated with sharp on upload, not on request — an ad platform rejecting a campaign at 4pm because a derivative was still rendering is not a trade worth making.

channels

One adapter per channel

Every platform implements the same interface, so adding one is a single file and a registry row — the publisher, the inbox and the analytics never change. Each row names the feature that builds it, and shows that feature’s real status.

5/15 shipped
channeltracknotesfeaturestatus
LinkedInorganicPages + personal postingF-041done
FacebookorganicOne Graph surface, two adaptersF-042done
InstagramorganicShares the Graph adapterF-042done
YouTubeorganicUploads + PubSubHubbubF-043done
XorganicAfter the first four are provenF-044in progress
ThreadsorganicAfter the first four are provenF-044in progress
TikTokorganicAfter the first four are provenF-044in progress
PinterestorganicAfter the first four are provenF-044in progress
Google BusinessorganicLocal profile postingF-044in progress
Google AdspaidOAuth, discovery, campaign read/writeF-050in progress
Meta AdspaidParity with Google AdsF-051in progress
GA4analyticsSite-side truth to reconcile againstF-064done
OpenSEOanalyticsKeywords, ranks, backlinks, AI visibilityF-091in progress
ApolloanalyticsCompany + contact enrichmentF-092planned
WhatsAppmessagingOpt-in only; Baileys bridgeF-048in progress
research

What we don't know yet

The interesting parts of this build are the ones nobody has an answer to. SEO has rank; AEO has no equivalent. Metered APIs bill per call, so how little data can we get away with? Does a human actually read a 40-line agent diff? Each question is recorded before its answer, with the hypothesis it will be judged against.

1 settled · 10 open

Hypothesis

brightbean rendered the composer preview server-side via a debounced HTMX POST, which forced the preview endpoint to stay stateless and added a round-trip per keystroke pause. Rendering per-channel previews client-side should remove both constraints.

Findings

Settled at design time, not by measurement: with React the preview is a pure function of the draft, so there is nothing to fetch. Recorded here because it is a deliberate divergence from the source app, not an oversight.

composerportingstarted 2026-07-29

Hypothesis

Groq returns a usable multi-channel draft fast enough that the composer can regenerate on keystroke-idle rather than behind an explicit 'Generate' button. If p95 is under ~800ms the interaction can feel live instead of batch.

Findings

Not run yet — this one is still an open question.

aicomposerlatency

Hypothesis

A 15-second polling worker against a Postgres jobs table holds up fine at our volume (tens of posts a day, not thousands), so Redis never needs to enter the stack. Measure lock contention and publish-time drift under a synthetic 10× load before committing.

Findings

Not run yet — this one is still an open question.

infraqueued-005

Hypothesis

Neither source app had benchmarks and there is no obvious free authoritative feed. Options to evaluate: published vertical reports (stale but free), the platforms' own auction-insights and competitive-metric endpoints (live but narrow), or our own historical baseline (honest but only after months of data). Likely a blend, clearly labelled by source.

Findings

Not run yet — this one is still an open question.

adsbenchmarksresearch

Hypothesis

An approval queue that shows a raw diff of 40 bid changes will be rubber-stamped, which defeats the gate. Test whether grouping by rationale ('3 changes to cut spend on losing keywords, projected saving X') produces measurably more rejections than a flat diff — i.e. whether people are actually reading it.

Findings

Not run yet — this one is still an open question.

agenticuxapprovals

Hypothesis

Platform-reported and GA4 conversion counts will disagree, sometimes by a lot. Rather than pick a winner, show both with the delta and a plain-language reason (attribution window, view-through, consent-mode modelling). Establish the typical delta range before the KPI surface ships, so an anomaly is recognisable.

Findings

Not run yet — this one is still an open question.

analyticsga4attribution

Hypothesis

SEMrush bills per API unit, so a naive 'refresh on page load' would be expensive fast. Test whether a weekly pull per project domain, cached, is fresh enough for the decisions people actually make — keyword sets and competitor positions move slowly.

Findings

Not run yet — this one is still an open question.

seosemrushcost

Hypothesis

SEO has rank. AEO has no equivalent: being cited by an assistant is not a position on a page. Candidate measure is citation rate across a fixed panel of prompts per assistant, sampled weekly — establish whether that is stable enough to steer on, or too noisy to be a metric.

Findings

Not run yet — this one is still an open question.

aeomeasurementresearch

Hypothesis

SEO tools produce lists nobody actions. Opening the fix as a pull request against the project's repo puts it in the workflow that already has a review gate. Test whether PR-shaped fixes get merged at a materially higher rate than the same fixes listed in the UI.

Findings

Not run yet — this one is still an open question.

githubseoux

Hypothesis

Hootsuite prices listening on breadth — 30+ networks, 300+ review sites, 150M websites — which is a selling point for a product with thousands of customers and mostly waste for one organization. Scoped to Verjson's brand terms and a named competitor set, the query volume may be small enough that a metered API beats a subscription by an order of magnitude. Price both before committing, the same way OpenSEO turned out cheaper than SEMrush.

Findings

Not run yet — this one is still an open question.

listeningcosthootsuite

Hypothesis

Marketing tools are dull for a reason worth naming, not just a lack of colour. The working guess: they present every number at equal weight, so nothing on the screen is ever surprising or actionable - the product asks the user to do the noticing. If that is the cause, the fix is editorial rather than visual: say what changed and what it means, and let the rest recede.

Findings

Not run yet — this one is still an open question.

designresearchpositioningstarted 2026-09-09
roadmap

What's next

Computed from the board, not written here. Nothing without a date appears — an undated intention is not a next step.

18 AugFeature

Mock testing — backend and frontend

Everything that leaves the process is mocked, except the database. The database stays real because tenant isolation is our hardest correctness property, and a mocked Prisma proves…

20 AugFeature

Workspaces inside an organization

A workspace is a brand or a client — the scope unit below an organization. Social accounts, projects and media all belong to one.

22 AugFeature

Timezone handling

Store UTC, render in the project's zone, schedule DST-correctly. Built before the calendar, not retrofitted after.

26 AugLab

F-015 OAuth (Google + GitHub)

One GitHub consent covers both sign-in and the repo integration.

28 AugFeature

Marketing calendar per project

Month, week and list views. Drag to reschedule, per-channel queues, recurring slots, timezone-correct across DST.

30 AugFeature

Media library

Upload, tag and reuse. Thumbnails via sharp, video transcodes via FFmpeg, processed before publish rather than on upload.

49 dated milestones across 6 months · undated work is deliberately absent

features

The whole checklist

All 170 features, including the 40 still planned. An internal front door that showed only the finished ones would be a brochure.

F-001Foundation

Monorepo with a hard backend/frontend split

npm workspaces: @verjson/api (Hono, owns Prisma and every DB credential), @verjson/web (Next.js, no DB driver), @verjson/contracts (zod schemas both import). The seam is enforced by no-rest…

F-002Foundation

Auth — email/password, JWT access + refresh

bcrypt password hashing, jose-signed HS256 access and refresh tokens, rate-limited signup and login. Login returns the same 401 for an unknown email and a wrong password, so the endpoint ca…

F-003Foundation

Organizations (multi-tenant)

Signup creates an organization and its owner user in one transaction. Every subsequent query is org-scoped; a cross-tenant read must 404 rather than leak.

F-004· 20 AugFoundation

Workspaces inside an organization

A workspace is a brand or a client — the scope unit below an organization. Social accounts, projects and media all belong to one.

F-005Foundation

Members & role-based access control

owner · admin · member · agency · client. Write access is limited to internal roles; only an owner or admin can manage who is on a project.

F-006Foundation

Agency / hired-agent logins

Outside agency staff get their own logins, scoped to the projects they are assigned — never the whole organization. Their work flows through the same approval gate as everyone else's.

F-007· 30 SepFoundation

Client portal (magic-link, read-only)

Stakeholders review and approve content without an account, via a signed magic link. 32-byte token stored as a SHA-256 hash.

F-110· 24 AugFoundation

Client & agency proposals from the calendar

An external contributor composes a post from the calendar and suggests a date. It lands draft with the time on proposed_publish_at, never scheduled_at — the publisher selects on a variant w…

F-112· 26 AugFoundation

Teams, individual roles & work assignment

Teams (Design, Content, Video), individual roles (Video Editor, Carousel Designer) and post assignment with status and due date. A team is a grouping, never an access grant — project_member…

F-116· 25 AugFoundation

Visitor paths — where people went after they landed

The aggregate of every journey, built from the tracker's own pageviews — no third-party analytics. Entry pages ranked by volume, next steps per depth, and leaving drawn as an explicit edge…

F-008· 25 AugFoundation

Platform credential vault

AES-256-GCM encryption at rest with per-purpose keys derived by HKDF, plus one-way hashing for tokens. Live and in use by OAuth; the credential-vault UI is still to come.

F-009· 15 SepFoundation

Configurable defaults & settings

Job intervals, rate limits, approval modes and per-project defaults, editable without a deploy.

F-010· 20 SepFoundation

Onboarding flow + checklist

First-run wizard: connect channels, set the timezone, invite the agency, create the first project.

F-011Foundation

Audit log

Append-only trail of security-relevant actions: actor, action, entity, metadata, IP. Every agent-initiated action lands here too, with the key that made it.

F-012· 25 SepFoundation

Notification engine

In-app, email and Slack. Triggers: approval requested, publish failed, tracking broke, spend anomaly, low budget.

F-013Foundation

Rate limiting

Postgres-backed fixed window, shared across instances, degrading to an in-memory bucket if the DB write fails — so a transient database hiccup never locks users out.

F-014Foundation

Object storage

S3-compatible put · get · delete · presign, against MinIO locally and managed object storage in production. Keys are sanitised so a filename cannot inject path separators.

F-015Foundation

OAuth social login (Google + GitHub)

Google and GitHub sign-in alongside email/password. State is a signed, short-lived JWT so the cross-site callback cannot be forged; accounts link only on a provider-verified email; provider…

F-016Foundation

Stripe subscriptions + billing

Four plans, Stripe Checkout, the hosted portal, and signature-verified idempotent webhooks. Entitlement is derived from the subscription, so a cancellation degrades to free limits rather th…

F-020Projects & planning

Projects

The top-level unit of work. Create a project, pick its marketing mix, and put a budget behind each channel. Everything else — campaigns, calendar entries, KPIs, agency assignments — hangs o…

F-021· 28 AugProjects & planning

Marketing calendar per project

Month, week and list views. Drag to reschedule, per-channel queues, recurring slots, timezone-correct across DST.

F-022· 10 SepProjects & planning

AI plan generation

A brief goes in; a channel mix, budget split, posting cadence and messaging direction come out — as a draft plan a human edits and approves.

F-023· 5 SepProjects & planning

Campaign briefs

Structured intent: audience, offer, constraints, budget, success metric. The input to plan generation and the record of what we meant to do.

F-024· 12 SepProjects & planning

Organic / paid / influencer tracks

One calendar, three tracks. Each has its own approval rules — an influencer brief and a paid campaign do not need the same sign-off.

F-025Projects & planning

Marketing mix per project

Twelve channels — SEO, AEO, paid search, paid social, organic social, email, WhatsApp, content, influencer, affiliate, PR, events. A project declares which it invests in, and a budget may o…

F-026Projects & planning

Budget per channel per period

One amount per channel per period, as integer minor units. Re-setting a channel and period replaces the amount rather than stacking rows, so the total is never a sum nobody can reason about.

F-027· 1 NovProjects & planning

Budget vs actual spend

spent_minor filled from real platform spend by the ingestion job, never typed in. Drives the over-budget state and the hard cap.

F-030· 2 SepContent

Post composer (multi-channel)

Write once, override per channel. Live preview, per-platform character limits, media attachment, first-comment support.

F-031· 8 SepContent

AI content composer

Groq-backed drafting from a brief and a channel. Output is always a draft — the composer never publishes.

F-032· 10 OctContent

AI video creator and editor

Make a video from a script - ElevenLabs voiceover, rendered and sized per channel - and edit an existing one: trim, caption, re-crop for another aspect ratio, swap the audio.

F-033· 30 AugContent

Media library

Upload, tag and reuse. Thumbnails via sharp, video transcodes via FFmpeg, processed before publish rather than on upload.

F-034· 20 OctContent

Content categories

A taxonomy that planning and reporting both use, so 'how did thought-leadership perform?' is answerable.

F-035· 18 SepContent

Approval workflows

Multi-step, per-track approval. Nothing reaches a third-party platform without a recorded approval — including anything an agent proposes.

F-036· 22 SepContent

Scheduling & queues

Named time slots per channel, recurring posts, and a queue that fills the next open slot.

F-037· 28 SepContent

Publishing engine

The outbound worker. Retries with backoff, partial-failure handling when one channel of a multi-channel post fails, idempotency so a retry cannot double-post.

F-038· 15 OctContent

Link shortening + UTM

Attribution that survives the click, applied automatically from the project's convention.

F-039· 25 OctContent

Post trash & soft delete

Recoverable for 30 days, then purged.

F-040· 25 SepChannels

Channel adapter interface

One interface every platform implements. Adding a channel is one file plus a registry row — no change to the publisher, inbox or analytics.

F-041· 2 OctChannels

LinkedIn

Publish, metrics, comments. No inbound webhook support — polling only.

F-042· 6 OctChannels

Facebook + Instagram

One Graph API surface, two adapters. The only two channels where inbound webhooks meaningfully replace polling.

F-043· 5 NovChannels

YouTube

OAuth, resumable video upload (session init, byte upload and cursor probing so a dropped connection resumes rather than restarts), per-video metrics, and comments pulled in by polling.

F-044Channels

X · Threads · TikTok · Pinterest · Google Business

Added once the first four are proven. Each is one adapter file.

F-045· 30 SepChannels

Social account connection (OAuth)

Per-platform OAuth flows, encrypted token storage, hourly refresh for tokens expiring within 24h, and a health check that flags a disconnected account before a publish fails.

F-046· 10 NovChannels

Unified inbox

Comments, mentions and DMs across every connected channel, in one queue, with sentiment tagging and reply-in-place.

F-047· 15 NovChannels

Inbound webhooks

HMAC-SHA256 verified receivers for Meta, PubSubHubbub for YouTube. Signature is checked before anything is parsed; unsigned requests get a 403.

F-048· 24 OctChannels

WhatsApp Business marketing

Templates, opt-in management, broadcasts and two-way conversations through a Baileys bridge running as its own container, behind the same ChannelProvider interface as every other channel.

F-050· 15 SepPaid media

Google Ads integration

OAuth, account discovery, campaign read/write via the Google Ads API.

F-051· 8 OctPaid media

Meta Ads integration

Parity with Google Ads, built to the same AdsProvider interface.

F-052· 14 OctPaid media

Ads benchmarks

Our CPC, CTR, CPA and ROAS against vertical benchmarks — the 'are these numbers actually good?' answer that a raw dashboard never gives.

F-053· 18 OctPaid media

Campaign creation wizard

Multi-step campaign build for SEARCH and PMAX, with the asset slots pre-filled by the AI composer.

F-054· 22 OctPaid media

Conversion-tracking health

Detect broken or absent conversion tracking and generate the fix. Silent tracking failure is the most expensive bug in paid media — it wastes spend without producing an error anywhere.

F-055· 28 OctPaid media

Ad asset pipeline

One upload becomes the five image sizes Google Ads requires, via sharp.

F-056· 20 NovPaid media

Optimisation engine

Daily metric pull → analysis → proposed changes (bids, budgets, pausing losers) → approval gate → apply.

F-057· 1 NovPaid media

Spend tracking & caps

Per-project budget, spend-to-date across platforms, and a hard cap that pauses rather than warns.

F-058Paid media

Offline / enhanced conversions

Feed qualified leads back to the ad platforms as a bid signal.

F-059· 20 OctPaid media

Live campaign control

Launch, pause, resume and adjust budgets on live campaigns from inside the studio, with the platform's real state polled back so the UI never shows a stale 'running'.

F-060· 30 OctAnalytics

Per-account analytics

Reach, engagement, follower growth and post-level performance per connected account.

F-061· 8 NovAnalytics

Cross-account / cross-project analytics

Roll-ups and comparisons across channels and projects.

F-062· 12 NovAnalytics

One KPI surface

Every channel, organic and paid, on one screen. The headline ask: answer 'what is running and what is it returning' in under 60 seconds.

F-063· 25 NovAnalytics

Report builder

Composable sections, scheduled delivery as PDF and email.

F-064· 18 NovAnalytics

GA4 integration

Site-side truth to reconcile against platform-reported numbers, which routinely disagree.

F-065· 22 NovAnalytics

Metric freshness indicators

Every number carries its as-of time. A stale number that looks live is worse than no number.

F-070· 5 OctAgentic layer

Agent REST API + OpenAPI

The same /api/v1, documented for machine consumption. Agents get no privileged side door.

F-071· 28 NovAgentic layer

MCP endpoint

Streamable-HTTP transport so Claude Code, Codex and other MCP clients connect directly.

F-072· 1 OctAgentic layer

Scoped API keys

Hashed at rest, scoped to a project and a permission set, revocable, with last-used tracking.

F-073Agentic layer

Agentic workflows

Multi-step runs — plan → draft → schedule → measure — as a resumable state machine, so a failure mid-run does not lose the work before it.

F-074Agentic layer

Human-in-the-loop gate for agents

Agents propose; a human approves. Enforced by the state machine rather than by convention — there is no transition from `running` to `applied`, and an agency contributor can see a run on th…

F-075Agentic layer

Agent run log

What ran, what it changed, what it cost, and which key authorised it.

F-080Platform & ops

Local Docker Compose

postgres + minio for day-to-day; a --profile apps mode that runs the full four-container production topology locally.

F-081· 12 OctPlatform & ops

Production Kubernetes

web · api · worker Deployments, managed Postgres, S3-compatible storage, Ingress with TLS. Migrations run as a pre-upgrade Job, not on container start.

F-082· 5 AugPlatform & ops

CI gate

typecheck → lint → test → build, on every push.

F-083· 18 AugPlatform & ops

Mock testing — backend and frontend

Everything that leaves the process is mocked, except the database. The database stays real because tenant isolation is our hardest correctness property, and a mocked Prisma proves nothing a…

F-084· 16 OctPlatform & ops

Backup & restore

Daily pg_dump to object storage with a manifest, 30-day retention, and a restore command that has actually been run.

F-085· 1 DecPlatform & ops

GDPR export / delete

Per-workspace data export and deletion.

F-086Platform & ops

Global search

Across posts, campaigns, media and projects.

F-087· 22 AugPlatform & ops

Timezone handling

Store UTC, render in the project's zone, schedule DST-correctly. Built before the calendar, not retrofitted after.

F-088Platform & ops

Project dashboard

This board. Seven tabs — Overview, Features, Flows, Architecture, Tests, Labs, Docs — all reading from data/dashboard/*.json and docs/*.md. No database, so it works from day one and is diff…

F-089Platform & ops

Landing page

The internal front door. Seven interactive sections, every number and status read from this dashboard data: an approval-gate simulator, a ⌘K palette over every feature/experiment/doc, a tab…

F-090Platform & ops

Design system + Style Lab

Tokens in globals.css, primitives in components/ui, an animation library, and a dev-only Style Lab at /style-guide that writes a chosen theme back into the stylesheet.

F-091· 16 SepGrowth intelligence

Real SERP + backlink data

Keyword rank tracking and backlink monitoring against live data, via DataForSEO's organic SERP and Backlinks endpoints behind modules/growth/. Both fall back to deterministic mocks when no…

F-092· 24 SepGrowth intelligence

Apollo integration

Company and contact enrichment for outbound: build a target list from a project's ICP, enrich it, and push it into email or WhatsApp sequences.

F-093Growth intelligence

SEO audit for a page or site

Crawl a project's pages and report the fixable things: titles, meta, headings, canonicals, structured data, internal links, Core Web Vitals, broken links.

F-094Growth intelligence

AEO readiness

Seven AEO rules over the same crawled pages, kept separate from SEO because the target differs: ranking asks 'is this a good result?', citation asks 'can a model find a self-contained claim…

F-095· 4 OctGrowth intelligence

GitHub integration for web pages

Connect a project's repo: see which pages exist in the codebase, open content and SEO/AEO fixes as pull requests, and read deploy status so a recommendation lands as a reviewable diff rathe…

F-096· 20 AugPlatform & ops

RabbitMQ work queue + worker process

Direct exchange, one durable queue per job kind, a broker-side delayed retry queue and a dead-letter queue. Worker is the same image as the API with a different command; WORKER_KINDS lets a…

F-097Agentic layer

trigger.dev for agentic workflows

Durable multi-step runs — research, draft, wait for approval, schedule — that survive a deploy and can retry from a step rather than the beginning.

F-098· 12 OctGrowth intelligence

Agent-Reach as the agents' external read layer

Unified read/search across ~14 platforms (X, Reddit, LinkedIn, YouTube, GitHub, RSS, podcasts, web search) via its MCP server, for competitor and audience research.

F-099Growth intelligence

Scraper framework

Fetch-and-parse as a queue consumer, so it inherits retries, dead-lettering and rate limiting rather than growing its own scheduler. robots.txt respected, per-host politeness delay, honest…

F-100Platform & ops

Developer docs site

/docs — a manifest-driven documentation site. data/docs/manifest.json holds the navigation and points each page at a markdown file, a generated view, or nothing yet.

F-101· 14 NovContent

Best time to post

Recommended send times per channel, derived from this project's own engagement history rather than a generic industry table.

F-102· 30 OctContent

Bulk scheduling

Import a quarter of planned posts from CSV, preview the parsed rows, and queue them against calendar slots.

F-111Content

Per-project email broadcasts

A mailing list the project owns, plus the mail sent to it. Contacts arrive by drag-and-drop CSV import and are filed into audience segments — the three built-in ones (Active Clients & Buyer…

F-111.1Content

Custom audience categories

Per-project audience categories with a name, description and colour, created from the Audience header and sitting beside the three built-in segments as filter cards with live counts. Contac…

F-111.2Content

Contact import from Google Sheets

A second source tab in the import modal: paste a Google Sheets link instead of uploading a file. The fallback-segment picker, the auto-create-categories switch and the result summary are sh…

F-113Content

Rich email composer

Replaces the four-field draft modal with a Gmail-shaped composer: a formatting toolbar, hyperlinks with their own display text, inline images, file attachments, personalisation tags that wo…

F-113.1Content

Formatting toolbar

Font, size, bold, italic, underline, strikethrough, text colour, highlight colour, alignment, bulleted and numbered lists, indent/outdent, blockquote, undo, redo and clear formatting. Built…

F-113.2Content

Inline images & attachments

Images go into the body by toolbar upload or by drag-and-drop, through the shared `POST /uploads` endpoint that already enforces the accepted MIME types and the per-kind size caps; they lan…

F-113.3Content

Personalisation tags

`{{first_name}}`, `{{last_name}}`, `{{full_name}}`, `{{email}}` and `{{company}}`, insertable at the caret in the subject line or the body from a picker in the toolbar. Every tag carries a…

F-113.4Content

Preview & test send

A Desktop (640px) and Mobile (375px) preview, rendered in an iframe with `sandbox=""` — a foreign origin with no scripts, showing sanitised HTML at the same measure the dispatcher wraps the…

F-113.5Content

Autosave, templates & signature

Drafts autosave into a real broadcast row from the first save — created, then PATCHed — rather than living in component state or localStorage, so a closed tab, a dead battery and a differen…

F-114Performance

Meta pixel picker

The ad-set builder's pixel field is a dropdown of the ad account's own pixels, fetched from Meta's `adspixels` edge through `GET /ad-accounts/:id/pixels`, each shown with the date it last f…

F-115Performance

Meta Conversions API forwarding

`POST /track/conversion` also sends the conversion server-to-server to Meta's Conversions API. The browser pixel is the least reliable part of the measurement stack — Safari's ITP caps its…

F-103· 20 NovChannels

Saved replies & inbox templates

Reusable responses with variable substitution, so common inbox replies are one click rather than retyped.

F-104· 15 JanAnalytics

Social listening

Brand mentions, sentiment and emerging trends across the channels we care about — scoped to our own brand and a named competitor set, not to the whole internet.

F-105· 10 DecAnalytics

Competitor tracking

A named competitor set's posting frequency, engagement rate and follower growth, next to ours.

F-106· 30 JanChannels

Employee advocacy

A feed of approved posts that staff and agency contractors can reshare to their own networks, with attribution back to the source post.

F-107· 18 DecAnalytics

Sentiment reporting

Sentiment aggregated over time and by channel, turning per-message tags into a trend.

F-108· 5 DecAnalytics

Scheduled report delivery

Email a report on a schedule, as PDF and inline summary.

F-109Channels

Review management

Google Business, Trustpilot and app-store reviews alongside social mentions, with replies from the same inbox.

F-117Analytics

Audience demographics ingestion

Who follows an account, per platform: age, gender, country and city, fetched from the platform rather than illustrated. An OPTIONAL getAudienceDemographics on ChannelAdapter feeds AccountAu…

F-118Projects & planning

Per-project invitations

Invite someone straight onto one project: Team -> Invitations asks whole-workspace or one-project, then a project and a project role. The accepted user lands on that project and sees no oth…

F-119Foundation

Project-scoped access, enforced everywhere

One ORG_WIDE_ROLES in core/org-scope.ts instead of eleven copies, and `member` narrowed to the projects they are a member of. Owner and admin stay org-wide; everyone else sees only what the…

F-120Analytics

Customer LTV

Lifetime value per customer, surfaced for quick access.

F-121Channels

Instagram Stories

Publish and measure Stories, not just feed posts.

F-122Content

Per-author attribution inside a team

See which posts each team member created, so contribution is visible rather than assumed.

F-123Content

Approver can edit, with an audit log

Let an approver fix a post themselves instead of bouncing it back, with every edit recorded.

F-124Analytics

Filter and drill down from the graph itself

Click a point on a chart to filter the metrics and reach the posts behind it, instead of reading a number and going hunting.

F-125Growth intelligence

Social listening

Watch what is being said about the brand across platforms, not only what arrives in our own inbox.

F-126Growth intelligence

Competitor analysis

Track competitors' posting, engagement and positioning alongside our own.

F-127Content

Content buckets with recommended allocation

Classify posts into buckets - educational, engagement, self-care and so on - show the current percentage split, and recommend an allocation.

F-128Content

Bucket allocation reviewed every six months

Re-derive the bucket split on a cycle from what actually performed, so the mix follows evidence rather than the first guess.

F-129Channels

Complaints across every platform, in one place

Every customer complaint - whichever platform it arrived on - collected into one view with its own section.

F-130Growth intelligence

Sentiment analysis

Score incoming messages, comments and reviews by sentiment so the angry ones surface first.

F-131Analytics

Online customer journey map

Map the real path into the brand - Instagram, website, Google reviews, TripAdvisor - so messaging can vary by stage rather than being uniform, and targeting and retargeting can follow it.

F-132Analytics

Journey map, second iteration: preference and platform

Answer which brand suits a given customer and which platforms they prefer to buy on, and why.

F-133Analytics

Buyer demographics from contact data

A small breakdown of who is buying - age and region - derived from phone numbers and emails.

F-134Platform & ops

Updates section

A place where product updates are announced to the people using the studio.

F-135Channels

Review sentiment and replies

Pull reviews from Google, Amazon and Blinkit, score them, and reply without leaving the studio.

F-136Channels

Email, Instagram and WhatsApp as inbox channels

Bring email, Instagram DMs and WhatsApp into the same inbox as everything else.

F-137Platform & ops

A stated list of capabilities

One page saying what the product can actually do, kept honest.

F-138Platform & ops

Tailor the studio to an industry

Match setup to the customer's industry and use case rather than presenting every feature to everyone.

F-139Paid media

Recommend spend per platform

Work out how budget should be split across platforms, from measured return rather than habit.

F-140Channels

Email workflows

Multi-step email sequences - triggered, scheduled and measured - rather than single broadcasts.

F-141Channels

Google Business Profile integration

Connect Google Business Profile for posts, reviews and the local presence.

F-142Content

Content repurposing

Turn one piece of content into the formats other channels want, instead of authoring each from scratch.

F-143Content

Resize and crop images per channel

Take one image and produce the sizes each channel wants - square, portrait, story, landscape - with a crop the user controls rather than a centre crop that beheads people.

F-146Content

Email audience — tags, custom fields, dynamic segments

Tags become rows rather than a column, so renaming one cannot orphan the contacts carrying it and a segment can join on it. Per-project custom fields with sparse values, richer contact fiel…

F-147Content

Email engagement and suppression

Sending moves to the Resend API for its event stream: delivery, bounce and complaint webhooks plus signed-token open and click tracking, an append-only event log, per-project suppression co…

F-170Content

Email section front door — overview, templates, deliverability

Three screens over records the API already kept and the UI never showed: an Overview that opens the section with a worst-first list of what needs attention, a Templates screen for EmailTemp…

F-171Content

Start an automation from a recipe

New automation opens a gallery — five complete journeys, the blank builder, or the assistant — instead of a form and an empty canvas. A recipe is a declarative tree flattened into the same…

F-172Content

Who actually enters this automation, and Tidy

Under every trigger picker, a sentence saying who is enrolled and — separately labelled — the audience that exists today, because in this engine nobody standing enters: triggers are raised…

F-173Content

segment_entered cannot enrol anybody — say so

Nothing raises the segment_entered trigger, so a journey on it validates, activates and never starts. AUTOMATION_TRIGGERS_NOT_YET_FIRING now carries the explanation, which the builder and c…

F-174Content

Test an automation against a real contact

Pick a contact and see the exact path they would take through a draft journey — which branch each condition sends them down, and why they would not enter at all. Needs a server endpoint tha…

F-175Content

Flow-level exit conditions, and making segment_entered fire

Two engine features, not screens. Exit conditions leave a journey as soon as something becomes true wherever the contact is in it (the classic 'they ordered, stop the cart series') — today…

F-148Content

Automation engine (headless)

The graph and the worker that walks it. A contact sits in an automation rather than running it: an enrollment row holds the current node and a next-run time, and a sweep claims due rows eve…

F-149Content

Visual automation builder

A React Flow canvas over the engine's graph - drag, connect, duplicate, delete, per-node editors, save as draft, activate - plus the two screens that make a running automation debuggable: a…

F-150Content

Lead capture — embeddable forms, then pages

A form builder, a public submit endpoint, and the form-submitted trigger: check the address, create or update the contact, apply tags, record the source, enrol. The drag-and-drop landing pa…

F-151· 21 SepChannels

Several accounts per platform in one project

One Meta login connects every Facebook Page and linked Instagram business account the user granted, each as its own account with its own Page token; analytics dashboards can switch between…

F-152· 21 SepChannels

Several platform apps per project

A project can register several apps for one platform (e.g. one Meta app per client brand), choose which to connect through, and every account keeps using the app that connected it.

F-153Content

Landing pages — drag-and-drop page builder

Drag-and-drop landing pages: a block palette (hero, text, image, button, sign-up form, features, spacer, divider), drop-into-gap insertion and handle reordering, desktop/mobile preview, the…

F-154· 21 SepChannels

Studio assistant that does the work — with a Confirm on everything

Prepares everything the email and automation screens can do — contacts (one or up to 50), tags, segments, drafts, test sends, sends, branching journeys and step edits — plus social posts an…

F-155· 22 SepChannels

Assistant reports, post media and brand voice

The assistant says how an email, an automation, a social channel or the website did — against the project's own usual — attaches images and video sent in the chat to posts, and writes in a…

F-156· 22 SepChannels

Assistant edits posts, knows best times, draws images, remembers

Change or reschedule an existing post under the project's approval rule, best posting and sending times from the project's own data, images drawn on Confirm, and a private memory carried ac…

F-157Platform & ops

Performance baseline — Lighthouse, bundle analyzer, Server-Timing, slow-query log

Measure before tuning: one Lighthouse run on a logged-in page, @next/bundle-analyzer on a production build, a Server-Timing header from the Hono handler wrapper, and Prisma/Postgres query-d…

F-158Platform & ops

Auth middleware — usage meter off the response path, single user lookup, session cache

meterApiCall awaits a usageMeter.upsert after next(), so every authenticated response waits on a write, and the upsert on one row per org serialises concurrent requests. The session middlew…

F-159Platform & ops

Move tick workers out of the API process into the worker container

main.ts starts ~20 interval workers (publisher, metrics, crawl, keywords, backlinks, AI citations, ad metrics, automations, reconciliation, usage reconcile, inbox polling, KPI rollups, repo…

F-160Platform & ops

Size the Prisma pool and tune Postgres

Prisma defaults to 5 connections shared between requests and workers; Postgres runs on container defaults (128 MB shared_buffers). Set connection_limit explicitly, raise shared_buffers/effe…

F-161Platform & ops

Lazy-load heavy client libraries with next/dynamic

mermaid, @xyflow/react, recharts, react-markdown and motion are all statically imported and the app has no next/dynamic at all. Load the dashboard markdown renderer, the automation canvas a…

F-162Platform & ops

Cursor pagination and select-over-include on growing lists

235 of 270 findMany calls carry no take. Most are lookup tables; posts, notifications, audit log and metrics are not and will slow linearly. Add cursor pagination to those endpoints and the…

F-163Platform & ops

Break the boot waterfall — cookie session and server prefetch

The bearer lives in localStorage, so 89 of 105 pages are client components and every hard load is shell → JS → hydrate → get-session (blocks the app shell) → page queries. Move the session…

F-164Platform & ops

Flatten dependent query chains with per-page bootstrap data

115 enabled: chains in apps/web/src/lib serialise page data. Prefetch the shared pieces (project, campaigns, accounts) in the project layout and add a per-page bootstrap endpoint where a vi…

F-165Platform & ops

Media images through next/image

37 raw <img> tags against 5 next/image usages and no images config: no resizing, no lazy loading, layout shift on MinIO uploads. Add remotePatterns for the storage origin and convert the me…

F-166Platform & ops

Fix the N+1 query sites

Four places in apps/api/src/modules run a Prisma query inside a loop or an async map. Replace each with one findMany over the collected ids.

F-167Platform & ops

Font diet — per-route-group loading, drop unused weights

The root layout loads four families and thirteen weight files. Geist is only used under .app-theme and Inter only on the public side; load each in its route group's layout and drop the weig…

F-168Platform & ops

Web container standalone output, static cache check, route-level loading.tsx

The web Dockerfile copies the full node_modules tree and runs npx next start; output: 'standalone' cuts memory and cold start on the 4 GB droplet. Confirm cf-cache-status is HIT on /_next/s…

F-169Platform & ops

React Compiler trial and dependency prune

reactCompiler is off and the app has a single memo() call; enable it behind the baseline numbers to see whether re-renders matter at all. Run depcheck once and drop unused packages. Five in…

F-176Foundation

Clearhouse brand — two blues, a gradient ground, glass surfaces

The product is Clearhouse. Ported palette (an action blue and an identity blue, a brand neutral ramp, magenta/vermilion/sky accents), four type families, a fixed page gradient and the glass…

F-177Projects & planning

Team chat — one thread per project, with the work reporting into it

A shared thread per project (ProjectMessage), distinct from the assistant's per-user conversation. People post; the product posts too — an approval, a rejection, a changes-requested, a publ…

F-178Foundation

Walkthrough — a guided tour of a project and of the workspace

Two tours: eight stops around a project and four around the workspace, anchored to real nav rows by data-tour attributes and restartable from the user menu. It never clicks or navigates for…

F-179Foundation

See what each person can reach, and change it from one place

The Team screen answers "who is on this project"; this answers the opposite question — "what can this person reach" — which is the one asked when somebody joins, changes role or leaves. A p…

Get a full demo of OmniChan.

See how OmniChan brings creation, publishing, advertising, measurement and optimisation into one connected workflow.

By submitting this form, you agree to OmniChan’s Terms of Service and Privacy Policy.