Case study · Full-stack web · 2025 – now

Publishing Studio

An AI publishing studio that plans a month of posts, produces the images and Reels, publishes them on time to Instagram, Facebook and WordPress, then reads the results back and suggests tomorrow's tasks.

Role
Sole designer and developer
Codebase
18K Python + 18K TypeScript
Scale
30 screens, 20 API modules, 30 tables
Used for
The Days We Keep, Noria Coffee
Publishing Studio publisher calendar screen
Publishing Studio publisher growth screen

01 · The content cycle

From a month plan to what it brought in

It replaced manual posting and scattered planning with one loop. Each stage feeds the next, and the results shape the next round.

  1. 1 · Plan

    Five-layer AI pipeline

    Brand → Month → Week → Series → Platform, plus a QA agent that checks every draft is on brand.

  2. 2 · Produce

    Images and Reels

    Image variations, a canvas editor with series templates, and 9:16 Reels with motion, captions and music.

  3. 3 · Publish

    On time, unattended

    Draft → Ready → Queued → Published. Posts, carousels and Reels go out to Instagram and Facebook on schedule.

  4. 4 · Learn

    Growth engine

    Daily Instagram, App Store and Google Play numbers. A weekly AI review finds the bottleneck and turns it into 3–5 daily tasks.

02 · Architecture

Runs on my Mac, reachable only by my devices

A Next.js app, a FastAPI backend and a scheduler daemon share one Postgres database. Tailscale puts it behind HTTPS for my own devices, with nothing exposed to the public internet.

Phone and laptopAny of my devices

My Mac

Tailscale ServeHTTPS, private to my devices
Next.js frontend30 screens, forwards /api to FastAPI
FastAPI backend20 route modules, JWT auth
Scheduler daemonPublishes, refreshes tokens, collects metrics
PostgreSQL30 tables
Meta Graph APIInstagram and Facebook
OpenRouterGPT and Gemini text and images
FirebaseMedia and sync with Social Companion
Growth dataApp Store, Google Play, Brave Search

03 · Hard problems

Rebuilding it live, and publishing with no one watching

Those were the two hardest parts of the project.

Re-architected with zero downtime

Moved from Streamlit and SQLite to Next.js, FastAPI and Postgres one screen at a time (the strangler-fig pattern), with a script to migrate the data.

Scheduling that survives sleep

Replaced fixed launchd jobs with a persistent APScheduler daemon. Times change on the fly, and a post still goes out if the Mac wakes within an hour.

Tokens that never silently expire

Facebook long-lived tokens lapse after about 60 days and publishing just stops. The daemon now refreshes every account's token each week.

Security by default

JWT over bcrypt hashes, an OAuth flow with CSRF state checks, and access tokens that stay on the server, never in the browser.

Fault-isolated data collection

Each growth source runs and logs on its own, so an expired Facebook token doesn't stop the App Store or Google Play numbers.

Desktop-to-phone sync

Postgres is the source of truth and Firestore a mirror. Each status carries a timestamp and the newest wins, so a tap on the phone is never overwritten.

Stack

Next.js 16 · React 19 · TypeScript · Tailwind · Python · FastAPI · APScheduler · PostgreSQL · MoviePy · Pillow · Fabric.js · Firebase · Meta Graph API v22 · OpenRouter · Tailscale