From 005fad6048cdd0dd76cf7278b3fad8fab25bab55 Mon Sep 17 00:00:00 2001 From: Josepablo Cruz Date: Tue, 31 Mar 2026 23:40:51 -0600 Subject: [PATCH] feat(sql): RBAC model with api_keys and application tenants --- db/Models/assets/RBAC_model.svg | 3660 ++++++++++++++++++--------- db/Models/model.mwb | Bin 16094 -> 21745 bytes db/Models/sql_generated/db_init.sql | 12 +- db/Models/sql_generated/root.sql | 18 + db/Models/sql_generated/schema.sql | 221 +- 5 files changed, 2661 insertions(+), 1250 deletions(-) create mode 100644 db/Models/sql_generated/root.sql diff --git a/db/Models/assets/RBAC_model.svg b/db/Models/assets/RBAC_model.svg index 2f7c5d1..493f7ba 100644 --- a/db/Models/assets/RBAC_model.svg +++ b/db/Models/assets/RBAC_model.svg @@ -3,1472 +3,2750 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + + + + - + - + - + - + - + - + - - - - - + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + + + + + + + + - - + + - - - - - - + + + + + + - + - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - + - - - - - - - + + + + + + + - + - - - - - - - - - + + + + + + + - - - - - - - + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + - - - - + + + + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - - + + - - - - - - + + + + + + - + - - - - - - - - - - - + + + + + + + + + + + - + - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - + + + + + + + - + - - - - - - - + + + + + + + - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - + + + + - - - - - - + + + + + + + + - + + - - - - - - - - - - - - - - - + + + + + + - + - - - - - - - - - - - - - + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + - + - - - - - - - + + + + + + + - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + - - - - - - + + + + + + + + + + + + + + + + + + + - + + - - - - - - - - - + + + + + + - + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + - + - - - - - - - + + + + + + + - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - + + + + + + + + + + + + + + + + + - - + + + + - - - - - - + + + + + + + + + + + + + + + + - + + - - - - - - - - - + + + + + + - + - - - - - - - - - - - - - - - - + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + - - - - - + - - - - - - - - - - - + + + + + + + - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + - + - - - - - - - + + + + + + + - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - + + + + + + + + + + + + + + - + + + + - - - - - - - - - - - + + + + + + + + + + + + + + + + - + + - - - - - - - - - - - - - - - - - + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + - + - - - - - - - + + + + + + + - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - + + + + - - - - - - - - - - + + + + + + + + + + + - - + + - - - - - - + + + + + + - + - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - + + + + + + + - + - - - - - - - + + + + + + + - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/db/Models/model.mwb b/db/Models/model.mwb index f2170271aed6424ff90eb0f0a23533aef47efca9..bbaaa992d49df787146118115e824b577f274920 100644 GIT binary patch delta 20955 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 J($mz8{{c=arTzc_ delta 15279 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 root @@ -17,9 +17,9 @@ INSERT INTO roles (name, description, created_at, updated_at) VALUES ("system_re INSERT INTO roles (name, description, created_at, updated_at) VALUES ("system_staff","System Level staff member",NOW(),NOW()); INSERT INTO roles (name, description, created_at, updated_at) VALUES ("company_owner","Unrestricted access to company resources",NOW(),NOW()); INSERT INTO roles (name, description, created_at, updated_at) VALUES ("company_manager","Access as manager to company resources",NOW(),NOW()); -INSERT INTO roles (name, description, created_at, updated_at) VALUES ("company_staff","Access as staff to company resources",NOW(),NOW()); -INSERT INTO roles (name, description, created_at, updated_at) VALUES ("company_driver","Simple access to company resources",NOW(),NOW()); -INSERT INTO roles (name, description, created_at, updated_at) VALUES ("company_observer","Limited access to company resources",NOW(),NOW()); +INSERT INTO roles (name, description, created_at, updated_at) VALUES ("staff","Access as staff to company resources",NOW(),NOW()); +INSERT INTO roles (name, description, created_at, updated_at) VALUES ("driver","Simple access to company resources",NOW(),NOW()); +INSERT INTO roles (name, description, created_at, updated_at) VALUES ("observer","Limited access to only read company resources",NOW(),NOW()); -- Creation of basic permissions INSERT INTO permissions (name, description) VALUES ("root","Root role with no restricted access"); diff --git a/db/Models/sql_generated/root.sql b/db/Models/sql_generated/root.sql new file mode 100644 index 0000000..d7f0c06 --- /dev/null +++ b/db/Models/sql_generated/root.sql @@ -0,0 +1,18 @@ +-- Creation of root and backoffice +INSERT INTO applications (name, slug, description) VALUES ('root/backoffice','root_backoffice',"This is the application with no restrictions to all resources"); + +INSERT INTO permissions (application_id, name, description) VALUES (1, 'root', "No restrictions"); + +INSERT INTO roles (application_id, name, description) VALUES (1, 'root', "No restrictions"); + +INSERT INTO role_permissions (role_id, permission_id) VALUES (1,1); + +INSERT INTO users (name, last_name) VALUES ('root','root'); + +INSERT INTO auth_identities (user_id, provider, identifier, password_hash, is_primary, is_verified) VALUES (1,'email','root@root.com','invalid_password_hash',1,1); + +INSERT INTO user_roles (user_id, role_id) VALUES (1,1); + +INSERT INTO user_permissions (user_id, permission_id) VALUES (1,1); + +INSERT INTO user_applications (user_id, application_id) VALUES (1,1); diff --git a/db/Models/sql_generated/schema.sql b/db/Models/sql_generated/schema.sql index d0dde57..0957712 100644 --- a/db/Models/sql_generated/schema.sql +++ b/db/Models/sql_generated/schema.sql @@ -1,5 +1,5 @@ -- MySQL Script generated by MySQL Workbench --- Sun Dec 7 08:38:42 2025 +-- Tue 31 Mar 2026 11:38:07 PM CST -- Model: New Model Version: 1.0 -- MySQL Workbench Forward Engineering @@ -17,36 +17,16 @@ SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,N CREATE SCHEMA IF NOT EXISTS `u947463964_etaviaporte` DEFAULT CHARACTER SET utf8 ; USE `u947463964_etaviaporte` ; --- ----------------------------------------------------- --- Table `u947463964_etaviaporte`.`user_types` --- ----------------------------------------------------- -CREATE TABLE IF NOT EXISTS `u947463964_etaviaporte`.`user_types` ( - `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, - `name` TEXT NOT NULL, - `description` TEXT NULL, - PRIMARY KEY (`id`), - UNIQUE INDEX `id_UNIQUE` (`id` ASC) VISIBLE) -ENGINE = InnoDB; - - -- ----------------------------------------------------- -- Table `u947463964_etaviaporte`.`users` -- ----------------------------------------------------- CREATE TABLE IF NOT EXISTS `u947463964_etaviaporte`.`users` ( `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, - `user_type` INT UNSIGNED NOT NULL, - `name` TEXT NOT NULL, - `last_name` TEXT NOT NULL, - `created_at` DATETIME NOT NULL, - `updated_at` DATETIME NOT NULL, - UNIQUE INDEX `id_UNIQUE` (`id` ASC) VISIBLE, - PRIMARY KEY (`id`), - INDEX `fk_users_user_types1_idx` (`user_type` ASC) VISIBLE, - CONSTRAINT `fk_users_user_types1` - FOREIGN KEY (`user_type`) - REFERENCES `u947463964_etaviaporte`.`user_types` (`id`) - ON DELETE NO ACTION - ON UPDATE NO ACTION) + `name` VARCHAR(512) NOT NULL, + `last_name` VARCHAR(512) NOT NULL, + `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`)) ENGINE = InnoDB; @@ -56,15 +36,16 @@ ENGINE = InnoDB; CREATE TABLE IF NOT EXISTS `u947463964_etaviaporte`.`auth_identities` ( `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, `user_id` INT UNSIGNED NOT NULL, - `provider` TEXT NOT NULL, - `identifier` TEXT NOT NULL COMMENT 'email, phone google, facebook, etc.', + `provider` VARCHAR(512) NOT NULL COMMENT 'type of identifier: email, phone, etc', + `identifier` VARCHAR(512) COLLATE 'Default Collation' NOT NULL COMMENT 'email, phone google, facebook, etc.', + `password_hash` VARCHAR(512) COLLATE 'Default Collation' NULL COMMENT 'password for phone or email', `is_primary` TINYINT NOT NULL DEFAULT 0, `is_verified` TINYINT NOT NULL DEFAULT 0, - `created_at` DATETIME NOT NULL, - `updated_at` DATETIME NOT NULL, + `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'when phone or email, password goes here.', PRIMARY KEY (`id`), - UNIQUE INDEX `id_UNIQUE` (`id` ASC) VISIBLE, INDEX `fk_auth_identities_users_idx` (`user_id` ASC) VISIBLE, + UNIQUE INDEX `provider_UNIQUE` (`provider` ASC, `identifier` ASC) VISIBLE, CONSTRAINT `fk_auth_identities_users` FOREIGN KEY (`user_id`) REFERENCES `u947463964_etaviaporte`.`users` (`id`) @@ -74,22 +55,18 @@ ENGINE = InnoDB; -- ----------------------------------------------------- --- Table `u947463964_etaviaporte`.`auth_credentials` +-- Table `u947463964_etaviaporte`.`applications` -- ----------------------------------------------------- -CREATE TABLE IF NOT EXISTS `u947463964_etaviaporte`.`auth_credentials` ( +CREATE TABLE IF NOT EXISTS `u947463964_etaviaporte`.`applications` ( `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, - `identity_id` INT UNSIGNED NOT NULL, - `password` TEXT NOT NULL, - `created_at` DATETIME NOT NULL, - `updated_at` DATETIME NOT NULL, + `name` VARCHAR(512) NOT NULL, + `slug` VARCHAR(512) NOT NULL, + `description` TEXT NULL, + `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), - UNIQUE INDEX `id_UNIQUE` (`id` ASC) VISIBLE, - INDEX `fk_auth_credentials_auth_identities1_idx` (`identity_id` ASC) VISIBLE, - CONSTRAINT `fk_auth_credentials_auth_identities1` - FOREIGN KEY (`identity_id`) - REFERENCES `u947463964_etaviaporte`.`auth_identities` (`id`) - ON DELETE CASCADE - ON UPDATE NO ACTION) + UNIQUE INDEX `slug_UNIQUE` (`slug` ASC) VISIBLE, + UNIQUE INDEX `name_UNIQUE` (`name` ASC) VISIBLE) ENGINE = InnoDB; @@ -98,12 +75,19 @@ ENGINE = InnoDB; -- ----------------------------------------------------- CREATE TABLE IF NOT EXISTS `u947463964_etaviaporte`.`roles` ( `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, - `name` TEXT NOT NULL, + `application_id` INT UNSIGNED NOT NULL, + `name` VARCHAR(512) NOT NULL, `description` TEXT NULL, - `created_at` DATETIME NOT NULL, - `updated_at` DATETIME NOT NULL, + `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), - UNIQUE INDEX `id_UNIQUE` (`id` ASC) VISIBLE) + UNIQUE INDEX `name_UNIQUE` (`application_id` ASC, `name` ASC) VISIBLE, + INDEX `fk_roles_applications1_idx` (`application_id` ASC) VISIBLE, + CONSTRAINT `fk_roles_applications1` + FOREIGN KEY (`application_id`) + REFERENCES `u947463964_etaviaporte`.`applications` (`id`) + ON DELETE NO ACTION + ON UPDATE NO ACTION) ENGINE = InnoDB; @@ -112,10 +96,17 @@ ENGINE = InnoDB; -- ----------------------------------------------------- CREATE TABLE IF NOT EXISTS `u947463964_etaviaporte`.`permissions` ( `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, - `name` TEXT NOT NULL, + `application_id` INT UNSIGNED NOT NULL, + `name` VARCHAR(512) NOT NULL, `description` TEXT NULL, PRIMARY KEY (`id`), - UNIQUE INDEX `id_UNIQUE` (`id` ASC) VISIBLE) + UNIQUE INDEX `name_UNIQUE` (`application_id` ASC, `name` ASC) VISIBLE, + INDEX `fk_permissions_applications1_idx` (`application_id` ASC) VISIBLE, + CONSTRAINT `fk_permissions_applications1` + FOREIGN KEY (`application_id`) + REFERENCES `u947463964_etaviaporte`.`applications` (`id`) + ON DELETE NO ACTION + ON UPDATE NO ACTION) ENGINE = InnoDB; @@ -127,9 +118,9 @@ CREATE TABLE IF NOT EXISTS `u947463964_etaviaporte`.`role_permissions` ( `role_id` INT UNSIGNED NOT NULL, `permission_id` INT UNSIGNED NOT NULL, PRIMARY KEY (`id`), - UNIQUE INDEX `id_UNIQUE` (`id` ASC) VISIBLE, INDEX `fk_role_permissions_roles1_idx` (`role_id` ASC) VISIBLE, INDEX `fk_role_permissions_permissions1_idx` (`permission_id` ASC) VISIBLE, + UNIQUE INDEX `role_id_UNIQUE` (`role_id` ASC, `permission_id` ASC) VISIBLE, CONSTRAINT `fk_role_permissions_roles1` FOREIGN KEY (`role_id`) REFERENCES `u947463964_etaviaporte`.`roles` (`id`) @@ -150,12 +141,12 @@ CREATE TABLE IF NOT EXISTS `u947463964_etaviaporte`.`user_roles` ( `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, `user_id` INT UNSIGNED NOT NULL, `role_id` INT UNSIGNED NOT NULL, - `created_at` DATETIME NOT NULL, + `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, `expires_at` DATETIME NULL, PRIMARY KEY (`id`), - UNIQUE INDEX `id_UNIQUE` (`id` ASC) VISIBLE, INDEX `fk_user_roles_users1_idx` (`user_id` ASC) VISIBLE, INDEX `fk_user_roles_roles1_idx` (`role_id` ASC) VISIBLE, + UNIQUE INDEX `user_id_UNIQUE` (`user_id` ASC, `role_id` ASC) VISIBLE, CONSTRAINT `fk_user_roles_users1` FOREIGN KEY (`user_id`) REFERENCES `u947463964_etaviaporte`.`users` (`id`) @@ -169,6 +160,130 @@ CREATE TABLE IF NOT EXISTS `u947463964_etaviaporte`.`user_roles` ( ENGINE = InnoDB; +-- ----------------------------------------------------- +-- Table `u947463964_etaviaporte`.`user_permissions` +-- ----------------------------------------------------- +CREATE TABLE IF NOT EXISTS `u947463964_etaviaporte`.`user_permissions` ( + `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, + `user_id` INT UNSIGNED NOT NULL, + `permission_id` INT UNSIGNED NOT NULL, + `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + `expires_at` DATETIME NULL, + PRIMARY KEY (`id`), + INDEX `fk_user_permissions_permissions1_idx` (`permission_id` ASC) VISIBLE, + INDEX `fk_user_permissions_users1_idx` (`user_id` ASC) VISIBLE, + UNIQUE INDEX `user_id_UNIQUE` (`user_id` ASC, `permission_id` ASC) VISIBLE, + CONSTRAINT `fk_user_permissions_permissions1` + FOREIGN KEY (`permission_id`) + REFERENCES `u947463964_etaviaporte`.`permissions` (`id`) + ON DELETE CASCADE + ON UPDATE NO ACTION, + CONSTRAINT `fk_user_permissions_users1` + FOREIGN KEY (`user_id`) + REFERENCES `u947463964_etaviaporte`.`users` (`id`) + ON DELETE CASCADE + ON UPDATE NO ACTION) +ENGINE = InnoDB; + + +-- ----------------------------------------------------- +-- Table `u947463964_etaviaporte`.`verification_tokens` +-- ----------------------------------------------------- +CREATE TABLE IF NOT EXISTS `u947463964_etaviaporte`.`verification_tokens` ( + `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, + `auth_identity_id` INT UNSIGNED NOT NULL, + `token_hash` VARCHAR(255) NOT NULL COMMENT 'Verification token for email/phone/notification mechanisms to either validate or reset passwords', + `purpose` ENUM('email_verification', 'phone_verification', 'password_reset') NOT NULL, + `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + `expires_at` DATETIME NOT NULL, + `used_at` DATETIME NULL, + PRIMARY KEY (`id`), + INDEX `fk_verification_tokens_auth_identities1_idx` (`auth_identity_id` ASC) VISIBLE, + UNIQUE INDEX `token_hash_UNIQUE` (`token_hash` ASC) VISIBLE, + CONSTRAINT `fk_verification_tokens_auth_identities1` + FOREIGN KEY (`auth_identity_id`) + REFERENCES `u947463964_etaviaporte`.`auth_identities` (`id`) + ON DELETE CASCADE + ON UPDATE NO ACTION) +ENGINE = InnoDB; + + +-- ----------------------------------------------------- +-- Table `u947463964_etaviaporte`.`sessions` +-- ----------------------------------------------------- +CREATE TABLE IF NOT EXISTS `u947463964_etaviaporte`.`sessions` ( + `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, + `user_id` INT UNSIGNED NOT NULL, + `application_id` INT UNSIGNED NOT NULL, + `session_token_hash` VARCHAR(255) NOT NULL, + `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `expires_at` DATETIME NOT NULL, + `revoked_at` DATETIME NULL, + PRIMARY KEY (`id`), + INDEX `fk_sessions_users1_idx` (`user_id` ASC) VISIBLE, + UNIQUE INDEX `session_token_hash_UNIQUE` (`application_id` ASC, `session_token_hash` ASC) VISIBLE, + INDEX `fk_sessions_applications1_idx` (`application_id` ASC) VISIBLE, + CONSTRAINT `fk_sessions_users1` + FOREIGN KEY (`user_id`) + REFERENCES `u947463964_etaviaporte`.`users` (`id`) + ON DELETE CASCADE + ON UPDATE NO ACTION, + CONSTRAINT `fk_sessions_applications1` + FOREIGN KEY (`application_id`) + REFERENCES `u947463964_etaviaporte`.`applications` (`id`) + ON DELETE NO ACTION + ON UPDATE NO ACTION) +ENGINE = InnoDB; + + +-- ----------------------------------------------------- +-- Table `u947463964_etaviaporte`.`user_applications` +-- ----------------------------------------------------- +CREATE TABLE IF NOT EXISTS `u947463964_etaviaporte`.`user_applications` ( + `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, + `user_id` INT UNSIGNED NOT NULL, + `application_id` INT UNSIGNED NOT NULL, + `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + INDEX `fk_user_application_users1_idx` (`user_id` ASC) VISIBLE, + INDEX `fk_user_application_applications1_idx` (`application_id` ASC) VISIBLE, + UNIQUE INDEX `user_id_UNIQUE` (`user_id` ASC, `application_id` ASC) VISIBLE, + CONSTRAINT `fk_user_application_users1` + FOREIGN KEY (`user_id`) + REFERENCES `u947463964_etaviaporte`.`users` (`id`) + ON DELETE CASCADE + ON UPDATE NO ACTION, + CONSTRAINT `fk_user_application_applications1` + FOREIGN KEY (`application_id`) + REFERENCES `u947463964_etaviaporte`.`applications` (`id`) + ON DELETE CASCADE + ON UPDATE NO ACTION) +ENGINE = InnoDB; + + +-- ----------------------------------------------------- +-- Table `u947463964_etaviaporte`.`api_keys` +-- ----------------------------------------------------- +CREATE TABLE IF NOT EXISTS `u947463964_etaviaporte`.`api_keys` ( + `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, + `application_id` INT UNSIGNED NOT NULL, + `name` VARCHAR(512) NOT NULL, + `description` TEXT NULL, + `key_hash` VARCHAR(255) NOT NULL, + `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + `expires_at` DATETIME NULL, + PRIMARY KEY (`id`), + UNIQUE INDEX `key_hash_UNIQUE` (`key_hash` ASC) VISIBLE, + INDEX `fk_api_keys_applications1_idx` (`application_id` ASC) VISIBLE, + CONSTRAINT `fk_api_keys_applications1` + FOREIGN KEY (`application_id`) + REFERENCES `u947463964_etaviaporte`.`applications` (`id`) + ON DELETE CASCADE + ON UPDATE NO ACTION) +ENGINE = InnoDB; + + SET SQL_MODE=@OLD_SQL_MODE; SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS; SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;