PubHub — social publishing platform
Owned the frontend for 8+ years: the internal platform a major media company's social team used to publish across six networks.
What I built
I owned the frontend of a national media company's social publishing platform for 8+ years as its domain expert — the tool a 40+-person social team used to plan, compose, and publish across six networks.
- Composer — a guided flow (pick channel → post type → media → schedule) with platform-specific detail views across 15 post types, plus a mixed-media carousel composer.
- Planner — a weekly / 4-day scheduling calendar with drag-and-drop rescheduling and a hover preview of real post content without leaving the grid.
- Recommendation queue — a review surface where automation-suggested posts wait for human approval, with filtering, drag-to-schedule, and impression tracking.
- Automations admin — per-channel rule tables (trigger → filters → publish / schedule / recommend) backed by a content-safety exclusion pipeline (profanity + thumbnail OCR, NSFW flags, broken-embed detection, seasonal windowing).
- Accounts — a platform × account manager with OAuth connect / reconnect and per-account connection health.
- .bio — a cross-brand link-in-bio product for Instagram and TikTok, plus an embeddable publishing SDK and a Chrome extension that was the primary link-publishing surface.
I also helped integrate ML-based content recommendations in 2018, before the current wave.



How it works
Automation proposes, a human disposes. Rule-based bots watch upstream CMS content and either publish, schedule, or drop a candidate into the recommendation queue — where a person approves it before anything reaches a platform.
- Flow: connect an account → compose → the scheduler / queue holds the post → it publishes to YouTube, Instagram, Facebook, Twitter, or TikTok.
- Backend: a publishing API as the system of record for drafts, channels, and jobs; an async job-processing loop (accepted → pending → running → complete / error); a rule-based automation router matching content against per-channel conditions; and a per-platform API-helper layer.
- Auth: a tiered token model — application, tenant, and per-user access — differentiated per platform.
How I built it
Frontend: React + Redux + React Router, bundled with Webpack and styled in Sass on the company's internal design system; drag-and-drop scheduling (react-dnd, later dnd-kit), real-time queue / planner updates over websockets, and per-platform embeds. The React surface grew to ~160 components across composer, planner, settings, automations, and the SDK.
Backend: Python on an async (Tornado) I/O loop, deployed through the company's internal PaaS, with Datadog instrumentation and event messaging for downstream consumers. Testing: Jest + Enzyme unit tests and a Selenium-based end-to-end suite.
Decisions that shaped it:
- Job-loop over a new microservice for a channel-sync fix — comparable cost, but running it through the existing job loop got Datadog instrumentation, alerting, and a consistent job UX for free. That sync also cut a hot channel-lookup path from ~1,200ms to ~25ms.
- Per-user OAuth tokens over a shared system token — system tokens obscure attribution, share a blast radius on copyright takedowns, and can't be revoked when someone leaves; per-user tokens cost a re-auth step but keep the platform accountable.
- Moved de-duplication into the automation router after real duplicate-publish incidents during a platform outage — a mid-life architecture correction, not a day-one design.
- Shipped a narrow automation MVP and iterated in public (a beta channel) rather than big-bang launching to every page.
Eight years in, I designed the agent loop that finally moved this codebase off Python/Tornado onto Next.js — see the Agentic Framework Migration case study.
That internal design system is its own story: I led its evolution twice — the Solid → Bootstrap migration, then proposing and building the Foundation UI system it ran on for its final four years. Full case study: Foundation UI — a design system that held.
Questions this project answers
What does owning one domain for eight-plus years teach you that a short stint can't? You live with every decision long enough to see which ones aged well. I shipped a narrow automation MVP and iterated it in a beta channel rather than big-banging it; I moved de-duplication into the automation router only after real duplicate-publish incidents showed where the seam belonged. Long tenure turns architecture from a guess into a feedback loop — you own the consequences, so you design for them.
How do you design automation that a 40-person team will actually trust? Automation proposes, a human disposes. Rule-based bots watch upstream content and either publish, schedule, or drop a candidate into a recommendation queue where a person approves it before anything reaches a platform — and a content-safety pipeline screens candidates first. Trust came from keeping a human on the trigger for anything consequential, which is also why the tool held a 95% satisfaction score for a team that depended on it daily.
Walk me through an architecture call you made and the trade-off behind it. For a channel-sync fix I chose the existing async job loop over standing up a new microservice. The cost was comparable, but routing it through the job loop inherited Datadog instrumentation, alerting, and a consistent job UX for free — and the synced-table redesign cut a hot channel-lookup path from ~1,200ms to ~25ms. I also chose per-user OAuth tokens over a shared system token, trading a re-auth step for real attribution and the ability to revoke access when someone leaves.
How do you keep a frontend that grew to ~160 components from becoming unmaintainable? By treating the internal design system as the source of truth and building on it rather than around it, and by keeping the surface coherent as it spanned composer, planner, settings, automations, and an SDK. Real-time updates over websockets and drag-and-drop scheduling were built as shared primitives, not per-screen one-offs. The test discipline — Jest/Enzyme units plus a Selenium end-to-end suite — is what let a codebase that large keep changing safely for years.
Results
- 95% of users satisfied or extremely satisfied in the 2023 internal survey (97.4% the year before) — for a tool 100+ channels depended on daily, the number that mattered most.
- Automations saved editors roughly 3–5 hours a week of manual re-posting.
- 100+ connected channels · 40+ editors · hundreds of posts a day, across 15 post types on 6 networks.
- Cut a core channel-lookup path from ~1,200ms to ~25ms with a synced-table redesign.
Skills
AI / Agentic
- ML-based content recommendations (2018)
- automation rule design
- content-safety filtering (OCR / NSFW / heuristics)
Frontend
- React
- Redux
- React Router
- Webpack
- Sass
- design systems
- drag-and-drop scheduling
- real-time UI (websockets)
- Chrome extension
- embeddable publishing SDK
Backend / Infra
- Python
- Tornado (async job loop)
- OAuth token management
- rule-based automation routing
- event messaging
- Datadog
- internal PaaS deploy
- Jest + Enzyme
- Selenium E2E
Leadership
- 8+ years domain ownership
- mentoring engineers
- QA ownership
- cross-brand rollout
- incident-response practice