Appearance
Infrastructure Philosophy & Technology Decisions
Core Principle: Pragmatism With Future-Ready Architecture
Jubiloop's infrastructure embodies pragmatic decision-making with deliberate growth paths. Every choice is made to:
- Optimize for today while ensuring tomorrow's scaling is straightforward
- Keep costs predictable without limiting future options
- Maintain simplicity that doesn't sacrifice flexibility
- Protect what matters (data) while staying lean elsewhere
Key Technology Decisions
Frontend Hosting: Why Cloudflare Pages
The Numbers:
- Vercel: 100GB bandwidth/month on free tier, only 1 project
- Cloudflare Pages: Unlimited bandwidth, unlimited projects
- Vercel Pro ($20/month): Still only 1 team member
- Vercel scaling: Need $150/month plan for 3 projects
Key Advantage: Unlimited projects means separate projects per environment:
jubiloop-webapp-devjubiloop-webapp-qajubiloop-webapp-prodjubiloop-marketing-devjubiloop-marketing-qajubiloop-marketing-prod
Decision: Cloudflare's unlimited projects enable proper environment isolation at zero cost
Backend Hosting: Why DigitalOcean
Current Setup:
- 2 droplets: $12/month total ($6 dev-qa + $6 production)
- Scaling: Resize droplets → Add droplets → Move to AWS
Why Not Hetzner?
- Considered Hetzner (cheaper VPS option)
- Chose DigitalOcean for:
- Superior developer experience
- Extensive documentation
- Managed services (databases, spaces, etc.)
- Better community support
Comparison:
- AWS: Enterprise-grade but complex pricing, steep learning curve
- DigitalOcean: Predictable pricing, excellent developer experience
- Future: Can move to AWS when we need its advanced services
Database: Why Neon + PostgreSQL
The Logic:
- Database = critical data = must not fail
- Backups, failover, scaling are complex
- Neon's free tier: 0.5GB storage, good for starting
- Scaling path: Free → $19/month → Enterprise
- Built-in branching for development/preview environments
Key Insight: "Never self-host what you can't afford to lose"
Backend Framework: Why AdonisJS
Why AdonisJS:
- Batteries included: Auth, ORM, validation, migrations out of the box
- Laravel-like: Proven patterns, great DX
- TypeScript first: Not bolted on
- Integrated: No need to wire 20 packages together
Code Impact:
typescript
// This is all built-in, no setup needed:
@column()
public email: string
@hasMany(() => Event)
public events: HasMany<typeof Event>
// vs Express: install 20 packages, wire them up, hope they work togetherFrontend Framework: Why React + TanStack
React + Vite:
- Team knows it well
- Massive ecosystem
- TanStack Router for type-safe routing
- Zustand for simple state management
Why Not Next.js for Web App:
- We don't need SSR for an authenticated app
- Adds complexity without benefits for our use case
- Marketing site uses Next.js where SEO matters
Infrastructure as Code: Why Not Kubernetes?
Current Reality:
- Team of 2 developers
- No dedicated DevOps engineer
- ~100-1000 initial users expected
The Math:
- EKS: ~$75/month just for control plane
- Plus: 2-3 nodes minimum (~$150/month)
- Plus: Time cost of Kubernetes expertise
- Total: ~$225/month + significant complexity
Our Choice: Docker + docker compose
- Cost: $0 (runs on existing infrastructure)
- Deployment: Simple, debuggable, rollback-friendly
- Future path: Can migrate to Kubernetes when justified
Infrastructure Evolution Path
Our infrastructure is designed to evolve with clear triggers:
Phase 1: Current (0-1K users)
- Cost: ~$12-15/month
- Stack: 2 DO droplets ($12), Neon free tier, Cloudflare free
- Monitoring: Basic health checks (planned: Sentry for error tracking)
Phase 2: Growth (1K-10K users)
- Trigger: API response time >500ms consistently
- Changes:
- Larger droplet (vertical scaling)
- Neon paid tier for better performance
- Add Redis for caching
- Implement Sentry for error tracking
- Cost: ~$100-200/month
Phase 3: Scale (10K-50K users)
- Trigger: Vertical scaling limits reached
- Changes:
- Multiple droplets (horizontal scaling)
- Load balancer
- Dedicated Redis instance
- Consider managed services
- Cost: ~$300-500/month
Phase 4: Enterprise (50K+ users)
- Trigger: Worth dedicated DevOps engineer
- Changes:
- Migrate to AWS/Kubernetes
- Multi-region deployment
- Advanced monitoring
- Cost: ~$1000+/month
Configuration Philosophy
The env.deploy.yml Pattern
Problem: Environment variables scattered everywhere Solution: Single source of truth
yaml
# env.deploy.yml
DEV:
server:
DATABASE_URL: from_secrets # Becomes DEV_SERVER_DATABASE_URL
REDIS_URL: 'redis://localhost:6379'
webapp:
API_URL: 'https://dev-api.jubiloop.ca'Benefits:
- Developers add variables to env.deploy.yml file
- Add secrets to GitHub Secrets once
- Scripts auto-generate all needed files
- GitHub Actions injects them everywhere
- No manual Cloudflare/DigitalOcean console work
Conventions Over Configuration
Naming Conventions:
- Service names match everywhere (docker-compose, env.deploy.yml)
- Environment prefixes are predictable (DEV*, QA*, PROD_)
- File locations follow patterns
Development Philosophy
Local Development = Production-Like
Principle: If it works locally, it should work in production
Implementation:
- Docker Compose locally mirrors production
- Same PostgreSQL version
- Same Redis setup
- Same environment variable patterns
Deployment Simplicity
Current Process:
- Push to GitHub
- GitHub Actions builds and tests
- Ansible deploys to DigitalOcean
- Zero-downtime deployment via Docker
No:
- Complex orchestration
- Service meshes
- Multi-stage builds (yet)
- Helm charts
Yes:
- Simple, understandable process
- Quick rollbacks
- Clear logs
- Fast iteration
Monitoring & Observability Strategy
Current State
- Application logs via Docker
- Basic uptime monitoring
- Manual error checking
Planned Additions
- Sentry (coming soon): Error tracking and performance monitoring
- Generous free tier (5K errors/month)
- Easy integration with both frontend and backend
- Real user monitoring
- Future: OpenTelemetry when complexity justifies it
Security Principles
Data Security First
- Managed database: Automatic encryption, backups
- HTTPS everywhere: Via Cloudflare
- Secrets in GitHub: Never in code
- Session-based auth: HTTP-only cookies, not JWT
Simple Security
- No: Complex IAM policies, VPNs, bastion hosts
- Yes: SSH keys, firewall rules, regular updates
Cost Management
Current Monthly Breakdown
- DigitalOcean Droplets: $12 (2x $6 droplets)
- Neon Database: $0 (free tier)
- Cloudflare: $0 (free tier)
- Domains: ~$2/month (annual cost divided)
- Total: ~$14/month
Cost Scaling Principles
- Use free tiers while they meet needs
- Pay for managed services for critical components
- Self-host only when cost savings are significant
- Monitor usage to predict scaling needs
Technology Integration Benefits
Single Dashboard Approach
- Cloudflare: DNS + Frontend hosting + SSL
- DigitalOcean: Backend + Redis + future services
- GitHub: Code + CI/CD + Secrets
- Neon: Database with branching
Migration-Ready Architecture
- Containerized: Apps portable to any cloud
- Terraform: Infrastructure reproducible anywhere
- Standard tools: PostgreSQL, Redis, Docker
- No vendor lock-in: Can switch any component
Future Considerations
When to Migrate Components
Database → Paid Tier:
- Approaching 0.5GB data limit
- Need better performance SLAs
- Require advanced features
Hosting → AWS:
- Need auto-scaling
- Require multiple regions
- Have dedicated DevOps resources
Monitoring → Advanced:
- Debugging becomes time-consuming
- Need distributed tracing
- Require custom metrics
What We're NOT Doing (Yet)
- Microservices: Monolith works great for our scale
- Kubernetes: Overkill for current needs
- Multi-region: Single region is fine for now
- CDN for API: Cloudflare handles static assets
- Message queues: Direct HTTP calls suffice
- GraphQL: REST API is simpler and sufficient
Decision Framework
When evaluating new technology, we ask:
- Does it solve a real problem we have today?
- Is the complexity worth the benefit?
- Can we migrate away from it easily?
- Does it fit our budget constraints?
- Can our small team manage it?
If not 5/5 "yes", we wait.
Summary
Our infrastructure philosophy is simple:
- Start simple, with clear paths to scale
- Protect the data, everything else is replaceable
- Optimize for developer productivity, not theoretical scale
- Pay for what matters, self-host what doesn't
- Monitor costs and performance, scale when data justifies it
This approach lets us focus on building features while maintaining a robust, scalable foundation that can grow with our success.