Skip to content

Technical Architecture

System Overview

Oddxer is built as a modern, scalable microservices-ready application with real-time capabilities, secure authentication, and optimized database performance.

mermaid
graph TB
    subgraph "Client Layer"
        A[Web App - React 18]
        B[Mobile App - React Native]
        C[Admin Dashboard]
    end
    
    subgraph "API Gateway"
        D[Express.js Server]
        E[Socket.io Server]
    end
    
    subgraph "Business Logic"
        F[Auth Service]
        G[Code Service]
        H[Wallet Service]
        I[Vote Service]
        J[Leaderboard Service]
    end
    
    subgraph "Data Layer"
        K[(MongoDB)]
        L[(Redis Cache)]
    end
    
    subgraph "External Services"
        M[SMS Provider]
        N[Mobile Money APIs]
        O[Bookmaker APIs]
    end
    
    A --> D
    B --> D
    C --> D
    A --> E
    B --> E
    
    D --> F
    D --> G
    D --> H
    D --> I
    D --> J
    
    F --> K
    G --> K
    H --> K
    I --> K
    J --> K
    
    F --> L
    G --> L
    
    F --> M
    H --> N
    I --> O
    
    style A fill:#4CAF50
    style B fill:#4CAF50
    style C fill:#4CAF50
    style D fill:#2196F3
    style E fill:#FF9800
    style K fill:#9C27B0

Technology Stack

Backend

  • Runtime: Node.js 18+
  • Framework: Express.js 4.x
  • Language: TypeScript 5.x
  • Real-time: Socket.io 4.x
  • Authentication: JWT (jsonwebtoken)
  • Validation: Joi
  • Password Hashing: bcryptjs

Database

  • Primary Database: MongoDB 6.x
  • ODM: Mongoose 8.x
  • Caching: Redis 7.x (planned)
  • Indexing: Compound indexes for performance

Frontend

  • Framework: React 18
  • Build Tool: Vite 5.x
  • Styling: TailwindCSS 3.x
  • State Management: Context API / Redux (planned)
  • HTTP Client: Axios / Fetch API
  • WebSocket: Socket.io Client

DevOps

  • Version Control: Git
  • CI/CD: GitHub Actions (planned)
  • Containerization: Docker (planned)
  • Hosting: VPS / Cloud (AWS/DigitalOcean)
  • Monitoring: Grafana + Prometheus (planned)

Application Architecture

Layered Architecture

┌─────────────────────────────────────┐
│         Presentation Layer          │
│   (Routes, Controllers, Middleware) │
├─────────────────────────────────────┤
│         Business Logic Layer        │
│           (Services)                │
├─────────────────────────────────────┤
│          Data Access Layer          │
│      (Models, Repositories)         │
├─────────────────────────────────────┤
│           Database Layer            │
│      (MongoDB, Redis)               │
└─────────────────────────────────────┘

Directory Structure

oddxer-api/
├── src/
│   ├── app.ts                 # Express app configuration
│   ├── server.ts              # Server entry point
│   ├── config/
│   │   ├── database.ts        # MongoDB connection
│   │   ├── socket.ts          # Socket.io setup
│   │   └── jwt.ts             # JWT configuration
│   ├── controllers/
│   │   ├── auth.controller.ts
│   │   ├── code.controller.ts
│   │   ├── wallet.controller.ts
│   │   ├── vote.controller.ts
│   │   └── leaderboard.controller.ts
│   ├── services/
│   │   ├── auth.service.ts
│   │   ├── code.service.ts
│   │   ├── wallet.service.ts
│   │   ├── vote.service.ts
│   │   └── leaderboard.service.ts
│   ├── models/
│   │   ├── user.model.ts
│   │   ├── betting-code.model.ts
│   │   ├── wallet.model.ts
│   │   ├── transaction.model.ts
│   │   ├── vote.model.ts
│   │   └── leaderboard.model.ts
│   ├── routes/
│   │   ├── auth.routes.ts
│   │   ├── code.routes.ts
│   │   ├── wallet.routes.ts
│   │   ├── vote.routes.ts
│   │   └── leaderboard.routes.ts
│   ├── middleware/
│   │   ├── auth.ts            # JWT authentication
│   │   ├── validate.ts        # Joi validation
│   │   ├── errorHandler.ts    # Global error handler
│   │   └── rateLimiter.ts     # Rate limiting
│   ├── validators/
│   │   ├── auth.validator.ts
│   │   ├── code.validator.ts
│   │   ├── wallet.validator.ts
│   │   └── vote.validator.ts
│   ├── utils/
│   │   ├── ApiResponse.ts     # Standardized responses
│   │   ├── ApiError.ts        # Custom error class
│   │   └── generateOtp.ts     # OTP generation
│   └── types/
│       └── index.ts           # TypeScript interfaces
├── package.json
├── tsconfig.json
└── .env

