Lyuze is a self-hosted C# Discord bot built with the .NET Generic Host, dependency injection, Discord.NET, and MongoDB.
- Features: User-facing modules and feature services under
Core/Features/. - Infrastructure: Discord.NET event wiring, startup, configuration, database, HTTP, and logging under
Core/Infrastructure/. - Shared: Reusable cross-feature helpers under
Core/Shared/. - Abstractions: Cross-feature interfaces under
Core/Abstractions/Interfaces/. - Persistence: MongoDB access through
DatabaseContextand feature/application services.
Core/
├── Abstractions/
│ └── Interfaces/
├── Features/
│ ├── Admin/
│ ├── Anime/
│ ├── Examples/
│ ├── Leveling/
│ │ └── Services/
│ │ └── LevelingService.cs
│ ├── Players/
│ │ ├── Models/
│ │ │ └── PlayerModel.cs
│ │ └── Services/
│ │ └── PlayerService.cs
│ ├── Profiles/
│ ├── Roles/
│ └── Utility/
├── Infrastructure/
│ ├── Configuration/
│ ├── Database/
│ ├── DiscordNet/
│ │ └── Handlers/
│ ├── Http/
│ └── Logging/
└── Shared/
├── Embeds/
├── Images/
└── Status/
Program.cs creates the Generic Host and registers services with dependency injection.
The main startup path is:
Host.CreateDefaultBuilder()creates the application host.ConfigureServicesregisters configuration, database, Discord.NET, feature services, and handlers.DiscordStartupServicestarts and stops the Discord client.InteractionHandlerdiscovers and executes interaction modules.EventHandlersubscribes to Discord.NET events that are not handled directly byInteractionService.
Discord Gateway
-> DiscordSocketClient.InteractionCreated
-> InteractionHandler
-> InteractionService
-> Feature module
-> Feature service
-> MongoDB or external API when needed
-> Discord interaction response
DiscordSocketClient.MessageReceived
-> Infrastructure EventHandler
-> bot/DM eligibility checks
-> Players service for profile lookup
-> LevelingService for cooldown and XP behavior
-> MongoDB persistence
-> in-channel level-up notification when enabled
DiscordSocketClient.UserJoined
-> Infrastructure EventHandler
-> IPlayerService.HasProfileAsync
-> PlayerService.CreateProfileAsync when needed
-> welcome/role behavior
Core/Features/Players/ owns the player model and persistence service.
PlayerModelis the MongoDB player document.PlayerServicecreates, reads, and updates player records.- Player and XP identity is based on Discord user ID for this self-hosted deployment model.
The future application-boundary migration may replace Discord.NET user objects with ulong IDs in lower-level service methods.
Core/Features/Leveling/ owns the XP and progression rules.
The current service handles message cooldowns, XP awards, the existing quadratic threshold, carryover, and level-up notifications. Atomic XP updates and additional XP sources are planned follow-up work.
Core/Features/Profiles/ owns profile commands and profile-specific orchestration.
Profile and leveling presentation overlap today. A future task may extract profile/leveling-specific presentation methods from the shared embed service without moving generic embed helpers unnecessarily.
Discord.NET event wiring remains under:
Core/Infrastructure/DiscordNet/Handlers/
EventHandler currently handles several event categories. A future maintenance task may split focused classes under Handlers/Events/, but event handlers should continue translating Discord events into feature-service calls rather than owning feature rules.
SettingsServiceloads private runtime settings fromResources/Settings/settings.json.DatabaseContextcreates MongoDB collections from the configured database settings.- Player data is not generally partitioned by guild.
- Guild IDs are used when a record refers to a guild-owned channel, role, or message.
The current application has an ILoggingService compatibility layer. The roadmap moves new code toward Microsoft ILogger, a custom console formatter, structured properties, rotating file output, and a separate audit service. That migration is gradual.
- Keep Discord.NET adapters in infrastructure.
- Keep business rules in feature services.
- Keep persistence behind service/database boundaries.
- Avoid adding new public features before the current refactor and verification work is complete.
- Never introduce DM-based workflows.
- Never commit runtime secrets.