The Challenge: Multiple Products, One Team
When we started Accepire in 2024, we faced a common startup challenge: ambitious product goals with limited resources. We needed to build multiple products (AxiomFlow for ESG compliance, CuratoAI for content generation, AutoInvoice.AI, and more) while maintaining the engineering quality we promised clients.
This constraint forced discipline. We couldn't afford to rebuild infrastructure for each product. We needed patterns that scaled across projects and a tech stack that maximized developer velocity without sacrificing reliability.
Two years later, our platforms serve over 50,000 users with 99.97% uptime. Here's what we learned.
Tech Stack Decisions (And Why)
Backend: Node.js + TypeScript
Why: JavaScript everywhere means one language across frontend and backend, easier hiring, and shared code (validation schemas, types). TypeScript adds the safety net we need for production systems.
The tradeoff: Node isn't the fastest runtime. For CPU-intensive work, we offload to Go microservices. But for 90% of web application logic, Node's ecosystem and developer productivity win.
Database: PostgreSQL
Why: Postgres handles 95% of use cases well. JSONB for flexible schemas, excellent full-text search, strong consistency, and the best ecosystem of extensions. We use Supabase for managed hosting with real-time subscriptions built in.
The tradeoff: For truly high-scale time-series data (IoT sensors in AxiomFlow), we added TimescaleDB. For caching and sessions, Redis. But Postgres is the source of truth.
Frontend: React + Next.js
Why: Next.js gives us the best of both worlds—static generation for marketing pages (SEO), server-side rendering for dynamic content (performance), and client-side React for interactivity. Edge deployment via Vercel means global performance without managing CDN configuration.
Infrastructure: AWS + Vercel
Why: Vercel for frontend (zero-config deployments, edge functions, preview environments). AWS for backend services (Lambda, RDS, S3, SQS). This split lets us move fast on UI while maintaining control over data and business logic.
Architecture Patterns That Enabled Scale
1. Multi-Tenancy with Row-Level Security
Every table includes a tenant_id column. PostgreSQL Row-Level Security policies ensure queries only return data for the authenticated tenant. This is enforced at the database level, not application code—so bugs can't leak data between customers.
-- Every query automatically filtered by tenant
CREATE POLICY tenant_isolation ON orders
USING (tenant_id = current_setting('app.tenant_id')::uuid);
2. Event-Driven Processing
Heavy processing (PDF generation, AI inference, data aggregation) happens asynchronously via queues. The user action triggers an event, returns immediately, and a background worker processes the job. This keeps the UI snappy and allows horizontal scaling of workers independently.
3. API Design: REST + GraphQL Hybrid
REST for simple CRUD and external integrations (predictable, cacheable). GraphQL for complex dashboard queries where the frontend needs flexibility. This hybrid avoids the over-fetching of pure REST and the complexity overhead of pure GraphQL.
4. Feature Flags from Day One
Every new feature ships behind a flag. This enables gradual rollouts, easy rollbacks, and A/B testing without deploying new code. We use a simple in-house system backed by Redis—nothing fancy, but essential.
4 Mistakes We Made (And How We Fixed Them)
Mistake 1: Premature Microservices
What we did: Started with separate services for auth, notifications, and billing because "that's how you scale."
The problem: Coordination overhead killed velocity. Debugging across services was painful. We had distributed system problems without distributed system scale.
The fix: Consolidated into a modular monolith. Clear module boundaries, but one deployable unit. We'll split when we actually need to—which is probably never for our scale.
Mistake 2: Insufficient Monitoring
What we did: Launched with basic error tracking and called it "monitoring."
The problem: When users reported "it's slow," we had no visibility into why. No distributed tracing, no performance baselines, no alerting on anomalies.
The fix: Implemented comprehensive observability: structured logging, request tracing, performance metrics, and anomaly detection. Now we often know about issues before users do.
Mistake 3: N+1 Queries in GraphQL
What we did: Naive GraphQL resolvers that fetched related data one record at a time.
The problem: A dashboard query that should take 50ms was taking 3 seconds. Database was getting hammered.
The fix: DataLoader pattern for batching and caching within a request. Query performance improved 10x.
Mistake 4: No Chaos Engineering
What we did: Assumed our error handling worked because the code looked right.
The problem: First time a third-party API went down, our "graceful degradation" turned out to be not so graceful.
The fix: Regular failure injection in staging. We break things on purpose to verify the system handles it correctly.
Cost Optimization Strategies
Our AWS bill for platforms serving 50K+ users is under $3,000/month. Here's how:
1. Right-Size Everything
We started with the smallest instance sizes and scaled up based on actual metrics. Most startups over-provision by 50%+ out of fear. Monitor first, scale second.
2. Reserved Instances for Predictable Workloads
Database and baseline compute run on reserved instances (40% savings). Burst capacity uses on-demand. This hybrid captures most of the savings without lock-in risk.
3. Aggressive Caching
Edge caching for static assets, Redis for application data, query result caching for expensive computations. Every cache hit is a database query avoided.
4. Serverless for Spiky Workloads
Background jobs run on Lambda. We pay only for execution time, and scaling is automatic. Perfect for workloads that spike (report generation, bulk imports) but don't need always-on infrastructure.
Key Lessons for Founders Building Their First Product
The TL;DR
- Start boring: Postgres, React, Node. Proven tools beat novel solutions.
- Monolith first: Split into services only when you have a clear reason.
- Invest in observability: You can't fix what you can't see.
- Design for multi-tenancy from day one: Retrofitting is painful.
- Ship, measure, iterate: Real user data beats theoretical architecture.
Building software at scale is less about brilliant architecture and more about consistent execution of fundamentals. Get the basics right, measure everything, and improve iteratively.
Building Your First Product?
Skip the learning curve. Work with engineers who've already solved these problems. Book a free technical consultation to discuss your architecture.
Book Your Free Technical Consultation →