Database Schema Design

Entity Relationship Diagram

mermaid
erDiagram
    User ||--o{ BettingCode : creates
    User ||--|| Wallet : has
    User ||--o{ Transaction : makes
    User ||--o{ Vote : casts
    User ||--|| Leaderboard : has
    
    BettingCode ||--o| User : soldTo
    BettingCode ||--o{ Vote : receives
    BettingCode ||--o{ Transaction : generates
    
    Wallet ||--o{ Transaction : contains
    
    User {
        ObjectId _id PK
        string phoneNumber UK
        string username UK
        string email
        enum role
        boolean isVerified
        boolean isActive
        string otp
        date otpExpires
        array refreshTokens
        date createdAt
        date updatedAt
    }
    
    BettingCode {
        ObjectId _id PK
        ObjectId seller FK
        enum sport
        string title
        string description
        number odds
        string bookmaker
        number price
        enum status
        string code
        date expiresAt
        ObjectId soldTo FK
        date soldAt
        date finalizedAt
        number winVotes
        number lossVotes
        number totalVotes
        date createdAt
        date updatedAt
    }
    
    Wallet {
        ObjectId _id PK
        ObjectId user FK
        number balance
        string currency
        date createdAt
        date updatedAt
    }
    
    Transaction {
        ObjectId _id PK
        ObjectId user FK
        enum type
        number amount
        string currency
        enum paymentMethod
        enum status
        string reference UK
        ObjectId bettingCode FK
        object metadata
        date createdAt
        date updatedAt
    }
    
    Vote {
        ObjectId _id PK
        ObjectId bettingCode FK
        ObjectId voter FK
        enum voteType
        date createdAt
    }
    
    Leaderboard {
        ObjectId _id PK
        ObjectId seller FK
        number totalSales
        number totalWins
        number totalLosses
        number winRate
        number averageROI
        number totalRevenue
        number rank
        date updatedAt
    }

Database Indexes

Optimized indexes for high-performance queries:

User Collection

javascript
db.users.createIndex({ phoneNumber: 1 })        // Login lookup
db.users.createIndex({ username: 1 })            // Unique username
db.users.createIndex({ role: 1 })                // Role filtering
db.users.createIndex({ isActive: 1 })            // Active users

BettingCode Collection

javascript
db.bettingcodes.createIndex({ seller: 1, status: 1 })          // Seller's codes
db.bettingcodes.createIndex({ sport: 1, status: 1 })           // Sport filtering
db.bettingcodes.createIndex({ status: 1, sport: 1, price: 1 }) // Marketplace query
db.bettingcodes.createIndex({ price: 1 })                       // Price sorting
db.bettingcodes.createIndex({ expiresAt: 1 })                  // Expiry checks
db.bettingcodes.createIndex({ createdAt: -1 })                 // Recent codes
db.bettingcodes.createIndex({ soldTo: 1 })                     // Buyer's purchases

Transaction Collection

javascript
db.transactions.createIndex({ user: 1, type: 1 })    // User's transaction type
db.transactions.createIndex({ user: 1, status: 1 })  // User's pending transactions
db.transactions.createIndex({ reference: 1 })         // Reference lookup
db.transactions.createIndex({ createdAt: -1 })        // Recent transactions

Vote Collection

javascript
db.votes.createIndex({ bettingCode: 1, voter: 1 }, { unique: true }) // One vote per user
db.votes.createIndex({ bettingCode: 1, voteType: 1 })                // Vote counting
db.votes.createIndex({ voter: 1 })                                    // User's votes

Leaderboard Collection

javascript
db.leaderboards.createIndex({ seller: 1 })                                // Seller lookup
db.leaderboards.createIndex({ winRate: -1 })                              // Win rate ranking
db.leaderboards.createIndex({ totalSales: -1 })                           // Sales ranking
db.leaderboards.createIndex({ totalRevenue: -1 })                         // Revenue ranking
db.leaderboards.createIndex({ winRate: -1, totalSales: -1, totalRevenue: -1 }) // Composite ranking
db.leaderboards.createIndex({ rank: 1 })                                  // Rank lookup

Authentication Flow

mermaid
sequenceDiagram
    participant U as User
    participant C as Client App
    participant A as API Server
    participant DB as Database
    participant SMS as SMS Provider
    
    Note over U,SMS: Registration Flow
    U->>C: Enter phone + username
    C->>A: POST /auth/register
    A->>DB: Check if user exists
    DB-->>A: Not exists
    A->>A: Generate 6-digit OTP
    A->>DB: Save user with OTP
    A->>SMS: Send OTP to phone
    SMS-->>U: SMS with OTP
    A-->>C: 201 Created (OTP sent)
    
    Note over U,SMS: Verification Flow
    U->>C: Enter OTP
    C->>A: POST /auth/verify-otp
    A->>DB: Validate OTP
    DB-->>A: OTP valid
    A->>A: Generate JWT tokens
    A->>DB: Update user.isVerified = true
    A->>DB: Store refresh token (hashed)
    A-->>C: Access + Refresh tokens
    C->>C: Store tokens
    
    Note over U,SMS: Authenticated Request
    C->>A: GET /wallet (Bearer token)
    A->>A: Verify JWT signature
    A->>A: Check token expiry
    A->>DB: Fetch user data
    DB-->>A: User data
    A-->>C: Wallet data
    
    Note over U,SMS: Token Refresh
    C->>A: POST /auth/refresh
    A->>DB: Validate refresh token
    DB-->>A: Token valid
    A->>A: Generate new access token
    A->>DB: Rotate refresh token
    A-->>C: New tokens

Real-Time Architecture

Socket.io Event Flow

mermaid
graph LR
    A[User Action] --> B[API Endpoint]
    B --> C[Service Layer]
    C --> D[Database Update]
    D --> E[Emit Socket Event]
    E --> F[Socket.io Server]
    F --> G[Connected Clients]
    G --> H[UI Update]
    
    style E fill:#FF9800
    style F fill:#FF9800

Socket.io Connection Management

Server-Side (config/socket.ts):

typescript
import { Server } from 'socket.io';
import jwt from 'jsonwebtoken';

export const initializeSocket = (server: http.Server) => {
  const io = new Server(server, {
    cors: { origin: process.env.CLIENT_URL }
  });
  
  // Authentication middleware
  io.use((socket, next) => {
    const token = socket.handshake.auth.token;
    if (!token) return next(new Error('Authentication required'));
    
    try {
      const decoded = jwt.verify(token, process.env.JWT_SECRET);
      socket.data.userId = decoded.userId;
      next();
    } catch (error) {
      next(new Error('Invalid token'));
    }
  });
  
  io.on('connection', (socket) => {
    console.log(`User connected: ${socket.data.userId}`);
    
    // Join user's personal room
    socket.join(`user:${socket.data.userId}`);
    
    // Subscribe to sport-specific channels
    socket.on('subscribe:sport', ({ sport }) => {
      socket.join(`sport:${sport}`);
    });
    
    socket.on('disconnect', () => {
      console.log(`User disconnected: ${socket.data.userId}`);
    });
  });
  
  return io;
};

// Emit functions
export const emitNewCode = (code: any) => {
  io.to(`sport:${code.sport}`).emit('code:created', code);
};

export const emitCodePurchased = (codeId: string, sellerId: string) => {
  io.to(`user:${sellerId}`).emit('code:purchased', { codeId });
};

export const emitWalletUpdate = (userId: string, balance: number) => {
  io.to(`user:${userId}`).emit('wallet:updated', { balance });
};

Security Architecture

Security Layers

┌─────────────────────────────────────┐
│      1. Network Security            │
│  (HTTPS, CORS, Rate Limiting)       │
├─────────────────────────────────────┤
│      2. Authentication              │
│  (JWT, OTP, Refresh Tokens)         │
├─────────────────────────────────────┤
│      3. Authorization               │
│  (RBAC, Resource Ownership)         │
├─────────────────────────────────────┤
│      4. Input Validation            │
│  (Joi Schemas, Sanitization)        │
├─────────────────────────────────────┤
│      5. Data Protection             │
│  (Hashing, Encryption, Hiding)      │
└─────────────────────────────────────┘

Security Features

  1. Password-less Authentication: Phone-based OTP eliminates password vulnerabilities
  2. JWT Tokens: Short-lived access tokens (15min), long-lived refresh tokens (7d)
  3. Token Rotation: Refresh tokens rotated on each use
  4. Bcrypt Hashing: OTP and refresh tokens hashed before storage
  5. Role-Based Access Control: Granular permissions (BUYER, SELLER, ADMIN)
  6. Input Validation: All inputs validated with Joi schemas
  7. SQL Injection Protection: MongoDB prevents SQL injection
  8. XSS Protection: Data sanitization and Content Security Policy
  9. CORS Configuration: Whitelisted origins only
  10. Rate Limiting: Prevents brute force and DDoS attacks

Scalability Considerations

Horizontal Scaling

mermaid
graph TB
    A[Load Balancer] --> B[API Server 1]
    A --> C[API Server 2]
    A --> D[API Server 3]
    
    B --> E[(MongoDB Primary)]
    C --> E
    D --> E
    
    E --> F[(MongoDB Secondary)]
    E --> G[(MongoDB Secondary)]
    
    B --> H[(Redis Cache)]
    C --> H
    D --> H
    
    style A fill:#FF9800
    style E fill:#9C27B0
    style H fill:#F44336

Performance Optimizations

  1. Database Indexing: Strategic compound indexes for common queries
  2. Connection Pooling: Reuse MongoDB connections
  3. Caching Layer: Redis for frequently accessed data
  4. Pagination: All list endpoints paginated
  5. Lean Queries: Mongoose lean() for read-only operations
  6. Aggregation Pipeline: Efficient leaderboard calculations
  7. Lazy Loading: Code field hidden until purchase
  8. Virtual Fields: Calculated fields not stored in DB

Monitoring & Observability

Planned Implementation:

  • Application Metrics: Response times, error rates, throughput
  • Database Metrics: Query performance, connection pool usage
  • Real-time Metrics: Socket.io connections, events per second
  • Business Metrics: Transactions, user growth, revenue
  • Logging: Structured logging with Winston
  • Alerting: Critical error notifications via email/Slack

Deployment Architecture

Production Environment

┌─────────────────────────────────────────┐
│         Cloudflare (CDN + DDoS)         │
└─────────────────┬───────────────────────┘

┌─────────────────▼───────────────────────┐
│         Nginx (Reverse Proxy)           │
└─────────────────┬───────────────────────┘

      ┌───────────┴───────────┐
      │                       │
┌─────▼─────┐         ┌──────▼──────┐
│ API Server│         │ Socket.io   │
│ (PM2)     │         │ Server (PM2)│
└─────┬─────┘         └──────┬──────┘
      │                      │
      └───────────┬──────────┘

      ┌───────────▼──────────┐
      │  MongoDB Atlas       │
      │  (Replica Set)       │
      └──────────────────────┘

Environment Variables

bash
# Server
NODE_ENV=production
PORT=6793
API_URL=https://api.oddxer.com

# Database
MONGODB_URI=mongodb+srv://...
DB_NAME=oddxer

# JWT
JWT_SECRET=your_secret_key
JWT_ACCESS_EXPIRY=15m
JWT_REFRESH_EXPIRY=7d

# OTP
OTP_EXPIRY=10m
OTP_LENGTH=6

# SMS Provider
SMS_API_KEY=...
SMS_SENDER_ID=ODDXER

# Mobile Money
MTN_API_KEY=...
AIRTEL_API_KEY=...

# Socket.io
SOCKET_CORS_ORIGIN=https://oddxer.com

# Redis (optional)
REDIS_URL=redis://...

API Response Time Targets

Endpoint TypeTargetCurrent
Authentication<300ms~250ms
Code browsing<200ms~180ms
Code purchase<500ms~400ms
Wallet operations<300ms~280ms
Leaderboard<250ms~220ms
Voting<200ms~150ms

Future Architecture Enhancements

  1. Microservices: Split into Auth, Marketplace, Wallet, Voting services
  2. Message Queue: RabbitMQ/Kafka for async processing
  3. CDN: CloudFront for static asset delivery
  4. Redis Caching: Cache hot data (leaderboard, popular codes)
  5. Elasticsearch: Advanced search capabilities
  6. GraphQL: Alternative API for flexible queries
  7. gRPC: Inter-service communication
  8. Service Mesh: Istio for service management
  9. Kubernetes: Container orchestration
  10. Multi-Region: Deploy across multiple regions for low latency

Last Updated: 2025-12-01

One chat. Everything done.