The Premise: Why We Built Our Own Support Inbox
We were happy Help Scout customers. Their shared inbox worked well for our small team, and we'd been using it for years. Then came the pricing change announcement: they're moving from per-seat pricing to per-email-answered pricing.
For us, that meant a 10x increase in cost.
We had a choice: pay significantly more, migrate to another vendor (and face the same risk later), or try something different. We chose different.
Not Quite Vibe Coding
Let's be clear about what this isn't. We didn't type "build me a Help Scout clone" and watch an AI spit out a working product. That's not how this works — at least not yet.
What we did was something in between traditional software development and the "vibe coding" phenomenon. We combined:
- Open source foundations — We didn't start from scratch. There are excellent open source projects on GitHub that handle the hard parts: IMAP parsing, email threading, authentication
- A strong CLAUDE.md file — This became our project's brain. Every coding session started with Claude understanding our architecture, conventions, and constraints
- Constant reminders about best practices — We treated the AI like a junior developer who knows everything but needs guidance on what matters for this project
The CLAUDE.md Approach
The key insight was treating the instruction file as living documentation. Our CLAUDE.md includes:
- Project architecture and folder structure
- Database schema and relationships
- Code style and conventions (TypeScript strict mode, ESLint rules, naming patterns)
- Security considerations specific to email handling
- What NOT to do (no over-engineering, no premature abstractions)
- Key file references with line counts so the AI knows where to look
Here's a sample of actual guidance from our file:
Strong typing required - Never use `any`
Type all function parameters and return values
Define types centrally in src/server/lib/types.ts
And for frontend work:
Use shadcn/ui components - check if it exists before building custom
Use Tailwind CSS utility classes, avoid custom CSS
Check src/client/src/hooks/ before creating new ones
The pattern is clear: check what exists before creating something new. This prevents the AI from reinventing solutions that are already in the codebase.
Every time we start a conversation, Claude has full context. It knows our React component patterns. It knows our Tailwind conventions. It knows where business logic lives (src/server/lib/ticket.ts) versus database queries (src/server/lib/database-pg.ts). It knows that we're handling sensitive customer communications.
What We Actually Built
Support Inbox is an open-source email ticketing system. Here's what it does:
- IMAP/SMTP integration — Connect to any email provider
- Shared inbox — Multiple team members, one inbox
- Ticket management — Status, assignment, internal notes
- Customer context — See ticket history per customer
- Webhooks — Trigger external automations
- REST API — Build integrations
What it doesn't do (and doesn't need to):
- No live chat
- No WhatsApp/Facebook/Twitter integration
- No built-in AI features
- No complex workflow builders
That last point is intentional. We use webhooks to connect to AI services when we need them. The core product stays simple.
The Tech Stack: Boring on Purpose
We deliberately chose technologies that AI handles well and that minimize operational complexity:
graph TB
subgraph "Frontend"
React[React 19]
Tailwind[Tailwind CSS]
Shadcn[shadcn/ui]
end
subgraph "Backend"
Fastify[Fastify API]
TS[TypeScript]
SSE[Server-Sent Events]
end
subgraph "Email"
Nodemailer[Nodemailer]
IMAP[imap-simple]
end
subgraph "Data"
PG[(PostgreSQL)]
end
subgraph "Infrastructure"
Node[Node.js 20+]
VPS[Single VPS<br/>~$20/month]
end
React --> Fastify
Tailwind --> React
Shadcn --> React
Fastify --> TS
SSE --> Fastify
Fastify --> PG
Fastify --> Nodemailer
Fastify --> IMAP
Node --> Fastify
VPS --> Node
VPS --> PG
style React fill:#61DAFB
style Tailwind fill:#38BDF8
style PG fill:#336791
style TS fill:#3178C6
style Node fill:#339933
Full TypeScript, Front to Back
- 96% TypeScript codebase
- AI is remarkably good at writing and revising TypeScript
- Strong typing catches errors before they hit production
- One language across the entire stack means less context switching
Backend: Fastify + PostgreSQL
- Fastify for the API — fast, lightweight, well-documented
- PostgreSQL for data — reliable, no exotic extensions needed
- Server-Sent Events for real-time updates — simpler than WebSockets
- No microservices, no message queues, no Redis
Frontend: React 19 + Tailwind + shadcn/ui
- React because AI knows it cold
- Tailwind for styling — utility classes that AI generates consistently
- shadcn/ui components — copy-paste, not npm dependencies
- Modern stack but nothing bleeding edge
Email: Nodemailer + imap-simple
- Battle-tested libraries for SMTP and IMAP
- No reinventing email handling
Deployment: One server, one command
- Node.js 20+, PostgreSQL, done
- No containers, no Kubernetes, no CI/CD pipelines
- Runs on a modest VPS with room to spare
- Total infrastructure cost: ~$20/month
The goal was low technology sprawl. Every additional technology is something that can break, needs updates, and requires context in our CLAUDE.md. We resisted the urge to add Redis, Elasticsearch, or any other "nice to have" infrastructure.
The result? A developer (or AI) can understand the entire stack in an afternoon. That's not a limitation — it's a feature.
The Development Process
Here's what an actual development session looked like:
- Define the feature — "We need internal notes that aren't visible to customers"
- Review existing code — Claude reads the relevant controllers and templates
- Propose implementation — Claude suggests an approach, I approve or redirect
- Write code — Claude generates the code following our established patterns
- Test and refine — Fix issues, handle edge cases
- Commit — Claude generates commit messages following our conventions
The AI never worked autonomously for hours. Each session was collaborative, typically 30-60 minutes of focused work.
Guiding the AI: Prompting That Works
The AI knows how to code. What it doesn't know is your standards. Here's what we learned about getting consistent, production-quality output:
Set the persona upfront
In our CLAUDE.md, we include phrases like "You are a senior software engineer" and "Follow software engineering best practices." It sounds simple, but it changes the output. The AI writes more defensively, considers edge cases, and avoids clever shortcuts.
Demand code reviews — from the AI
Before committing, we'd ask Claude to review its own code: "Review this implementation for security issues, error handling, and edge cases." It catches things. Not everything, but enough to matter.
Be specific about what you don't want
Our instruction file explicitly states:
- No over-engineering
- No premature abstractions
- No "nice to have" features
- Keep functions small and focused
Without these guardrails, AI tends toward complexity. It'll add configuration options nobody asked for, create abstractions for things used once, and generally write more code than needed.
Remind constantly
Even with a good CLAUDE.md, we'd add reminders in our prompts: "Remember to follow our established patterns" or "Keep this simple — we can refactor later if needed." The AI responds to repetition.
Review everything
This is the big one. We reviewed every line of generated code. Not skimmed — reviewed. The AI makes mistakes. It hallucinates function names. It forgets context from earlier in the conversation. Human oversight isn't optional.
What Worked
The instruction file was essential. Without CLAUDE.md, every session would start with re-explaining the project. With it, Claude understood our codebase from the first message.
Open source saved months of work. Email is hard. IMAP is a nightmare. We didn't reinvent those wheels.
Best practices prompting mattered. Left to its own devices, the AI would over-engineer solutions. Constant reminders to keep things simple, avoid abstractions, and only build what's needed kept the codebase maintainable.
The AI is great at the boring parts. Migrations, CRUD operations, form validation — the tedious work that slows down development. Claude handles these quickly and consistently.
What Didn't Work
Complex logic needs human oversight. Email threading algorithms, permission systems, anything with subtle edge cases — these needed careful human review.
The AI doesn't remember previous sessions. Even with CLAUDE.md, you sometimes need to re-establish context about recent changes.
Testing still requires thought. Claude can write tests, but deciding what to test requires understanding user behavior.
The Real Lesson: The Future of SaaS
This project convinced us of something bigger: the era of one-size-fits-all SaaS is ending.
When the cost of building custom software drops dramatically, "good enough" vendor solutions become harder to justify. Especially when those vendors can change their pricing at any time.
We're not saying everyone should build their own support inbox. But if you have:
- A clear understanding of your requirements
- Development experience (or access to it)
- Patience for AI-assisted development
...then building exactly what you need becomes realistic.
Getting Started
If you want to try this approach:
- Find your open source base — Search GitHub for projects that solve 60-70% of your problem
- Create a strong CLAUDE.md — Document everything the AI needs to know about your project
- Start small — Build one feature, learn the workflow, then expand
- Stay hands-on — This is collaboration, not automation
The tools are there. The question is whether you're ready to use them.
Support Inbox is open source and available at github.com/bookatechie/support-inbox. We also offer hosted versions with premium support for teams who want the software without the operations overhead.