Database & schema
The Drizzle schema, the tables, and how migrations work.
FluffBoost uses PostgreSQL through Drizzle ORM. The schema in
apps/discord/src/database/schema.ts is the single source of truth — Drizzle
reads it at runtime, so there's no code-generation step.
Tables
| Table | Purpose |
|---|---|
guilds | Per-server config: channel, schedule (frequency/time/timezone/day), premium status, lastMotivationSentAt |
motivationQuotes | The approved quote library |
suggestionQuotes | User-submitted quotes pending admin review |
discordActivities | Bot status entries, with a type enum |
Two enums back these: motivationFrequencyEnum (Daily / Weekly / Monthly) and
discordActivityTypeEnum (Custom / Listening / Streaming / Playing).
Working with the schema
After editing schema.ts:
bun run db:pushPushes the schema straight to your dev database. Fast, no migration files.
bun run db:generate # create a migration from the schema diff
bun run db:migrate # apply pending migrationsOpen a visual browser with bun run db:studio.
How scheduling reads the data
The send-motivation worker job runs every minute and asks
isGuildDueForMotivation() (in apps/discord/src/utils/scheduleEvaluator.ts,
powered by dayjs with timezone support) which guilds are due right now. After a
successful send it updates lastMotivationSentAt so a quote is never delivered
twice.
Migrations run at deploy time. The container entrypoint runs
apps/discord/src/database/migrate.ts before starting the bot, so a fresh
database is created and kept up to date automatically. The repository ships
both the migration SQL and drizzle/meta/_journal.json, which is what the
script looks for — if that journal ever goes missing, the script silently
skips and the schema stops being applied. Set SKIP_MIGRATIONS=true to opt
out for a single deploy.
Don't mix db:push with migrations in production. db:push reshapes the
database directly without recording anything in the migration history, so a
later db:migrate can find the schema already changed and fail or drift. Use
db:push for local development only; let production go through generated
migrations.