The Challenge: From Idea to Product
A hotel group needed a SaaS marketing tool that would allow each hotel to manage its campaigns, promotions, and customer communications independently, while maintaining centralized administration.
The Project: Building from Scratch
Key Requirements
- Multi-tenancy: Complete data isolation between hotels
- Scalability: Support for growth to hundreds of hotels
- Complex roles: Corporate administrators, hotel managers, marketers
- Integrations: Email marketing, CRM, booking systems
- Performance: Fast response times even with high data volumes
Architecture Design
We chose a strategic multi-tenant architecture:
┌─────────────────────────────────────────┐
│ API Gateway (Load Balancer) │
└────────────┬────────────────────────────┘
│
┌────────┴────────┐
│ App Frontend │ (React SPA)
│ Multi-tenant │
└────────┬────────┘
│
┌────────┴────────┐
│ Backend API │ (.NET Core)
│ Tenant Router │
└────────┬────────┘
│
┌────────┴────────┐
│ Database │ (PostgreSQL)
│ Row-level │
│ Tenant ID │
└─────────────────┘
Critical Technical Decisions
1. Row-Level Multi-Tenancy
Instead of separate databases per tenant (expensive and hard to maintain), we used row-level tenancy:
// Every query automatically filters by tenant
public class TenantDbContext : DbContext
{
private readonly string _tenantId;
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// Global query filter
modelBuilder.Entity<Campaign>()
.HasQueryFilter(c => c.TenantId == _tenantId);
}
}
Benefits:
- Single DB schema (easy to update)
- Optimized infrastructure costs
- Simplified backups and maintenance
2. Shared but Customizable Frontend
A single React codebase that adapts based on the tenant:
// Per-tenant configuration
interface TenantConfig {
brandColors: {
primary: string
secondary: string
}
features: {
emailMarketing: boolean
smsMarketing: boolean
socialMedia: boolean
}
limits: {
campaignsPerMonth: number
emailsPerDay: number
}
}
// Hook to access tenant configuration
const { config } = useTenant()
3. Automated DevOps Pipelines
We implemented full CI/CD:
# Simplified pipeline
stages:
- test
- build
- deploy-staging
- smoke-tests
- deploy-production
deploy-production:
script:
- docker build -t app:$CI_COMMIT_SHA .
- kubectl set image deployment/app app=app:$CI_COMMIT_SHA
- kubectl rollout status deployment/app
only:
- main
Pipeline Features:
- Automated unit and integration tests
- Optimized Docker image builds
- Automatic deploy to staging on every PR
- One-click production deploy (manual approval)
- Automatic rollback if health checks fail
Tech Stack
Frontend
- React with TypeScript
- Redux Toolkit for state management
- Material-UI with dynamic per-tenant theming
- React Query for data fetching
Backend
- .NET Core 6 (Web API)
- Entity Framework Core with multi-tenancy
- SignalR for real-time notifications
- Hangfire for background jobs
Infrastructure
- Azure App Service for hosting
- Azure SQL Database with elastic pools
- Azure Blob Storage for assets
- Azure Application Insights for monitoring
- Azure DevOps for CI/CD
Integrations
- SendGrid for email marketing
- Twilio for SMS
- Stripe for payments/subscriptions
Development: Agile Methodology
2-Week Sprints
- Planning on Mondays
- Daily standups (15 min)
- Demo + Retro on Fridays
- Deploy to staging every sprint
- Production release every 2 sprints
Team
- 1 Product Owner
- 3 Fullstack Developers
- 1 UX/UI Designer
- 1 QA Engineer
- Myself as Tech Lead
Results
Business Metrics
- Launch: MVP in 4 months
- Adoption: 20 hotels in the first year
- Users: 4,000 active users
- Uptime: 99.7% in the first year
- Satisfaction: NPS of 72
Technical Metrics
- Performance: Average response time < 200ms
- Deploys: 2 releases per month with zero downtime
- Critical bugs: Only 3 in production (first year)
- Test coverage: 75%
User Impact
- 60% reduction in campaign creation time
- 40% increase in email open rates
- Centralized reporting (previously scattered across Excel spreadsheets)
Key Takeaways
1. Multi-Tenancy from Day One
Don't try to add multi-tenancy after the fact. Design your architecture with this in mind from the start:
- Tenant ID in every table
- Automatic query filters
- Per-tenant configuration in code
2. DevOps Is Not Optional
For a SaaS product, having robust CI/CD is critical:
- Deploy frequently with confidence
- Roll back quickly when issues arise
- Keep the staging environment identical to production
3. Start Simple, Scale Later
Don't over-engineer:
- We started with a well-designed monolith
- Added microservices only when necessary
- Cloud managed services > custom infrastructure
4. Monitoring from the Start
We implemented observability from the MVP:
- Structured logs (JSON)
- Application Performance Monitoring (APM)
- Automated alerts for key metrics
- Dashboards for stakeholders
5. Security First in SaaS
With multiple tenants, security is critical:
- Row-level security (RLS)
- Regular penetration testing
- Access auditing
- Encryption in transit and at rest
From MVP to Mature Product
The project didn't end at launch. We continued iterating:
Phase 2 (Months 6-12)
- Integration with more email providers
- Advanced analytics
- Campaign A/B testing
- Mobile app (React Native)
Phase 3 (Year 2)
- Artificial intelligence for campaign optimization
- Workflow automation
- Public API for integrations
- White-label for partners
Want to Build a SaaS?
If you're planning to build a SaaS product and need:
- Scalable multi-tenant architecture
- Robust DevOps pipelines
- Experienced tech leadership
- Mentorship for your team
Result: From an idea to a product generating value for 4,000 users across 20 hotels, with scalable architecture and DevOps processes that enable fast, confident iteration.


