FightRise Architecture

This document provides a high-level overview of the FightRise system architecture.

System Overview

flowchart TB
    subgraph External["External Services"]
        Discord["Discord API"]
        StartGG["Start.gg GraphQL API"]
    end

    subgraph Apps["FightRise Applications"]
        subgraph Bot["Discord Bot (apps/bot)"]
            Commands["Slash Commands"]
            Events["Event Handlers"]
            Handlers["Button/Modal Handlers"]
            Workers["BullMQ Workers"]
            Services["Services Layer"]
        end

        subgraph Web["Web Portal (apps/web)"]
            Pages["Next.js Pages"]
            API["API Routes"]
            Auth["NextAuth.js"]
        end
    end

    subgraph Packages["Shared Packages"]
        DB["Database<br/>(Prisma)"]
        StartGGClient["Start.gg Client"]
        Shared["Shared Types"]
        UI["UI Components"]
    end

    subgraph Infrastructure["Infrastructure"]
        Postgres[(PostgreSQL)]
        Redis[(Redis)]
    end

    %% Discord Bot Flow
    Discord --> Commands
    Discord --> Events
    Commands --> Handlers
    Events --> Handlers
    Handlers --> Services
    Services --> Workers
    Workers --> StartGGClient

    %% Web Portal Flow
    Web --> Pages
    Web --> API
    Web --> Auth
    API --> DB

    %% Service Dependencies
    Services --> DB
    Services --> StartGGClient
    StartGGClient --> StartGG
    Pages --> UI

    %% Database
    DB --> Postgres
    Workers --> Redis

Data Flow

1. Tournament Data Sync (Start.gg → Discord)

sequenceDiagram
    participant User
    participant Discord
    participant Bot
    participant StartGG
    participant DB
    participant Queue

    User->>Discord: /tournament setup
    Discord->>Bot: Command interaction
    Bot->>StartGG: Fetch tournament data
    StartGG-->>Bot: Tournament info
    Bot->>DB: Save tournament
    Bot->>Discord: Confirm setup

    loop Polling (BullMQ)
        Queue->>Bot: Process poll job
        Bot->>StartGG: Query tournament state
        StartGG-->>Bot: Updated data
        Bot->>DB: Update matches
        Note over Bot: Match ready → Create thread
        Bot->>Discord: Create match thread
    end

2. Match Flow (Check-in → Report → Sync)

sequenceDiagram
    participant Player
    participant Discord
    participant Bot
    participant DB
    participant StartGG

    Note over Player,Discord: Match Ready
    Discord->>Player: Thread + @mention

    Note over Player,Discord: Check-in
    Player->>Discord: Click check-in button
    Discord->>Bot: Button interaction
    Bot->>DB: Update check-in status
    Bot->>Discord: Confirm check-in

    Note over Player,Discord: Score Reporting
    Player->>Discord: /report score
    Discord->>Bot: Command interaction
    Bot->>DB: Record score
    Bot->>Discord: Request confirmation

    Player->>Discord: Confirm result
    Discord->>Bot: Confirmation
    Bot->>StartGG: Submit result
    StartGG-->>Bot: Confirmation
    Bot->>DB: Mark complete
    Bot->>Discord: Finalize thread

3. Web Portal Flow

flowchart LR
    User[User] -->|OAuth| Auth[NextAuth]
    Auth -->|Session| Dashboard[Dashboard]
    Dashboard -->|API| Tournaments[Tournaments]
    Tournaments -->|API| Matches[Matches]
    Tournaments --> DB[(PostgreSQL)]
    Matches --> DB
    Auth --> DB

Component Architecture

Discord Bot

apps/bot/src/
├── commands/           # 9 slash commands
│   ├── tournament.ts
│   ├── register.ts
│   ├── checkin.ts
│   ├── report.ts
│   └── ...
├── events/            # Discord event handlers
│   ├── interactionCreate.ts
│   ├── messageCreate.ts
│   └── ...
├── handlers/          # Button/modal interactions
│   ├── checkin.ts
│   ├── scoreHandler.ts
│   └── registration.ts
├── services/          # Business logic
│   ├── pollingService.ts     # BullMQ polling
│   ├── matchService.ts        # Match/thread management
│   ├── tournamentService.ts  # Tournament setup
│   └── ...
├── workers/           # BullMQ job workers
└── index.ts          # Bot entry point

Web Portal

apps/web/
├── app/
│   ├── (auth)/        # Auth pages
│   ├── api/           # API routes
│   │   ├── auth/      # NextAuth endpoints
│   │   ├── matches/   # Match operations
│   │   └── tournaments/
│   ├── dashboard/     # User dashboard
│   └── tournaments/   # Tournament pages
├── components/        # Page-specific components
└── lib/               # Utilities
    └── auth.ts        # NextAuth config

Database Schema (Prisma)

packages/database/prisma/schema.prisma

11 Models:
├── User              # Discord ↔ Start.gg link
├── Tournament        # Cached tournament data
├── Event             # Tournament events (brackets)
├── Match             # Individual matches
├── MatchPlayer       # Match participants
├── GameResult        # Game scores
├── Dispute           # Match disputes
├── Registration      # Tournament entries
├── TournamentAdmin   # Admin roles
├── GuildConfig       # Discord guild settings
└── AuditLog          # Admin action tracking

Technology Stack

Layer Technology
Discord Bot discord.js v14, BullMQ, ioredis
Web Portal Next.js 14 (App Router), NextAuth.js
Database PostgreSQL, Prisma ORM
API Client GraphQL (urql), Start.gg API
UI React, Shared component library
Infrastructure Docker, Redis, PostgreSQL

Key Patterns

Idempotent Database Operations

const result = await prisma.match.updateMany({
  where: { id: matchId, state: MatchState.NOT_STARTED },
  data: { discordThreadId: thread.id, state: MatchState.CALLED },
});

if (result.count === 0) {
  // Already processed - skip
  return;
}

Transactional Updates

await prisma.$transaction(async (tx) => {
  await tx.match.update({ where: { id }, data: { state: 'IN_PROGRESS' } });
  await tx.matchPlayer.updateMany({
    where: { matchId: id },
    data: { isCheckedIn: true }
  });
});

Service Layer Separation

  • Commands/Handlers: Discord interaction handling
  • Services: Business logic, database operations
  • Workers: Async job processing (polling and sync)