Skip to main content
Innovatrix Infotech — home
Behind the Build: How We Run a Full Digital Agency on a Production-Grade Stack with Zero Marketing Staff cover
Company News

Behind the Build: How We Run a Full Digital Agency on a Production-Grade Stack with Zero Marketing Staff

One person. 200+ published pages, 12 live case studies, automated cross-publishing, self-hosted live chat, and a CMS that rivals agencies 10x our size. Here's every tool, every architecture decision, and the honest reasoning behind all of it.

Photo of Rishabh SethiaRishabh SethiaFounder & CEO5 April 2026Updated 5 April 202632 min read4.8k words
#tech-stack#digital-agency#n8n#directus#next-js#ai-automation#behind-the-build#solopreneur#aws#headless-cms

Behind the Build: How We Run a Full Digital Agency on a Production-Grade Stack with Zero Marketing Staff

This website is operated by one person.

No content team. No DevOps engineer. No account manager. No social media coordinator. Just me — a former Senior Software Engineer and Head of Engineering — and the stack I built after starting over from scratch.

Here's what that one person is running right now: 200+ published pages across six content collections, 12 live client case studies, a cross-publishing pipeline that distributes to Dev.to, Hashnode, LinkedIn, and Twitter automatically, self-hosted live chat, a booking flow connected to automated email sequences, six lead magnets in various stages of rollout, and a Shopify + AI automation practice that's delivered results like +41% mobile conversion for FloraSoul India and ₹4.2L launch-month revenue for Baby Forest — for clients across India, UAE, Singapore, and Australia.

I'm not telling you this to impress you. I'm telling you this because if you're a D2C brand, a growth-stage startup, or another founder asking "how are they doing all this?", the answer is: the right stack, the right architecture decisions, and a very clear philosophy about what to own versus what to outsource.

This is the first entry in the Behind the Build series — where I open-source the decisions, trade-offs, and technical choices behind how Innovatrix operates.


Why We Built It This Way

I want to be honest about something before the stack reveal, because the why matters more than the what.

In early 2024, I lost everything I had built before. An employee I trusted walked out with our entire client database, contact lists, project history, and access credentials. There was no gradual wind-down. One day, years of relationship-building just disappeared.

I had two options: rebuild the way I had before, depending on people to carry pieces of the business I didn't fully control — or build something where I owned every layer of the infrastructure, every piece of content, every byte of client data.

I chose the second path.

That experience reframed how I think about technology. Every tool recommendation we make to clients, we run ourselves first. If I'm telling a D2C brand they should move to a headless Shopify setup with Hydrogen, it's because I've lived with the developer experience of building headlessly. If I'm telling a laundry business they should automate WhatsApp intake with n8n — as we did for Bandbox, saving them 130+ hours per month — it's because I've built and maintained that architecture myself.

Owning your infrastructure is owning your growth. When your content lives in someone else's platform, your data lives in someone else's database, and your workflows depend on tools that can be deprecated or price-hiked overnight — you don't actually control your business. You rent it.

The philosophy is simple: build for ownership, automate for scale, and never use a page builder.

WordPress with Elementor, Webflow, Framer — none of these are wrong choices in every context. But for a technical agency that recommends modern stacks to clients, we needed to run what we preach. The stack you're about to read through is opinionated, production-grade, and every part of it was chosen after evaluating the alternatives.


The Content Layer: Next.js + Directus

Why headless over monolithic

The moment you couple your content to your presentation layer, you've made a decision that's very hard to undo. With a monolithic CMS — WordPress being the canonical example — your content is tied to the database schema of that CMS, your frontend is tied to its theme engine, and your performance is a negotiation between your template and the PHP runtime.

The headless approach separates these concerns entirely. Content lives in Directus as structured data exposed over REST and GraphQL APIs. The frontend — built on Next.js 14 with the App Router — fetches that data at build time or request time and renders it however it needs to. The two systems don't know about each other's implementation details.

The practical upside: when I decided to switch from ISR to static generation for certain collections, I changed the generateStaticParams implementation in Next.js. Directus didn't care. When I restructured the blog_posts schema to add a cross_publish_targets field and a lead_magnet relation, the frontend just needed a query update. No theme migrations. No plugin conflicts.

Why Directus specifically

I evaluated Payload CMS, Strapi, and Sanity seriously before landing on Directus. Here's my actual reasoning:

Payload is excellent if you want your CMS embedded inside your Next.js application. The Local API approach — querying the database directly from Server Components without going over HTTP — is genuinely elegant. But I wanted my CMS to be a separate, persistent service that could serve multiple frontends and survive a complete frontend rebuild without any risk to content data. Directus as a standalone service gives me that clean separation.

