Skip to content

Developer OverviewΒΆ

Welcome to the OSCAR Bot developer documentation. This guide helps you understand, set up, and extend the bot.


Quick StartΒΆ


High-Level ArchitectureΒΆ

OSCAR connects Discord users with University module data. For detailed component diagrams and data flows, see the Architecture Guide.

graph LR
    %% --- STYLING ---
    classDef user fill:#0068b4,stroke:#dfe0e2,stroke-width:2px,color:#ffffff,font-weight:bold;
    classDef discord fill:#5865F2,stroke:#dfe0e2,stroke-width:2px,color:#ffffff,font-weight:bold;
    classDef oscar fill:#5f6af0,stroke:#dfe0e2,stroke-width:3px,color:#ffffff,font-weight:bold;
    classDef nextcloud fill:#0082c9,stroke:#dfe0e2,stroke-width:2px,color:#ffffff,font-weight:bold;
    classDef database fill:#727378,stroke:#dfe0e2,stroke-width:2px,color:#ffffff,font-weight:bold;

    %% --- NODES ---
    User("Discord User"):::user
    Discord("Discord API"):::discord
    OSCAR("OSCAR Bot"):::oscar

    %% Grouping data sources visually via positioning
    Nextcloud("Nextcloud tables<br/>Module Data"):::nextcloud
    Database("SQLite<br/>User Data & Cache"):::database

    %% --- CONNECTIONS ---
    %% Forward Flow
    User -->|Command| Discord
    Discord -->|Event| OSCAR

    %% Data Retrieval (Parallel)
    OSCAR <-->|Read/Write| Database
    OSCAR <-->|Fetch Data| Nextcloud

    %% Return Flow
    OSCAR -->|Response| Discord
    Discord -->|Result| User

    %% --- LINK STYLES ---
    linkStyle 0 stroke:#0068b4,stroke-width:2px,fill:none
    linkStyle 1 stroke:#5865F2,stroke-width:2px,fill:none
    linkStyle 2 stroke:#727378,stroke-width:2px,fill:none
    linkStyle 3 stroke:#0082c9,stroke-width:2px,fill:none
    linkStyle 4 stroke:#5f6af0,stroke-width:2px,fill:none
    linkStyle 5 stroke:#5865F2,stroke-width:2px,fill:none
graph TB
    subgraph System["OSCAR Discord Bot System"]
        subgraph Frontend["Frontend Layer"]
            Discord["Discord API<br/>Events & Interactions"]
        end

        subgraph Application["Application Layer"]
            BotCore["Bot Core<br/>oscar.py"]

            subgraph CommandLayer["Command Layer - Cogs"]
                ModulCog["πŸ” Module Cog<br/>Search & Filter"]
                AdminCog["πŸ“Š Admin Cog<br/>Feedback Review"]
                HelpCog["❓ Help Cog<br/>Support"]
            end

            subgraph PresentationLayer["Presentation Layer - UI"]
                Views["Views<br/>Start, Module, Feedback<br/>Semesterplan, Select"]
                Components["Components<br/>Buttons, Selects<br/>Custom Elements"]
            end
        end

        subgraph Business["Business Logic Layer"]
            Filter["Filter Engine<br/>CP/SWS Filtering"]
            Analytics["Analytics Engine<br/>Statistics & Plots"]
        end

        subgraph Data["Data Layer"]
            Database["SQLite<br/>User Data & Cache"]
            ModuleCache["Module Cache<br/>In Memory"]
        end

        subgraph Integration["Integration Layer"]
            TableAPI["Tables API Client<br/>Nextcloud API"]
        end

        subgraph Resources["Resources & Config"]
            i18n["i18n System<br/>Translations"]
            Enums["Enums & Types<br/>LanguageCode<br/>StudyCourse"]
            TypedDicts["TypedDicts<br/>Data Structures"]
        end
    end

    Discord -->|Events| BotCore
    BotCore -->|Routes Commands| CommandLayer

    ModulCog -->|Creates| Views
    AdminCog -->|Creates| Views
    HelpCog -->|Creates| Views

    Views -->|Contains| Components
    Views -->|Reads| i18n
    Views -->|Action| Database

    ModulCog -->|Uses| Filter
    Filter -->|Search| ModuleCache
    ModuleCache -->|Fetch Raw| TableAPI

    AdminCog -->|Uses| Analytics
    Analytics -->|Visualize| Database
    Analytics -->|Labels| i18n

    Database -->|Stores| ModuleCache
    Database -->|Validates| Enums
    Database -->|Types| TypedDicts

    Views -->|Respects| Enums
    Views -->|Maps| TypedDicts

    style System fill:#1e3a8a,color:#fff
    style Frontend fill:#5f6af0,color:#fff
    style Application fill:#4a9bc4,color:#fff
    style CommandLayer fill:#5ab5e0,color:#000
    style PresentationLayer fill:#6ac5e8,color:#000
    style Business fill:#6b7280,color:#fff
    style Data fill:#d4af37,color:#000
    style Integration fill:#10b981,color:#fff
    style Resources fill:#f59e0b,color:#000

Project StructureΒΆ

OSCAR is built using discord.py and structured into several key components:

