Skip to content
← back to work app

content factory

sveltekitfly.iogemini apisqliterest api

live on cf.notaslopbowl.com — instagram active, tiktok wired but pending platform audit.

what i use it for

i use this to schedule and post recipe content from not-a-slop-bowl to instagram on a daily cadence. external projects hit the api with their own credentials — the generator and the calendar are shared infrastructure.

the problem

content factory is posting infrastructure: it generates social content, owns a publishing calendar, and exposes an api so other projects can post through it. the problem it solves is time — producing one post (image, video, carousel, captions) takes an hour, and copying it across platforms takes another. tooling solves generation or scheduling, never both, and the few that come close expose no api hooks, so you can't drive them from another project's cron. not-a-slop-bowl needed to post recipe content daily with no human in the loop; nothing off the shelf could be both the generator and the pipe.

the approach

  1. 01 generate

    the dashboard produces every part of a post from a brief.

    • gemini generates the images and writes the captions and hashtags.
    • video runs through fal.ai and replicate — fifteen models in total, chosen per shot rather than fixed.
    • media can also come from cloudinary, supabase storage or a direct upload — generation is one source, not the only one.
  2. 02 schedule

    a planning calendar owns what posts, and when.

    • every post is a job in a durable sqlite queue, so a restart or deploy never drops a scheduled post.
    • each job carries its target platform and a posting mode — manual or automatic.
  3. 03 expose

    a rest api lets other projects drive the factory.

    • an external project upserts a post as a job through one endpoint and reads its status back through the same channel.
    • each caller authenticates with a project-scoped key — the factory is shared infrastructure, not a single-tenant tool.
  4. 04 post

    when a job is due, it posts one of two ways.

    • manual mode raises a notification and a calendar event, and a human posts.
    • automatic mode calls the platform api directly — instagram is live in production; tiktok is wired but waiting on platform audit.

engineering challenges

  • multi-tenant credential isolation

    the factory is shared — several projects post through one instance — so a leak between tenants would be a serious breach.

    • every api key and every platform connection (instagram, tiktok) belongs to exactly one project.
    • a request must never be able to see or act on another project's data or credentials.

    isolation is enforced at the data layer, not by convention.

    • a project-scoped key resolves to a single project id, and every query the request makes is bound to it.
    • platform credentials live in a per-project table, so one tenant's instagram token can never be reached by another.
    • keys are hashed at rest — a database leak doesn't hand over working credentials.
  • durable scheduling

    a post scheduled for 9am has to fire even if the server restarted at 8:59.

    • an in-memory scheduler loses every pending job on a crash or deploy.
    • for infrastructure other projects depend on, a silently dropped post is a real failure, not a glitch.

    the schedule lives in the database, never only in memory.

    • every scheduled post is a row in the sqlite queue with its fire time and status.
    • on startup the scheduler rebuilds itself from the queue — nothing pending is ever lost.
  • asynchronous platform apis

    posting to instagram isn't a single call — the platform processes media on its own schedule.

    • you upload, but the post isn't live until instagram finishes processing, and that takes an unpredictable amount of time.
    • treat it as synchronous and the factory reports success before the post actually exists.

    a job isn't done until the platform confirms it.

    • after upload the factory polls instagram's media-processing status until the post is genuinely published.
    • only then is the job marked complete and the live post id written back through the api.