-- NB: This is a manually squashed view of all the CREATE and ALTER statements, -- with comments attached to the fields for centralized documentation. -- noinspection SqlDialectInspectionForFile -- noinspection SqlNoDataSourceInspectionForFile -- noinspection SqlResolveForFile CREATE TABLE users ( -- Not used for anything except replication. id BIGINT(20) NOT NULL AUTO_INCREMENT, -- Visible "primary key" token VARCHAR(32) NOT NULL, -- Username is a lookup key; display_name allows the user to add custom case. username VARCHAR(20) NOT NULL, display_name VARCHAR(20) NOT NULL, -- If the username the user currently has was automatically generated by our -- system rather than manually entered. If the user selects the username we -- made for them, we still leave this as true. username_is_generated BOOLEAN NOT NULL DEFAULT false, -- Users with new randomly generated usernames have this flag set to true. -- If a user then changes their username from the default, we set this to false. -- Or if a user elects that the random username we generated for them is fine, -- we also set this to false. username_is_not_customized BOOLEAN NOT NULL DEFAULT false, -- Set by the user at sign up: -- - When email + password signup, this is the email provided. -- - When Google SSO, this is the email provided by Google. email_address VARCHAR(255) NOT NULL, -- Email address is confirmed by us. -- We do not set this on 3rd party (ie. Google) "email confirmation", only our own. email_confirmed BOOLEAN NOT NULL DEFAULT false, -- Email address is confirmed by Google. email_confirmed_by_google BOOLEAN NOT NULL DEFAULT false, -- The role assigned to the user confers permissions. user_role_slug VARCHAR(16) NOT NULL, -- An optional comma separated list of flags for user accounts -- If a user has a flag, then they're enabled for that given feature. -- There are better ways to do this, but this hack will do for now. -- This should replace `can_access_studio`. -- -- Possible flag values (multiple is okay) : -- - "explore_media" -- - "studio" -- - "video_style_transfer" maybe_feature_flags VARCHAR(255) DEFAULT NULL, -- DEPRECATED -- TODO(bt, 2024-03-05): Remove after new flags are in place. -- Rollout flag for Storyteller Studio -- Default to false until rollout is 100%, then remove the column. can_access_studio BOOLEAN NOT NULL DEFAULT false, -- The user is predominantly an API user, eg. "AI streamer" on Twitch -- This flag serves both an analytics purpose (to disentangle from metrics) -- as well as a permissions feature flag for API users. is_api_user BOOLEAN NOT NULL DEFAULT false, -- ========== PREMIUM FEATURES ========== -- If the user has a Stripe subscription (or has had one), we link it to the user here. -- Will never exceed 255 characters: https://groups.google.com/a/lists.stripe.com/g/api-discuss/c/1F5Wb4HRnNQ maybe_stripe_customer_id VARCHAR(255) DEFAULT NULL, -- If a user is a known-good contributor, we can assign them premium service for free. -- Internally, our system statically maps keys to zero or more premium products. -- The business logic can live in the plans code. maybe_loyalty_program_key VARCHAR(32) DEFAULT NULL, -- ========== CREDENTIALS ========== -- Bcrypt password hash. Granted, there are newer methods: -- https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html -- Passwords may be a max of 64 characters per BCrypt. password_hash BINARY(60) NOT NULL, -- Incremented with every update to the password. password_version INT UNSIGNED NOT NULL DEFAULT 0, -- Users signing up from SSO do not have a password at time of account creation. is_without_password BOOLEAN NOT NULL DEFAULT false, -- ========== ABUSE TRACKING ========== -- For abuse tracking. -- Wide enough for IPv4/6 ip_address_creation VARCHAR(40) NOT NULL, ip_address_last_login VARCHAR(40) NOT NULL, ip_address_last_update VARCHAR(40) NOT NULL, -- ========== DISPLAY / PROFILE ========== -- The "avatar" image is a media file of type image that serves as a -- small avatar or profile picture icon. maybe_avatar_media_file_token VARCHAR(32) DEFAULT NULL, -- The "cover" image is a media file of type image that covers the -- top of the page. maybe_cover_media_file_token VARCHAR(32) DEFAULT NULL, -- Gravatar image hashes are precomputed. email_gravatar_hash CHAR(32) NOT NULL, -- The profile of the user in markdown (user editable). profile_markdown TEXT NOT NULL, -- Generated HTML (not user-editable). profile_rendered_html TEXT NOT NULL, -- An uploaded avatar. Public hash in our bucket. -- avatar_public_bucket_hash CHAR(32) DEFAULT NULL, -- ========== SOCIAL MEDIA ========== -- Social media usernames -- These are not confirmed. We'll need to build an OAuth system to handle that. discord_username VARCHAR(36) DEFAULT NULL, twitter_username VARCHAR(36) DEFAULT NULL, twitch_username VARCHAR(36) DEFAULT NULL, patreon_username VARCHAR(36) DEFAULT NULL, github_username VARCHAR(36) DEFAULT NULL, cashapp_username VARCHAR(36) DEFAULT NULL, website_url VARCHAR(255) DEFAULT NULL, -- ========== USER PREFERENCES ========== -- If the user doesn't want to use gravatar and doesn't have an uploaded avatar. disable_gravatar BOOLEAN NOT NULL DEFAULT false, -- (THIS MIGHT NOT BE USED) -- NB: DO NOT SORT! -- THIS MUST MATCH THE RESPECTIVE JOBS TABLE. -- Visibility preference used at TTS inference time (which can be changed on the result itself). -- Moderators will still see them. preferred_tts_result_visibility ENUM( 'public', 'hidden', 'private' ) NOT NULL DEFAULT 'public', -- (THIS MIGHT NOT BE USED) -- NB: DO NOT SORT! -- THIS MUST MATCH THE RESPECTIVE JOBS TABLE. -- Visibility preference used at TTS inference time (which can be changed on the result itself). -- Moderators will still see them. preferred_w2l_result_visibility ENUM( 'public', 'hidden', 'private' ) NOT NULL DEFAULT 'public', -- Auto play preferences -- Tri-state because we want to potentially change the default behavior. auto_play_audio_preference BOOLEAN DEFAULT NULL, auto_play_video_preference BOOLEAN DEFAULT NULL, -- Favorite TTS voice to use by default -- maybe_preferred_tts_model_token VARCHAR(32) DEFAULT NULL, -- Favorite W2L model to use by default -- maybe_preferred_w2l_template_token VARCHAR(32) DEFAULT NULL, -- Settings -- DO NOT REORDER. -- dark_mode_preference ENUM( -- 'light-mode', -- 'dark-mode', -- 'use-clock' -- ) NOT NULL DEFAULT 'light-mode', -- ========== STATS ========== -- For tracking stats. -- The "cached" values are updated by a background job. -- cached_tts_rendered_counter INT(10) NOT NULL DEFAULT 0, -- cached_w2l_rendered_counter INT(10) NOT NULL DEFAULT 0, -- ========== TRACKING ========== -- Where the user signed up from (NOT NECESSARILY AN ENUM!) -- For now this will be "artcraft", "fakeyou", or "storyteller", -- though we may extend or overload this to handle other cases or metadata. maybe_source VARCHAR(255) DEFAULT NULL, -- How users created their account -- Initially this will be "email_password" or "google_sign_in" -- Older users do not have a value and are assumed to be "email_sign_in" maybe_signup_method VARCHAR(16) DEFAULT NULL, -- ========== MODERATION DETAILS ========== -- Different than deleted. -- Users still show up, but can't do anything. is_banned BOOLEAN NOT NULL DEFAULT false, -- If a moderator has comments. maybe_mod_comments VARCHAR(255) DEFAULT NULL, -- The last moderator that made changes. maybe_mod_user_token VARCHAR(32) DEFAULT NULL, -- ========== VECTOR CLOCK ========== -- Incremented with every update. version INT UNSIGNED NOT NULL DEFAULT 0, -- ========== TIMESTAMPS ========== created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- If the user is deleted, we set this. -- This is different than banned. These users won't show up at all. user_deleted_at TIMESTAMP NULL, mod_deleted_at TIMESTAMP NULL, -- INDICES -- PRIMARY KEY (id), UNIQUE KEY (token), UNIQUE KEY (username), UNIQUE KEY (email_address), KEY fk_user_role_slug (user_role_slug), KEY index_can_access_studio (can_access_studio), KEY index_is_api_user (is_api_user), KEY fk_maybe_avatar_media_file_token (maybe_avatar_media_file_token), KEY fk_maybe_cover_media_file_token (maybe_cover_media_file_token) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;