Skip to main content

Software Architecture Document: Learnille Server

1. Introduction

1.1. Purpose 1.2. Scope 1.3. Definitions, Acronyms, and Abbreviations 1.4. References 1.5. Overview of the Remainder of the Document

2. Architectural Representation

2.1. Architectural Goals

  • Modularity: Achieved through NestJS modules for distinct features.
  • Scalability: Leveraging technologies like Node.js, PostgreSQL, Redis, and BullMQ.
  • Maintainability: TypeScript for type safety, consistent structure via NestJS.
  • Security: JWT-based authentication, role-based access control (CASL observed), Helmet for security headers.
  • Testability: Structure supports unit, integration, and e2e testing (Jest setup observed). 2.2. Constraints
  • Technology Stack: Primarily NestJS (Node.js/TypeScript), PostgreSQL, Redis.
  • Reliance on specific third-party services (e.g., Paystack, Novu, Sentry, New Relic, Cloudflare R2 / S3, InstantDB/Triplit, ClickHouse, Shlink). 2.3. Key Architectural Decisions & Rationale
  • Choice of NestJS: Provides a robust, modular framework for building scalable server-side applications with TypeScript.
  • Modular Design: Enhances separation of concerns, maintainability, and team collaboration.
  • Use of TypeORM: Offers a powerful ORM for database interaction with PostgreSQL.
  • JWT for Authentication: Standard and stateless approach for API security.
  • Asynchronous Processing with BullMQ: For handling background tasks and improving responsiveness.
  • Centralized Configuration: Using @nestjs/config with environment-specific files and Joi validation.
  • Event-Driven Elements: Use of @nestjs/event-emitter for decoupling components.

3. System Overview and Context

3.1. System Context Diagram (Conceptual - to be described textually for now) The Learnille Server acts as the central backend API for various clients (web application, mobile applications). It interacts with:

  • Databases: Self-Hosted PostgreSQL (primary), Redis (caching/session/rate-limiting), OpenSearch (search), InstantDB/Triplit.
  • Payment Gateways: Paystack, Flutterwave.
  • Notification Service: Novu.
  • Error Tracking & Monitoring: Sentry, New Relic.
  • File Storage: Cloudflare R2 (S3 API compatible) / MinIO.
  • Authentication: Google & Apple (for social login).
  • URL Shortening: Shlink. 3.2. Major Components
  • API Layer: Exposes RESTful endpoints (NestJS Controllers).
  • Application Core: Business logic encapsulated in NestJS Services and Modules.
  • Data Access Layer: TypeORM repositories interacting with databases.
  • Infrastructure Services: Wrappers or integrations for Redis, BullMQ, OpenSearch, Novu, New Relic, Sentry, etc.
  • External Service Integrations: Clients/SDKs for Paystack, Flutterwave, Google, Cloudflare R2, etc.

4. Architectural Views

4.1. Logical View / Module View 4.1.1. Overview The application is structured as a set of NestJS modules. A root AppModule imports core infrastructure modules and feature-specific modules.

graph LR
subgraph User Interaction
UI(Frontend)
end

subgraph Backend API (NestJS)
subgraph Core Modules
AppMod(AppModule) --> Cfg(ConfigModule)
AppMod --> DB(DatabaseModule)
AppMod --> Auth(AuthModule)
AppMod --> Redis(RedisModule)
AppMod --> Bull(BullMQModule)
AppMod --> Elastic(ElasticModule)
AppMod --> Notify(NotificationModule)
AppMod --> Common(Common Utils)
end

subgraph Feature Modules
Market(MarketplaceModule) -- uses --> Elastic
Consult(ConsultationModule) -- uses --> User(UsersModule)
Consult -- uses --> Timeslot(TimeslotService)
Consult -- triggers --> Pay(PaymentModule)
Cart(CartModule) -- holds --> ConsultEntity(Consultation Entity)
Cart -- holds --> CourseEntity(Course Entity)
Pay -- uses --> User
Pay -- uses --> PayGW(PaystackModule)
Pay -- updates --> Wallet(WalletService)
Pay -- triggers --> Enroll(EnrollmentModule)
Pay -- triggers --> Notify
end
end

