Skip to main content

Overview

Architecture Decision Records (ADRs) capture important architectural decisions made during the development of the Learnille platform. Each ADR describes the context, decision, and consequences of a significant architectural choice.

ADR Template

ADR [Number]: [Title]

Date: YYYY-MM-DD Status: [Proposed | Accepted | Rejected | Deprecated | Superseded] Context: [Describe the context and problem being solved] Decision: [Describe the decision that was made] Consequences: [Describe the positive and negative consequences of the decision] Alternatives Considered: [List alternative solutions that were considered] Related ADRs: [Links to related ADRs]

Current ADRs

ADR 001: Technology Stack Selection

Date: 2024-01-15 Status: Accepted Context: We needed to choose a technology stack for building the Learnille platform that would support rapid development, scalability, and maintainability. The platform requires handling user authentication, course management, payments, and real-time features. Decision: We decided to use:
  • Frontend: React with TypeScript (Vite)
  • Backend: Node.js with NestJS framework
  • Database: PostgreSQL (Self-Hosted)
  • Cache & Queue: Redis / BullMQ
  • Search: OpenSearch for vector and course search
  • Storage: Cloudflare R2 (S3 API compatible) / MinIO locally
  • Hosting & Observability: Self-Hosted Infrastructure with New Relic APM/Logs & Sentry
Consequences:
  • Positive:
    • Strong TypeScript support improves code quality and developer experience
    • NestJS provides excellent structure and scalability
    • PostgreSQL offers robust relational data management
    • Cloudflare R2 eliminates egress bandwidth costs
    • Self-hosting provides operational autonomy and predictable costs
    • New Relic provides centralized APM and log aggregation
  • Negative:
    • Self-hosting requires maintaining server deployment scripts and backups
    • Team operational responsibility for infrastructure health
Alternatives Considered:
  • Python/Django: More mature but slower development
  • Ruby on Rails: Rapid development but less scalable
  • Go: High performance but smaller ecosystem

ADR 002: Microservices Architecture

Date: 2024-01-20 Status: Accepted Context: As the platform grows, we need to ensure scalability and maintainability. The monolithic architecture was becoming complex to manage and deploy. Decision: We decided to adopt a microservices architecture with the following services:
  • User Service
  • Course Service
  • Payment Service
  • Notification Service
  • Analytics Service
Consequences:
  • Positive:
    • Independent deployment and scaling
    • Technology diversity per service
    • Better fault isolation
    • Smaller, focused teams
  • Negative:
    • Increased complexity in deployment and monitoring
    • Distributed system challenges (consistency, latency)
    • Higher operational overhead
Alternatives Considered:
  • Monolithic with modules: Simpler but less scalable
  • Serverless functions: Good scalability but vendor lock-in

ADR 003: API Design with REST

Date: 2024-01-25 Status: Accepted Context: We needed a consistent API design that would be easy to understand, version, and maintain for both internal and external consumers. Decision: We chose RESTful API design with the following principles:
  • Resource-based URLs
  • Standard HTTP methods
  • JSON responses
  • OpenAPI/Swagger documentation
  • Versioning through URL paths (/api/v1/)
Consequences:
  • Positive:
    • Widely adopted and understood
    • Good tooling support
    • Easy to cache and debug
    • Works well with HTTP infrastructure
  • Negative:
    • Can lead to over-fetching/under-fetching
    • Multiple round trips for complex data
    • Less efficient for mobile networks
Alternatives Considered:
  • GraphQL: More flexible but complex
  • gRPC: High performance but language-specific

ADR 004: Database Schema Design

Date: 2024-02-01 Status: Accepted Context: We needed to design a database schema that supports the core business entities while maintaining data integrity and performance. Decision: We chose PostgreSQL with the following design principles:
  • Normalized schema to reduce redundancy
  • UUID primary keys for scalability
  • JSONB columns for flexible data
  • Proper indexing strategy
  • Foreign key constraints for data integrity
Consequences:
  • Positive:
    • Strong data consistency
    • Excellent JSON support for flexible data
    • Advanced querying capabilities
    • Good performance with proper indexing
  • Negative:
    • More complex queries for denormalized data
    • Migration complexity
    • Learning curve for advanced features
Alternatives Considered:
  • MongoDB: Flexible schema but weaker consistency
  • MySQL: Familiar but less advanced features

ADR 005: Authentication with JWT

Date: 2024-02-05 Status: Accepted Context: We needed a secure and scalable authentication system that works well with microservices and mobile applications. Decision: We implemented JWT-based authentication with:
  • Access tokens with short expiration (1 hour)
  • Refresh tokens for session management
  • Role-based access control (RBAC)
  • Secure token storage
