Fact System
Relevant source files
The following files were used as context for generating this wiki page:
The Fact System is a comprehensive module within the Poixpixel Discord Bot designed to manage a community-driven database of interesting facts. Its primary purpose is to allow users to submit facts, enable moderators to review and approve them, and automatically broadcast a "Fact of the Day" to a designated channel.
The system integrates directly with the bot's database layer for persistent storage, utilizes Redis for caching to optimize random selection, and includes a scheduling mechanism to ensure daily delivery.
System Architecture and Components
The Fact System is composed of three primary layers: the User Interface (Slash Commands), the Management Logic (Scheduler and Moderator actions), and the Data Persistence layer.
1. User Interaction Layer
Users interact with the system through the /fact slash command. This command supports several subcommands tailored to different user roles:
- Submit: Allows any user to contribute a fact.
- Approve/Delete/Pending: Restricted to moderators for managing the queue.
- Post: Restricted to administrators for manually triggering a broadcast.
Sources: src/commands/fun/fact.ts:21-72, src/commands/fun/fact.ts:167-175
2. Moderation Workflow
When a non-administrator submits a fact, it enters a "pending" state. The bot generates an embed in the configured factApproval channel with interactive buttons (Approve/Reject). Administrators' submissions are automatically approved and bypass this queue.
3. Fact of the Day Scheduler
The FactManager handles the automated posting logic. It calculates the time remaining until midnight and sets a timeout to trigger the postFactOfTheDay function.
- Logic: It fetches a random unused fact. If all facts in the database have been marked as used, the system automatically resets the
usedOnflags for all approved facts to ensure a continuous cycle. - Notification: The post pings a specific role defined in the configuration (
factPingRole).
Sources: src/util/factManager.ts:11-40, src/db/functions/factFunctions.ts:98-118
Data Management and Caching
The system utilizes the Drizzle ORM to interact with a PostgreSQL database. To reduce database load, the list of unused facts is cached in Redis under the key unused-facts.
Fact Data Model
| Field | Type | Description |
|---|---|---|
id | Integer | Unique identifier (Auto-incrementing) |
content | String | The text of the fact |
source | String (Optional) | The source or reference for the fact |
addedBy | String | Discord ID of the submitter |
approved | Boolean | Approval status (Default: false) |
usedOn | Date (Optional) | The timestamp of when the fact was posted |
Sources: src/db/functions/factFunctions.ts:20-30, src/db/functions/factFunctions.ts:135-145
Cache Invalidation Strategy
The system ensures data consistency by invalidating the unused-facts cache whenever:
- A new fact is added.
- A fact is approved or deleted.
- A fact is marked as used after being posted.
Sources: src/db/functions/factFunctions.ts:46, src/db/functions/factFunctions.ts:152, src/db/functions/factFunctions.ts:182
Component Sequence Diagram
The following diagram illustrates the lifecycle of a fact from submission through automated posting.
Configuration Options
The Fact System relies on specific channel and role IDs defined in the bot's configuration file.
| Configuration Key | Type | Description |
|---|---|---|
channels.factOfTheDay | String (Snowflake) | Target channel for daily fact broadcasts. |
channels.factApproval | String (Snowflake) | Channel where moderators review submissions. |
roles.factPingRole | String (Snowflake) | Role ID to be pinged when a fact is posted. |
Sources: config.example.json:66-67, config.example.json:98, src/util/factManager.ts:55-75
Key Implementation Details
Random Selection with Reset Logic
The system selects a random fact from the pool of approved, unused entries. If the pool is empty, it resets the entire collection.
// src/db/functions/factFunctions.ts:108-118
if (facts.length === 0) {
await withDbRetryDrizzle(
async () => {
return await db
.update(schema.factTable)
.set({ usedOn: null })
.where(eq(schema.factTable.approved, true));
},
{ operationName: 'reset-used-facts', forceRetry: true }
);
await invalidateCache(cacheKey);
return await getRandomUnusedFact();
}
Sources: src/db/functions/factFunctions.ts:108-118
Interaction Handling
Button interactions for facts are handled globally in the interactionCreate event. The system extracts the Fact ID from the button's customId (e.g., approve_fact_42) to perform the database update.
Sources: src/events/interactionCreate.ts:173-205
Conclusion
The Fact System provides a robust framework for community engagement and automated content delivery. By combining a clear moderation workflow with efficient caching and self-healing selection logic (resetting used facts), it maintains a high-quality stream of information with minimal administrative overhead.