discord-bot/
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ oscar/                   # Bot core
β”‚   β”‚   β”œβ”€β”€ main.py              # Entry point (sets up intents)
β”‚   β”‚   β”œβ”€β”€ oscar.py             # Custom Bot class (auto-loads cogs)
β”‚   β”‚   β”‚
β”‚   β”‚   β”œβ”€β”€ cogs/                # Command handlers
β”‚   β”‚   β”‚   β”œβ”€β”€ modul.py         # /module, /filter, /semesterplan, /standard_plan
β”‚   β”‚   β”‚   β”œβ”€β”€ admin.py         # /feedback_review (admin-only)
β”‚   β”‚   β”‚   β”œβ”€β”€ help.py          # /help (with translations)
β”‚   β”‚   β”‚   └── examples.py      # /colors, /buttons (dev tools)
β”‚   β”‚   β”‚
β”‚   β”‚   └── ui/                  # UI framework
β”‚   β”‚       β”œβ”€β”€ base_views.py    # TranslatedView, CustomView
β”‚   β”‚       β”œβ”€β”€ all_info_view.py # Detailed module attributes view
β”‚   β”‚       β”œβ”€β”€ custom_view.py   # Base class wrapper
β”‚   β”‚       β”œβ”€β”€ paginated_view.py    # Pagination logic for long lists
β”‚   β”‚       β”œβ”€β”€ select_button.py     # Selection UI components
β”‚   β”‚       β”œβ”€β”€ semesterplan_view.py # Semester planning interface
β”‚   β”‚       β”œβ”€β”€ translated_view.py   # i18n-aware base view
β”‚   β”‚       β”œβ”€β”€ buttons.py       # Reusable button components
β”‚   β”‚       β”œβ”€β”€ start_view.py    # /start onboarding
β”‚   β”‚       β”œβ”€β”€ module_view.py   # Module display card
β”‚   β”‚       β”œβ”€β”€ select_view.py   # /filter interface
β”‚   β”‚       └── feedback_view.py # /feedback form
β”‚   β”‚
β”‚   └── util/                    # Helper modules
β”‚       β”œβ”€β”€ database.py          # SQLite wrapper (singleton)
β”‚       β”œβ”€β”€ tables.py            # Nextcloud API client
β”‚       β”œβ”€β”€ module.py            # Module data model
β”‚       β”œβ”€β”€ translations.py      # i18n dictionaries
β”‚       β”œβ”€β”€ enums.py             # LanguageCode, StudyCourse
β”‚       β”œβ”€β”€ modules_filter.py    # Filter logic (CP, SWS)
β”‚       β”œβ”€β”€ typed_dicts.py       # Type definitions
β”‚       └── plots.py             # Matplotlib charts (feedback)
β”‚
β”œβ”€β”€ docs/                        # MkDocs documentation (this site)
β”œβ”€β”€ database/                    # SQLite files (auto-created)
β”‚   └── oscar.db                 # Main database
β”œβ”€β”€ .env                         # Environment config (YOU create)
β”œβ”€β”€ .gitlab-ci.yml               # CI/CD pipeline
β”œβ”€β”€ pyproject.toml               # Dependencies & metadata
└── README.md                    # Project overview

Tech Stack & PrerequisitesΒΆ

We use pyproject.toml for dependency management.

Check pyproject.toml
pyproject.toml
[build-system]
requires = ["hatchling >= 1.27"]
build-backend = "hatchling.build"

[tool.hatch.build.targets.wheel]
packages = ["src/oscar", "src/util"]

# https://docs.basedpyright.com/latest/configuration/config-files/
[tool.basedpyright]
"typeCheckingMode" = "recommended"
# "reportUnusedFunction" = false

[tool.pylint]
# disable = "unused-function"
[tool.pylint.options]
good-names-rgx = "(_[a-z_]*|command|group|listen)"

[tool.pylint.messages_control]
disable = [
    "C0114", # missing-module-docstring
    "C0115", # missing-class-docstring
    "C0116", # missing-function-docstring
    "R0903", # too-few-public-methods
    "W0511", # fixme (TODOs)
    "R0801", # duplicate-code
]


[project.scripts]
oscar_ovgu = "oscar.main:main"

[project]
name = "oscar_ovgu"
version = "1.0.0"
authors = [
  { name="ISG", email="jana.goers@ovgu.de" },
]
description = "Organized Study Choice & Academic Roadmapper"
readme = "README.md"
requires-python = ">=3.12"
dependencies = [
    "discord-py",
    "python-dotenv",
    "loguru",
    "cyclopts",
    "requests",
    "rapidfuzz",
    "translate",
    "matplotlib>=3.9.4",
    "numpy",
    "toml"
]
classifiers = [
    "Programming Language :: Python :: 3",
    "Operating System :: OS Independent",
]
license = "Apache-2.0"
license-files = ["./license"]

[project.urls]
Homepage = "https://www.fin.ovgu.de/"
Issues = "https://www.fin.ovgu.de/Fakultaet.html"

[project.optional-dependencies]
dev = [
    "pytest>=8.0.0",
    "pytest-mock>=3.12.0",
    "pytest-cov>=4.0.0",
    "pylint>=3.0.0",
    "pytest-asyncio>=0.23.0",
]
docs = [
    "mkdocs-material>=9.6.20",
    "mkdocstrings[python]>=0.30.1",
    "mkdocs-glightbox",
    "mkdocs-macros-plugin",
]

[tool.pytest.ini_options]
testpaths = ["tests"]
addopts = "-v --tb=short"
asyncio_mode = "auto"
filterwarnings = [
    "ignore::DeprecationWarning:discord",
]
Technology Version Purpose Why this choice?
Python 3.12+ Language Modern async/await, type hints, rich ecosystem
discord.py Latest Discord API Most mature & actively maintained Discord library
SQLite 3.x Database Zero-config, perfect for caching, ACID compliant
loguru Latest Logging Structured logs, better DX than stdlib logging
matplotlib 3.9+ Visualization Admin feedback charts (boxplot, timeline)
basedpyright Latest Type checking Strict typing catches bugs at dev time

| Nextcloud Tables | API v1 | Data source | Faculty's existing module management system | | MkDocs Material | Latest | Documentation | Beautiful, searchable, mobile-friendly |

Next StepsΒΆ