Consequences:
  • Positive:
    • Stateless authentication
    • Works well with microservices
    • Good mobile app support
    • Industry standard
  • Negative:
    • Token revocation complexity
    • No server-side session invalidation
    • Token size can be large
Alternatives Considered:
  • Session-based auth: Server state management
  • OAuth 2.0: More complex but more secure

ADR 006: Payment Processing with Stripe

Date: 2024-02-10 Status: Accepted Context: We needed a reliable payment processing solution that handles various payment methods and provides good developer experience. Decision: We integrated Stripe for payment processing with:
  • Support for multiple payment methods
  • Webhook handling for payment events
  • PCI compliance
  • Subscription management
Consequences:
  • Positive:
    • Excellent developer documentation
    • Comprehensive API
    • Strong security and compliance
    • Good international support
  • Negative:
    • Transaction fees
    • Dependency on third-party service
    • Webhook reliability concerns
Alternatives Considered:
  • PayPal: Higher fees, less developer-friendly
  • Braintree: Good but more complex integration

ADR 007: Deployment with Kubernetes

Date: 2024-02-15 Status: Proposed Context: We need a container orchestration solution that can handle our microservices deployment, scaling, and management. Decision: We are considering Kubernetes for container orchestration with:
  • Automated deployment and scaling
  • Service discovery and load balancing
  • Configuration management
  • Monitoring and logging integration
Consequences:
  • Positive:
    • Industry standard for container orchestration
    • Highly scalable and reliable
    • Rich ecosystem of tools
    • Cloud-agnostic
  • Negative:
    • Steep learning curve
    • Complex setup and maintenance
    • Resource overhead
Alternatives Considered:
  • Docker Compose: Simple but not scalable
  • AWS ECS: AWS-specific, less flexible

ADR Process

Creating a New ADR

  1. Identify Decision: Recognize when an architectural decision needs to be made
  2. Gather Context: Document the problem and constraints
  3. Evaluate Options: Consider multiple alternatives
  4. Make Decision: Choose the best option based on criteria
  5. Document ADR: Create ADR document following the template
  6. Review: Get feedback from team members
  7. Implement: Put the decision into practice
  8. Monitor: Track outcomes and adjust if needed

ADR Status Definitions

  • Proposed: Decision is being considered
  • Accepted: Decision has been made and implemented
  • Rejected: Decision was considered but not chosen
  • Deprecated: Decision is no longer relevant
  • Superseded: Decision has been replaced by another

ADR Maintenance

  • Review ADRs annually for relevance
  • Update status when decisions change
  • Link related ADRs for context
  • Use ADRs for onboarding new team members

Tools and Templates

ADR Creation Script

ADR Template File (adr-template.md)

ADR 008: Beacon Analytics - Direct Database Writes

Date: 2025-01-15 Status: Accepted Context: The beacon analytics system tracks user engagement events (impressions, clicks, bounces) for marketplace entities. We needed to decide between:
  1. Direct database writes on each event
  2. Queue-based processing with background workers
  3. Time-series database for analytics data
Current traffic estimate: ~100 events/minute at launch, scaling with user growth. Decision: We chose direct PostgreSQL writes with the following mitigations:
  • Client-side batching (10 events or 2s timeout)
  • Redis-based deduplication (prevents duplicate DB writes)
  • Rate limiting (50 requests per 5 minutes per IP)
  • Session-based authentication (reduces spam)
Consequences:
  • Positive:
    • Simple architecture, easy to debug
    • No additional infrastructure (queues, workers)
    • Lower latency for real-time dashboards
    • Fewer moving parts to maintain
  • Negative:
    • DB load scales linearly with traffic
    • Potential write contention at high scale
    • No built-in retry mechanism for failed writes
Scaling Triggers: Reconsider this decision when:
  • DB write latency consistently exceeds 50ms
  • Traffic reaches ~1000 concurrent users (~10k events/min)
  • Analytics queries start impacting main DB performance
Migration Path: When scaling is needed:
  1. Phase 1: BullMQ queue with background worker (already in stack)
  2. Phase 2: Batch inserts (100-500 events per query)
  3. Phase 3: TimescaleDB for time-series optimization
Alternatives Considered:
  • BullMQ Queue: Better scalability but added complexity
  • Kafka: Enterprise-grade but overkill for current scale
  • TimescaleDB: Excellent for analytics but migration overhead
  • ClickHouse: High performance but operational complexity
Related ADRs:
  • ADR 001: Technology Stack Selection
  • ADR 004: Database Schema Design