GenelOctober 4, 20265 min read

How I Built IGFlow: The Architecture of an Instagram Automation Platform

The architecture decisions behind IGFlow, a platform that manages Instagram accounts, DMs and automation flows from one panel: per-account queues, services decoupled with Kafka, limits designed as throttles, a data layer behind WireGuard and isolated AI calls.

ReactNext.jsTypeScriptPostgreSQLDockerAWSTailwind CSSSpring bootKafkaGoMongodbJava

Agencies and businesses that run Instagram accounts repeat the same manual work every day: answering DMs, following their target audience, scheduling posts. IGFlow is an Instagram automation platform that brings this work into one panel. In this

post I go through the architecture decisions I made while building it from scratch, and what I learned along the way.

What IGFlow does

- Tasks: follow, unfollow, like, comment, story viewing and data collection

- Visual flow editor: drag-and-drop scenarios such as "when someone DMs price, send this reply"

- Real-time inbox: read and answer DMs from the panel

- AI replies: agents that run on the user's own AI connection and tools

- Scheduled publishing: photos, carousels, Reels and stories

The technically interesting part is making all of this run safely and consistently without overloading any single account.

Splitting into services

The first version was a single backend, but the workloads were very different. A panel request has to return in milliseconds, a follow task can run for hours, and keeping a persistent connection to Instagram is a different job altogether. The system ended up as:

ServiceJobTechnology
PanelUI and BFF layerNext.js, React, TypeScript
BackendAPI, authentication, plansSpring Boot, PostgreSQL
WorkerRuns tasks and flowsSpring Boot, Kafka, MongoDB
Realtime gatewayPersistent Instagram connection, DM eventsSpring Boot, MQTT
EgressOutbound AI and MCP callsGo

Services hand work to each other over Kafka. The backend queues a task and returns immediately; the worker processes it at its own pace, so the panel stays fast no matter how much work runs behind it.

Ordered queues per account

Two actions on the same account at the same time look suspicious to Instagram, but there is no reason for different accounts to wait for each other. The answer is ordered per account, parallel across accounts. Each account's jobs wait in a durable MongoDB queue,

and Java 21 virtual threads let hundreds of accounts work through their own queues at once. If a job is interrupted by a restart, the queue resumes it.

Limits as throttles, not gates

In the first design, limits acted as a gate: a 1000-target task on an account with a 30-per-hour limit was rejected at creation. That made no sense to users. I redesigned limits as a throttle: the task is always accepted, and the worker checks the remaining

allowance right before every action. When it runs out, the task is deferred without holding a thread, and it resumes on its own when the window frees up.

Real-time inbox

The realtime gateway keeps a persistent MQTT connection to Instagram for every connected account and turns incoming messages into events for the flow engine and the panel. One small but important rule: **when the account owner writes in a conversation by hand,

automations in that conversation go quiet for a while.** A bot talking over a human is one of the most common complaints about automation tools.

Security: the data layer is never exposed

The system runs on two servers: one for the panel, backend and HashiCorp Vault, the other for the worker, gateway and data layer (MongoDB, Redis, Kafka).

- The data layer is reachable only over a private WireGuard network. Its ports do not listen on the public IP.

- Secrets live in Vault, and sensitive fields are encrypted with AES-256-GCM.

- Panel security: JWT with HttpOnly session cookies, TOTP two-factor auth, an audit log, rate limiting and idempotency keys.

A lesson I learned: protecting an endpoint with "if the path starts with…" is not enough. If the security filter reads the raw URL while the framework routes on the decoded one, they can see the same request differently. Check the path the framework actually matches,

and check it in more than one layer.

Isolating AI calls

Users can add their own AI connections and MCP tools to their flows, which means the server makes requests to addresses users provide. Done wrong, that is a door into the internal network. So every outbound call goes through a small egress service written in Go.

It has no route to internal systems, only sends HTTPS requests out, and verifies at connect time that the target IP is not internal.

Deploys: every push is tested and shipped

Gitea Actions runs the tests on every push and then updates the services in the right order: worker first, then backend. The order matters because an old worker cannot process a message field it does not know, and the pipeline itself enforces it.

Conclusion

The principle that helped most while building IGFlow: where a mistake is easy to make, make it impossible. Turning limits into throttles, moving the data layer onto a private network and isolating outbound calls are all structural answers to "what happens if we

forget to be careful?"

Take a look at the platform: igflow.app

> IGFlow uses session-based access rather than Meta's official API and is not affiliated with Meta. This risk is stated clearly to users, and the system is designed to protect accounts with limits.

If you found this post helpful, don't forget to share!