UI --> Market
UI --> Consult
UI --> Cart
Market --> Consult
Consult --> Pay
Cart --> Pay # Assumed Checkout Flow

4.1.2. Core Infrastructure Modules

  • ConfigModule: Manages environment variables and application configuration with Joi validation.
  • DatabaseModule (custom, likely wraps TypeOrmModule): Manages PostgreSQL database connections and entity registration.
  • AuthModule: Handles authentication (JWT, local, Google), authorization strategies, and user session management.
  • CryptoModule: Provides cryptographic functions (password hashing, JWT signing/verification).
  • RedisModule: Manages Redis connections for caching and potentially other uses (e.g., Throttler storage).
  • BullmqCustomModule: Manages BullMQ for background job processing.
  • ElasticModule: Integrates with Elasticsearch for search capabilities.
  • NotificationModule & NovuModule: Manages notifications via Novu (workflows, subscribers).
  • SentryModule: Integrates Sentry for error tracking and performance monitoring.
  • MailerModule: Handles email sending via SMTP with Handlebars templating.
  • ClickHouseModule: Integrates ClickHouse for analytics.
  • StorageModule (with SimpleStorageService): Manages file storage (e.g., S3).
  • LoggerModule (nestjs-pino) / Winston: Provides structured logging capabilities.
  • TerminusModule: For health checks.
  • ThrottlerModule: For API rate limiting.
  • EventEmitterModule: For in-application event handling. 4.1.3. Key Feature Modules (Initial list based on analysis)
  • UsersModule: Manages user profiles, roles, and basic user data.
  • CourseModule: Manages course creation, content (sections, subsections, items), instructors, categories, levels, pricing, and related metadata.
  • ConsultationModule: Manages consultation offerings, consultant availability (timeslots), user bookings, and individual consultation sessions. It supports different consultation types (e.g., one-off, recurring) and integrates with ElasticModule for search, PaymentModule for billing, NotificationModule for reminders, and ReviewsModule for feedback. It has its own set of entities for consultations, bookings, timeslots, and type-specific metadata.
  • PaymentModule: Orchestrates financial transactions. It integrates with payment gateways (e.g., PaystackModule) to process incoming payments for orders. It manages Payment entities and includes a WalletService and WalletController for user fund management and withdrawals. It interacts closely with OrderModule, UsersModule, CourseModule, ConsultationModule, and EnrollmentModule.
  • PaystackModule: (If not already listed separately) Provides a dedicated interface for interacting with the Paystack payment gateway API, including payment initiation and webhook handling.
  • InstructorsModule: Manages instructor-specific profiles, linking them to base User accounts. It handles details like professional experience, achievements, expertise, and resume. It's tightly coupled with UsersModule and CourseModule (as instructors create courses) and interacts with FilesModule for resume/profile picture storage and potentially EnrollmentModule for viewing course enrollments. It may use a shared ProviderService for managing common profile sections like experiences and achievements.
  • ConsultantModule: Manages consultant-specific profiles, linking them to base User accounts. It handles details like professional experience, achievements, expertise, resume, and availability. It's tightly coupled with UsersModule and ConsultationModule (as consultants offer consultations) and interacts with FilesModule for resume/profile picture storage, ReviewsModule for feedback, and uses a shared ProviderService for managing common profile sections and availability.
  • CartModule: Provides shopping cart functionality, allowing users to add and manage items (courses, consultations) before purchase. It interacts with product modules for item details and OrderModule for checkout.
  • OrderModule: Manages the order creation process. It takes items (often from a cart), applies coupons, calculates totals, and creates Order records. It's a crucial intermediary to PaymentModule for initiating transactions and EnrollmentModule for post-payment fulfillment.
  • ReviewsModule: Handles user-submitted reviews and ratings for products (courses, consultations). Interacts with product modules to update aggregate ratings and EnrollmentModule for review eligibility. May integrate with ElasticModule.
  • MarketplaceModule: Powers the public-facing discovery of products. Relies heavily on ElasticModule for search/filtering and integrates RecommendationModule.
  • StudentsModule: Manages student-specific profiles (linked to User) and their interactions, particularly closely tied to EnrollmentModule.
  • ImpressionModule: Tracks user views/interactions with content like courses and consultations, likely feeding data to analytics or recommendation systems.
  • EnrollmentModule: Manages user enrollment in products, often triggered by successful payments. Includes an EnrollmentListener for event-driven enrollment creation and tracks granular progress.
  • CommsModule: Integrates with third-party communication platforms (e.g., Stream, CometChat) for features like chat/calls, managing user tokens for these services.
  • CategoryModule: Manages the hierarchical categorization of content (courses, consultations).
  • (Others to be detailed as analysis progresses: Product, etc.) 4.2. Development View 4.2.1. Source Code Organization: Primarily within src/, with modules in dedicated subdirectories (e.g., src/users, src/course). Common utilities might reside in src/common or src/shared. Configuration in src/config.ts and env/ directory. 4.2.2. Key Frameworks and Libraries: NestJS, TypeORM, Express.js (underlying NestJS), Passport.js, Joi, BullMQ, Elasticsearch client, Novu SDK, Sentry SDK, Paystack SDK. 4.2.3. Build Process: npm run build (uses nest build). 4.3. Deployment View 4.3.1. Target Environment(s): Local, Development, Staging, Production (as indicated by .env file structure and NODE_ENV usage). 4.3.2. Physical Infrastructure (Conceptual):
  • Application Server(s) running Node.js (v22 specified).
  • PostgreSQL Database Server.
  • Redis Server.
  • Elasticsearch Cluster.
  • ClickHouse Server.
  • InstantDB/Triplit Server (can be run via docker-compose.yml locally).
  • Dependencies on external services (Paystack, Novu, Sentry, Google, S3, Shlink). 4.3.3. Containerization Strategy: docker-compose.yml provided is for triplit-server. The main application's containerization strategy for deployment is not yet fully detailed from current files but likely involves Docker. 4.3.4. Technology Stack Summary: Node.js (v22), TypeScript, NestJS, PostgreSQL, Redis, Elasticsearch, BullMQ, Novu, Sentry, Paystack, S3, ClickHouse, InstantDB.