Strapi felt too opinionated about its content modeling paradigm for my taste. Directus's database-first approach — where you define your PostgreSQL schema and Directus wraps it with an admin UI and auto-generated APIs — is more aligned with how I think as an engineer. I'm comfortable in SQL. I want to see what's actually in the database, not be abstracted away from it.

Sanity is a great product, but it's cloud-first by design. I wanted self-hosted, because data ownership was the whole point of this rebuild.

Directus gave me a clean PostgreSQL backend, REST and GraphQL APIs auto-generated from any schema I define, a polished admin Studio for content management, a built-in Flows engine for automation, and full self-hosting with Docker on EC2. Our DPIIT Recognized Startup status comes with certain data residency expectations from enterprise clients — having everything on ap-south-1 (Mumbai region) with no third-party SaaS in the chain is a clean story to tell.

How the collections are structured

The current schema has seven core collections: blog_posts, services, hire_pages, technology_pages, portfolio_items, pages, and industry_pages. Each serves a distinct content purpose with its own field structure — and critically, each maps to a distinct URL pattern on the frontend. Blog posts live at /blog/*. Service and geo pages live at /services/*. Portfolio case studies live at /portfolio/*. The routing is clean and never bleeds between collections.

blog_posts is the most elaborate collection. It carries SEO fields, a markdown body, lead magnet relations, cross-publish target arrays, tags, reading time, author attribution, and a view count that increments automatically on each unique visit. The lead_magnet field is a Many-to-One relation to a separate lead_magnets collection, which lets me swap the lead magnet associated with any post without editing the post itself — a schema design decision that pays off when you're managing six different lead magnets across dozens of content categories.

The schema design for scale matters. We're at 200+ published items right now. When that reaches 1,000+, query performance depends on having the right indexes on status, slug, category, and published_at. I added a composite index on (status, published_at) early on — a small decision that prevents a full table scan on every listing page render. This is exactly the kind of thing that's invisible until it isn't.

Next.js App Router and ISR in practice

The frontend uses Next.js 14 with the App Router. Blog listing pages use Incremental Static Regeneration (ISR) with a 2-hour revalidation window — which aligns with the Cloudflare edge TTL we have set. Individual blog posts use generateStaticParams to pre-render at build time, with on-demand revalidation triggered by a Directus Flow whenever a post is published or updated.

The revalidation chain:

  1. A post is published in Directus Studio (or via MCP API call).
  2. A Directus Flow fires on the items.create or items.update event for the blog_posts collection.
  3. The Flow calls a Next.js revalidation endpoint with the post's slug as a query parameter.
  4. Next.js purges the static cache for that specific path using revalidatePath.
  5. A second webhook call goes to Cloudflare's Purge API to clear the edge cache for that URL.

Result: a post goes from creation to live, indexable page in under 60 seconds. No Git commit. No deployment pipeline queue. No Vercel redeploy.

How a geo location page gets created

Here's a concrete example. When we built the AI Automation Agency Australia page, the workflow was:

  1. Create a record in the services collection in Directus with all fields populated: title, slug, description (plain text — the frontend renders it as raw text), SEO title, SEO description, H1, and structured FAQs.
  2. Set status: published.
  3. The Directus Flow fires, the revalidation chain runs, Cloudflare purges.
  4. The page is live, properly structured, and indexed within the minute.

No Git commit. No Vercel deployment. No staging environment review. The architecture separates content operations from code deployments entirely — which is the correct separation of concerns for a team of our size.


The Automation Layer: n8n + Brevo

Free Download: 3 Detailed Case Studies with Real Numbers

FloraSoul (+41% mobile conversion), Baby Forest (₹4.2L launch month), Zevarly (+55% session duration) — full breakdowns inside.

Where the leverage actually lives

People sometimes ask how we maintain a publishing cadence that most agencies with full content teams can't match. The answer is n8n.

n8n is a self-hosted, open-source workflow automation platform. Think Zapier, but with actual code support — you can drop into JavaScript or Python mid-workflow — self-hosted on your own infrastructure, and without the per-task pricing that makes Zapier economically broken at scale. We run n8n on our primary EC2 instance in ap-south-1, inside a Docker container networked to the Directus instance.

The pricing difference alone justifies the operational overhead. At our current execution volume, cloud Zapier would cost well over $300/month. Self-hosted n8n costs exactly the compute it runs on — which is shared with other services on an instance we're already paying for. For a DPIIT Recognized Startup operating lean, that difference is material.

The cross-publish engine

The cross-publish workflow is the highest-leverage automation in the stack. When Directus marks a blog_posts record as published, a Directus Flow fires a webhook to n8n with the post's UUID. n8n then:

  1. Fetches the full post record from the Directus REST API — title, body, excerpt, slug, tags, category, and cross_publish_targets.
  2. Checks the cross_publish_targets array. Technical tutorial posts distribute to ["devto", "hashnode", "linkedin", "twitter"]. Thought leadership and company news pieces go to ["linkedin", "twitter"].
  3. For Dev.to: strips raw markdown into the Dev.to format, adds frontmatter with the canonical URL pointing to our domain, posts via the Dev.to API.
  4. For Hashnode: reformats for their GraphQL mutation API, sets canonical URL.
  5. For LinkedIn: generates a condensed post version via API and posts with the article link.
  6. For Twitter/X: generates a thread-opener and posts the first tweet with the article link.

The canonical URL handling is non-negotiable for SEO. Every cross-posted piece includes canonical_url: https://innovatrixinfotech.com/blog/[slug]. We get full distribution benefits without the duplicate content penalty that would otherwise dilute domain authority.

Before this workflow, cross-posting was a 45-minute manual task per article. Now it executes in under 90 seconds after publish, with zero human involvement.

Brevo for email and lead magnet delivery

Brevo (formerly Sendinblue) handles transactional email and drip sequences. When a visitor downloads a lead magnet — the AI ROI Calculator, the Shopify Launch Checklist, the App Cost Estimator, the Website RFP Template, the Case Studies PDF, or the UAE Starter Kit — a form submission fires a webhook, n8n processes the contact data, Brevo delivers the asset, and the contact is enrolled in the appropriate category-matched nurture sequence.

Each lead magnet is matched to content categories at the database level. The lead_magnet field on blog_posts resolves via relation to the correct asset for that post's topic. A visitor reading a Shopify migration post gets the Shopify Launch Checklist. A visitor reading an AI automation comparison gets the AI ROI Calculator. The matching is structural, not manual.


The Infrastructure Layer: EC2 + S3 + Nginx + Tailscale

What runs where

The primary EC2 instance runs in ap-south-1 (Mumbai). This choice wasn't arbitrary. Our clients span India, UAE, Singapore, and Australia. Mumbai gives us sub-20ms latency for Indian clients, reasonable performance to the GCC via the peering backbone, and a clear data residency story for enterprise conversations — which matters as an AWS Partner serving clients who ask about data handling.

On the primary instance, Docker containers handle: Directus CMS and its PostgreSQL database, Nginx as reverse proxy and SSL terminator, Chatwoot for live chat, n8n for automation, and Umami for privacy-first analytics. Everything communicates over Docker's internal bridge network. Nothing is publicly exposed except Nginx-proxied HTTPS endpoints.

A worker EC2 instance handles scraper workloads and DMS automation tasks — isolated from the primary instance both for performance stability and because I prefer to keep web-facing services and batch-processing workloads separated behind different security groups.

Nginx as the backbone

Nginx sits in front of everything. Every subdomain — cms.innovatrixinfotech.com, chat.innovatrixinfotech.com, n8n.innovatrixinfotech.in — routes through Nginx reverse proxy rules. SSL termination happens at Nginx using Let's Encrypt certificates refreshed via Certbot on a cron schedule.

The default Nginx configuration is wrong for most production deployments. The default worker_connections assumes traffic profiles that don't match a content-heavy site with concurrent API requests from a Next.js frontend. We tune worker_processes auto, set keepalive_timeout appropriate for our client connection profile, configure gzip compression for text assets, and use proxy_buffering settings that match Directus's response patterns. None of this is exotic — but it's the kind of configuration that gets skipped when Nginx is just "set up and forgotten."

S3 and backup strategy

Directus uses S3 as its file storage backend. Every asset — featured images, case study attachments, lead magnet PDFs — lives in S3 with versioning enabled. Database backups run via a cron job that executes pg_dump, compresses the output to .gz, and ships to a separate S3 bucket with a 30-day retention lifecycle policy. A daily health check verifies backup completion and sizes, alerting if the backup appears incomplete.

The backup strategy is deliberately boring. Boring infrastructure is reliable infrastructure.

Tailscale for access

SSH is not publicly accessible. All server access goes through Tailscale — a WireGuard-based mesh VPN that gives every machine in the network a stable private IP regardless of where I'm connecting from. Fail2ban runs as a second layer on the public interface for the small set of services that must expose something publicly.

After losing control of client data once because I trusted the wrong person, I'm not cavalier about access security. The attack surface is minimal by design.


The Client Communication Layer: Chatwoot + Cal.com

Self-hosted live chat

Chatwoot is an open-source customer support and live chat platform. We self-host it on the primary EC2 instance. The reason we didn't go with Intercom, Crisp, or Tidio is straightforward: data ownership and cost at scale.

Intercom at our conversation volume would cost $299–$799/month depending on seat configuration. Crisp is more affordable but cloud-only — meaning client conversations that sometimes include project scopes and budget discussions live on someone else's servers. For an agency working with enterprise clients who ask about data handling, that's a difficult position to defend.

Self-hosted Chatwoot costs us the compute it shares with other services. Our entire self-hosted infrastructure bill is a fraction of what SaaS alternatives would cost. That difference compounds over 12 months into meaningful operating leverage — leverage that goes into hiring engineers or investing in client work, not tool subscriptions.

Cal.com for zero-friction discovery calls

Cal.com handles discovery call booking. It's open-source, integrates with Google Calendar natively, and the booking link sits prominently in the Chatwoot welcome message, in the site header, and at the end of every piece of content.

The philosophy: async-first, but never cold. A visitor can read our content, verify our case studies, and book a 30-minute discovery call without ever sending a cold email or waiting for a sales reply. The booking confirmation triggers a Brevo sequence delivering a pre-call questionnaire and context document automatically.

From chat interest to booked call, the handoff is zero friction and zero human involvement until the actual conversation. That's the only way a 12-person engineering team can punch above its weight on sales without burning engineering time on top-of-funnel coordination.


The AI Layer: Claude + AI-Assisted Development

This is the section most people will share. So I want to be precise about both the capability and the limits — because the honest version is more useful than the hype version.

How Claude fits into the workflow

I use Claude as the execution layer for content operations. Not as a casual AI assistant I prompt off the cuff. As a structured content engine with a defined operating context: a house style guide, every Directus collection schema, our internal metrics, our case study data, and a pipeline it follows with consistency across every piece of content.

Here's what that looks like in practice:

Every blog post goes through a research-first flow. Before any content is created, the current top-ranking pages for the target keyword are analyzed for coverage gaps. Recent data on the topic is pulled. People Also Ask questions are inventoried. Only then does writing begin — and it follows a structural framework specific to the content type. Tutorials have different structural requirements than thought leadership pieces, which differ from comparison posts.

The result reads like it came from an experienced technical founder — because the context embedded in every session is exactly that: a former SSE who has built these systems, with real client metrics, real infrastructure decisions, and strong opinions.

What AI handles well in our workflow:

  • First drafts built on research and structured prompts
  • Boilerplate code: API integration wrappers, schema migration scripts, Nginx config blocks, Docker compose templates
  • SEO metadata generation for a target keyword given topic context
  • Proposal structure when I've already defined the technical scope
  • Cross-platform content reformatting: LinkedIn post from a blog article, Twitter hook from a listicle

What stays human:

  • Architecture sign-off on client projects — always
  • All client calls: the reading of the room, trust signals, scope negotiation
  • Strategic decisions about which markets to pursue and how to position
  • Tone calibration when a draft is technically correct but doesn't sound like me
  • Code review, every time. AI-generated code tends to handle the happy path cleanly and miss edge cases in production. I review everything before it ships to a client.

What AI gets wrong and how I catch it

Statistics. Claude sometimes fills a factual gap with a plausible-sounding number when it can't find a verified source. The fix in our pipeline: every factual claim in published content goes through a search verification pass. We use only our own case study metrics for specific numbers — the +41% mobile conversion from FloraSoul, the +55% session duration from Zevarly, the 130+ hours/month saved for Bandbox. These are real. Everything else gets sourced or cut.

AI-generated code assumes the happy path. When I had Claude write a Directus Flow configuration recently, the initial output handled success states cleanly but had no error handling for LinkedIn API rate limit responses (HTTP 429). The fix took five minutes. But only because I knew to look for it. Junior developers taking AI output at face value would ship that gap.

The mental model: AI is a very fast, very knowledgeable collaborator who needs a technical reviewer. It compresses hours of work into minutes. It does not replace judgment.

AI automation as a client-facing service

This stack isn't just internal infrastructure. The same n8n + AI patterns we use for our own content engine are the foundation of our AI Automation service for clients. When we built the WhatsApp AI agent for Bandbox — an n8n workflow handling dry cleaning intake, order status queries, and automated follow-ups — we saved them 130+ hours per month and reduced response time from hours to seconds.

As an AWS Partner, we're particularly positioned for AI automation work involving document processing, structured data extraction, and long-running workflow orchestration on EC2 — use cases where serverless functions hit cold-start and execution time limits that managed instances handle cleanly.

The AI Chatbot for E-commerce service we launched recently is a direct productization of patterns we built and tested on our own operations first. That's the only way to sell something with confidence: run it yourself.


The Analytics Layer: GA4 + Search Console + Umami

Three tools, not one

Each tool answers a different question, and none of them answer all three.

Google Analytics 4 is the conversion layer. Funnel analysis, session depth, event tracking, goal completions. GA4's event-based model is genuinely powerful once you've moved past the cognitive shift from Universal Analytics. The downside: cookie-based tracking means adblockers (which a significant share of developer-adjacent audiences use) miss a meaningful percentage of traffic. And GA4's free tier samples data at high volumes.

Google Search Console is the SEO layer. What queries drive clicks, which pages have strong ranking positions but low CTR (we found 6 such posts in our last optimization pass and rewrote their title tags — CTR lifted an average of 34% within 3 weeks), and indexing health. I check Search Console weekly. It's the closest thing to a direct readout of organic growth momentum.

Umami is the real-time, privacy-first layer. Self-hosted on the primary EC2 instance, no cookies, no GDPR consent banner required, and immune to adblocker blocking because it serves from our own domain. The dashboard shows current active visitors, today's page views by page, and traffic source breakdown — clean and instant. Because it's self-hosted, the data isn't sampled or shared with third parties.

Weekly check: Search Console for keyword health, Umami for traffic velocity on new posts. Monthly: GA4 funnel analysis and cohort data on return visitors.

The metric I've learned to care most about beyond traffic: time-on-page on case study pages. A visitor spending 4+ minutes reading the Zevarly case study — which delivered +55% session duration and +33% repeat purchase rate for the client — is a qualified lead. Traffic counts. Engagement converts.


What This Stack Enables

Here's the thing about infrastructure: the stack isn't the point. The compounding is the point.

Every published blog post feeds the cross-publish engine, which feeds LinkedIn and Dev.to distribution, which drives backlinks, which improves domain authority, which improves the ranking of the next blog post. Every case study published in Directus gets indexed within 60 seconds via the revalidation chain, lives on a fast edge-cached Next.js page, and links to service pages that convert. Every lead magnet downloaded enters a Brevo sequence that nurtures toward a discovery call booking.

None of these systems work in isolation. Each one feeds the next. That's what a well-designed stack looks like — not a collection of tools, but a compound machine where the output of one layer becomes input for the next.

One person can build a lot when the systems work that way.

What this means for client work

The reason we built this stack for ourselves is the same reason we recommend pieces of it to clients: we know exactly where the edges are.

We know that Directus's Flows module handles simple automation well but hits limits with complex branching logic that n8n handles better. We know that Next.js App Router's ISR behavior has subtle edge cases around tag-based revalidation that require careful handling. We know that Chatwoot's Android mobile app has notification reliability issues that require a specific FCM configuration to resolve. We know these things because we've hit them ourselves, under real load, with real content, serving real traffic.

That operational knowledge is what separates a vendor who sells technology from an agency that recommends what's genuinely right for your situation.

If you're a D2C brand thinking about headless commerce, or a startup asking whether AI automation is real or hype, or a founder looking at building something similar to what you've just read — this is exactly the kind of engagement we take on at Innovatrix Infotech. Not as a vendor pitching a solution, but as a technical partner who has built the systems we're recommending.


This Is Just the First Entry

Future entries in the Behind the Build series will go deeper on individual components: the exact schema design decisions behind scaling blog_posts past 1,000 records without query degradation, the full n8n workflow structure of the cross-publish engine, how we handle multi-locale content for UAE and GCC clients, and what the Managed Services retainer actually looks like from the inside.

If there's a specific component you want me to open-source next, reach out on LinkedIn or book a discovery call directly.


Free Download: 3 Detailed Case Studies with Real Numbers

FloraSoul (+41% mobile conversion), Baby Forest (₹4.2L launch month), Zevarly (+55% session duration) — full breakdowns inside.

Frequently Asked Questions

Written by

Photo of Rishabh Sethia
Rishabh Sethia

Founder & CEO

Rishabh Sethia is the founder and CEO of Innovatrix Infotech, a Kolkata-based digital engineering agency. He leads a team that delivers web development, mobile apps, Shopify stores, and AI automation for startups and SMBs across India and beyond.

Connect on LinkedIn
Get started

Ready to talk about your project?

Whether you have a clear brief or an idea on a napkin, we'd love to hear from you. Most projects start with a 30-minute call — no pressure, no sales pitch.

No upfront commitmentResponse within 24 hoursFixed-price quotes