DEV Community

Cover image for PostAll Is Live: I Spent 100 Days Building a Content Automation SaaS. Here's Everything.
Aakash Gour
Aakash Gour

Posted on

PostAll Is Live: I Spent 100 Days Building a Content Automation SaaS. Here's Everything.

Day one of building PostAll, I wasn't trying to build a SaaS. I was trying to stop writing the same product description eleven different ways for eleven different platforms.

100 days later, that side problem is a platform. It's live today. This is the post where I tell you what's actually inside it — the architecture, the part that took way longer than it should have, and the three things that almost broke it before launch.

What PostAll Actually Does, In One Sentence

You give it one piece of content. It renders that content into every format you need — blog post, social caption, email — and it refuses to ship anything that fails a quality check first.

That second half is the part most content tools skip. Plenty of tools will generate you a blog post. Almost none of them will tell you, before you publish, that the post you just generated is 60% similar to something already on your site, or that its readability score puts it at a college-reading level when your audience needs sixth grade. I built PostAll because I needed both halves, and I couldn't find a single tool that did.

The Architecture, In Two Pieces

Piece one: parse once, render many

The first version of PostAll generated content per-platform. Need a blog post? New prompt. Need the social version? Another prompt, another LLM call, another chance for the two versions to contradict each other.

That fell apart almost immediately — not on cost, on consistency. A blog post and its social caption need to agree on facts, tone, and claims. Generating them independently meant they sometimes didn't.

So the architecture became: parse the input once into a structured content model, then render that single model into however many output formats you need.

Input (brief / outline)
        │
        ▼
[ Universal Content Model ]
        │
   ┌────┼────┐
   ▼    ▼    ▼
 Blog  Social Email
Enter fullscreen mode Exit fullscreen mode

One source of truth, multiple renderers. I open-sourced this piece a few weeks back if you want the actual implementation — link's at the bottom.

Piece two: the quality gate

Nothing renders to a final output without going through three checks first: readability, uniqueness, and SEO validity. Each one returns a score, and the scores get combined into a single composite number.

# composite_score.py
WEIGHTS = {
    "readability": 0.35,
    "uniqueness": 0.40,
    "seo": 0.25,
}
# Uniqueness gets the heaviest weight. Readability and SEO issues are
# annoying. Duplicate content is the one that actually gets a client's
# site penalized by search engines, so it costs the most when it fails.
Enter fullscreen mode Exit fullscreen mode

Readability runs through a small Python/FastAPI service using textstat. SEO validation runs through a Node orchestrator that checks things like heading structure and keyword placement. Uniqueness was the one that gave me the most trouble, and it's worth its own section.

The Part That Took Longer Than It Should Have

My first uniqueness checker used Jaccard similarity over text shingles — break the content into overlapping chunks of words, compare chunk sets between documents, get a similarity score. It's fast, it's simple, and for three weeks I thought it was done.

Then it let through a blog post that was a paraphrased rewrite of an existing article. Same structure, same claims, different words. Jaccard similarity on shingles caught near-identical text. It had no idea what to do with content that says the same thing in different words, because shingle overlap on synonym-swapped text drops fast even when the meaning hasn't changed at all.

The fix was combining two approaches instead of picking one: shingling first, because it's cheap and catches the obvious cases instantly, then sentence embeddings for anything that passes the first check, because embeddings catch semantic similarity that word overlap can't see. Shingling alone was fast and blind. Embeddings alone would've been accurate and too slow to run on every single piece of content. Together, they cover each other's blind spots.

I was wrong about uniqueness detection being a solved problem with an off-the-shelf algorithm. It's not — not when the failure mode is paraphrasing, not exact duplication.

What Almost Broke This (Reality Check)

The quality gate was too strict at first. Early on, I set the thresholds based on what felt right, not on data. Result: the gate rejected legitimately good content because the readability score landed half a point outside an arbitrary cutoff. I had to go back and tune thresholds against a real sample of accepted and rejected content instead of guessing.

The email renderer broke silently in Outlook. The blog and social renderers worked fine in every preview I checked. Outlook's rendering engine handles CSS differently enough that formatting that looked fine everywhere else came out broken specifically there, and nothing in my pipeline flagged it. I only caught it because a beta user mentioned their email looked "off," and "off" turned out to mean visibly broken in one specific client.

LLM re-prompting created its own bugs. When content failed the quality gate, my first instinct was to automatically re-prompt the LLM with the failure reason and try again. Sometimes that worked. Sometimes the model "fixed" the readability score by gutting the part of the content that made it useful in the first place — technically passing, practically worse. Automatic re-prompting needed its own quality check, which felt a little absurd to build but turned out to be necessary.

Where PostAll Stands Today

As of launch, PostAll has run through 100s of beta users and generated 1000 pieces of content across blog, social, and email formats. The quality gate currently catches roughly 80% of content before it ever reaches a human reviewer — which is the number I actually care about, because that's hours back in someone's week.

I'm leaving these as placeholders on purpose. By the time you're reading this, swap in your real numbers — they'll be more current and more honest than anything I write here today.

What's Next

I've been open-sourcing pieces of PostAll as I go, partly because I think the developer community gets more out of seeing how this works than out of another SaaS landing page, and partly because writing these up forces me to be honest about what actually worked. The formatting engine and the quality scoring system are already out there if you want to dig into either one in more depth than this post allows.

More of PostAll's internals are coming in the same format — real code, real failure modes, no polish where polish would be dishonest.

The One-Sentence Version

The hard part of content automation isn't generating text. It's generating text you can trust enough to ship without checking it yourself — and building the system that does the checking turned out to be most of the actual work.

If you've built something that validates its own output before a human sees it, I'd genuinely like to know what your failure modes looked like. Mine were quality thresholds set on vibes and a renderer that worked everywhere except the one client that mattered. What was yours?

Top comments (0)