5. Data Architecture

5.1. Data Persistence Strategy

  • Primary Relational Database: PostgreSQL (managed via TypeORM).
  • Caching/Session/Rate-Limiting: Redis.
  • Search Indexing: Elasticsearch.
  • Analytics: ClickHouse.
  • Real-time/Collaborative Data: InstantDB/Triplit. 5.2. High-Level Data Model (Key entities identified so far)
  • User: Core user information, roles, credentials.
  • Login: Tracks login sessions/attempts.
  • ForgotPassword, VerifyEmail: Tokens for account recovery/verification.
  • Course: Main course details, pricing, instructor, category, level.
  • CourseSection, CourseSubSection, CourseItem: Hierarchical course content.
  • Instructor: Profile specific to instructors, linked to a User, contains professional details, resume, and courses they manage.
  • Consultant: Profile specific to consultants, linked to a User, contains professional details, resume, availability, and consultations they offer.
  • Student: Role-specific profiles linked to Users.
  • Consultation: Main consultation offering details, type, consultant, pricing.
  • Booking: User bookings for consultations.
  • ConsultationTimeSlot: Consultant availability.
  • ConsultationSession: Individual consultation sessions.
  • OneOffConsultationMeta, RecurringConsultation: Metadata for specific consultation types.
  • Payment: Records of financial transactions, linked to orders, users, and gateways.
  • Withdrawal: Records of user withdrawal requests from their wallets.
  • Order: Represents a user's intention to purchase items (courses, consultations).
  • OrderItem: Represents individual items within an order.
  • Cart: Represents a user's shopping cart.
  • CartItem: Represents individual items within a cart.
  • Coupon, CouponUsage: For managing discount codes.
  • Category: For course categorization.
  • Student: Profile for student users.
  • Enrollment, SectionEnrollment: Tracks user enrollment and progress in products.
  • Review: Stores user reviews and ratings.
  • UserAuthTokens (Comms): Stores tokens for external communication services.
  • File: For storing references to uploaded files (profile photos, course materials).
  • (Others to be added: PaymentTransaction, EnrollmentRecord, Product, etc.) 5.3. Data Flow for Key Use Cases
  • User Registration: Client -> API (/auth/register) -> AuthService -> UsersService (creates User) -> Role-specific service (creates Instructor/Student/Consultant profile) -> DB. Event emitted, Novu notification triggered.
  • Course Creation: Client -> API (/course) -> CourseController -> CourseService -> DB (creates Course, links to Instructor, Category, Files, etc.). Event emitted.
  • Consultation Booking: User (Client) browses consultations (via API, potentially using Elasticsearch) -> Selects a consultation and an available timeslot -> Submits booking request (API: POST /consultation/booking) -> ConsultationController -> ConsultationService (validates timeslot, creates Booking entity, potentially links to ConsultationSession) -> Triggers payment flow (via PaymentModule) -> On success, confirms booking, sends notifications (via NovuModule).
  • Checkout Flow: User adds items to Cart (via CartModule) -> User proceeds to checkout -> OrderService creates an Order from Cart items, applies coupons, calculates total, sets status to PENDING -> (Rest of payment flow as previously described, starting with PaymentsService._initiatePaymentForOrder).
  • Product Discovery: User searches/filters on Marketplace UI -> API (/marketplace/*) -> MarketplaceController -> MarketplaceService -> ElasticModule (queries Elasticsearch) -> Returns product list.
  • Leaving a Review: User (Student) submits review for a Course -> API (/review) -> ReviewsController -> ReviewsService (validates eligibility, e.g., via EnrollmentService) -> Saves Review entity -> Updates aggregate rating on Course entity.

6. Cross-Cutting Concerns

6.1. Security Architecture

  • Authentication: JWT-based. LocalStrategy for email/password, GoogleStrategy for Google OAuth. Managed by AuthModule and Passport.js.
  • Authorization: Role-based access control (RBAC) implied by UserRole and potentially fine-grained with CaslGuard (seen in CourseController).
  • Input Validation: class-validator DTOs with ValidationPipe.
  • HTTP Security Headers: helmet middleware.
  • CORS: Enabled via app.enableCors().
  • Secret Management: Primarily through environment variables (.env files, ConfigModule). KEYS_DIR in config suggests potential for local key storage. 6.2. Error Handling and Fault Tolerance
  • Global Exception Filter: AllExceptionsFilter in main.ts for standardized error responses.
  • Custom exceptions defined per module (e.g., PhotoNotFoundException in UsersModule).
  • Sentry: Integrated for error tracking and reporting (SentryModule, process-level handlers in main.ts). 6.3. Logging and Monitoring
  • Structured Logging: nestjs-pino or Winston (conditional in main.ts). AppRequestLoggerMiddleware for HTTP request logging.
  • Performance Monitoring: Sentry APM (implied by instrument.ts and Sentry setup).
  • Health Checks: TerminusModule imported, likely for /health endpoints. 6.4. Configuration Management
  • @nestjs/config loading environment-specific .env files from env/.
  • Joi schema validation (src/config.ts) for environment variables.
  • Type-safe access via ConfigService and Config interface. 6.5. API Design
  • RESTful principles generally followed.
  • Standardized response format via ResponseInterceptor (seen in main.ts).
  • API documentation via Swagger (setup in main.ts, available at /docs). 6.6. Asynchronous Processing
  • BullmqCustomModule for background jobs (e.g., email sending, long computations).

7. Design Rationale

7.1. Why NestJS?

  • Opinionated framework providing structure for large applications.
  • Excellent TypeScript support.
  • Modular architecture promotes separation of concerns.
  • Built-in support for microservices, testing, and common patterns. 7.2. Why a Modular Architecture?
  • Improved maintainability and testability.
  • Allows for parallel development by teams.
  • Clear boundaries between different functional areas of the application. 7.3. Rationale for Database Choices
  • PostgreSQL: Robust, feature-rich relational database suitable for complex data models.
  • Redis: High-performance key-value store ideal for caching, session management, and rate limiting.
  • Elasticsearch: Powerful search engine for providing fast and relevant search results (e.g., for courses).
  • ClickHouse: Columnar database optimized for OLAP queries and analytics.
  • InstantDB/Triplit: Real-time database capabilities.

Appendix

  • (Diagrams can be added here later if text-based representations are feasible)