Tabsir CGBack to all projects
Eric BihrPod-page media operation — ~500 Facebook pagesEric Bihr, founder of PostChart

PostChart - Facebook page management SaaS case study

A Facebook page-management system built end to end for one client's pod-page operation — five hundred pages, one engineer, ten months.

Role
Solo — design, build, ship
Timeline
Ten months — 2025-26
Sector
Social media SaaS
Stack
React · Node · MongoDB · Redis

What it runs in production

27,736
Uploads pushed through the scheduler
500
Facebook pages under management
10K
Posts scheduled a month
100+
Operator accounts

Context

Where it started

Eric Bihr runs pod pages — Facebook pages that push hundreds of reaction-driven videos a month, with several operators working the same page on a rotation. When he found me the whole operation lived in a Google Drive folder, a spreadsheet of posting times, and a rotation only he could see. Every post was hand-placed: download the clip, open the page, write the caption, set the time, log it somewhere else.

What the operation needed, against the tools already on the market
RequirementBufferMeta Business Suite
Bulk upload straight from a Drive folderNoNo
Evergreen recycling on an intervalPartialNo
Per-operator attribution on a shared pageNoNo
Collision locks inside one pageNoNo
Cost at five hundred pagesPer pageFree, manual

Nothing he had tried covered it. The tools that came closest price per page, and at five hundred pages that arithmetic ends the conversation on its own. He hired me off Upwork to build the one that would, and the brief was blunt: five hundred pages, several operators, no spreadsheet.

Approach

Two weeks before any code

I spent the first two weeks not writing code. I watched the actual workflow — where a clip came from, who touched it, what got typed twice — and the problem was never missing information. It was missing sequence. Every tool in the stack was fine on its own; the operation lost its hours in the seams between them.

The lifecycle one clip travels, end to end

  1. Drive folderwhere editors drop clips
  2. Bulk importthe whole folder, one screen
  3. Rulesspacing, windows, recycling
  4. Queueone slot per page per minute
  5. PublishedGraph API, on the minute
  6. Recycledevergreen, back in the pool

So the product target became a single sentence: an operator should take a folder of fifty clips and have them scheduled, spaced and attributed without opening a second tab. Everything below follows from that one line.

The system

What shipped

PostChart is built around the folder, not the post. The screen that matters takes a Drive folder and turns it into a schedule; a single-post composer exists, but it is the exception path rather than the main one. Three decisions carried most of the weight.

Bulk-first

instead of a composer per post

An operator arrives with fifty clips, not one. The primary screen takes the whole folder, applies a rule and shows the resulting calendar before anything is committed.

Rules, not timestamps

instead of picking a time per post

Nobody wants to choose four hundred times. Spacing, daily windows and a recycling interval are set once; the system derives every slot and shows you what it produced.

Roles on the page

instead of one shared login

Pod pages are worked by several operators. Permissions attach to the page, so a post carries the name of whoever queued it and attribution survives the rotation.

PostChart bulk uploader turning a Google Drive folder of videos into a schedule, with a scheduling rule open
The bulk screen — a Drive folder in, a rule on top, the resulting calendar before anything is committed.

The scheduler

Redis, not a queue

Underneath, the scheduler is one Redis sorted set per page. Scores are epoch milliseconds; a poller pops everything past its score once a second and hands it to the Graph API. MongoDB stays the source of truth — Redis only ever holds what is about to happen.

One post, from committed slot to published

  1. MongoDBsource of truth
  2. Redis ZSETscore = epoch ms
  3. Pollerpops due, every second
  4. Graph APIpublishes to the page
  5. MongoDBresult written back

I rejected BullMQ for this. Eric pays for RAM by the gigabyte, and a million scheduled posts fit in roughly fifty megabytes of sorted set — a fraction of what a general-purpose queue carries per job. The queue only has to answer one question, what is due, and a sorted set answers it in log time. The collision rule lives at the same layer: one page cannot take two posts inside the same minute boundary, so operators dump thousands of slots without checking each other's work.

The wall

What Meta wouldn't allow

The most expensive feature I built never shipped. Story uploads worked end to end in testing and died in production — the endpoint burns a quota scoped to the whole app rather than the page, so one operator's burst starves every other page on the platform. No plan tier raises it. The ceiling was Meta's, not ours.

Built
Story uploads, end to end
Blocked by
App-level rate quota
Shipped
Never

So I ripped it out and told the client it was not coming back. A narrow browser-automation version surfaced months later and I turned it down — it would have worked for a handful of power users and broken the moment the fleet grew. Saying that plainly, with the reasoning, is part of the job.

Billing

Making it a business

Then the parts nobody demos. Stripe Checkout with webhooks and a subscription state that survives whatever Stripe decides to send. The Meta app review: screen recordings, use-case justifications, one rejection, a resubmission with a tighter narrative, approved. Small shops do not have that level of API access, and getting it is slow, unglamorous work.

I also walked Eric through Google Cloud credentials, his own Facebook developer account and the live Stripe keys. The product is his, in his name, on his accounts — which is the part of delivering a SaaS nobody mentions until you have shipped one.

The handoff

Leaving well

Ten months in, Eric brought on a junior developer to keep the monthly burn manageable. I reviewed his pull requests for a month and walked him through the scheduler and the non-obvious corners of the Facebook integration — the things that would have cost him weeks to find alone.

“If you have a chance to work with him, I would absolutely pick him over anybody else.”

Eric Bihr, founder of PostChartEric BihrFounder — PostChart

Two days after my last commit the scheduler broke. I took an hour-long call, screen-shared with the junior, narrowed it to his regression and we fixed it. I did not bill for the hour. Leaving well is worth more than the invoice.

Today

Still running

PostChart is live at postchart.com and still ingesting — the newest upload in its bucket landed days before this page was written. The product has since grown YouTube support; that part is not my build. The Facebook core is: the scheduler, the recycling, the roles, the billing.

Delivered
Full-stack app — React, Node, MongoDB, Redis
Delivered
Custom scheduler and collision engine
Delivered
Stripe billing, Meta review, handover
PostChart dashboard showing reach, views, engagements and revenue across a fleet of managed Facebook pages
The page dashboard as it runs today.