From 5f107d03a78708e66a11de4094704d094398e1da Mon Sep 17 00:00:00 2001 From: syntaxbullet Date: Thu, 12 Feb 2026 14:57:24 +0100 Subject: [PATCH] feat(db): add guild_settings table for per-guild configuration Store guild-specific settings (roles, channels, moderation options) in database instead of config file, enabling per-guild configuration and runtime updates without redeployment. --- .../db/migrations/0004_bored_kat_farrell.sql | 17 + shared/db/migrations/meta/0004_snapshot.json | 1313 +++++++++++++++++ shared/db/migrations/meta/_journal.json | 7 + shared/db/schema/guild-settings.ts | 31 + shared/db/schema/index.ts | 1 + 5 files changed, 1369 insertions(+) create mode 100644 shared/db/migrations/0004_bored_kat_farrell.sql create mode 100644 shared/db/migrations/meta/0004_snapshot.json create mode 100644 shared/db/schema/guild-settings.ts diff --git a/shared/db/migrations/0004_bored_kat_farrell.sql b/shared/db/migrations/0004_bored_kat_farrell.sql new file mode 100644 index 0000000..1301cb0 --- /dev/null +++ b/shared/db/migrations/0004_bored_kat_farrell.sql @@ -0,0 +1,17 @@ +CREATE TABLE "guild_settings" ( + "guild_id" bigint PRIMARY KEY NOT NULL, + "student_role_id" bigint, + "visitor_role_id" bigint, + "color_role_ids" jsonb DEFAULT '[]'::jsonb, + "welcome_channel_id" bigint, + "welcome_message" text, + "feedback_channel_id" bigint, + "terminal_channel_id" bigint, + "terminal_message_id" bigint, + "moderation_log_channel_id" bigint, + "moderation_dm_on_warn" jsonb DEFAULT 'true'::jsonb, + "moderation_auto_timeout_threshold" jsonb, + "feature_overrides" jsonb DEFAULT '{}'::jsonb, + "created_at" timestamp with time zone DEFAULT now() NOT NULL, + "updated_at" timestamp with time zone DEFAULT now() NOT NULL +); diff --git a/shared/db/migrations/meta/0004_snapshot.json b/shared/db/migrations/meta/0004_snapshot.json new file mode 100644 index 0000000..018739f --- /dev/null +++ b/shared/db/migrations/meta/0004_snapshot.json @@ -0,0 +1,1313 @@ +{ + "id": "0c36eda2-c12c-40ea-a750-67d8be85aed8", + "prevId": "d1b9b948-4cff-4aaf-9f8f-a57ebb7a06b7", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.classes": { + "name": "classes", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigint", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "balance": { + "name": "balance", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": "0" + }, + "role_id": { + "name": "role_id", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "classes_name_unique": { + "name": "classes_name_unique", + "nullsNotDistinct": false, + "columns": [ + "name" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.feature_flag_access": { + "name": "feature_flag_access", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "flag_id": { + "name": "flag_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "guild_id": { + "name": "guild_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "role_id": { + "name": "role_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "idx_ffa_flag_id": { + "name": "idx_ffa_flag_id", + "columns": [ + { + "expression": "flag_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_ffa_guild_id": { + "name": "idx_ffa_guild_id", + "columns": [ + { + "expression": "guild_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_ffa_user_id": { + "name": "idx_ffa_user_id", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_ffa_role_id": { + "name": "idx_ffa_role_id", + "columns": [ + { + "expression": "role_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "feature_flag_access_flag_id_feature_flags_id_fk": { + "name": "feature_flag_access_flag_id_feature_flags_id_fk", + "tableFrom": "feature_flag_access", + "tableTo": "feature_flags", + "columnsFrom": [ + "flag_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.feature_flags": { + "name": "feature_flags", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "feature_flags_name_unique": { + "name": "feature_flags_name_unique", + "nullsNotDistinct": false, + "columns": [ + "name" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.guild_settings": { + "name": "guild_settings", + "schema": "", + "columns": { + "guild_id": { + "name": "guild_id", + "type": "bigint", + "primaryKey": true, + "notNull": true + }, + "student_role_id": { + "name": "student_role_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "visitor_role_id": { + "name": "visitor_role_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "color_role_ids": { + "name": "color_role_ids", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'[]'::jsonb" + }, + "welcome_channel_id": { + "name": "welcome_channel_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "welcome_message": { + "name": "welcome_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "feedback_channel_id": { + "name": "feedback_channel_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "terminal_channel_id": { + "name": "terminal_channel_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "terminal_message_id": { + "name": "terminal_message_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "moderation_log_channel_id": { + "name": "moderation_log_channel_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "moderation_dm_on_warn": { + "name": "moderation_dm_on_warn", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'true'::jsonb" + }, + "moderation_auto_timeout_threshold": { + "name": "moderation_auto_timeout_threshold", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "feature_overrides": { + "name": "feature_overrides", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'{}'::jsonb" + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.inventory": { + "name": "inventory", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "item_id": { + "name": "item_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "quantity": { + "name": "quantity", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": "1" + } + }, + "indexes": {}, + "foreignKeys": { + "inventory_user_id_users_id_fk": { + "name": "inventory_user_id_users_id_fk", + "tableFrom": "inventory", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "inventory_item_id_items_id_fk": { + "name": "inventory_item_id_items_id_fk", + "tableFrom": "inventory", + "tableTo": "items", + "columnsFrom": [ + "item_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "inventory_user_id_item_id_pk": { + "name": "inventory_user_id_item_id_pk", + "columns": [ + "user_id", + "item_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "quantity_check": { + "name": "quantity_check", + "value": "\"inventory\".\"quantity\" > 0" + } + }, + "isRLSEnabled": false + }, + "public.item_transactions": { + "name": "item_transactions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "related_user_id": { + "name": "related_user_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "item_id": { + "name": "item_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "quantity": { + "name": "quantity", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "item_transactions_user_id_users_id_fk": { + "name": "item_transactions_user_id_users_id_fk", + "tableFrom": "item_transactions", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "item_transactions_related_user_id_users_id_fk": { + "name": "item_transactions_related_user_id_users_id_fk", + "tableFrom": "item_transactions", + "tableTo": "users", + "columnsFrom": [ + "related_user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "item_transactions_item_id_items_id_fk": { + "name": "item_transactions_item_id_items_id_fk", + "tableFrom": "item_transactions", + "tableTo": "items", + "columnsFrom": [ + "item_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.items": { + "name": "items", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "rarity": { + "name": "rarity", + "type": "varchar(20)", + "primaryKey": false, + "notNull": false, + "default": "'C'" + }, + "type": { + "name": "type", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true, + "default": "'MATERIAL'" + }, + "usage_data": { + "name": "usage_data", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'{}'::jsonb" + }, + "price": { + "name": "price", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "icon_url": { + "name": "icon_url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "image_url": { + "name": "image_url", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "items_name_unique": { + "name": "items_name_unique", + "nullsNotDistinct": false, + "columns": [ + "name" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.lootdrops": { + "name": "lootdrops", + "schema": "", + "columns": { + "message_id": { + "name": "message_id", + "type": "varchar(255)", + "primaryKey": true, + "notNull": true + }, + "channel_id": { + "name": "channel_id", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "reward_amount": { + "name": "reward_amount", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "currency": { + "name": "currency", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "claimed_by": { + "name": "claimed_by", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "lootdrops_claimed_by_users_id_fk": { + "name": "lootdrops_claimed_by_users_id_fk", + "tableFrom": "lootdrops", + "tableTo": "users", + "columnsFrom": [ + "claimed_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.moderation_cases": { + "name": "moderation_cases", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "case_id": { + "name": "case_id", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "varchar(20)", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "username": { + "name": "username", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "moderator_id": { + "name": "moderator_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "moderator_name": { + "name": "moderator_name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "reason": { + "name": "reason", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'{}'::jsonb" + }, + "active": { + "name": "active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "resolved_at": { + "name": "resolved_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "resolved_by": { + "name": "resolved_by", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "resolved_reason": { + "name": "resolved_reason", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "moderation_cases_user_id_idx": { + "name": "moderation_cases_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "moderation_cases_case_id_idx": { + "name": "moderation_cases_case_id_idx", + "columns": [ + { + "expression": "case_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "moderation_cases_case_id_unique": { + "name": "moderation_cases_case_id_unique", + "nullsNotDistinct": false, + "columns": [ + "case_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.quests": { + "name": "quests", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "trigger_event": { + "name": "trigger_event", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "requirements": { + "name": "requirements", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "rewards": { + "name": "rewards", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.transactions": { + "name": "transactions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "related_user_id": { + "name": "related_user_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "amount": { + "name": "amount", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": { + "transactions_created_at_idx": { + "name": "transactions_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "transactions_user_id_users_id_fk": { + "name": "transactions_user_id_users_id_fk", + "tableFrom": "transactions", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "transactions_related_user_id_users_id_fk": { + "name": "transactions_related_user_id_users_id_fk", + "tableFrom": "transactions", + "tableTo": "users", + "columnsFrom": [ + "related_user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_quests": { + "name": "user_quests", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "quest_id": { + "name": "quest_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "progress": { + "name": "progress", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_quests_user_id_users_id_fk": { + "name": "user_quests_user_id_users_id_fk", + "tableFrom": "user_quests", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_quests_quest_id_quests_id_fk": { + "name": "user_quests_quest_id_quests_id_fk", + "tableFrom": "user_quests", + "tableTo": "quests", + "columnsFrom": [ + "quest_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "user_quests_user_id_quest_id_pk": { + "name": "user_quests_user_id_quest_id_pk", + "columns": [ + "user_id", + "quest_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_timers": { + "name": "user_timers", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "key": { + "name": "key", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'{}'::jsonb" + } + }, + "indexes": { + "user_timers_expires_at_idx": { + "name": "user_timers_expires_at_idx", + "columns": [ + { + "expression": "expires_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "user_timers_lookup_idx": { + "name": "user_timers_lookup_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "user_timers_user_id_users_id_fk": { + "name": "user_timers_user_id_users_id_fk", + "tableFrom": "user_timers", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "user_timers_user_id_type_key_pk": { + "name": "user_timers_user_id_type_key_pk", + "columns": [ + "user_id", + "type", + "key" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.users": { + "name": "users", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigint", + "primaryKey": true, + "notNull": true + }, + "class_id": { + "name": "class_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "username": { + "name": "username", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "balance": { + "name": "balance", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": "0" + }, + "xp": { + "name": "xp", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": "0" + }, + "level": { + "name": "level", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 1 + }, + "daily_streak": { + "name": "daily_streak", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "settings": { + "name": "settings", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'{}'::jsonb" + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": { + "users_username_idx": { + "name": "users_username_idx", + "columns": [ + { + "expression": "username", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "users_balance_idx": { + "name": "users_balance_idx", + "columns": [ + { + "expression": "balance", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "users_level_xp_idx": { + "name": "users_level_xp_idx", + "columns": [ + { + "expression": "level", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "xp", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "users_class_id_classes_id_fk": { + "name": "users_class_id_classes_id_fk", + "tableFrom": "users", + "tableTo": "classes", + "columnsFrom": [ + "class_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "users_username_unique": { + "name": "users_username_unique", + "nullsNotDistinct": false, + "columns": [ + "username" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": {}, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/shared/db/migrations/meta/_journal.json b/shared/db/migrations/meta/_journal.json index 6a48bb9..e22875d 100644 --- a/shared/db/migrations/meta/_journal.json +++ b/shared/db/migrations/meta/_journal.json @@ -29,6 +29,13 @@ "when": 1770903573324, "tag": "0003_new_senator_kelly", "breakpoints": true + }, + { + "idx": 4, + "version": "7", + "when": 1770904612078, + "tag": "0004_bored_kat_farrell", + "breakpoints": true } ] } \ No newline at end of file diff --git a/shared/db/schema/guild-settings.ts b/shared/db/schema/guild-settings.ts new file mode 100644 index 0000000..85b0925 --- /dev/null +++ b/shared/db/schema/guild-settings.ts @@ -0,0 +1,31 @@ +import { + pgTable, + bigint, + timestamp, + text, + jsonb, +} from 'drizzle-orm/pg-core'; +import { relations, type InferSelectModel, type InferInsertModel } from 'drizzle-orm'; + +export type GuildSettings = InferSelectModel; +export type GuildSettingsInsert = InferInsertModel; + +export const guildSettings = pgTable('guild_settings', { + guildId: bigint('guild_id', { mode: 'bigint' }).primaryKey(), + studentRoleId: bigint('student_role_id', { mode: 'bigint' }), + visitorRoleId: bigint('visitor_role_id', { mode: 'bigint' }), + colorRoleIds: jsonb('color_role_ids').$type().default([]), + welcomeChannelId: bigint('welcome_channel_id', { mode: 'bigint' }), + welcomeMessage: text('welcome_message'), + feedbackChannelId: bigint('feedback_channel_id', { mode: 'bigint' }), + terminalChannelId: bigint('terminal_channel_id', { mode: 'bigint' }), + terminalMessageId: bigint('terminal_message_id', { mode: 'bigint' }), + moderationLogChannelId: bigint('moderation_log_channel_id', { mode: 'bigint' }), + moderationDmOnWarn: jsonb('moderation_dm_on_warn').$type().default(true), + moderationAutoTimeoutThreshold: jsonb('moderation_auto_timeout_threshold').$type(), + featureOverrides: jsonb('feature_overrides').$type>().default({}), + createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(), + updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow().notNull(), +}); + +export const guildSettingsRelations = relations(guildSettings, () => ({})); diff --git a/shared/db/schema/index.ts b/shared/db/schema/index.ts index 10f5bb6..e6e875e 100644 --- a/shared/db/schema/index.ts +++ b/shared/db/schema/index.ts @@ -5,3 +5,4 @@ export * from './economy'; export * from './quests'; export * from './moderation'; export * from './feature-flags'; +export * from './guild-settings';