Backend Architecture
Foundation backends are cloud-native, event-driven, and designed for scale from day one.
Architectural Patterns
Microservices Architecture
Engineering11 uses a microservices architecture with clear domain boundaries:
Core Principles:
- Domain-driven design - Each service owns a specific business domain
- Independent deployment - Services deploy independently without coordination
- Autonomous scaling - Services scale based on their own demand patterns
- Clear contracts - Well-defined APIs and event schemas between services
Benefits:
- Teams can work independently without blocking each other
- Failures are isolated to specific domains
- New features don’t require refactoring the entire system
- Services use the most appropriate data store for their domain
Event-Driven Workflows
Engineering11 embraces event-driven architecture for async communication:
Pub/Sub Messaging:
- Services publish domain events to Pub/Sub topics
- Consumers subscribe to relevant events
- Decoupled producers and consumers
- Natural fit for AI enrichment pipelines
Event Flow:
Service A → Publish Event → Pub/Sub Topic → Multiple Subscribers
├→ Service B (enrichment)
├→ Service C (analytics)
└→ Service D (notifications)Benefits:
- Loose coupling between services
- Easy to add new event consumers
- Natural backpressure and retry mechanisms
- AI and automation added without blocking user flows
Repository Pattern
All data access goes through repository classes that abstract storage implementations:
Abstraction Benefits:
- Business logic doesn’t depend on storage details
- Easy to swap data stores (Firestore → SQL)
- Simplified testing with mock repositories
- Consistent patterns across all services
Common Repositories:
CollectionRepository<T>- Document/collection-based storageSubcollectionRepository<T, P>- Nested collectionsSqlRepository<T>- SQL-based storage- Custom repositories for specific query patterns
Multi-Tenancy
Data isolation is built into every layer of the architecture:
Tenant Context:
- Every request carries tenant/customer context
- Repositories filter data by tenant automatically
- Cross-tenant data access is explicitly prevented
- Audit logs capture tenant information
Isolation Strategies:
- Logical partitioning in shared databases
- Separate database instances for enterprise customers
- Row-level security in Cloud SQL
- Document-level filtering in Firestore
White-Label Support:
- Custom domains per tenant
- Tenant-specific configuration
- Branding and theme customization
- Feature flags per tenant
API-First Design
All services expose well-documented, versioned APIs:
REST APIs:
- OpenAPI/Swagger documentation
- Versioned endpoints (
/v1/,/v2/) - Generated TypeScript clients
- Standard error responses
IPC (Inter-Process Communication):
- Service-to-service REST endpoints
- Authenticated via Google IAM
- Used for synchronous operations
- Circuit breakers and retries built in
Server APIs (Packages):
- Published npm packages
- Shared domain models and types
- Repository-based data access
- Business logic services
- Consumed by other backend services
Explore Server API Packages →
Service Anatomy
Every Foundation microservice follows the same structured parts:
Server API Part
Published as an npm package (e.g., @engineering11/user-api):
Contents:
- Domain models and interfaces
- Repository classes for data access
- Business logic services
- Constants (collections, topics, permissions)
- Shared utilities
Used By:
- Other backend services that need this domain’s data or logic
- Ensures type safety and consistent behavior
- Versioned for backward compatibility
REST Part
Client-facing HTTP endpoints:
Responsibilities:
- Expose domain functionality to frontend apps
- Request validation using DTOs
- Authentication and authorization
- Rate limiting and throttling
Technology:
- NestJS framework
- Express HTTP server
- JWT authentication
- OpenAPI documentation
IPC REST Part
Service-to-service communication endpoints:
Responsibilities:
- Internal APIs for backend coordination
- Not exposed to external clients
- Authenticated via Google IAM
- Used for synchronous workflows
Tasks Part
Asynchronous event processing:
CQRS Pattern:
- Event receivers (controllers)
- Event definitions
- Command definitions
- Command handlers
- Sagas (event → command mapping)
Use Cases:
- Process background workflows
- React to domain events from other services
- Enrich data asynchronously
- Trigger AI pipelines
Functions Part
Cloud Functions triggered by events:
Triggers:
- Firestore document changes
- Cloud Storage uploads
- Pub/Sub messages
- HTTP requests
Use Cases:
- Real-time data transformations
- Lightweight event handling
- Third-party webhooks
- Scheduled lightweight tasks
Jobs Part
Scheduled and recurring background jobs:
Technology:
- Cloud Scheduler triggers
- Background job queues
- Configurable schedules (cron expressions)
Use Cases:
- Daily data exports
- Periodic cleanup tasks
- Report generation
- Batch processing
Migrations Part
Database schema and data evolution:
Strategy:
- Version-controlled migration scripts
- Run once per environment
- Idempotent where possible
- Rollback scripts for critical changes
Types:
- Schema migrations (add/modify fields)
- Data migrations (backfill, transform)
- Index creation
- Security rules updates
Technology Stack
Backend Technologies
Runtime & Language:
- Node.js
- TypeScript for type safety
- ES Modules
Framework:
- NestJS for REST APIs and dependency injection
- Express as HTTP server
- CQRS module for event-driven workflows
Data Stores:
- Firestore for document storage
- SQL for relational data
- Redis for caching and sessions
- Cloud Storage for files
Messaging & Events:
- Google Pub/Sub for async messaging
- Cloud Tasks for queued workflows
- Cloud Scheduler for cron jobs
Authentication & Security:
- Google Identity Platform
- JWT tokens
- Google IAM for service-to-service auth
- Cloud Secret Manager for secrets
Modern Development Tooling
Engineering11 systems use modern tooling to improve the developer experience:
Monorepo Management:
- Yarn workspaces for dependency management
- Nx for build orchestration and caching
- Release Please for automated versioning and changelogs
Quality & Testing:
- Jest for unit and integration tests
- Supertest for API testing
- gts (Google TypeScript Style) for linting and formatting
- Husky + lint-staged for pre-commit hooks
- Commitlint for conventional commits
Development Environment:
- Docker for containerization
- Docker Compose for local orchestration
- Hot reload for rapid iteration
Infrastructure
Cloud Platform:
- Google Cloud Platform (GCP)
- Cloud Run for container deployment
- Kubernetes Engine for advanced orchestration
Deployment:
- Terraform for Infrastructure as Code
- Cloud Build for CI/CD pipelines
- Multi-environment strategy (dev, CI, QA, stage, prod)
Observability:
- Cloud Logging (structured logs)
- Cloud Monitoring (metrics and alerting)
- Cloud Trace (distributed tracing)
- Error Reporting for exception tracking
Operational Patterns
Deployment Pipeline
Code Push → Cloud Build
↓
Run Tests & Linters
↓
Build Docker Image
↓
Push to Container Registry
↓
Deploy to Environment
↓
Health Checks
↓
Rollback on FailureEnvironment Strategy
Development (dev):
- Rapid iteration
- Frequent deployments
- Shared by all engineers
Continuous Integration (CI):
- Automated testing environment
- Triggered by pull requests
- Validates changes before merge
Quality Assurance (QA):
- Manual and automated testing
- Stable, pre-production environment
- Customer demo and UAT
Staging (stage):
- Production mirror
- Final validation before release
- Performance and load testing
Production (prod):
- Live customer environment
- Automated deployments with approval gates
- Blue-green or canary deployments
Observability & Monitoring
Structured Logging:
- JSON formatted logs
- Correlation IDs for request tracing
- Tenant and user context in all logs
- Severity levels (debug, info, warn, error)
Metrics:
- Request latency and throughput
- Error rates and types
- Resource utilization (CPU, memory)
- Business metrics (signups, revenue)
Alerting:
- Error rate thresholds
- Latency SLOs
- Resource exhaustion
- Integration with PagerDuty/Slack
Distributed Tracing:
- Request flow across services
- Performance bottleneck identification
- Dependency mapping
- Latency analysis
Resilience & Reliability
Circuit Breakers:
- Prevent cascading failures
- Fail fast when dependencies are down
- Automatic recovery when service stabilizes
Retry Logic:
- Exponential backoff
- Jittered retries to prevent thundering herd
- Maximum retry limits
- Idempotent operations
Health Checks:
- Liveness probes (is service running?)
- Readiness probes (is service ready for traffic?)
- Dependency health checks
- Graceful shutdown
Rate Limiting:
- Per-user rate limits
- Per-tenant quotas
- Burst allowances
- 429 responses with retry-after headers
Design Principles
1. Consistency Over Flexibility
All services follow the same patterns:
- Same project structure
- Same naming conventions
- Same deployment workflows
- Same observability patterns
Result: Lower cognitive load, faster onboarding, easier maintenance.
2. Explicit Over Implicit
- Clear, well-defined contracts between services
- Explicit error handling
- Type safety through TypeScript
- Documented assumptions
Result: Fewer bugs, easier debugging, better collaboration.
3. Async Over Sync
- Prefer async workflows for non-critical paths
- Events for cross-service communication
- Background jobs for heavy processing
- Avoid blocking user requests
Result: Better scalability, natural AI integration, improved UX.
4. Secure by Default
- Authentication required unless explicitly public
- Tenant isolation at every layer
- Secrets in Secret Manager, never in code
- Principle of least privilege for IAM
Result: Reduced security risk, compliance-ready, customer trust.
Next Steps
- Microservice Implementation Guide - Build your first custom service
- Platform Microservices - Explore the 20+ available services
- Server API Packages - Review installable packages
- Getting Started - Set up your development environment