From f6aff013f15acd9c87adc94fe3f8535404654e9c Mon Sep 17 00:00:00 2001 From: Ricardo Amorim <102877738+risixdzn@users.noreply.github.com> Date: Wed, 27 May 2026 10:07:45 -0300 Subject: [PATCH 1/9] feat(DB): Setup makers + models + images schemas --- .../db/drizzle/0006_curved_doctor_octopus.sql | 93 ++ packages/db/drizzle/meta/0006_snapshot.json | 1077 +++++++++++++++++ packages/db/drizzle/meta/_journal.json | 7 + packages/db/package.json | 8 +- packages/db/src/schema/categories.ts | 15 + packages/db/src/schema/index.ts | 1 + packages/db/src/schema/makers.ts | 22 + packages/db/src/schema/model-images.ts | 32 + packages/db/src/schema/models.ts | 96 ++ 9 files changed, 1347 insertions(+), 4 deletions(-) create mode 100644 packages/db/drizzle/0006_curved_doctor_octopus.sql create mode 100644 packages/db/drizzle/meta/0006_snapshot.json create mode 100644 packages/db/src/schema/categories.ts create mode 100644 packages/db/src/schema/makers.ts create mode 100644 packages/db/src/schema/model-images.ts create mode 100644 packages/db/src/schema/models.ts diff --git a/packages/db/drizzle/0006_curved_doctor_octopus.sql b/packages/db/drizzle/0006_curved_doctor_octopus.sql new file mode 100644 index 0000000..6333cb5 --- /dev/null +++ b/packages/db/drizzle/0006_curved_doctor_octopus.sql @@ -0,0 +1,93 @@ +CREATE TABLE `categories` ( + `id` varchar(25) NOT NULL, + `name` varchar(100) NOT NULL, + `slug` varchar(100) NOT NULL, + CONSTRAINT `categories_id` PRIMARY KEY(`id`), + CONSTRAINT `categories_slug_unique` UNIQUE(`slug`) +); +--> statement-breakpoint +CREATE TABLE `makers` ( + `id` varchar(25) NOT NULL, + `name` varchar(100) NOT NULL, + `slug` varchar(100) NOT NULL, + `url` varchar(255) NOT NULL, + `device_count` int NOT NULL DEFAULT 0, + `page_count` int, + `created_at` timestamp NOT NULL DEFAULT (now()), + CONSTRAINT `makers_id` PRIMARY KEY(`id`), + CONSTRAINT `makers_slug_unique` UNIQUE(`slug`) +); +--> statement-breakpoint +CREATE TABLE `model_images` ( + `id` varchar(25) NOT NULL, + `model_id` varchar(25) NOT NULL, + `original_url` varchar(255), + `r2_key` varchar(255), + `is_primary` boolean NOT NULL DEFAULT false, + `variant` varchar(50), + `position` int NOT NULL DEFAULT 0, + `created_at` timestamp NOT NULL DEFAULT (now()), + CONSTRAINT `model_images_id` PRIMARY KEY(`id`) +); +--> statement-breakpoint +CREATE TABLE `models` ( + `id` varchar(25) NOT NULL, + `maker_id` varchar(25) NOT NULL, + `name` varchar(255) NOT NULL, + `slug` varchar(100) NOT NULL, + `url` varchar(255) NOT NULL, + `image_url` varchar(255), + `image_local_path` varchar(255), + `category_id` varchar(25), + `announced` varchar(100), + `status` varchar(100), + `dimensions` varchar(255), + `weight` varchar(100), + `build` varchar(255), + `sim` varchar(100), + `display_type` varchar(255), + `display_size` varchar(100), + `display_resolution` varchar(100), + `display_protection` varchar(100), + `os` varchar(255), + `chipset` varchar(255), + `cpu` varchar(255), + `gpu` varchar(255), + `card_slot` varchar(255), + `internal_memory` varchar(255), + `main_camera` varchar(255), + `main_camera_features` text, + `main_camera_video` varchar(255), + `selfie_camera` varchar(255), + `selfie_features` text, + `selfie_video` varchar(255), + `battery` varchar(255), + `battery_charging` varchar(255), + `network_tech` varchar(255), + `sensors` varchar(255), + `colors` varchar(255), + `colors_hex` text, + `models_text` varchar(255), + `price` varchar(100), + `dimensions_width` float, + `dimensions_height` float, + `dimensions_thickness` float, + `weight_grams` float, + `display_size_inches` float, + `display_size_ratio` varchar(100), + `display_res_width` int, + `display_res_height` int, + `display_res_ppi` int, + `released` varchar(100), + `meta` text, + `company_id` varchar(25), + `created_at` timestamp NOT NULL DEFAULT (now()), + CONSTRAINT `models_id` PRIMARY KEY(`id`), + CONSTRAINT `slug_company_unique` UNIQUE(`slug`,`company_id`) +); +--> statement-breakpoint +ALTER TABLE `employees` MODIFY COLUMN `roles` enum('guest','technician','warehouse','financial','manager','admin') NOT NULL;--> statement-breakpoint +ALTER TABLE `model_images` ADD CONSTRAINT `model_images_model_id_models_id_fk` FOREIGN KEY (`model_id`) REFERENCES `models`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE `models` ADD CONSTRAINT `models_maker_id_makers_id_fk` FOREIGN KEY (`maker_id`) REFERENCES `makers`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE `models` ADD CONSTRAINT `models_category_id_categories_id_fk` FOREIGN KEY (`category_id`) REFERENCES `categories`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE `models` ADD CONSTRAINT `models_company_id_companies_id_fk` FOREIGN KEY (`company_id`) REFERENCES `companies`(`id`) ON DELETE no action ON UPDATE no action; \ No newline at end of file diff --git a/packages/db/drizzle/meta/0006_snapshot.json b/packages/db/drizzle/meta/0006_snapshot.json new file mode 100644 index 0000000..22338db --- /dev/null +++ b/packages/db/drizzle/meta/0006_snapshot.json @@ -0,0 +1,1077 @@ +{ + "version": "5", + "dialect": "mysql", + "id": "469411a6-c473-42e2-89d1-da5d3e144652", + "prevId": "96fef0d8-3c1e-4d2f-990d-625797fa1861", + "tables": { + "categories": { + "name": "categories", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "slug": { + "name": "slug", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "categories_id": { + "name": "categories_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "categories_slug_unique": { + "name": "categories_slug_unique", + "columns": ["slug"] + } + }, + "checkConstraint": {} + }, + "clients": { + "name": "clients", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cpf": { + "name": "cpf", + "type": "varchar(11)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "phone": { + "name": "phone", + "type": "varchar(11)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "user_id": { + "name": "user_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "clients_user_id_users_id_fk": { + "name": "clients_user_id_users_id_fk", + "tableFrom": "clients", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "clients_id": { + "name": "clients_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "clients_cpf_unique": { + "name": "clients_cpf_unique", + "columns": ["cpf"] + } + }, + "checkConstraint": {} + }, + "companies": { + "name": "companies", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cnpj": { + "name": "cnpj", + "type": "varchar(14)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "address": { + "name": "address", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "subdomain": { + "name": "subdomain", + "type": "varchar(32)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "companies_id": { + "name": "companies_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "companies_cnpj_unique": { + "name": "companies_cnpj_unique", + "columns": ["cnpj"] + }, + "companies_subdomain_unique": { + "name": "companies_subdomain_unique", + "columns": ["subdomain"] + } + }, + "checkConstraint": {} + }, + "employees": { + "name": "employees", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cpf": { + "name": "cpf", + "type": "varchar(11)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "phone": { + "name": "phone", + "type": "varchar(11)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "roles": { + "name": "roles", + "type": "enum('guest','technician','warehouse','financial','manager','admin')", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "user_id": { + "name": "user_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "company_id": { + "name": "company_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "employees_user_id_users_id_fk": { + "name": "employees_user_id_users_id_fk", + "tableFrom": "employees", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "employees_company_id_companies_id_fk": { + "name": "employees_company_id_companies_id_fk", + "tableFrom": "employees", + "tableTo": "companies", + "columnsFrom": ["company_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "employees_id": { + "name": "employees_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "employees_cpf_unique": { + "name": "employees_cpf_unique", + "columns": ["cpf"] + } + }, + "checkConstraint": {} + }, + "makers": { + "name": "makers", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "slug": { + "name": "slug", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "device_count": { + "name": "device_count", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "page_count": { + "name": "page_count", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "makers_id": { + "name": "makers_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "makers_slug_unique": { + "name": "makers_slug_unique", + "columns": ["slug"] + } + }, + "checkConstraint": {} + }, + "model_images": { + "name": "model_images", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "model_id": { + "name": "model_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "original_url": { + "name": "original_url", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "r2_key": { + "name": "r2_key", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "is_primary": { + "name": "is_primary", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "variant": { + "name": "variant", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "position": { + "name": "position", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": { + "model_images_model_id_models_id_fk": { + "name": "model_images_model_id_models_id_fk", + "tableFrom": "model_images", + "tableTo": "models", + "columnsFrom": ["model_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "model_images_id": { + "name": "model_images_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "models": { + "name": "models", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "maker_id": { + "name": "maker_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "slug": { + "name": "slug", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "image_url": { + "name": "image_url", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "image_local_path": { + "name": "image_local_path", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "category_id": { + "name": "category_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "announced": { + "name": "announced", + "type": "varchar(100)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "varchar(100)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "dimensions": { + "name": "dimensions", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "weight": { + "name": "weight", + "type": "varchar(100)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "build": { + "name": "build", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "sim": { + "name": "sim", + "type": "varchar(100)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_type": { + "name": "display_type", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_size": { + "name": "display_size", + "type": "varchar(100)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_resolution": { + "name": "display_resolution", + "type": "varchar(100)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_protection": { + "name": "display_protection", + "type": "varchar(100)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "os": { + "name": "os", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "chipset": { + "name": "chipset", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "cpu": { + "name": "cpu", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "gpu": { + "name": "gpu", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "card_slot": { + "name": "card_slot", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "internal_memory": { + "name": "internal_memory", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "main_camera": { + "name": "main_camera", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "main_camera_features": { + "name": "main_camera_features", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "main_camera_video": { + "name": "main_camera_video", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "selfie_camera": { + "name": "selfie_camera", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "selfie_features": { + "name": "selfie_features", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "selfie_video": { + "name": "selfie_video", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "battery": { + "name": "battery", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "battery_charging": { + "name": "battery_charging", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "network_tech": { + "name": "network_tech", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "sensors": { + "name": "sensors", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "colors": { + "name": "colors", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "colors_hex": { + "name": "colors_hex", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "models_text": { + "name": "models_text", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "price": { + "name": "price", + "type": "varchar(100)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "dimensions_width": { + "name": "dimensions_width", + "type": "float", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "dimensions_height": { + "name": "dimensions_height", + "type": "float", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "dimensions_thickness": { + "name": "dimensions_thickness", + "type": "float", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "weight_grams": { + "name": "weight_grams", + "type": "float", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_size_inches": { + "name": "display_size_inches", + "type": "float", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_size_ratio": { + "name": "display_size_ratio", + "type": "varchar(100)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_res_width": { + "name": "display_res_width", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_res_height": { + "name": "display_res_height", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_res_ppi": { + "name": "display_res_ppi", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "released": { + "name": "released", + "type": "varchar(100)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "meta": { + "name": "meta", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "company_id": { + "name": "company_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": { + "models_maker_id_makers_id_fk": { + "name": "models_maker_id_makers_id_fk", + "tableFrom": "models", + "tableTo": "makers", + "columnsFrom": ["maker_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "models_category_id_categories_id_fk": { + "name": "models_category_id_categories_id_fk", + "tableFrom": "models", + "tableTo": "categories", + "columnsFrom": ["category_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "models_company_id_companies_id_fk": { + "name": "models_company_id_companies_id_fk", + "tableFrom": "models", + "tableTo": "companies", + "columnsFrom": ["company_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "models_id": { + "name": "models_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "slug_company_unique": { + "name": "slug_company_unique", + "columns": ["slug", "company_id"] + } + }, + "checkConstraint": {} + }, + "one_time_tokens": { + "name": "one_time_tokens", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "ott_type": { + "name": "ott_type", + "type": "enum('confirmation','password_reset','account_deletion')", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "relates_to": { + "name": "relates_to", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "one_time_tokens_user_id_users_id_fk": { + "name": "one_time_tokens_user_id_users_id_fk", + "tableFrom": "one_time_tokens", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "one_time_tokens_id": { + "name": "one_time_tokens_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "one_time_tokens_token_unique": { + "name": "one_time_tokens_token_unique", + "columns": ["token"] + } + }, + "checkConstraint": {} + }, + "refresh_tokens": { + "name": "refresh_tokens", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "refresh_tokens_user_id_users_id_fk": { + "name": "refresh_tokens_user_id_users_id_fk", + "tableFrom": "refresh_tokens", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "refresh_tokens_id": { + "name": "refresh_tokens_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "refresh_tokens_token_unique": { + "name": "refresh_tokens_token_unique", + "columns": ["token"] + } + }, + "checkConstraint": {} + }, + "users": { + "name": "users", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "password_hash": { + "name": "password_hash", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "google_id": { + "name": "google_id", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "avatar_url": { + "name": "avatar_url", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "verified": { + "name": "verified", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "users_id": { + "name": "users_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "users_email_unique": { + "name": "users_email_unique", + "columns": ["email"] + }, + "users_google_id_unique": { + "name": "users_google_id_unique", + "columns": ["google_id"] + } + }, + "checkConstraint": {} + } + }, + "views": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "tables": {}, + "indexes": {} + } +} diff --git a/packages/db/drizzle/meta/_journal.json b/packages/db/drizzle/meta/_journal.json index 6e81e16..bee8bc9 100644 --- a/packages/db/drizzle/meta/_journal.json +++ b/packages/db/drizzle/meta/_journal.json @@ -43,6 +43,13 @@ "when": 1760755210443, "tag": "0005_faulty_mandarin", "breakpoints": true + }, + { + "idx": 6, + "version": "5", + "when": 1779887155497, + "tag": "0006_curved_doctor_octopus", + "breakpoints": true } ] } diff --git a/packages/db/package.json b/packages/db/package.json index abdebb7..1bf2c94 100644 --- a/packages/db/package.json +++ b/packages/db/package.json @@ -4,10 +4,10 @@ "type": "module", "private": true, "scripts": { - "db:push": "dotenv -- drizzle-kit push", - "db:generate": "dotenv -- drizzle-kit generate", - "db:studio": "dotenv -- drizzle-kit studio", - "db:migrate": "dotenv -- tsx src/migrate.ts", + "db:push": "bunx --bun drizzle-kit push", + "db:generate": "bunx --bun drizzle-kit generate", + "db:studio": "bunx --bun drizzle-kit studio", + "db:migrate": "bunx --bun tsx src/migrate.ts", "db:start": "docker compose up -d", "db:watch": "docker compose up", "db:stop": "docker compose stop", diff --git a/packages/db/src/schema/categories.ts b/packages/db/src/schema/categories.ts new file mode 100644 index 0000000..49480d0 --- /dev/null +++ b/packages/db/src/schema/categories.ts @@ -0,0 +1,15 @@ +import { createId } from "@paralleldrive/cuid2"; +import { mysqlTable, varchar } from "drizzle-orm/mysql-core"; +import { createSelectSchema } from "drizzle-zod"; + +export const categories = mysqlTable("categories", { + id: varchar("id", { length: 25 }) + .$defaultFn(() => createId()) + .primaryKey(), + name: varchar("name", { length: 100 }).notNull(), + slug: varchar("slug", { length: 100 }).unique().notNull(), +}); + +export const categorySelectSchema = createSelectSchema(categories); +export type CategoryInsert = typeof categories.$inferInsert; +export type CategorySelect = typeof categories.$inferSelect; diff --git a/packages/db/src/schema/index.ts b/packages/db/src/schema/index.ts index 4cbaa08..a3877c5 100644 --- a/packages/db/src/schema/index.ts +++ b/packages/db/src/schema/index.ts @@ -1,3 +1,4 @@ +export * from "./categories"; export * from "./clients"; export * from "./companies"; export * from "./employees"; diff --git a/packages/db/src/schema/makers.ts b/packages/db/src/schema/makers.ts new file mode 100644 index 0000000..d9178a6 --- /dev/null +++ b/packages/db/src/schema/makers.ts @@ -0,0 +1,22 @@ +import { createId } from "@paralleldrive/cuid2"; +import { int, mysqlTable, timestamp, varchar } from "drizzle-orm/mysql-core"; +import { createSelectSchema } from "drizzle-zod"; +import { z } from "zod"; + +export const makers = mysqlTable("makers", { + id: varchar("id", { length: 25 }) + .$defaultFn(() => createId()) + .primaryKey(), + name: varchar("name", { length: 100 }).notNull(), + slug: varchar("slug", { length: 100 }).unique().notNull(), + url: varchar("url", { length: 255 }).notNull(), + deviceCount: int("device_count").notNull().default(0), + pageCount: int("page_count"), + createdAt: timestamp("created_at").defaultNow().notNull(), +}); + +export const makerSelectSchema = createSelectSchema(makers, { + createdAt: z.coerce.date(), +}); +export type MakerInsert = typeof makers.$inferInsert; +export type MakerSelect = typeof makers.$inferSelect; diff --git a/packages/db/src/schema/model-images.ts b/packages/db/src/schema/model-images.ts new file mode 100644 index 0000000..6636c66 --- /dev/null +++ b/packages/db/src/schema/model-images.ts @@ -0,0 +1,32 @@ +import { createId } from "@paralleldrive/cuid2"; +import { + boolean, + int, + mysqlTable, + timestamp, + varchar, +} from "drizzle-orm/mysql-core"; +import { createSelectSchema } from "drizzle-zod"; +import { z } from "zod"; +import { models } from "./models"; + +export const modelImages = mysqlTable("model_images", { + id: varchar("id", { length: 25 }) + .$defaultFn(() => createId()) + .primaryKey(), + modelId: varchar("model_id", { length: 25 }) + .notNull() + .references(() => models.id), + originalUrl: varchar("original_url", { length: 255 }), + r2Key: varchar("r2_key", { length: 255 }), + isPrimary: boolean("is_primary").notNull().default(false), + variant: varchar("variant", { length: 50 }), + position: int("position").notNull().default(0), + createdAt: timestamp("created_at").defaultNow().notNull(), +}); + +export const modelImageSelectSchema = createSelectSchema(modelImages, { + createdAt: z.coerce.date(), +}); +export type ModelImageInsert = typeof modelImages.$inferInsert; +export type ModelImageSelect = typeof modelImages.$inferSelect; diff --git a/packages/db/src/schema/models.ts b/packages/db/src/schema/models.ts new file mode 100644 index 0000000..6cca532 --- /dev/null +++ b/packages/db/src/schema/models.ts @@ -0,0 +1,96 @@ +import { createId } from "@paralleldrive/cuid2"; +import { + float, + int, + mysqlTable, + text, + timestamp, + unique, + varchar, +} from "drizzle-orm/mysql-core"; +import { createSelectSchema } from "drizzle-zod"; +import { z } from "zod"; +import { categories } from "./categories"; +import { companies } from "./companies"; +import { makers } from "./makers"; + +export const models = mysqlTable( + "models", + { + id: varchar("id", { length: 25 }) + .$defaultFn(() => createId()) + .primaryKey(), + makerId: varchar("maker_id", { length: 25 }) + .notNull() + .references(() => makers.id), + name: varchar("name", { length: 255 }).notNull(), + slug: varchar("slug", { length: 100 }).notNull(), + url: varchar("url", { length: 255 }).notNull(), + imageUrl: varchar("image_url", { length: 255 }), + imageLocalPath: varchar("image_local_path", { length: 255 }), + + categoryId: varchar("category_id", { length: 25 }).references( + () => categories.id + ), + + announced: varchar("announced", { length: 100 }), + status: varchar("status", { length: 100 }), + dimensions: varchar("dimensions", { length: 255 }), + weight: varchar("weight", { length: 100 }), + build: varchar("build", { length: 255 }), + sim: varchar("sim", { length: 100 }), + displayType: varchar("display_type", { length: 255 }), + displaySize: varchar("display_size", { length: 100 }), + displayResolution: varchar("display_resolution", { length: 100 }), + displayProtection: varchar("display_protection", { length: 100 }), + os: varchar("os", { length: 255 }), + chipset: varchar("chipset", { length: 255 }), + cpu: varchar("cpu", { length: 255 }), + gpu: varchar("gpu", { length: 255 }), + cardSlot: varchar("card_slot", { length: 255 }), + internalMemory: varchar("internal_memory", { length: 255 }), + mainCamera: varchar("main_camera", { length: 255 }), + mainCameraFeatures: text("main_camera_features"), + mainCameraVideo: varchar("main_camera_video", { length: 255 }), + selfieCamera: varchar("selfie_camera", { length: 255 }), + selfieFeatures: text("selfie_features"), + selfieVideo: varchar("selfie_video", { length: 255 }), + battery: varchar("battery", { length: 255 }), + batteryCharging: varchar("battery_charging", { length: 255 }), + networkTech: varchar("network_tech", { length: 255 }), + sensors: varchar("sensors", { length: 255 }), + colors: varchar("colors", { length: 255 }), + colorsHex: text("colors_hex"), + modelsText: varchar("models_text", { length: 255 }), + price: varchar("price", { length: 100 }), + dimensionsWidth: float("dimensions_width"), + dimensionsHeight: float("dimensions_height"), + dimensionsThickness: float("dimensions_thickness"), + weightGrams: float("weight_grams"), + displaySizeInches: float("display_size_inches"), + displaySizeRatio: varchar("display_size_ratio", { length: 100 }), + displayResWidth: int("display_res_width"), + displayResHeight: int("display_res_height"), + displayResPpi: int("display_res_ppi"), + released: varchar("released", { length: 100 }), + + meta: text("meta"), + + companyId: varchar("company_id", { length: 25 }).references( + () => companies.id + ), + createdAt: timestamp("created_at").defaultNow().notNull(), + }, + (table) => ({ + slugCompanyUnique: unique("slug_company_unique").on( + table.slug, + table.companyId + ), + }) +); + +export const modelSelectSchema = createSelectSchema(models, { + createdAt: z.coerce.date(), +}); +export type ModelInsert = typeof models.$inferInsert; +export type ModelSelect = typeof models.$inferSelect; From d72d887c5a1e1dc3a716e3317334761a33b085e4 Mon Sep 17 00:00:00 2001 From: Ricardo Amorim <102877738+risixdzn@users.noreply.github.com> Date: Wed, 27 May 2026 10:34:46 -0300 Subject: [PATCH 2/9] refactor(DB): Compat column types to hold scraped data --- package.json | 1 + .../0007_powerful_mulholland_black.sql | 10 + packages/db/drizzle/0008_dear_karnak.sql | 29 + packages/db/drizzle/meta/0007_snapshot.json | 1077 +++++++++++++++++ packages/db/drizzle/meta/0008_snapshot.json | 1077 +++++++++++++++++ packages/db/drizzle/meta/_journal.json | 14 + packages/db/package.json | 3 +- packages/db/src/schema/models.ts | 58 +- packages/db/tsconfig.json | 2 +- 9 files changed, 2240 insertions(+), 31 deletions(-) create mode 100644 packages/db/drizzle/0007_powerful_mulholland_black.sql create mode 100644 packages/db/drizzle/0008_dear_karnak.sql create mode 100644 packages/db/drizzle/meta/0007_snapshot.json create mode 100644 packages/db/drizzle/meta/0008_snapshot.json diff --git a/package.json b/package.json index 017ae81..e9bbae4 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "db:studio": "bun run --elide-lines 0 --filter @fixr/db db:studio", "db:generate": "bun run --elide-lines 0 --filter @fixr/db db:generate", "db:migrate": "bun run --elide-lines 0 --filter @fixr/db db:migrate", + "db:seed": "bun run --elide-lines 0 --filter @fixr/db db:seed", "db:start": "bun run --elide-lines 0 --filter @fixr/db db:start", "db:watch": "bun run --elide-lines 0 --filter @fixr/db db:watch", "db:stop": "bun run --elide-lines 0 --filter @fixr/db db:stop", diff --git a/packages/db/drizzle/0007_powerful_mulholland_black.sql b/packages/db/drizzle/0007_powerful_mulholland_black.sql new file mode 100644 index 0000000..c24da9f --- /dev/null +++ b/packages/db/drizzle/0007_powerful_mulholland_black.sql @@ -0,0 +1,10 @@ +ALTER TABLE `models` MODIFY COLUMN `announced` varchar(255);--> statement-breakpoint +ALTER TABLE `models` MODIFY COLUMN `status` varchar(255);--> statement-breakpoint +ALTER TABLE `models` MODIFY COLUMN `weight` varchar(255);--> statement-breakpoint +ALTER TABLE `models` MODIFY COLUMN `sim` varchar(255);--> statement-breakpoint +ALTER TABLE `models` MODIFY COLUMN `display_size` varchar(255);--> statement-breakpoint +ALTER TABLE `models` MODIFY COLUMN `display_resolution` varchar(255);--> statement-breakpoint +ALTER TABLE `models` MODIFY COLUMN `display_protection` varchar(255);--> statement-breakpoint +ALTER TABLE `models` MODIFY COLUMN `price` varchar(255);--> statement-breakpoint +ALTER TABLE `models` MODIFY COLUMN `display_size_ratio` varchar(255);--> statement-breakpoint +ALTER TABLE `models` MODIFY COLUMN `released` varchar(255); \ No newline at end of file diff --git a/packages/db/drizzle/0008_dear_karnak.sql b/packages/db/drizzle/0008_dear_karnak.sql new file mode 100644 index 0000000..207642b --- /dev/null +++ b/packages/db/drizzle/0008_dear_karnak.sql @@ -0,0 +1,29 @@ +ALTER TABLE `models` MODIFY COLUMN `announced` text;--> statement-breakpoint +ALTER TABLE `models` MODIFY COLUMN `status` text;--> statement-breakpoint +ALTER TABLE `models` MODIFY COLUMN `dimensions` text;--> statement-breakpoint +ALTER TABLE `models` MODIFY COLUMN `weight` text;--> statement-breakpoint +ALTER TABLE `models` MODIFY COLUMN `build` text;--> statement-breakpoint +ALTER TABLE `models` MODIFY COLUMN `sim` text;--> statement-breakpoint +ALTER TABLE `models` MODIFY COLUMN `display_type` text;--> statement-breakpoint +ALTER TABLE `models` MODIFY COLUMN `display_size` text;--> statement-breakpoint +ALTER TABLE `models` MODIFY COLUMN `display_resolution` text;--> statement-breakpoint +ALTER TABLE `models` MODIFY COLUMN `display_protection` text;--> statement-breakpoint +ALTER TABLE `models` MODIFY COLUMN `os` text;--> statement-breakpoint +ALTER TABLE `models` MODIFY COLUMN `chipset` text;--> statement-breakpoint +ALTER TABLE `models` MODIFY COLUMN `cpu` text;--> statement-breakpoint +ALTER TABLE `models` MODIFY COLUMN `gpu` text;--> statement-breakpoint +ALTER TABLE `models` MODIFY COLUMN `card_slot` text;--> statement-breakpoint +ALTER TABLE `models` MODIFY COLUMN `internal_memory` text;--> statement-breakpoint +ALTER TABLE `models` MODIFY COLUMN `main_camera` text;--> statement-breakpoint +ALTER TABLE `models` MODIFY COLUMN `main_camera_video` text;--> statement-breakpoint +ALTER TABLE `models` MODIFY COLUMN `selfie_camera` text;--> statement-breakpoint +ALTER TABLE `models` MODIFY COLUMN `selfie_video` text;--> statement-breakpoint +ALTER TABLE `models` MODIFY COLUMN `battery` text;--> statement-breakpoint +ALTER TABLE `models` MODIFY COLUMN `battery_charging` text;--> statement-breakpoint +ALTER TABLE `models` MODIFY COLUMN `network_tech` text;--> statement-breakpoint +ALTER TABLE `models` MODIFY COLUMN `sensors` text;--> statement-breakpoint +ALTER TABLE `models` MODIFY COLUMN `colors` text;--> statement-breakpoint +ALTER TABLE `models` MODIFY COLUMN `models_text` text;--> statement-breakpoint +ALTER TABLE `models` MODIFY COLUMN `price` text;--> statement-breakpoint +ALTER TABLE `models` MODIFY COLUMN `display_size_ratio` text;--> statement-breakpoint +ALTER TABLE `models` MODIFY COLUMN `released` text; \ No newline at end of file diff --git a/packages/db/drizzle/meta/0007_snapshot.json b/packages/db/drizzle/meta/0007_snapshot.json new file mode 100644 index 0000000..7418b2a --- /dev/null +++ b/packages/db/drizzle/meta/0007_snapshot.json @@ -0,0 +1,1077 @@ +{ + "version": "5", + "dialect": "mysql", + "id": "46d97f25-6199-4c7a-ab20-1a0f9cb032f3", + "prevId": "469411a6-c473-42e2-89d1-da5d3e144652", + "tables": { + "categories": { + "name": "categories", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "slug": { + "name": "slug", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "categories_id": { + "name": "categories_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "categories_slug_unique": { + "name": "categories_slug_unique", + "columns": ["slug"] + } + }, + "checkConstraint": {} + }, + "clients": { + "name": "clients", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cpf": { + "name": "cpf", + "type": "varchar(11)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "phone": { + "name": "phone", + "type": "varchar(11)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "user_id": { + "name": "user_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "clients_user_id_users_id_fk": { + "name": "clients_user_id_users_id_fk", + "tableFrom": "clients", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "clients_id": { + "name": "clients_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "clients_cpf_unique": { + "name": "clients_cpf_unique", + "columns": ["cpf"] + } + }, + "checkConstraint": {} + }, + "companies": { + "name": "companies", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cnpj": { + "name": "cnpj", + "type": "varchar(14)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "address": { + "name": "address", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "subdomain": { + "name": "subdomain", + "type": "varchar(32)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "companies_id": { + "name": "companies_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "companies_cnpj_unique": { + "name": "companies_cnpj_unique", + "columns": ["cnpj"] + }, + "companies_subdomain_unique": { + "name": "companies_subdomain_unique", + "columns": ["subdomain"] + } + }, + "checkConstraint": {} + }, + "employees": { + "name": "employees", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cpf": { + "name": "cpf", + "type": "varchar(11)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "phone": { + "name": "phone", + "type": "varchar(11)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "roles": { + "name": "roles", + "type": "enum('guest','technician','warehouse','financial','manager','admin')", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "user_id": { + "name": "user_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "company_id": { + "name": "company_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "employees_user_id_users_id_fk": { + "name": "employees_user_id_users_id_fk", + "tableFrom": "employees", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "employees_company_id_companies_id_fk": { + "name": "employees_company_id_companies_id_fk", + "tableFrom": "employees", + "tableTo": "companies", + "columnsFrom": ["company_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "employees_id": { + "name": "employees_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "employees_cpf_unique": { + "name": "employees_cpf_unique", + "columns": ["cpf"] + } + }, + "checkConstraint": {} + }, + "makers": { + "name": "makers", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "slug": { + "name": "slug", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "device_count": { + "name": "device_count", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "page_count": { + "name": "page_count", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "makers_id": { + "name": "makers_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "makers_slug_unique": { + "name": "makers_slug_unique", + "columns": ["slug"] + } + }, + "checkConstraint": {} + }, + "model_images": { + "name": "model_images", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "model_id": { + "name": "model_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "original_url": { + "name": "original_url", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "r2_key": { + "name": "r2_key", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "is_primary": { + "name": "is_primary", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "variant": { + "name": "variant", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "position": { + "name": "position", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": { + "model_images_model_id_models_id_fk": { + "name": "model_images_model_id_models_id_fk", + "tableFrom": "model_images", + "tableTo": "models", + "columnsFrom": ["model_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "model_images_id": { + "name": "model_images_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "models": { + "name": "models", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "maker_id": { + "name": "maker_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "slug": { + "name": "slug", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "image_url": { + "name": "image_url", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "image_local_path": { + "name": "image_local_path", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "category_id": { + "name": "category_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "announced": { + "name": "announced", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "dimensions": { + "name": "dimensions", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "weight": { + "name": "weight", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "build": { + "name": "build", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "sim": { + "name": "sim", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_type": { + "name": "display_type", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_size": { + "name": "display_size", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_resolution": { + "name": "display_resolution", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_protection": { + "name": "display_protection", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "os": { + "name": "os", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "chipset": { + "name": "chipset", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "cpu": { + "name": "cpu", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "gpu": { + "name": "gpu", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "card_slot": { + "name": "card_slot", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "internal_memory": { + "name": "internal_memory", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "main_camera": { + "name": "main_camera", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "main_camera_features": { + "name": "main_camera_features", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "main_camera_video": { + "name": "main_camera_video", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "selfie_camera": { + "name": "selfie_camera", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "selfie_features": { + "name": "selfie_features", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "selfie_video": { + "name": "selfie_video", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "battery": { + "name": "battery", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "battery_charging": { + "name": "battery_charging", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "network_tech": { + "name": "network_tech", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "sensors": { + "name": "sensors", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "colors": { + "name": "colors", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "colors_hex": { + "name": "colors_hex", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "models_text": { + "name": "models_text", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "price": { + "name": "price", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "dimensions_width": { + "name": "dimensions_width", + "type": "float", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "dimensions_height": { + "name": "dimensions_height", + "type": "float", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "dimensions_thickness": { + "name": "dimensions_thickness", + "type": "float", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "weight_grams": { + "name": "weight_grams", + "type": "float", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_size_inches": { + "name": "display_size_inches", + "type": "float", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_size_ratio": { + "name": "display_size_ratio", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_res_width": { + "name": "display_res_width", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_res_height": { + "name": "display_res_height", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_res_ppi": { + "name": "display_res_ppi", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "released": { + "name": "released", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "meta": { + "name": "meta", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "company_id": { + "name": "company_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": { + "models_maker_id_makers_id_fk": { + "name": "models_maker_id_makers_id_fk", + "tableFrom": "models", + "tableTo": "makers", + "columnsFrom": ["maker_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "models_category_id_categories_id_fk": { + "name": "models_category_id_categories_id_fk", + "tableFrom": "models", + "tableTo": "categories", + "columnsFrom": ["category_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "models_company_id_companies_id_fk": { + "name": "models_company_id_companies_id_fk", + "tableFrom": "models", + "tableTo": "companies", + "columnsFrom": ["company_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "models_id": { + "name": "models_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "slug_company_unique": { + "name": "slug_company_unique", + "columns": ["slug", "company_id"] + } + }, + "checkConstraint": {} + }, + "one_time_tokens": { + "name": "one_time_tokens", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "ott_type": { + "name": "ott_type", + "type": "enum('confirmation','password_reset','account_deletion')", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "relates_to": { + "name": "relates_to", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "one_time_tokens_user_id_users_id_fk": { + "name": "one_time_tokens_user_id_users_id_fk", + "tableFrom": "one_time_tokens", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "one_time_tokens_id": { + "name": "one_time_tokens_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "one_time_tokens_token_unique": { + "name": "one_time_tokens_token_unique", + "columns": ["token"] + } + }, + "checkConstraint": {} + }, + "refresh_tokens": { + "name": "refresh_tokens", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "refresh_tokens_user_id_users_id_fk": { + "name": "refresh_tokens_user_id_users_id_fk", + "tableFrom": "refresh_tokens", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "refresh_tokens_id": { + "name": "refresh_tokens_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "refresh_tokens_token_unique": { + "name": "refresh_tokens_token_unique", + "columns": ["token"] + } + }, + "checkConstraint": {} + }, + "users": { + "name": "users", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "password_hash": { + "name": "password_hash", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "google_id": { + "name": "google_id", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "avatar_url": { + "name": "avatar_url", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "verified": { + "name": "verified", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "users_id": { + "name": "users_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "users_email_unique": { + "name": "users_email_unique", + "columns": ["email"] + }, + "users_google_id_unique": { + "name": "users_google_id_unique", + "columns": ["google_id"] + } + }, + "checkConstraint": {} + } + }, + "views": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "tables": {}, + "indexes": {} + } +} diff --git a/packages/db/drizzle/meta/0008_snapshot.json b/packages/db/drizzle/meta/0008_snapshot.json new file mode 100644 index 0000000..95d4b19 --- /dev/null +++ b/packages/db/drizzle/meta/0008_snapshot.json @@ -0,0 +1,1077 @@ +{ + "version": "5", + "dialect": "mysql", + "id": "c6166889-3f02-4a1b-8963-5bd45d4efba5", + "prevId": "46d97f25-6199-4c7a-ab20-1a0f9cb032f3", + "tables": { + "categories": { + "name": "categories", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "slug": { + "name": "slug", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "categories_id": { + "name": "categories_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "categories_slug_unique": { + "name": "categories_slug_unique", + "columns": ["slug"] + } + }, + "checkConstraint": {} + }, + "clients": { + "name": "clients", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cpf": { + "name": "cpf", + "type": "varchar(11)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "phone": { + "name": "phone", + "type": "varchar(11)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "user_id": { + "name": "user_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "clients_user_id_users_id_fk": { + "name": "clients_user_id_users_id_fk", + "tableFrom": "clients", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "clients_id": { + "name": "clients_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "clients_cpf_unique": { + "name": "clients_cpf_unique", + "columns": ["cpf"] + } + }, + "checkConstraint": {} + }, + "companies": { + "name": "companies", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cnpj": { + "name": "cnpj", + "type": "varchar(14)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "address": { + "name": "address", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "subdomain": { + "name": "subdomain", + "type": "varchar(32)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "companies_id": { + "name": "companies_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "companies_cnpj_unique": { + "name": "companies_cnpj_unique", + "columns": ["cnpj"] + }, + "companies_subdomain_unique": { + "name": "companies_subdomain_unique", + "columns": ["subdomain"] + } + }, + "checkConstraint": {} + }, + "employees": { + "name": "employees", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cpf": { + "name": "cpf", + "type": "varchar(11)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "phone": { + "name": "phone", + "type": "varchar(11)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "roles": { + "name": "roles", + "type": "enum('guest','technician','warehouse','financial','manager','admin')", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "user_id": { + "name": "user_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "company_id": { + "name": "company_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "employees_user_id_users_id_fk": { + "name": "employees_user_id_users_id_fk", + "tableFrom": "employees", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "employees_company_id_companies_id_fk": { + "name": "employees_company_id_companies_id_fk", + "tableFrom": "employees", + "tableTo": "companies", + "columnsFrom": ["company_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "employees_id": { + "name": "employees_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "employees_cpf_unique": { + "name": "employees_cpf_unique", + "columns": ["cpf"] + } + }, + "checkConstraint": {} + }, + "makers": { + "name": "makers", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "slug": { + "name": "slug", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "device_count": { + "name": "device_count", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "page_count": { + "name": "page_count", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "makers_id": { + "name": "makers_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "makers_slug_unique": { + "name": "makers_slug_unique", + "columns": ["slug"] + } + }, + "checkConstraint": {} + }, + "model_images": { + "name": "model_images", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "model_id": { + "name": "model_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "original_url": { + "name": "original_url", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "r2_key": { + "name": "r2_key", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "is_primary": { + "name": "is_primary", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "variant": { + "name": "variant", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "position": { + "name": "position", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": { + "model_images_model_id_models_id_fk": { + "name": "model_images_model_id_models_id_fk", + "tableFrom": "model_images", + "tableTo": "models", + "columnsFrom": ["model_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "model_images_id": { + "name": "model_images_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "models": { + "name": "models", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "maker_id": { + "name": "maker_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "slug": { + "name": "slug", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "image_url": { + "name": "image_url", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "image_local_path": { + "name": "image_local_path", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "category_id": { + "name": "category_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "announced": { + "name": "announced", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "dimensions": { + "name": "dimensions", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "weight": { + "name": "weight", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "build": { + "name": "build", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "sim": { + "name": "sim", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_type": { + "name": "display_type", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_size": { + "name": "display_size", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_resolution": { + "name": "display_resolution", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_protection": { + "name": "display_protection", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "os": { + "name": "os", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "chipset": { + "name": "chipset", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "cpu": { + "name": "cpu", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "gpu": { + "name": "gpu", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "card_slot": { + "name": "card_slot", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "internal_memory": { + "name": "internal_memory", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "main_camera": { + "name": "main_camera", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "main_camera_features": { + "name": "main_camera_features", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "main_camera_video": { + "name": "main_camera_video", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "selfie_camera": { + "name": "selfie_camera", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "selfie_features": { + "name": "selfie_features", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "selfie_video": { + "name": "selfie_video", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "battery": { + "name": "battery", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "battery_charging": { + "name": "battery_charging", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "network_tech": { + "name": "network_tech", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "sensors": { + "name": "sensors", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "colors": { + "name": "colors", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "colors_hex": { + "name": "colors_hex", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "models_text": { + "name": "models_text", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "price": { + "name": "price", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "dimensions_width": { + "name": "dimensions_width", + "type": "float", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "dimensions_height": { + "name": "dimensions_height", + "type": "float", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "dimensions_thickness": { + "name": "dimensions_thickness", + "type": "float", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "weight_grams": { + "name": "weight_grams", + "type": "float", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_size_inches": { + "name": "display_size_inches", + "type": "float", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_size_ratio": { + "name": "display_size_ratio", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_res_width": { + "name": "display_res_width", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_res_height": { + "name": "display_res_height", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_res_ppi": { + "name": "display_res_ppi", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "released": { + "name": "released", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "meta": { + "name": "meta", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "company_id": { + "name": "company_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": { + "models_maker_id_makers_id_fk": { + "name": "models_maker_id_makers_id_fk", + "tableFrom": "models", + "tableTo": "makers", + "columnsFrom": ["maker_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "models_category_id_categories_id_fk": { + "name": "models_category_id_categories_id_fk", + "tableFrom": "models", + "tableTo": "categories", + "columnsFrom": ["category_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "models_company_id_companies_id_fk": { + "name": "models_company_id_companies_id_fk", + "tableFrom": "models", + "tableTo": "companies", + "columnsFrom": ["company_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "models_id": { + "name": "models_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "slug_company_unique": { + "name": "slug_company_unique", + "columns": ["slug", "company_id"] + } + }, + "checkConstraint": {} + }, + "one_time_tokens": { + "name": "one_time_tokens", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "ott_type": { + "name": "ott_type", + "type": "enum('confirmation','password_reset','account_deletion')", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "relates_to": { + "name": "relates_to", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "one_time_tokens_user_id_users_id_fk": { + "name": "one_time_tokens_user_id_users_id_fk", + "tableFrom": "one_time_tokens", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "one_time_tokens_id": { + "name": "one_time_tokens_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "one_time_tokens_token_unique": { + "name": "one_time_tokens_token_unique", + "columns": ["token"] + } + }, + "checkConstraint": {} + }, + "refresh_tokens": { + "name": "refresh_tokens", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "refresh_tokens_user_id_users_id_fk": { + "name": "refresh_tokens_user_id_users_id_fk", + "tableFrom": "refresh_tokens", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "refresh_tokens_id": { + "name": "refresh_tokens_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "refresh_tokens_token_unique": { + "name": "refresh_tokens_token_unique", + "columns": ["token"] + } + }, + "checkConstraint": {} + }, + "users": { + "name": "users", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "password_hash": { + "name": "password_hash", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "google_id": { + "name": "google_id", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "avatar_url": { + "name": "avatar_url", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "verified": { + "name": "verified", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "users_id": { + "name": "users_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "users_email_unique": { + "name": "users_email_unique", + "columns": ["email"] + }, + "users_google_id_unique": { + "name": "users_google_id_unique", + "columns": ["google_id"] + } + }, + "checkConstraint": {} + } + }, + "views": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "tables": {}, + "indexes": {} + } +} diff --git a/packages/db/drizzle/meta/_journal.json b/packages/db/drizzle/meta/_journal.json index bee8bc9..4ca78c0 100644 --- a/packages/db/drizzle/meta/_journal.json +++ b/packages/db/drizzle/meta/_journal.json @@ -50,6 +50,20 @@ "when": 1779887155497, "tag": "0006_curved_doctor_octopus", "breakpoints": true + }, + { + "idx": 7, + "version": "5", + "when": 1779888252559, + "tag": "0007_powerful_mulholland_black", + "breakpoints": true + }, + { + "idx": 8, + "version": "5", + "when": 1779888404608, + "tag": "0008_dear_karnak", + "breakpoints": true } ] } diff --git a/packages/db/package.json b/packages/db/package.json index 1bf2c94..72ce746 100644 --- a/packages/db/package.json +++ b/packages/db/package.json @@ -7,7 +7,8 @@ "db:push": "bunx --bun drizzle-kit push", "db:generate": "bunx --bun drizzle-kit generate", "db:studio": "bunx --bun drizzle-kit studio", - "db:migrate": "bunx --bun tsx src/migrate.ts", + "db:migrate": "tsx src/migrate.ts", + "db:seed": "bun src/seed.ts", "db:start": "docker compose up -d", "db:watch": "docker compose up", "db:stop": "docker compose stop", diff --git a/packages/db/src/schema/models.ts b/packages/db/src/schema/models.ts index 6cca532..087c7c6 100644 --- a/packages/db/src/schema/models.ts +++ b/packages/db/src/schema/models.ts @@ -33,46 +33,46 @@ export const models = mysqlTable( () => categories.id ), - announced: varchar("announced", { length: 100 }), - status: varchar("status", { length: 100 }), - dimensions: varchar("dimensions", { length: 255 }), - weight: varchar("weight", { length: 100 }), - build: varchar("build", { length: 255 }), - sim: varchar("sim", { length: 100 }), - displayType: varchar("display_type", { length: 255 }), - displaySize: varchar("display_size", { length: 100 }), - displayResolution: varchar("display_resolution", { length: 100 }), - displayProtection: varchar("display_protection", { length: 100 }), - os: varchar("os", { length: 255 }), - chipset: varchar("chipset", { length: 255 }), - cpu: varchar("cpu", { length: 255 }), - gpu: varchar("gpu", { length: 255 }), - cardSlot: varchar("card_slot", { length: 255 }), - internalMemory: varchar("internal_memory", { length: 255 }), - mainCamera: varchar("main_camera", { length: 255 }), + announced: text("announced"), + status: text("status"), + dimensions: text("dimensions"), + weight: text("weight"), + build: text("build"), + sim: text("sim"), + displayType: text("display_type"), + displaySize: text("display_size"), + displayResolution: text("display_resolution"), + displayProtection: text("display_protection"), + os: text("os"), + chipset: text("chipset"), + cpu: text("cpu"), + gpu: text("gpu"), + cardSlot: text("card_slot"), + internalMemory: text("internal_memory"), + mainCamera: text("main_camera"), mainCameraFeatures: text("main_camera_features"), - mainCameraVideo: varchar("main_camera_video", { length: 255 }), - selfieCamera: varchar("selfie_camera", { length: 255 }), + mainCameraVideo: text("main_camera_video"), + selfieCamera: text("selfie_camera"), selfieFeatures: text("selfie_features"), - selfieVideo: varchar("selfie_video", { length: 255 }), - battery: varchar("battery", { length: 255 }), - batteryCharging: varchar("battery_charging", { length: 255 }), - networkTech: varchar("network_tech", { length: 255 }), - sensors: varchar("sensors", { length: 255 }), - colors: varchar("colors", { length: 255 }), + selfieVideo: text("selfie_video"), + battery: text("battery"), + batteryCharging: text("battery_charging"), + networkTech: text("network_tech"), + sensors: text("sensors"), + colors: text("colors"), colorsHex: text("colors_hex"), - modelsText: varchar("models_text", { length: 255 }), - price: varchar("price", { length: 100 }), + modelsText: text("models_text"), + price: text("price"), dimensionsWidth: float("dimensions_width"), dimensionsHeight: float("dimensions_height"), dimensionsThickness: float("dimensions_thickness"), weightGrams: float("weight_grams"), displaySizeInches: float("display_size_inches"), - displaySizeRatio: varchar("display_size_ratio", { length: 100 }), + displaySizeRatio: text("display_size_ratio"), displayResWidth: int("display_res_width"), displayResHeight: int("display_res_height"), displayResPpi: int("display_res_ppi"), - released: varchar("released", { length: 100 }), + released: text("released"), meta: text("meta"), diff --git a/packages/db/tsconfig.json b/packages/db/tsconfig.json index 314d12f..8ee2d72 100644 --- a/packages/db/tsconfig.json +++ b/packages/db/tsconfig.json @@ -10,5 +10,5 @@ "esModuleInterop": true }, "include": ["src/**/*"], - "exclude": ["node_modules", "dist"] + "exclude": ["node_modules", "dist", "src/sqlites/sqlite-db"] } From d64af4e43464a4e8ae67e94421d47c4c42115ee3 Mon Sep 17 00:00:00 2001 From: Ricardo Amorim <102877738+risixdzn@users.noreply.github.com> Date: Wed, 27 May 2026 14:14:16 -0300 Subject: [PATCH 3/9] chore(DB): Fix hanging migrations + table names --- .../db/drizzle/0006_curved_doctor_octopus.sql | 93 -- .../0007_powerful_mulholland_black.sql | 10 - packages/db/drizzle/0008_dear_karnak.sql | 29 - packages/db/drizzle/meta/0006_snapshot.json | 1077 ----------------- packages/db/drizzle/meta/0007_snapshot.json | 1077 ----------------- packages/db/drizzle/meta/0008_snapshot.json | 1077 ----------------- packages/db/drizzle/meta/_journal.json | 21 - packages/db/src/schema/categories.ts | 15 - packages/db/src/schema/index.ts | 1 - packages/db/src/schema/makers.ts | 22 - packages/db/src/schema/model-categories.ts | 8 +- packages/db/src/schema/model-makers.ts | 19 +- packages/db/src/schema/models.ts | 8 +- 13 files changed, 19 insertions(+), 3438 deletions(-) delete mode 100644 packages/db/drizzle/0006_curved_doctor_octopus.sql delete mode 100644 packages/db/drizzle/0007_powerful_mulholland_black.sql delete mode 100644 packages/db/drizzle/0008_dear_karnak.sql delete mode 100644 packages/db/drizzle/meta/0006_snapshot.json delete mode 100644 packages/db/drizzle/meta/0007_snapshot.json delete mode 100644 packages/db/drizzle/meta/0008_snapshot.json delete mode 100644 packages/db/src/schema/categories.ts delete mode 100644 packages/db/src/schema/makers.ts diff --git a/packages/db/drizzle/0006_curved_doctor_octopus.sql b/packages/db/drizzle/0006_curved_doctor_octopus.sql deleted file mode 100644 index 6333cb5..0000000 --- a/packages/db/drizzle/0006_curved_doctor_octopus.sql +++ /dev/null @@ -1,93 +0,0 @@ -CREATE TABLE `categories` ( - `id` varchar(25) NOT NULL, - `name` varchar(100) NOT NULL, - `slug` varchar(100) NOT NULL, - CONSTRAINT `categories_id` PRIMARY KEY(`id`), - CONSTRAINT `categories_slug_unique` UNIQUE(`slug`) -); ---> statement-breakpoint -CREATE TABLE `makers` ( - `id` varchar(25) NOT NULL, - `name` varchar(100) NOT NULL, - `slug` varchar(100) NOT NULL, - `url` varchar(255) NOT NULL, - `device_count` int NOT NULL DEFAULT 0, - `page_count` int, - `created_at` timestamp NOT NULL DEFAULT (now()), - CONSTRAINT `makers_id` PRIMARY KEY(`id`), - CONSTRAINT `makers_slug_unique` UNIQUE(`slug`) -); ---> statement-breakpoint -CREATE TABLE `model_images` ( - `id` varchar(25) NOT NULL, - `model_id` varchar(25) NOT NULL, - `original_url` varchar(255), - `r2_key` varchar(255), - `is_primary` boolean NOT NULL DEFAULT false, - `variant` varchar(50), - `position` int NOT NULL DEFAULT 0, - `created_at` timestamp NOT NULL DEFAULT (now()), - CONSTRAINT `model_images_id` PRIMARY KEY(`id`) -); ---> statement-breakpoint -CREATE TABLE `models` ( - `id` varchar(25) NOT NULL, - `maker_id` varchar(25) NOT NULL, - `name` varchar(255) NOT NULL, - `slug` varchar(100) NOT NULL, - `url` varchar(255) NOT NULL, - `image_url` varchar(255), - `image_local_path` varchar(255), - `category_id` varchar(25), - `announced` varchar(100), - `status` varchar(100), - `dimensions` varchar(255), - `weight` varchar(100), - `build` varchar(255), - `sim` varchar(100), - `display_type` varchar(255), - `display_size` varchar(100), - `display_resolution` varchar(100), - `display_protection` varchar(100), - `os` varchar(255), - `chipset` varchar(255), - `cpu` varchar(255), - `gpu` varchar(255), - `card_slot` varchar(255), - `internal_memory` varchar(255), - `main_camera` varchar(255), - `main_camera_features` text, - `main_camera_video` varchar(255), - `selfie_camera` varchar(255), - `selfie_features` text, - `selfie_video` varchar(255), - `battery` varchar(255), - `battery_charging` varchar(255), - `network_tech` varchar(255), - `sensors` varchar(255), - `colors` varchar(255), - `colors_hex` text, - `models_text` varchar(255), - `price` varchar(100), - `dimensions_width` float, - `dimensions_height` float, - `dimensions_thickness` float, - `weight_grams` float, - `display_size_inches` float, - `display_size_ratio` varchar(100), - `display_res_width` int, - `display_res_height` int, - `display_res_ppi` int, - `released` varchar(100), - `meta` text, - `company_id` varchar(25), - `created_at` timestamp NOT NULL DEFAULT (now()), - CONSTRAINT `models_id` PRIMARY KEY(`id`), - CONSTRAINT `slug_company_unique` UNIQUE(`slug`,`company_id`) -); ---> statement-breakpoint -ALTER TABLE `employees` MODIFY COLUMN `roles` enum('guest','technician','warehouse','financial','manager','admin') NOT NULL;--> statement-breakpoint -ALTER TABLE `model_images` ADD CONSTRAINT `model_images_model_id_models_id_fk` FOREIGN KEY (`model_id`) REFERENCES `models`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint -ALTER TABLE `models` ADD CONSTRAINT `models_maker_id_makers_id_fk` FOREIGN KEY (`maker_id`) REFERENCES `makers`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint -ALTER TABLE `models` ADD CONSTRAINT `models_category_id_categories_id_fk` FOREIGN KEY (`category_id`) REFERENCES `categories`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint -ALTER TABLE `models` ADD CONSTRAINT `models_company_id_companies_id_fk` FOREIGN KEY (`company_id`) REFERENCES `companies`(`id`) ON DELETE no action ON UPDATE no action; \ No newline at end of file diff --git a/packages/db/drizzle/0007_powerful_mulholland_black.sql b/packages/db/drizzle/0007_powerful_mulholland_black.sql deleted file mode 100644 index c24da9f..0000000 --- a/packages/db/drizzle/0007_powerful_mulholland_black.sql +++ /dev/null @@ -1,10 +0,0 @@ -ALTER TABLE `models` MODIFY COLUMN `announced` varchar(255);--> statement-breakpoint -ALTER TABLE `models` MODIFY COLUMN `status` varchar(255);--> statement-breakpoint -ALTER TABLE `models` MODIFY COLUMN `weight` varchar(255);--> statement-breakpoint -ALTER TABLE `models` MODIFY COLUMN `sim` varchar(255);--> statement-breakpoint -ALTER TABLE `models` MODIFY COLUMN `display_size` varchar(255);--> statement-breakpoint -ALTER TABLE `models` MODIFY COLUMN `display_resolution` varchar(255);--> statement-breakpoint -ALTER TABLE `models` MODIFY COLUMN `display_protection` varchar(255);--> statement-breakpoint -ALTER TABLE `models` MODIFY COLUMN `price` varchar(255);--> statement-breakpoint -ALTER TABLE `models` MODIFY COLUMN `display_size_ratio` varchar(255);--> statement-breakpoint -ALTER TABLE `models` MODIFY COLUMN `released` varchar(255); \ No newline at end of file diff --git a/packages/db/drizzle/0008_dear_karnak.sql b/packages/db/drizzle/0008_dear_karnak.sql deleted file mode 100644 index 207642b..0000000 --- a/packages/db/drizzle/0008_dear_karnak.sql +++ /dev/null @@ -1,29 +0,0 @@ -ALTER TABLE `models` MODIFY COLUMN `announced` text;--> statement-breakpoint -ALTER TABLE `models` MODIFY COLUMN `status` text;--> statement-breakpoint -ALTER TABLE `models` MODIFY COLUMN `dimensions` text;--> statement-breakpoint -ALTER TABLE `models` MODIFY COLUMN `weight` text;--> statement-breakpoint -ALTER TABLE `models` MODIFY COLUMN `build` text;--> statement-breakpoint -ALTER TABLE `models` MODIFY COLUMN `sim` text;--> statement-breakpoint -ALTER TABLE `models` MODIFY COLUMN `display_type` text;--> statement-breakpoint -ALTER TABLE `models` MODIFY COLUMN `display_size` text;--> statement-breakpoint -ALTER TABLE `models` MODIFY COLUMN `display_resolution` text;--> statement-breakpoint -ALTER TABLE `models` MODIFY COLUMN `display_protection` text;--> statement-breakpoint -ALTER TABLE `models` MODIFY COLUMN `os` text;--> statement-breakpoint -ALTER TABLE `models` MODIFY COLUMN `chipset` text;--> statement-breakpoint -ALTER TABLE `models` MODIFY COLUMN `cpu` text;--> statement-breakpoint -ALTER TABLE `models` MODIFY COLUMN `gpu` text;--> statement-breakpoint -ALTER TABLE `models` MODIFY COLUMN `card_slot` text;--> statement-breakpoint -ALTER TABLE `models` MODIFY COLUMN `internal_memory` text;--> statement-breakpoint -ALTER TABLE `models` MODIFY COLUMN `main_camera` text;--> statement-breakpoint -ALTER TABLE `models` MODIFY COLUMN `main_camera_video` text;--> statement-breakpoint -ALTER TABLE `models` MODIFY COLUMN `selfie_camera` text;--> statement-breakpoint -ALTER TABLE `models` MODIFY COLUMN `selfie_video` text;--> statement-breakpoint -ALTER TABLE `models` MODIFY COLUMN `battery` text;--> statement-breakpoint -ALTER TABLE `models` MODIFY COLUMN `battery_charging` text;--> statement-breakpoint -ALTER TABLE `models` MODIFY COLUMN `network_tech` text;--> statement-breakpoint -ALTER TABLE `models` MODIFY COLUMN `sensors` text;--> statement-breakpoint -ALTER TABLE `models` MODIFY COLUMN `colors` text;--> statement-breakpoint -ALTER TABLE `models` MODIFY COLUMN `models_text` text;--> statement-breakpoint -ALTER TABLE `models` MODIFY COLUMN `price` text;--> statement-breakpoint -ALTER TABLE `models` MODIFY COLUMN `display_size_ratio` text;--> statement-breakpoint -ALTER TABLE `models` MODIFY COLUMN `released` text; \ No newline at end of file diff --git a/packages/db/drizzle/meta/0006_snapshot.json b/packages/db/drizzle/meta/0006_snapshot.json deleted file mode 100644 index 22338db..0000000 --- a/packages/db/drizzle/meta/0006_snapshot.json +++ /dev/null @@ -1,1077 +0,0 @@ -{ - "version": "5", - "dialect": "mysql", - "id": "469411a6-c473-42e2-89d1-da5d3e144652", - "prevId": "96fef0d8-3c1e-4d2f-990d-625797fa1861", - "tables": { - "categories": { - "name": "categories", - "columns": { - "id": { - "name": "id", - "type": "varchar(25)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(100)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(100)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "categories_id": { - "name": "categories_id", - "columns": ["id"] - } - }, - "uniqueConstraints": { - "categories_slug_unique": { - "name": "categories_slug_unique", - "columns": ["slug"] - } - }, - "checkConstraint": {} - }, - "clients": { - "name": "clients", - "columns": { - "id": { - "name": "id", - "type": "varchar(25)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(100)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "cpf": { - "name": "cpf", - "type": "varchar(11)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "phone": { - "name": "phone", - "type": "varchar(11)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "user_id": { - "name": "user_id", - "type": "varchar(25)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": { - "clients_user_id_users_id_fk": { - "name": "clients_user_id_users_id_fk", - "tableFrom": "clients", - "tableTo": "users", - "columnsFrom": ["user_id"], - "columnsTo": ["id"], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "clients_id": { - "name": "clients_id", - "columns": ["id"] - } - }, - "uniqueConstraints": { - "clients_cpf_unique": { - "name": "clients_cpf_unique", - "columns": ["cpf"] - } - }, - "checkConstraint": {} - }, - "companies": { - "name": "companies", - "columns": { - "id": { - "name": "id", - "type": "varchar(25)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(100)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "cnpj": { - "name": "cnpj", - "type": "varchar(14)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "address": { - "name": "address", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "subdomain": { - "name": "subdomain", - "type": "varchar(32)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "companies_id": { - "name": "companies_id", - "columns": ["id"] - } - }, - "uniqueConstraints": { - "companies_cnpj_unique": { - "name": "companies_cnpj_unique", - "columns": ["cnpj"] - }, - "companies_subdomain_unique": { - "name": "companies_subdomain_unique", - "columns": ["subdomain"] - } - }, - "checkConstraint": {} - }, - "employees": { - "name": "employees", - "columns": { - "id": { - "name": "id", - "type": "varchar(25)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(100)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "cpf": { - "name": "cpf", - "type": "varchar(11)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "phone": { - "name": "phone", - "type": "varchar(11)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "roles": { - "name": "roles", - "type": "enum('guest','technician','warehouse','financial','manager','admin')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "user_id": { - "name": "user_id", - "type": "varchar(25)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "company_id": { - "name": "company_id", - "type": "varchar(25)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": { - "employees_user_id_users_id_fk": { - "name": "employees_user_id_users_id_fk", - "tableFrom": "employees", - "tableTo": "users", - "columnsFrom": ["user_id"], - "columnsTo": ["id"], - "onDelete": "no action", - "onUpdate": "no action" - }, - "employees_company_id_companies_id_fk": { - "name": "employees_company_id_companies_id_fk", - "tableFrom": "employees", - "tableTo": "companies", - "columnsFrom": ["company_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "employees_id": { - "name": "employees_id", - "columns": ["id"] - } - }, - "uniqueConstraints": { - "employees_cpf_unique": { - "name": "employees_cpf_unique", - "columns": ["cpf"] - } - }, - "checkConstraint": {} - }, - "makers": { - "name": "makers", - "columns": { - "id": { - "name": "id", - "type": "varchar(25)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(100)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(100)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "url": { - "name": "url", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "device_count": { - "name": "device_count", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": 0 - }, - "page_count": { - "name": "page_count", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "makers_id": { - "name": "makers_id", - "columns": ["id"] - } - }, - "uniqueConstraints": { - "makers_slug_unique": { - "name": "makers_slug_unique", - "columns": ["slug"] - } - }, - "checkConstraint": {} - }, - "model_images": { - "name": "model_images", - "columns": { - "id": { - "name": "id", - "type": "varchar(25)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "model_id": { - "name": "model_id", - "type": "varchar(25)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "original_url": { - "name": "original_url", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "r2_key": { - "name": "r2_key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "is_primary": { - "name": "is_primary", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": false - }, - "variant": { - "name": "variant", - "type": "varchar(50)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "position": { - "name": "position", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": 0 - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - } - }, - "indexes": {}, - "foreignKeys": { - "model_images_model_id_models_id_fk": { - "name": "model_images_model_id_models_id_fk", - "tableFrom": "model_images", - "tableTo": "models", - "columnsFrom": ["model_id"], - "columnsTo": ["id"], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "model_images_id": { - "name": "model_images_id", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "models": { - "name": "models", - "columns": { - "id": { - "name": "id", - "type": "varchar(25)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "maker_id": { - "name": "maker_id", - "type": "varchar(25)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(100)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "url": { - "name": "url", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "image_url": { - "name": "image_url", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "image_local_path": { - "name": "image_local_path", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "category_id": { - "name": "category_id", - "type": "varchar(25)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "announced": { - "name": "announced", - "type": "varchar(100)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "status": { - "name": "status", - "type": "varchar(100)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "dimensions": { - "name": "dimensions", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "weight": { - "name": "weight", - "type": "varchar(100)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "build": { - "name": "build", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "sim": { - "name": "sim", - "type": "varchar(100)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "display_type": { - "name": "display_type", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "display_size": { - "name": "display_size", - "type": "varchar(100)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "display_resolution": { - "name": "display_resolution", - "type": "varchar(100)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "display_protection": { - "name": "display_protection", - "type": "varchar(100)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "os": { - "name": "os", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "chipset": { - "name": "chipset", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cpu": { - "name": "cpu", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "gpu": { - "name": "gpu", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "card_slot": { - "name": "card_slot", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "internal_memory": { - "name": "internal_memory", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "main_camera": { - "name": "main_camera", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "main_camera_features": { - "name": "main_camera_features", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "main_camera_video": { - "name": "main_camera_video", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "selfie_camera": { - "name": "selfie_camera", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "selfie_features": { - "name": "selfie_features", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "selfie_video": { - "name": "selfie_video", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "battery": { - "name": "battery", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "battery_charging": { - "name": "battery_charging", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "network_tech": { - "name": "network_tech", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "sensors": { - "name": "sensors", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "colors": { - "name": "colors", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "colors_hex": { - "name": "colors_hex", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "models_text": { - "name": "models_text", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "price": { - "name": "price", - "type": "varchar(100)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "dimensions_width": { - "name": "dimensions_width", - "type": "float", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "dimensions_height": { - "name": "dimensions_height", - "type": "float", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "dimensions_thickness": { - "name": "dimensions_thickness", - "type": "float", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "weight_grams": { - "name": "weight_grams", - "type": "float", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "display_size_inches": { - "name": "display_size_inches", - "type": "float", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "display_size_ratio": { - "name": "display_size_ratio", - "type": "varchar(100)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "display_res_width": { - "name": "display_res_width", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "display_res_height": { - "name": "display_res_height", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "display_res_ppi": { - "name": "display_res_ppi", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "released": { - "name": "released", - "type": "varchar(100)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "meta": { - "name": "meta", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "company_id": { - "name": "company_id", - "type": "varchar(25)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - } - }, - "indexes": {}, - "foreignKeys": { - "models_maker_id_makers_id_fk": { - "name": "models_maker_id_makers_id_fk", - "tableFrom": "models", - "tableTo": "makers", - "columnsFrom": ["maker_id"], - "columnsTo": ["id"], - "onDelete": "no action", - "onUpdate": "no action" - }, - "models_category_id_categories_id_fk": { - "name": "models_category_id_categories_id_fk", - "tableFrom": "models", - "tableTo": "categories", - "columnsFrom": ["category_id"], - "columnsTo": ["id"], - "onDelete": "no action", - "onUpdate": "no action" - }, - "models_company_id_companies_id_fk": { - "name": "models_company_id_companies_id_fk", - "tableFrom": "models", - "tableTo": "companies", - "columnsFrom": ["company_id"], - "columnsTo": ["id"], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "models_id": { - "name": "models_id", - "columns": ["id"] - } - }, - "uniqueConstraints": { - "slug_company_unique": { - "name": "slug_company_unique", - "columns": ["slug", "company_id"] - } - }, - "checkConstraint": {} - }, - "one_time_tokens": { - "name": "one_time_tokens", - "columns": { - "id": { - "name": "id", - "type": "varchar(25)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "token": { - "name": "token", - "type": "varchar(128)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "ott_type": { - "name": "ott_type", - "type": "enum('confirmation','password_reset','account_deletion')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "relates_to": { - "name": "relates_to", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "varchar(25)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "expires_at": { - "name": "expires_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": { - "one_time_tokens_user_id_users_id_fk": { - "name": "one_time_tokens_user_id_users_id_fk", - "tableFrom": "one_time_tokens", - "tableTo": "users", - "columnsFrom": ["user_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "one_time_tokens_id": { - "name": "one_time_tokens_id", - "columns": ["id"] - } - }, - "uniqueConstraints": { - "one_time_tokens_token_unique": { - "name": "one_time_tokens_token_unique", - "columns": ["token"] - } - }, - "checkConstraint": {} - }, - "refresh_tokens": { - "name": "refresh_tokens", - "columns": { - "id": { - "name": "id", - "type": "varchar(25)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "token": { - "name": "token", - "type": "varchar(128)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "varchar(25)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "expires_at": { - "name": "expires_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": { - "refresh_tokens_user_id_users_id_fk": { - "name": "refresh_tokens_user_id_users_id_fk", - "tableFrom": "refresh_tokens", - "tableTo": "users", - "columnsFrom": ["user_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "refresh_tokens_id": { - "name": "refresh_tokens_id", - "columns": ["id"] - } - }, - "uniqueConstraints": { - "refresh_tokens_token_unique": { - "name": "refresh_tokens_token_unique", - "columns": ["token"] - } - }, - "checkConstraint": {} - }, - "users": { - "name": "users", - "columns": { - "id": { - "name": "id", - "type": "varchar(25)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "password_hash": { - "name": "password_hash", - "type": "varchar(128)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "google_id": { - "name": "google_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "avatar_url": { - "name": "avatar_url", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "verified": { - "name": "verified", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "users_id": { - "name": "users_id", - "columns": ["id"] - } - }, - "uniqueConstraints": { - "users_email_unique": { - "name": "users_email_unique", - "columns": ["email"] - }, - "users_google_id_unique": { - "name": "users_google_id_unique", - "columns": ["google_id"] - } - }, - "checkConstraint": {} - } - }, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "tables": {}, - "indexes": {} - } -} diff --git a/packages/db/drizzle/meta/0007_snapshot.json b/packages/db/drizzle/meta/0007_snapshot.json deleted file mode 100644 index 7418b2a..0000000 --- a/packages/db/drizzle/meta/0007_snapshot.json +++ /dev/null @@ -1,1077 +0,0 @@ -{ - "version": "5", - "dialect": "mysql", - "id": "46d97f25-6199-4c7a-ab20-1a0f9cb032f3", - "prevId": "469411a6-c473-42e2-89d1-da5d3e144652", - "tables": { - "categories": { - "name": "categories", - "columns": { - "id": { - "name": "id", - "type": "varchar(25)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(100)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(100)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "categories_id": { - "name": "categories_id", - "columns": ["id"] - } - }, - "uniqueConstraints": { - "categories_slug_unique": { - "name": "categories_slug_unique", - "columns": ["slug"] - } - }, - "checkConstraint": {} - }, - "clients": { - "name": "clients", - "columns": { - "id": { - "name": "id", - "type": "varchar(25)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(100)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "cpf": { - "name": "cpf", - "type": "varchar(11)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "phone": { - "name": "phone", - "type": "varchar(11)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "user_id": { - "name": "user_id", - "type": "varchar(25)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": { - "clients_user_id_users_id_fk": { - "name": "clients_user_id_users_id_fk", - "tableFrom": "clients", - "tableTo": "users", - "columnsFrom": ["user_id"], - "columnsTo": ["id"], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "clients_id": { - "name": "clients_id", - "columns": ["id"] - } - }, - "uniqueConstraints": { - "clients_cpf_unique": { - "name": "clients_cpf_unique", - "columns": ["cpf"] - } - }, - "checkConstraint": {} - }, - "companies": { - "name": "companies", - "columns": { - "id": { - "name": "id", - "type": "varchar(25)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(100)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "cnpj": { - "name": "cnpj", - "type": "varchar(14)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "address": { - "name": "address", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "subdomain": { - "name": "subdomain", - "type": "varchar(32)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "companies_id": { - "name": "companies_id", - "columns": ["id"] - } - }, - "uniqueConstraints": { - "companies_cnpj_unique": { - "name": "companies_cnpj_unique", - "columns": ["cnpj"] - }, - "companies_subdomain_unique": { - "name": "companies_subdomain_unique", - "columns": ["subdomain"] - } - }, - "checkConstraint": {} - }, - "employees": { - "name": "employees", - "columns": { - "id": { - "name": "id", - "type": "varchar(25)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(100)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "cpf": { - "name": "cpf", - "type": "varchar(11)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "phone": { - "name": "phone", - "type": "varchar(11)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "roles": { - "name": "roles", - "type": "enum('guest','technician','warehouse','financial','manager','admin')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "user_id": { - "name": "user_id", - "type": "varchar(25)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "company_id": { - "name": "company_id", - "type": "varchar(25)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": { - "employees_user_id_users_id_fk": { - "name": "employees_user_id_users_id_fk", - "tableFrom": "employees", - "tableTo": "users", - "columnsFrom": ["user_id"], - "columnsTo": ["id"], - "onDelete": "no action", - "onUpdate": "no action" - }, - "employees_company_id_companies_id_fk": { - "name": "employees_company_id_companies_id_fk", - "tableFrom": "employees", - "tableTo": "companies", - "columnsFrom": ["company_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "employees_id": { - "name": "employees_id", - "columns": ["id"] - } - }, - "uniqueConstraints": { - "employees_cpf_unique": { - "name": "employees_cpf_unique", - "columns": ["cpf"] - } - }, - "checkConstraint": {} - }, - "makers": { - "name": "makers", - "columns": { - "id": { - "name": "id", - "type": "varchar(25)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(100)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(100)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "url": { - "name": "url", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "device_count": { - "name": "device_count", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": 0 - }, - "page_count": { - "name": "page_count", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "makers_id": { - "name": "makers_id", - "columns": ["id"] - } - }, - "uniqueConstraints": { - "makers_slug_unique": { - "name": "makers_slug_unique", - "columns": ["slug"] - } - }, - "checkConstraint": {} - }, - "model_images": { - "name": "model_images", - "columns": { - "id": { - "name": "id", - "type": "varchar(25)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "model_id": { - "name": "model_id", - "type": "varchar(25)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "original_url": { - "name": "original_url", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "r2_key": { - "name": "r2_key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "is_primary": { - "name": "is_primary", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": false - }, - "variant": { - "name": "variant", - "type": "varchar(50)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "position": { - "name": "position", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": 0 - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - } - }, - "indexes": {}, - "foreignKeys": { - "model_images_model_id_models_id_fk": { - "name": "model_images_model_id_models_id_fk", - "tableFrom": "model_images", - "tableTo": "models", - "columnsFrom": ["model_id"], - "columnsTo": ["id"], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "model_images_id": { - "name": "model_images_id", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "models": { - "name": "models", - "columns": { - "id": { - "name": "id", - "type": "varchar(25)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "maker_id": { - "name": "maker_id", - "type": "varchar(25)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(100)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "url": { - "name": "url", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "image_url": { - "name": "image_url", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "image_local_path": { - "name": "image_local_path", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "category_id": { - "name": "category_id", - "type": "varchar(25)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "announced": { - "name": "announced", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "status": { - "name": "status", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "dimensions": { - "name": "dimensions", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "weight": { - "name": "weight", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "build": { - "name": "build", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "sim": { - "name": "sim", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "display_type": { - "name": "display_type", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "display_size": { - "name": "display_size", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "display_resolution": { - "name": "display_resolution", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "display_protection": { - "name": "display_protection", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "os": { - "name": "os", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "chipset": { - "name": "chipset", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cpu": { - "name": "cpu", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "gpu": { - "name": "gpu", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "card_slot": { - "name": "card_slot", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "internal_memory": { - "name": "internal_memory", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "main_camera": { - "name": "main_camera", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "main_camera_features": { - "name": "main_camera_features", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "main_camera_video": { - "name": "main_camera_video", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "selfie_camera": { - "name": "selfie_camera", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "selfie_features": { - "name": "selfie_features", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "selfie_video": { - "name": "selfie_video", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "battery": { - "name": "battery", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "battery_charging": { - "name": "battery_charging", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "network_tech": { - "name": "network_tech", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "sensors": { - "name": "sensors", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "colors": { - "name": "colors", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "colors_hex": { - "name": "colors_hex", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "models_text": { - "name": "models_text", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "price": { - "name": "price", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "dimensions_width": { - "name": "dimensions_width", - "type": "float", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "dimensions_height": { - "name": "dimensions_height", - "type": "float", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "dimensions_thickness": { - "name": "dimensions_thickness", - "type": "float", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "weight_grams": { - "name": "weight_grams", - "type": "float", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "display_size_inches": { - "name": "display_size_inches", - "type": "float", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "display_size_ratio": { - "name": "display_size_ratio", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "display_res_width": { - "name": "display_res_width", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "display_res_height": { - "name": "display_res_height", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "display_res_ppi": { - "name": "display_res_ppi", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "released": { - "name": "released", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "meta": { - "name": "meta", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "company_id": { - "name": "company_id", - "type": "varchar(25)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - } - }, - "indexes": {}, - "foreignKeys": { - "models_maker_id_makers_id_fk": { - "name": "models_maker_id_makers_id_fk", - "tableFrom": "models", - "tableTo": "makers", - "columnsFrom": ["maker_id"], - "columnsTo": ["id"], - "onDelete": "no action", - "onUpdate": "no action" - }, - "models_category_id_categories_id_fk": { - "name": "models_category_id_categories_id_fk", - "tableFrom": "models", - "tableTo": "categories", - "columnsFrom": ["category_id"], - "columnsTo": ["id"], - "onDelete": "no action", - "onUpdate": "no action" - }, - "models_company_id_companies_id_fk": { - "name": "models_company_id_companies_id_fk", - "tableFrom": "models", - "tableTo": "companies", - "columnsFrom": ["company_id"], - "columnsTo": ["id"], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "models_id": { - "name": "models_id", - "columns": ["id"] - } - }, - "uniqueConstraints": { - "slug_company_unique": { - "name": "slug_company_unique", - "columns": ["slug", "company_id"] - } - }, - "checkConstraint": {} - }, - "one_time_tokens": { - "name": "one_time_tokens", - "columns": { - "id": { - "name": "id", - "type": "varchar(25)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "token": { - "name": "token", - "type": "varchar(128)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "ott_type": { - "name": "ott_type", - "type": "enum('confirmation','password_reset','account_deletion')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "relates_to": { - "name": "relates_to", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "varchar(25)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "expires_at": { - "name": "expires_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": { - "one_time_tokens_user_id_users_id_fk": { - "name": "one_time_tokens_user_id_users_id_fk", - "tableFrom": "one_time_tokens", - "tableTo": "users", - "columnsFrom": ["user_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "one_time_tokens_id": { - "name": "one_time_tokens_id", - "columns": ["id"] - } - }, - "uniqueConstraints": { - "one_time_tokens_token_unique": { - "name": "one_time_tokens_token_unique", - "columns": ["token"] - } - }, - "checkConstraint": {} - }, - "refresh_tokens": { - "name": "refresh_tokens", - "columns": { - "id": { - "name": "id", - "type": "varchar(25)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "token": { - "name": "token", - "type": "varchar(128)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "varchar(25)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "expires_at": { - "name": "expires_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": { - "refresh_tokens_user_id_users_id_fk": { - "name": "refresh_tokens_user_id_users_id_fk", - "tableFrom": "refresh_tokens", - "tableTo": "users", - "columnsFrom": ["user_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "refresh_tokens_id": { - "name": "refresh_tokens_id", - "columns": ["id"] - } - }, - "uniqueConstraints": { - "refresh_tokens_token_unique": { - "name": "refresh_tokens_token_unique", - "columns": ["token"] - } - }, - "checkConstraint": {} - }, - "users": { - "name": "users", - "columns": { - "id": { - "name": "id", - "type": "varchar(25)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "password_hash": { - "name": "password_hash", - "type": "varchar(128)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "google_id": { - "name": "google_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "avatar_url": { - "name": "avatar_url", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "verified": { - "name": "verified", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "users_id": { - "name": "users_id", - "columns": ["id"] - } - }, - "uniqueConstraints": { - "users_email_unique": { - "name": "users_email_unique", - "columns": ["email"] - }, - "users_google_id_unique": { - "name": "users_google_id_unique", - "columns": ["google_id"] - } - }, - "checkConstraint": {} - } - }, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "tables": {}, - "indexes": {} - } -} diff --git a/packages/db/drizzle/meta/0008_snapshot.json b/packages/db/drizzle/meta/0008_snapshot.json deleted file mode 100644 index 95d4b19..0000000 --- a/packages/db/drizzle/meta/0008_snapshot.json +++ /dev/null @@ -1,1077 +0,0 @@ -{ - "version": "5", - "dialect": "mysql", - "id": "c6166889-3f02-4a1b-8963-5bd45d4efba5", - "prevId": "46d97f25-6199-4c7a-ab20-1a0f9cb032f3", - "tables": { - "categories": { - "name": "categories", - "columns": { - "id": { - "name": "id", - "type": "varchar(25)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(100)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(100)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "categories_id": { - "name": "categories_id", - "columns": ["id"] - } - }, - "uniqueConstraints": { - "categories_slug_unique": { - "name": "categories_slug_unique", - "columns": ["slug"] - } - }, - "checkConstraint": {} - }, - "clients": { - "name": "clients", - "columns": { - "id": { - "name": "id", - "type": "varchar(25)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(100)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "cpf": { - "name": "cpf", - "type": "varchar(11)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "phone": { - "name": "phone", - "type": "varchar(11)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "user_id": { - "name": "user_id", - "type": "varchar(25)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": { - "clients_user_id_users_id_fk": { - "name": "clients_user_id_users_id_fk", - "tableFrom": "clients", - "tableTo": "users", - "columnsFrom": ["user_id"], - "columnsTo": ["id"], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "clients_id": { - "name": "clients_id", - "columns": ["id"] - } - }, - "uniqueConstraints": { - "clients_cpf_unique": { - "name": "clients_cpf_unique", - "columns": ["cpf"] - } - }, - "checkConstraint": {} - }, - "companies": { - "name": "companies", - "columns": { - "id": { - "name": "id", - "type": "varchar(25)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(100)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "cnpj": { - "name": "cnpj", - "type": "varchar(14)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "address": { - "name": "address", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "subdomain": { - "name": "subdomain", - "type": "varchar(32)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "companies_id": { - "name": "companies_id", - "columns": ["id"] - } - }, - "uniqueConstraints": { - "companies_cnpj_unique": { - "name": "companies_cnpj_unique", - "columns": ["cnpj"] - }, - "companies_subdomain_unique": { - "name": "companies_subdomain_unique", - "columns": ["subdomain"] - } - }, - "checkConstraint": {} - }, - "employees": { - "name": "employees", - "columns": { - "id": { - "name": "id", - "type": "varchar(25)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(100)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "cpf": { - "name": "cpf", - "type": "varchar(11)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "phone": { - "name": "phone", - "type": "varchar(11)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "roles": { - "name": "roles", - "type": "enum('guest','technician','warehouse','financial','manager','admin')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "user_id": { - "name": "user_id", - "type": "varchar(25)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "company_id": { - "name": "company_id", - "type": "varchar(25)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": { - "employees_user_id_users_id_fk": { - "name": "employees_user_id_users_id_fk", - "tableFrom": "employees", - "tableTo": "users", - "columnsFrom": ["user_id"], - "columnsTo": ["id"], - "onDelete": "no action", - "onUpdate": "no action" - }, - "employees_company_id_companies_id_fk": { - "name": "employees_company_id_companies_id_fk", - "tableFrom": "employees", - "tableTo": "companies", - "columnsFrom": ["company_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "employees_id": { - "name": "employees_id", - "columns": ["id"] - } - }, - "uniqueConstraints": { - "employees_cpf_unique": { - "name": "employees_cpf_unique", - "columns": ["cpf"] - } - }, - "checkConstraint": {} - }, - "makers": { - "name": "makers", - "columns": { - "id": { - "name": "id", - "type": "varchar(25)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(100)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(100)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "url": { - "name": "url", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "device_count": { - "name": "device_count", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": 0 - }, - "page_count": { - "name": "page_count", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "makers_id": { - "name": "makers_id", - "columns": ["id"] - } - }, - "uniqueConstraints": { - "makers_slug_unique": { - "name": "makers_slug_unique", - "columns": ["slug"] - } - }, - "checkConstraint": {} - }, - "model_images": { - "name": "model_images", - "columns": { - "id": { - "name": "id", - "type": "varchar(25)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "model_id": { - "name": "model_id", - "type": "varchar(25)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "original_url": { - "name": "original_url", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "r2_key": { - "name": "r2_key", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "is_primary": { - "name": "is_primary", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": false - }, - "variant": { - "name": "variant", - "type": "varchar(50)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "position": { - "name": "position", - "type": "int", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": 0 - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - } - }, - "indexes": {}, - "foreignKeys": { - "model_images_model_id_models_id_fk": { - "name": "model_images_model_id_models_id_fk", - "tableFrom": "model_images", - "tableTo": "models", - "columnsFrom": ["model_id"], - "columnsTo": ["id"], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "model_images_id": { - "name": "model_images_id", - "columns": ["id"] - } - }, - "uniqueConstraints": {}, - "checkConstraint": {} - }, - "models": { - "name": "models", - "columns": { - "id": { - "name": "id", - "type": "varchar(25)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "maker_id": { - "name": "maker_id", - "type": "varchar(25)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "slug": { - "name": "slug", - "type": "varchar(100)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "url": { - "name": "url", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "image_url": { - "name": "image_url", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "image_local_path": { - "name": "image_local_path", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "category_id": { - "name": "category_id", - "type": "varchar(25)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "announced": { - "name": "announced", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "status": { - "name": "status", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "dimensions": { - "name": "dimensions", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "weight": { - "name": "weight", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "build": { - "name": "build", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "sim": { - "name": "sim", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "display_type": { - "name": "display_type", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "display_size": { - "name": "display_size", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "display_resolution": { - "name": "display_resolution", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "display_protection": { - "name": "display_protection", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "os": { - "name": "os", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "chipset": { - "name": "chipset", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cpu": { - "name": "cpu", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "gpu": { - "name": "gpu", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "card_slot": { - "name": "card_slot", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "internal_memory": { - "name": "internal_memory", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "main_camera": { - "name": "main_camera", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "main_camera_features": { - "name": "main_camera_features", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "main_camera_video": { - "name": "main_camera_video", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "selfie_camera": { - "name": "selfie_camera", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "selfie_features": { - "name": "selfie_features", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "selfie_video": { - "name": "selfie_video", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "battery": { - "name": "battery", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "battery_charging": { - "name": "battery_charging", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "network_tech": { - "name": "network_tech", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "sensors": { - "name": "sensors", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "colors": { - "name": "colors", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "colors_hex": { - "name": "colors_hex", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "models_text": { - "name": "models_text", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "price": { - "name": "price", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "dimensions_width": { - "name": "dimensions_width", - "type": "float", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "dimensions_height": { - "name": "dimensions_height", - "type": "float", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "dimensions_thickness": { - "name": "dimensions_thickness", - "type": "float", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "weight_grams": { - "name": "weight_grams", - "type": "float", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "display_size_inches": { - "name": "display_size_inches", - "type": "float", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "display_size_ratio": { - "name": "display_size_ratio", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "display_res_width": { - "name": "display_res_width", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "display_res_height": { - "name": "display_res_height", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "display_res_ppi": { - "name": "display_res_ppi", - "type": "int", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "released": { - "name": "released", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "meta": { - "name": "meta", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "company_id": { - "name": "company_id", - "type": "varchar(25)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - } - }, - "indexes": {}, - "foreignKeys": { - "models_maker_id_makers_id_fk": { - "name": "models_maker_id_makers_id_fk", - "tableFrom": "models", - "tableTo": "makers", - "columnsFrom": ["maker_id"], - "columnsTo": ["id"], - "onDelete": "no action", - "onUpdate": "no action" - }, - "models_category_id_categories_id_fk": { - "name": "models_category_id_categories_id_fk", - "tableFrom": "models", - "tableTo": "categories", - "columnsFrom": ["category_id"], - "columnsTo": ["id"], - "onDelete": "no action", - "onUpdate": "no action" - }, - "models_company_id_companies_id_fk": { - "name": "models_company_id_companies_id_fk", - "tableFrom": "models", - "tableTo": "companies", - "columnsFrom": ["company_id"], - "columnsTo": ["id"], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "models_id": { - "name": "models_id", - "columns": ["id"] - } - }, - "uniqueConstraints": { - "slug_company_unique": { - "name": "slug_company_unique", - "columns": ["slug", "company_id"] - } - }, - "checkConstraint": {} - }, - "one_time_tokens": { - "name": "one_time_tokens", - "columns": { - "id": { - "name": "id", - "type": "varchar(25)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "token": { - "name": "token", - "type": "varchar(128)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "ott_type": { - "name": "ott_type", - "type": "enum('confirmation','password_reset','account_deletion')", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "relates_to": { - "name": "relates_to", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "varchar(25)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "expires_at": { - "name": "expires_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": { - "one_time_tokens_user_id_users_id_fk": { - "name": "one_time_tokens_user_id_users_id_fk", - "tableFrom": "one_time_tokens", - "tableTo": "users", - "columnsFrom": ["user_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "one_time_tokens_id": { - "name": "one_time_tokens_id", - "columns": ["id"] - } - }, - "uniqueConstraints": { - "one_time_tokens_token_unique": { - "name": "one_time_tokens_token_unique", - "columns": ["token"] - } - }, - "checkConstraint": {} - }, - "refresh_tokens": { - "name": "refresh_tokens", - "columns": { - "id": { - "name": "id", - "type": "varchar(25)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "token": { - "name": "token", - "type": "varchar(128)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "varchar(25)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "expires_at": { - "name": "expires_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": { - "refresh_tokens_user_id_users_id_fk": { - "name": "refresh_tokens_user_id_users_id_fk", - "tableFrom": "refresh_tokens", - "tableTo": "users", - "columnsFrom": ["user_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "refresh_tokens_id": { - "name": "refresh_tokens_id", - "columns": ["id"] - } - }, - "uniqueConstraints": { - "refresh_tokens_token_unique": { - "name": "refresh_tokens_token_unique", - "columns": ["token"] - } - }, - "checkConstraint": {} - }, - "users": { - "name": "users", - "columns": { - "id": { - "name": "id", - "type": "varchar(25)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "password_hash": { - "name": "password_hash", - "type": "varchar(128)", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "google_id": { - "name": "google_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "avatar_url": { - "name": "avatar_url", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(now())" - }, - "verified": { - "name": "verified", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "users_id": { - "name": "users_id", - "columns": ["id"] - } - }, - "uniqueConstraints": { - "users_email_unique": { - "name": "users_email_unique", - "columns": ["email"] - }, - "users_google_id_unique": { - "name": "users_google_id_unique", - "columns": ["google_id"] - } - }, - "checkConstraint": {} - } - }, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "tables": {}, - "indexes": {} - } -} diff --git a/packages/db/drizzle/meta/_journal.json b/packages/db/drizzle/meta/_journal.json index 4ca78c0..6e81e16 100644 --- a/packages/db/drizzle/meta/_journal.json +++ b/packages/db/drizzle/meta/_journal.json @@ -43,27 +43,6 @@ "when": 1760755210443, "tag": "0005_faulty_mandarin", "breakpoints": true - }, - { - "idx": 6, - "version": "5", - "when": 1779887155497, - "tag": "0006_curved_doctor_octopus", - "breakpoints": true - }, - { - "idx": 7, - "version": "5", - "when": 1779888252559, - "tag": "0007_powerful_mulholland_black", - "breakpoints": true - }, - { - "idx": 8, - "version": "5", - "when": 1779888404608, - "tag": "0008_dear_karnak", - "breakpoints": true } ] } diff --git a/packages/db/src/schema/categories.ts b/packages/db/src/schema/categories.ts deleted file mode 100644 index 49480d0..0000000 --- a/packages/db/src/schema/categories.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { createId } from "@paralleldrive/cuid2"; -import { mysqlTable, varchar } from "drizzle-orm/mysql-core"; -import { createSelectSchema } from "drizzle-zod"; - -export const categories = mysqlTable("categories", { - id: varchar("id", { length: 25 }) - .$defaultFn(() => createId()) - .primaryKey(), - name: varchar("name", { length: 100 }).notNull(), - slug: varchar("slug", { length: 100 }).unique().notNull(), -}); - -export const categorySelectSchema = createSelectSchema(categories); -export type CategoryInsert = typeof categories.$inferInsert; -export type CategorySelect = typeof categories.$inferSelect; diff --git a/packages/db/src/schema/index.ts b/packages/db/src/schema/index.ts index a3877c5..4cbaa08 100644 --- a/packages/db/src/schema/index.ts +++ b/packages/db/src/schema/index.ts @@ -1,4 +1,3 @@ -export * from "./categories"; export * from "./clients"; export * from "./companies"; export * from "./employees"; diff --git a/packages/db/src/schema/makers.ts b/packages/db/src/schema/makers.ts deleted file mode 100644 index d9178a6..0000000 --- a/packages/db/src/schema/makers.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { createId } from "@paralleldrive/cuid2"; -import { int, mysqlTable, timestamp, varchar } from "drizzle-orm/mysql-core"; -import { createSelectSchema } from "drizzle-zod"; -import { z } from "zod"; - -export const makers = mysqlTable("makers", { - id: varchar("id", { length: 25 }) - .$defaultFn(() => createId()) - .primaryKey(), - name: varchar("name", { length: 100 }).notNull(), - slug: varchar("slug", { length: 100 }).unique().notNull(), - url: varchar("url", { length: 255 }).notNull(), - deviceCount: int("device_count").notNull().default(0), - pageCount: int("page_count"), - createdAt: timestamp("created_at").defaultNow().notNull(), -}); - -export const makerSelectSchema = createSelectSchema(makers, { - createdAt: z.coerce.date(), -}); -export type MakerInsert = typeof makers.$inferInsert; -export type MakerSelect = typeof makers.$inferSelect; diff --git a/packages/db/src/schema/model-categories.ts b/packages/db/src/schema/model-categories.ts index 9037fa4..ba5e27f 100644 --- a/packages/db/src/schema/model-categories.ts +++ b/packages/db/src/schema/model-categories.ts @@ -7,11 +7,9 @@ export const modelCategories = mysqlTable("model_categories", { .$defaultFn(() => createId()) .primaryKey(), name: varchar("name", { length: 100 }).notNull(), + slug: varchar("slug", { length: 100 }).unique().notNull(), }); export const modelCategorySelectSchema = createSelectSchema(modelCategories); - -/** @deprecated Renamed to {@link modelCategories} */ -export const deviceCategories = modelCategories; -/** @deprecated Renamed to {@link modelCategorySelectSchema} */ -export const deviceCategorySelectSchema = modelCategorySelectSchema; +export type CategoryInsert = typeof modelCategories.$inferInsert; +export type CategorySelect = typeof modelCategories.$inferSelect; diff --git a/packages/db/src/schema/model-makers.ts b/packages/db/src/schema/model-makers.ts index eb30ca0..a92588b 100644 --- a/packages/db/src/schema/model-makers.ts +++ b/packages/db/src/schema/model-makers.ts @@ -1,17 +1,22 @@ import { createId } from "@paralleldrive/cuid2"; -import { mysqlTable, varchar } from "drizzle-orm/mysql-core"; +import { int, mysqlTable, timestamp, varchar } from "drizzle-orm/mysql-core"; import { createSelectSchema } from "drizzle-zod"; +import { z } from "zod"; export const modelMakers = mysqlTable("model_makers", { id: varchar("id", { length: 25 }) .$defaultFn(() => createId()) .primaryKey(), name: varchar("name", { length: 100 }).notNull(), + slug: varchar("slug", { length: 100 }).unique().notNull(), + url: varchar("url", { length: 255 }).notNull(), + deviceCount: int("device_count").notNull().default(0), + pageCount: int("page_count"), + createdAt: timestamp("created_at").defaultNow().notNull(), }); -export const modelMakerSelectSchema = createSelectSchema(modelMakers); - -/** @deprecated Renamed to {@link modelMakers} */ -export const deviceBrands = modelMakers; -/** @deprecated Renamed to {@link modelMakerSelectSchema} */ -export const deviceBrandSelectSchema = modelMakerSelectSchema; +export const modelMakerSelectSchema = createSelectSchema(modelMakers, { + createdAt: z.coerce.date(), +}); +export type MakerInsert = typeof modelMakers.$inferInsert; +export type MakerSelect = typeof modelMakers.$inferSelect; diff --git a/packages/db/src/schema/models.ts b/packages/db/src/schema/models.ts index 087c7c6..d0a8509 100644 --- a/packages/db/src/schema/models.ts +++ b/packages/db/src/schema/models.ts @@ -10,9 +10,9 @@ import { } from "drizzle-orm/mysql-core"; import { createSelectSchema } from "drizzle-zod"; import { z } from "zod"; -import { categories } from "./categories"; import { companies } from "./companies"; -import { makers } from "./makers"; +import { modelCategories } from "./model-categories"; +import { modelMakers } from "./model-makers"; export const models = mysqlTable( "models", @@ -22,7 +22,7 @@ export const models = mysqlTable( .primaryKey(), makerId: varchar("maker_id", { length: 25 }) .notNull() - .references(() => makers.id), + .references(() => modelMakers.id), name: varchar("name", { length: 255 }).notNull(), slug: varchar("slug", { length: 100 }).notNull(), url: varchar("url", { length: 255 }).notNull(), @@ -30,7 +30,7 @@ export const models = mysqlTable( imageLocalPath: varchar("image_local_path", { length: 255 }), categoryId: varchar("category_id", { length: 25 }).references( - () => categories.id + () => modelCategories.id ), announced: text("announced"), From b0234e99ecdc7969f3b90f35eeeab268a846a6a0 Mon Sep 17 00:00:00 2001 From: Ricardo Amorim <102877738+risixdzn@users.noreply.github.com> Date: Wed, 27 May 2026 14:58:14 -0300 Subject: [PATCH 4/9] fix(DB): Revert migration states to correct order --- packages/db/drizzle/0006_awesome_cloak.sql | 76 ++ packages/db/drizzle/meta/0006_snapshot.json | 962 ++++++++++++++++++++ packages/db/drizzle/meta/_journal.json | 7 + 3 files changed, 1045 insertions(+) create mode 100644 packages/db/drizzle/0006_awesome_cloak.sql create mode 100644 packages/db/drizzle/meta/0006_snapshot.json diff --git a/packages/db/drizzle/0006_awesome_cloak.sql b/packages/db/drizzle/0006_awesome_cloak.sql new file mode 100644 index 0000000..d05a057 --- /dev/null +++ b/packages/db/drizzle/0006_awesome_cloak.sql @@ -0,0 +1,76 @@ +CREATE TABLE `model_categories` ( + `id` varchar(25) NOT NULL, + `name` varchar(100) NOT NULL, + `slug` varchar(100) NOT NULL, + CONSTRAINT `model_categories_id` PRIMARY KEY(`id`), + CONSTRAINT `model_categories_slug_unique` UNIQUE(`slug`) +); +--> statement-breakpoint +CREATE TABLE `model_makers` ( + `id` varchar(25) NOT NULL, + `name` varchar(100) NOT NULL, + `slug` varchar(100) NOT NULL, + `url` varchar(255) NOT NULL, + `device_count` int NOT NULL DEFAULT 0, + `page_count` int, + `created_at` timestamp NOT NULL DEFAULT (now()), + CONSTRAINT `model_makers_id` PRIMARY KEY(`id`), + CONSTRAINT `model_makers_slug_unique` UNIQUE(`slug`) +); +--> statement-breakpoint +CREATE TABLE `service_order_images` ( + `id` varchar(25) NOT NULL, + `service_order_id` varchar(25) NOT NULL, + `employee_id` varchar(25) NOT NULL, + `upload_id` varchar(25) NOT NULL, + `image_url` varchar(255) NOT NULL, + `file_name` varchar(255) NOT NULL, + `size_in_bytes` int NOT NULL, + `content_type` varchar(50) NOT NULL, + `description` varchar(255), + `created_at` timestamp NOT NULL DEFAULT (now()), + CONSTRAINT `service_order_images_id` PRIMARY KEY(`id`) +); +--> statement-breakpoint +CREATE TABLE `service_orders` ( + `id` varchar(25) NOT NULL, + `company_id` varchar(25) NOT NULL, + `client_id` varchar(25) NOT NULL, + `employee_id` varchar(25) NOT NULL, + `device_brand_id` varchar(25) NOT NULL, + `device_category_id` varchar(25) NOT NULL, + `device_model` varchar(100) NOT NULL, + `imei` varchar(50), + `reported_defect` text NOT NULL, + `observations` text, + `status` enum('pending','diagnosing','waiting_approval','approved','fixing','ready','delivered') NOT NULL DEFAULT 'pending', + `created_at` timestamp NOT NULL DEFAULT (now()), + `updated_at` timestamp NOT NULL DEFAULT (now()), + CONSTRAINT `service_orders_id` PRIMARY KEY(`id`) +); +--> statement-breakpoint +CREATE TABLE `uploads` ( + `id` varchar(25) NOT NULL, + `company_id` varchar(25) NOT NULL, + `employee_id` varchar(25) NOT NULL, + `key` varchar(512) NOT NULL, + `url` varchar(512) NOT NULL, + `file_name` varchar(255) NOT NULL, + `content_type` varchar(50) NOT NULL, + `size_in_bytes` int NOT NULL, + `status` varchar(20) NOT NULL DEFAULT 'pending', + `created_at` timestamp NOT NULL DEFAULT (now()), + CONSTRAINT `uploads_id` PRIMARY KEY(`id`) +); +--> statement-breakpoint +ALTER TABLE `employees` MODIFY COLUMN `roles` enum('guest','technician','warehouse','financial','manager','admin') NOT NULL;--> statement-breakpoint +ALTER TABLE `service_order_images` ADD CONSTRAINT `service_order_images_service_order_id_service_orders_id_fk` FOREIGN KEY (`service_order_id`) REFERENCES `service_orders`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE `service_order_images` ADD CONSTRAINT `service_order_images_employee_id_employees_id_fk` FOREIGN KEY (`employee_id`) REFERENCES `employees`(`id`) ON DELETE restrict ON UPDATE no action;--> statement-breakpoint +ALTER TABLE `service_order_images` ADD CONSTRAINT `service_order_images_upload_id_uploads_id_fk` FOREIGN KEY (`upload_id`) REFERENCES `uploads`(`id`) ON DELETE restrict ON UPDATE no action;--> statement-breakpoint +ALTER TABLE `service_orders` ADD CONSTRAINT `service_orders_company_id_companies_id_fk` FOREIGN KEY (`company_id`) REFERENCES `companies`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE `service_orders` ADD CONSTRAINT `service_orders_client_id_clients_id_fk` FOREIGN KEY (`client_id`) REFERENCES `clients`(`id`) ON DELETE restrict ON UPDATE no action;--> statement-breakpoint +ALTER TABLE `service_orders` ADD CONSTRAINT `service_orders_employee_id_employees_id_fk` FOREIGN KEY (`employee_id`) REFERENCES `employees`(`id`) ON DELETE restrict ON UPDATE no action;--> statement-breakpoint +ALTER TABLE `service_orders` ADD CONSTRAINT `service_orders_device_brand_id_model_makers_id_fk` FOREIGN KEY (`device_brand_id`) REFERENCES `model_makers`(`id`) ON DELETE restrict ON UPDATE no action;--> statement-breakpoint +ALTER TABLE `service_orders` ADD CONSTRAINT `service_orders_device_category_id_model_categories_id_fk` FOREIGN KEY (`device_category_id`) REFERENCES `model_categories`(`id`) ON DELETE restrict ON UPDATE no action;--> statement-breakpoint +ALTER TABLE `uploads` ADD CONSTRAINT `uploads_company_id_companies_id_fk` FOREIGN KEY (`company_id`) REFERENCES `companies`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE `uploads` ADD CONSTRAINT `uploads_employee_id_employees_id_fk` FOREIGN KEY (`employee_id`) REFERENCES `employees`(`id`) ON DELETE restrict ON UPDATE no action; \ No newline at end of file diff --git a/packages/db/drizzle/meta/0006_snapshot.json b/packages/db/drizzle/meta/0006_snapshot.json new file mode 100644 index 0000000..0249b7c --- /dev/null +++ b/packages/db/drizzle/meta/0006_snapshot.json @@ -0,0 +1,962 @@ +{ + "version": "5", + "dialect": "mysql", + "id": "ab909380-0bce-443b-b2a8-5ebb6488b252", + "prevId": "96fef0d8-3c1e-4d2f-990d-625797fa1861", + "tables": { + "clients": { + "name": "clients", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cpf": { + "name": "cpf", + "type": "varchar(11)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "phone": { + "name": "phone", + "type": "varchar(11)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "user_id": { + "name": "user_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "clients_user_id_users_id_fk": { + "name": "clients_user_id_users_id_fk", + "tableFrom": "clients", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "clients_id": { + "name": "clients_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "clients_cpf_unique": { + "name": "clients_cpf_unique", + "columns": ["cpf"] + } + }, + "checkConstraint": {} + }, + "companies": { + "name": "companies", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cnpj": { + "name": "cnpj", + "type": "varchar(14)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "address": { + "name": "address", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "subdomain": { + "name": "subdomain", + "type": "varchar(32)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "companies_id": { + "name": "companies_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "companies_cnpj_unique": { + "name": "companies_cnpj_unique", + "columns": ["cnpj"] + }, + "companies_subdomain_unique": { + "name": "companies_subdomain_unique", + "columns": ["subdomain"] + } + }, + "checkConstraint": {} + }, + "employees": { + "name": "employees", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cpf": { + "name": "cpf", + "type": "varchar(11)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "phone": { + "name": "phone", + "type": "varchar(11)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "roles": { + "name": "roles", + "type": "enum('guest','technician','warehouse','financial','manager','admin')", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "user_id": { + "name": "user_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "company_id": { + "name": "company_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "employees_user_id_users_id_fk": { + "name": "employees_user_id_users_id_fk", + "tableFrom": "employees", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "employees_company_id_companies_id_fk": { + "name": "employees_company_id_companies_id_fk", + "tableFrom": "employees", + "tableTo": "companies", + "columnsFrom": ["company_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "employees_id": { + "name": "employees_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "employees_cpf_unique": { + "name": "employees_cpf_unique", + "columns": ["cpf"] + } + }, + "checkConstraint": {} + }, + "model_categories": { + "name": "model_categories", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "slug": { + "name": "slug", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "model_categories_id": { + "name": "model_categories_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "model_categories_slug_unique": { + "name": "model_categories_slug_unique", + "columns": ["slug"] + } + }, + "checkConstraint": {} + }, + "model_makers": { + "name": "model_makers", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "slug": { + "name": "slug", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "device_count": { + "name": "device_count", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "page_count": { + "name": "page_count", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "model_makers_id": { + "name": "model_makers_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "model_makers_slug_unique": { + "name": "model_makers_slug_unique", + "columns": ["slug"] + } + }, + "checkConstraint": {} + }, + "one_time_tokens": { + "name": "one_time_tokens", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "ott_type": { + "name": "ott_type", + "type": "enum('confirmation','password_reset','account_deletion')", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "relates_to": { + "name": "relates_to", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "one_time_tokens_user_id_users_id_fk": { + "name": "one_time_tokens_user_id_users_id_fk", + "tableFrom": "one_time_tokens", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "one_time_tokens_id": { + "name": "one_time_tokens_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "one_time_tokens_token_unique": { + "name": "one_time_tokens_token_unique", + "columns": ["token"] + } + }, + "checkConstraint": {} + }, + "refresh_tokens": { + "name": "refresh_tokens", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "refresh_tokens_user_id_users_id_fk": { + "name": "refresh_tokens_user_id_users_id_fk", + "tableFrom": "refresh_tokens", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "refresh_tokens_id": { + "name": "refresh_tokens_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "refresh_tokens_token_unique": { + "name": "refresh_tokens_token_unique", + "columns": ["token"] + } + }, + "checkConstraint": {} + }, + "service_order_images": { + "name": "service_order_images", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "service_order_id": { + "name": "service_order_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "employee_id": { + "name": "employee_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "upload_id": { + "name": "upload_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "image_url": { + "name": "image_url", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "file_name": { + "name": "file_name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "size_in_bytes": { + "name": "size_in_bytes", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "content_type": { + "name": "content_type", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": { + "service_order_images_service_order_id_service_orders_id_fk": { + "name": "service_order_images_service_order_id_service_orders_id_fk", + "tableFrom": "service_order_images", + "tableTo": "service_orders", + "columnsFrom": ["service_order_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "service_order_images_employee_id_employees_id_fk": { + "name": "service_order_images_employee_id_employees_id_fk", + "tableFrom": "service_order_images", + "tableTo": "employees", + "columnsFrom": ["employee_id"], + "columnsTo": ["id"], + "onDelete": "restrict", + "onUpdate": "no action" + }, + "service_order_images_upload_id_uploads_id_fk": { + "name": "service_order_images_upload_id_uploads_id_fk", + "tableFrom": "service_order_images", + "tableTo": "uploads", + "columnsFrom": ["upload_id"], + "columnsTo": ["id"], + "onDelete": "restrict", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "service_order_images_id": { + "name": "service_order_images_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "service_orders": { + "name": "service_orders", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "company_id": { + "name": "company_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "client_id": { + "name": "client_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "employee_id": { + "name": "employee_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "device_brand_id": { + "name": "device_brand_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "device_category_id": { + "name": "device_category_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "device_model": { + "name": "device_model", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "imei": { + "name": "imei", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "reported_defect": { + "name": "reported_defect", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "observations": { + "name": "observations", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "enum('pending','diagnosing','waiting_approval','approved','fixing','ready','delivered')", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'pending'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": { + "service_orders_company_id_companies_id_fk": { + "name": "service_orders_company_id_companies_id_fk", + "tableFrom": "service_orders", + "tableTo": "companies", + "columnsFrom": ["company_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "service_orders_client_id_clients_id_fk": { + "name": "service_orders_client_id_clients_id_fk", + "tableFrom": "service_orders", + "tableTo": "clients", + "columnsFrom": ["client_id"], + "columnsTo": ["id"], + "onDelete": "restrict", + "onUpdate": "no action" + }, + "service_orders_employee_id_employees_id_fk": { + "name": "service_orders_employee_id_employees_id_fk", + "tableFrom": "service_orders", + "tableTo": "employees", + "columnsFrom": ["employee_id"], + "columnsTo": ["id"], + "onDelete": "restrict", + "onUpdate": "no action" + }, + "service_orders_device_brand_id_model_makers_id_fk": { + "name": "service_orders_device_brand_id_model_makers_id_fk", + "tableFrom": "service_orders", + "tableTo": "model_makers", + "columnsFrom": ["device_brand_id"], + "columnsTo": ["id"], + "onDelete": "restrict", + "onUpdate": "no action" + }, + "service_orders_device_category_id_model_categories_id_fk": { + "name": "service_orders_device_category_id_model_categories_id_fk", + "tableFrom": "service_orders", + "tableTo": "model_categories", + "columnsFrom": ["device_category_id"], + "columnsTo": ["id"], + "onDelete": "restrict", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "service_orders_id": { + "name": "service_orders_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "uploads": { + "name": "uploads", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "company_id": { + "name": "company_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "employee_id": { + "name": "employee_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "key": { + "name": "key", + "type": "varchar(512)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "varchar(512)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "file_name": { + "name": "file_name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "content_type": { + "name": "content_type", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "size_in_bytes": { + "name": "size_in_bytes", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "varchar(20)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'pending'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": { + "uploads_company_id_companies_id_fk": { + "name": "uploads_company_id_companies_id_fk", + "tableFrom": "uploads", + "tableTo": "companies", + "columnsFrom": ["company_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "uploads_employee_id_employees_id_fk": { + "name": "uploads_employee_id_employees_id_fk", + "tableFrom": "uploads", + "tableTo": "employees", + "columnsFrom": ["employee_id"], + "columnsTo": ["id"], + "onDelete": "restrict", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "uploads_id": { + "name": "uploads_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "users": { + "name": "users", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "password_hash": { + "name": "password_hash", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "google_id": { + "name": "google_id", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "avatar_url": { + "name": "avatar_url", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "verified": { + "name": "verified", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "users_id": { + "name": "users_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "users_email_unique": { + "name": "users_email_unique", + "columns": ["email"] + }, + "users_google_id_unique": { + "name": "users_google_id_unique", + "columns": ["google_id"] + } + }, + "checkConstraint": {} + } + }, + "views": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "tables": {}, + "indexes": {} + } +} diff --git a/packages/db/drizzle/meta/_journal.json b/packages/db/drizzle/meta/_journal.json index 6e81e16..a3a26fd 100644 --- a/packages/db/drizzle/meta/_journal.json +++ b/packages/db/drizzle/meta/_journal.json @@ -43,6 +43,13 @@ "when": 1760755210443, "tag": "0005_faulty_mandarin", "breakpoints": true + }, + { + "idx": 6, + "version": "5", + "when": 1779902286658, + "tag": "0006_awesome_cloak", + "breakpoints": true } ] } From fb753f385c35db18690efb67f5431669705b0161 Mon Sep 17 00:00:00 2001 From: Ricardo Amorim <102877738+risixdzn@users.noreply.github.com> Date: Sun, 31 May 2026 16:06:05 -0300 Subject: [PATCH 5/9] feat(Devices): Routes for reading categories, makers and models --- apps/server/src/config/r2.ts | 23 +- .../core/docs/categories/categories.docs.ts | 61 +++++ .../src/core/docs/makers/makers.docs.ts | 79 ++++++ .../src/core/docs/models/models.docs.ts | 202 +++++++++++++++ .../src/core/docs/service-orders.docs.ts | 12 +- apps/server/src/core/errors/index.ts | 6 + apps/server/src/core/lib/r2.ts | 16 ++ .../modules/categories/controllers/index.ts | 32 +++ .../src/modules/categories/errors/index.ts | 10 + .../modules/categories/repositories/index.ts | 33 +++ .../src/modules/categories/routes/index.ts | 46 ++++ .../src/modules/categories/services/index.ts | 64 +++++ .../src/modules/makers/controllers/index.ts | 41 +++ .../server/src/modules/makers/errors/index.ts | 15 ++ .../src/modules/makers/repositories/index.ts | 62 +++++ .../server/src/modules/makers/routes/index.ts | 54 ++++ .../src/modules/makers/services/index.ts | 134 ++++++++++ .../src/modules/models/controllers/index.ts | 62 +++++ .../server/src/modules/models/errors/index.ts | 25 ++ .../src/modules/models/repositories/index.ts | 244 ++++++++++++++++++ .../server/src/modules/models/routes/index.ts | 63 +++++ .../src/modules/models/services/index.ts | 202 +++++++++++++++ apps/server/src/server.ts | 22 +- apps/web/app/(public)/downtime/page.tsx | 4 +- packages/db/src/schema/index.ts | 2 + packages/db/src/schema/model-categories.ts | 8 +- packages/db/src/schema/model-makers.ts | 18 +- packages/permissions/src/abilities.ts | 7 + packages/schemas/package.json | 4 + packages/schemas/src/models.ts | 43 +++ 30 files changed, 1573 insertions(+), 21 deletions(-) create mode 100644 apps/server/src/core/docs/categories/categories.docs.ts create mode 100644 apps/server/src/core/docs/makers/makers.docs.ts create mode 100644 apps/server/src/core/docs/models/models.docs.ts create mode 100644 apps/server/src/modules/categories/controllers/index.ts create mode 100644 apps/server/src/modules/categories/errors/index.ts create mode 100644 apps/server/src/modules/categories/repositories/index.ts create mode 100644 apps/server/src/modules/categories/routes/index.ts create mode 100644 apps/server/src/modules/categories/services/index.ts create mode 100644 apps/server/src/modules/makers/controllers/index.ts create mode 100644 apps/server/src/modules/makers/errors/index.ts create mode 100644 apps/server/src/modules/makers/repositories/index.ts create mode 100644 apps/server/src/modules/makers/routes/index.ts create mode 100644 apps/server/src/modules/makers/services/index.ts create mode 100644 apps/server/src/modules/models/controllers/index.ts create mode 100644 apps/server/src/modules/models/errors/index.ts create mode 100644 apps/server/src/modules/models/repositories/index.ts create mode 100644 apps/server/src/modules/models/routes/index.ts create mode 100644 apps/server/src/modules/models/services/index.ts create mode 100644 packages/schemas/src/models.ts diff --git a/apps/server/src/config/r2.ts b/apps/server/src/config/r2.ts index c5c34f6..6c3f995 100644 --- a/apps/server/src/config/r2.ts +++ b/apps/server/src/config/r2.ts @@ -1,11 +1,16 @@ -import { S3Client } from "@aws-sdk/client-s3"; +import { GetObjectCommand, S3Client } from "@aws-sdk/client-s3"; +import { getSignedUrl } from "@aws-sdk/s3-request-presigner"; import { env } from "@fixr/env/server"; import { buildObjectPublicUrl as _buildObjectPublicUrl, isAllowedCompanyPhotoUrl as _isAllowedCompanyPhotoUrl, } from "../core/lib/r2"; -export { buildUploadObjectKey, sanitizeUploadFileName } from "../core/lib/r2"; +export { + buildModelObjectKey, + buildUploadObjectKey, + sanitizeUploadFileName, +} from "../core/lib/r2"; function parseR2BucketUrl(bucketUrl: string) { const parsed = new URL(bucketUrl); @@ -45,3 +50,17 @@ export function buildObjectPublicUrl(key: string) { export function isAllowedCompanyPhotoUrl(url: string, companyId: string) { return _isAllowedCompanyPhotoUrl(r2PublicBaseUrl, url, companyId); } + +/** + * Generate a presigned GET URL for reading an object from R2 + * + * @param key - The R2 object key + * @returns A presigned URL valid for 24 hours + */ +export async function generatePresignedGetUrl(key: string): Promise { + const command = new GetObjectCommand({ + Bucket: r2Bucket, + Key: key, + }); + return await getSignedUrl(r2Client, command, { expiresIn: 86_400 }); +} diff --git a/apps/server/src/core/docs/categories/categories.docs.ts b/apps/server/src/core/docs/categories/categories.docs.ts new file mode 100644 index 0000000..8d02610 --- /dev/null +++ b/apps/server/src/core/docs/categories/categories.docs.ts @@ -0,0 +1,61 @@ +import { modelCategorySelectSchema } from "@fixr/db/schema"; +import { + getModelCategoriesQuerySchema, + getModelCategoryParamsSchema, +} from "@fixr/schemas/models"; +import type { FastifySchema } from "fastify"; +import { z } from "zod"; +import { zodResponseSchema } from "../types"; + +const listCategoriesSchema: FastifySchema = { + tags: ["Devices"], + summary: "List model categories", + description: ` +**Retrieves all device categories.** +Categories are global and not tied to a specific company. + +Optional filter (query string): +- \`query\`: search by category name +`, + querystring: getModelCategoriesQuerySchema, + response: { + 200: zodResponseSchema({ + status: 200, + error: null, + message: "Categories retrieved successfully.", + code: "list_categories_success", + data: z.array(modelCategorySelectSchema), + }).describe("Categories retrieved successfully."), + }, + security: [{ JWT: [] }], +}; + +const getCategoryBySlugSchema: FastifySchema = { + tags: ["Devices"], + summary: "Get category by slug", + description: "Retrieves a single device category by its slug.", + params: getModelCategoryParamsSchema, + response: { + 200: zodResponseSchema({ + status: 200, + error: null, + message: "Category retrieved successfully.", + code: "get_category_success", + data: modelCategorySelectSchema, + }).describe("Category retrieved successfully."), + 404: zodResponseSchema({ + status: 404, + error: "Not Found", + code: "category_not_found", + message: "Category not found.", + data: null, + }).describe("Category not found."), + }, + security: [{ JWT: [] }], +}; + +/** @description OpenAPI schemas for the categories module */ +export const categoriesDocs = { + listCategoriesSchema, + getCategoryBySlugSchema, +}; diff --git a/apps/server/src/core/docs/makers/makers.docs.ts b/apps/server/src/core/docs/makers/makers.docs.ts new file mode 100644 index 0000000..225aa62 --- /dev/null +++ b/apps/server/src/core/docs/makers/makers.docs.ts @@ -0,0 +1,79 @@ +import { modelMakerSelectSchema } from "@fixr/db/schema"; +import { + getModelMakerParamsSchema, + getModelMakersQuerySchema, +} from "@fixr/schemas/models"; +import { paginatedDataSchema } from "@fixr/schemas/utils"; +import type { FastifySchema } from "fastify"; +import { z } from "zod"; +import { zodResponseSchema } from "../types"; + +const makerListRecordSchema = z.object({ + id: z.string(), + name: z.string(), + slug: z.string(), + url: z.string(), + deviceCount: z.number(), + pageCount: z.number().nullable(), + createdAt: z.coerce.date(), +}); + +const listMakersSchema: FastifySchema = { + tags: ["Devices"], + summary: "List model makers", + description: ` +**Retrieves device makers (brands) with pagination.** + +Optional filters (query string): +- \`query\`: search by maker name +- \`page\`, \`perPage\`, \`sort\` (\`newer\` | \`older\` | \`name\` | \`most_devices\`): pagination (see API pagination docs) +`, + querystring: getModelMakersQuerySchema, + response: { + 200: zodResponseSchema({ + status: 200, + error: null, + message: "Makers successfully retrieved.", + code: "list_makers_success", + data: paginatedDataSchema(makerListRecordSchema), + }).describe("Makers retrieved successfully."), + 416: zodResponseSchema({ + status: 416, + error: "Range Not Satisfiable", + code: "page_out_of_bounds", + message: "The requested page exceeds the total number of pages.", + data: null, + }).describe("Requested page exceeds total pages."), + }, + security: [{ JWT: [] }], +}; + +const getMakerBySlugSchema: FastifySchema = { + tags: ["Devices"], + summary: "Get maker by slug", + description: "Retrieves a single device maker by its slug.", + params: getModelMakerParamsSchema, + response: { + 200: zodResponseSchema({ + status: 200, + error: null, + message: "Maker retrieved successfully.", + code: "get_maker_success", + data: modelMakerSelectSchema, + }).describe("Maker retrieved successfully."), + 404: zodResponseSchema({ + status: 404, + error: "Not Found", + code: "maker_not_found", + message: "Maker not found.", + data: null, + }).describe("Maker not found."), + }, + security: [{ JWT: [] }], +}; + +/** @description OpenAPI schemas for the makers module */ +export const makersDocs = { + listMakersSchema, + getMakerBySlugSchema, +}; diff --git a/apps/server/src/core/docs/models/models.docs.ts b/apps/server/src/core/docs/models/models.docs.ts new file mode 100644 index 0000000..59f637c --- /dev/null +++ b/apps/server/src/core/docs/models/models.docs.ts @@ -0,0 +1,202 @@ +import { getCompanyNestedDataSchema } from "@fixr/schemas/companies"; +import { getModelsQuerySchema } from "@fixr/schemas/models"; +import { paginatedDataSchema } from "@fixr/schemas/utils"; +import type { FastifySchema } from "fastify"; +import { z } from "zod"; +import { zodResponseSchema } from "../types"; + +const modelListRecordSchema = z.object({ + id: z.string(), + name: z.string(), + slug: z.string(), + imageUrl: z.string().nullable(), + imageLocalPath: z.string().nullable(), + presignedImageUrl: z.string().nullable(), + status: z.string().nullable(), + price: z.string().nullable(), + released: z.string().nullable(), + maker: z.object({ + id: z.string(), + name: z.string(), + slug: z.string(), + }), + category: z + .object({ + id: z.string(), + name: z.string(), + slug: z.string(), + }) + .nullable(), +}); + +const modelImageRecordSchema = z.object({ + id: z.string(), + modelId: z.string(), + originalUrl: z.string().nullable(), + r2Key: z.string().nullable(), + presignedUrl: z.string().nullable(), + isPrimary: z.boolean(), + variant: z.string().nullable(), + position: z.number(), + createdAt: z.coerce.date(), +}); + +const modelDetailRecordSchema = z.object({ + id: z.string(), + makerId: z.string(), + name: z.string(), + slug: z.string(), + url: z.string(), + imageUrl: z.string().nullable(), + imageLocalPath: z.string().nullable(), + presignedImageUrl: z.string().nullable(), + categoryId: z.string().nullable(), + announced: z.string().nullable(), + status: z.string().nullable(), + dimensions: z.string().nullable(), + weight: z.string().nullable(), + build: z.string().nullable(), + sim: z.string().nullable(), + displayType: z.string().nullable(), + displaySize: z.string().nullable(), + displayResolution: z.string().nullable(), + displayProtection: z.string().nullable(), + os: z.string().nullable(), + chipset: z.string().nullable(), + cpu: z.string().nullable(), + gpu: z.string().nullable(), + cardSlot: z.string().nullable(), + internalMemory: z.string().nullable(), + mainCamera: z.string().nullable(), + mainCameraFeatures: z.string().nullable(), + mainCameraVideo: z.string().nullable(), + selfieCamera: z.string().nullable(), + selfieFeatures: z.string().nullable(), + selfieVideo: z.string().nullable(), + battery: z.string().nullable(), + batteryCharging: z.string().nullable(), + networkTech: z.string().nullable(), + sensors: z.string().nullable(), + colors: z.string().nullable(), + colorsHex: z.string().nullable(), + modelsText: z.string().nullable(), + price: z.string().nullable(), + dimensionsWidth: z.number().nullable(), + dimensionsHeight: z.number().nullable(), + dimensionsThickness: z.number().nullable(), + weightGrams: z.number().nullable(), + displaySizeInches: z.number().nullable(), + displaySizeRatio: z.string().nullable(), + displayResWidth: z.number().nullable(), + displayResHeight: z.number().nullable(), + displayResPpi: z.number().nullable(), + released: z.string().nullable(), + meta: z.string().nullable(), + companyId: z.string().nullable(), + createdAt: z.coerce.date(), + maker: z.object({ + id: z.string(), + name: z.string(), + slug: z.string(), + url: z.string(), + }), + category: z + .object({ + id: z.string(), + name: z.string(), + slug: z.string(), + }) + .nullable(), + images: z.array(modelImageRecordSchema), +}); + +const modelDetailParamsSchema = z + .object({ + subdomain: z.string(), + slug: z.string(), + }) + .describe("Company subdomain and model slug."); + +const listModelsSchema: FastifySchema = { + tags: ["Devices"], + summary: "List device models", + description: ` +**Retrieves device models (paginated minimal list) for mounting a table.** + +Returns base (global) models plus company-specific models. + +Optional filters (query string): +- \`query\`: fulltext search on name, model variants, chipset, CPU, internal memory, OS +- \`makerId\`: filter by brand (cuid2) +- \`categoryId\`: filter by category (cuid2) +- \`status\`: release status: Available, Discontinued, Cancelled, Rumored +- \`page\`, \`perPage\`, \`sort\` (\`newer\` | \`older\` | \`name\`): pagination (see API pagination docs) +`, + params: getCompanyNestedDataSchema, + querystring: getModelsQuerySchema, + response: { + 200: zodResponseSchema({ + status: 200, + error: null, + message: "Models successfully retrieved.", + code: "list_models_success", + data: paginatedDataSchema(modelListRecordSchema), + }).describe("Models retrieved successfully."), + 416: zodResponseSchema({ + status: 416, + error: "Range Not Satisfiable", + code: "page_out_of_bounds", + message: "The requested page exceeds the total number of pages.", + data: null, + }).describe("Requested page exceeds total pages."), + 403: zodResponseSchema({ + status: 403, + error: "Forbidden", + code: "not_allowed", + message: "You are not authorized to access this company.", + data: null, + }).describe("Not allowed to access this company."), + }, + security: [{ JWT: [] }], +}; + +const getModelBySlugSchema: FastifySchema = { + tags: ["Devices"], + summary: "Get device model by slug", + description: ` +**Retrieves full device model details by slug.** + +Returns all spec fields, related maker and category, and model images with presigned URLs. +`, + params: modelDetailParamsSchema, + response: { + 200: zodResponseSchema({ + status: 200, + error: null, + message: "Model retrieved successfully.", + code: "get_model_success", + data: modelDetailRecordSchema, + }).describe("Model retrieved successfully."), + 404: zodResponseSchema({ + status: 404, + error: "Not Found", + code: "model_not_found", + message: "Model not found.", + data: null, + }).describe("Model not found."), + 403: zodResponseSchema({ + status: 403, + error: "Forbidden", + code: "not_allowed", + message: "You are not authorized to access this company.", + data: null, + }).describe("Not allowed to access this company."), + }, + security: [{ JWT: [] }], +}; + +/** @description OpenAPI schemas for the models module */ +export const modelsDocs = { + listModelsSchema, + getModelBySlugSchema, +}; diff --git a/apps/server/src/core/docs/service-orders.docs.ts b/apps/server/src/core/docs/service-orders.docs.ts index 0ed65a1..1c8f511 100644 --- a/apps/server/src/core/docs/service-orders.docs.ts +++ b/apps/server/src/core/docs/service-orders.docs.ts @@ -44,12 +44,12 @@ const getCompanyServiceOrdersSchema: FastifySchema = { **Retrieves company service orders (paginated)** Optional filters (query string): -- \`deviceCategoryId\` — device category (cuid2) -- \`employeeId\` — responsible employee (cuid2) -- \`status\` — one of: ${serviceOrderStatuses.options.join(", ")} -- \`dateFrom\` / \`dateTo\` — filter by \`created_at\` (inclusive; ISO date or datetime) -- \`query\` — search in device model, reported defect, or client name -- \`page\`, \`perPage\`, \`sort\` (\`newer\` | \`older\`) — pagination (see API pagination docs) +- \`deviceCategoryId\`: device category (cuid2) +- \`employeeId\`: responsible employee (cuid2) +- \`status\`: one of: ${serviceOrderStatuses.options.join(", ")} +- \`dateFrom\` / \`dateTo\`: filter by \`created_at\` (inclusive; ISO date or datetime) +- \`query\`: search in device model, reported defect, or client name +- \`page\`, \`perPage\`, \`sort\` (\`newer\` | \`older\`): pagination (see API pagination docs) `, params: getCompanyNestedDataSchema, querystring: getServiceOrdersQuerySchema, diff --git a/apps/server/src/core/errors/index.ts b/apps/server/src/core/errors/index.ts index 6156b0a..c0d64fc 100644 --- a/apps/server/src/core/errors/index.ts +++ b/apps/server/src/core/errors/index.ts @@ -1,8 +1,11 @@ import { accountErrors } from "../../modules/account/errors"; import { authErrors } from "../../modules/auth/errors"; +import { categoriesErrors } from "../../modules/categories/errors"; import { companiesErrors } from "../../modules/companies/errors"; import { credentialsErrors } from "../../modules/credentials/errors"; import { employeesErrors } from "../../modules/employees/errors"; +import { makersErrors } from "../../modules/makers/errors"; +import { modelsErrors } from "../../modules/models/errors"; import { serviceOrdersErrors } from "../../modules/service-orders/errors"; import { tokensErrors } from "../../modules/tokens/errors"; import { uploadsErrors } from "../../modules/uploads/errors"; @@ -14,6 +17,9 @@ export const errors = defineErrors({ ...credentialsErrors, ...companiesErrors, ...employeesErrors, + ...categoriesErrors, + ...makersErrors, + ...modelsErrors, ...serviceOrdersErrors, ...tokensErrors, ...uploadsErrors, diff --git a/apps/server/src/core/lib/r2.ts b/apps/server/src/core/lib/r2.ts index 6e0af8d..bd518f4 100644 --- a/apps/server/src/core/lib/r2.ts +++ b/apps/server/src/core/lib/r2.ts @@ -56,3 +56,19 @@ export function buildUploadObjectKey({ return `companies/${companyId}/service-orders/${uniquePrefix}-${safeName}`; } + +/** + * Build an R2 object key for a model image + */ +export function buildModelObjectKey({ + companyId, + fileName, +}: { + companyId: string; + fileName: string; +}): string { + const safeName = sanitizeUploadFileName(fileName); + const uniquePrefix = `${Date.now()}-${randomUUID().slice(0, 8)}`; + + return `companies/${companyId}/models/${uniquePrefix}-${safeName}`; +} diff --git a/apps/server/src/modules/categories/controllers/index.ts b/apps/server/src/modules/categories/controllers/index.ts new file mode 100644 index 0000000..da13dc5 --- /dev/null +++ b/apps/server/src/modules/categories/controllers/index.ts @@ -0,0 +1,32 @@ +import type { + getModelCategoriesQuerySchema, + getModelCategoryParamsSchema, +} from "@fixr/schemas/models"; +import type { FastifyReply } from "fastify"; +import type { z } from "zod"; +import { CategoriesService } from "../services"; + +/** @description Categories request handlers */ +export class CategoriesController { + /** @description List all categories */ + static listCategories({ + query, + response, + }: { + query?: string; + response: FastifyReply; + } & z.infer) { + return CategoriesService.listCategories({ query, response }); + } + + /** @description Get a category by slug */ + static getCategoryBySlug({ + slug, + response, + }: { + slug: string; + response: FastifyReply; + } & z.infer) { + return CategoriesService.getCategoryBySlug({ slug, response }); + } +} diff --git a/apps/server/src/modules/categories/errors/index.ts b/apps/server/src/modules/categories/errors/index.ts new file mode 100644 index 0000000..15ccd62 --- /dev/null +++ b/apps/server/src/modules/categories/errors/index.ts @@ -0,0 +1,10 @@ +import { defineErrors } from "../../../core/utils/errors"; + +/** @description Error definitions for the categories module */ +export const categoriesErrors = defineErrors({ + CATEGORY_NOT_FOUND: { + code: "category_not_found", + message: "Category not found.", + status: 404, + }, +}); diff --git a/apps/server/src/modules/categories/repositories/index.ts b/apps/server/src/modules/categories/repositories/index.ts new file mode 100644 index 0000000..702446d --- /dev/null +++ b/apps/server/src/modules/categories/repositories/index.ts @@ -0,0 +1,33 @@ +import { asc, db, eq, like } from "@fixr/db/connection"; +import { modelCategories } from "@fixr/db/schema"; + +/** @description Data access layer for device categories */ +export class CategoriesRepository { + /** + * Query all categories, optionally filtering by name + * + * @param query - Optional name filter + */ + static async queryAllCategories(query?: string) { + const base = db.select().from(modelCategories).$dynamic(); + if (query) { + base.where(like(modelCategories.name, `%${query}%`)); + } + return await base.orderBy(asc(modelCategories.name)); + } + + /** + * Find a category by its slug + * + * @param slug - The category slug + * @returns The category record or null + */ + static async queryCategoryBySlug(slug: string) { + const [category] = await db + .select() + .from(modelCategories) + .where(eq(modelCategories.slug, slug)) + .limit(1); + return category ?? null; + } +} diff --git a/apps/server/src/modules/categories/routes/index.ts b/apps/server/src/modules/categories/routes/index.ts new file mode 100644 index 0000000..be1c8a8 --- /dev/null +++ b/apps/server/src/modules/categories/routes/index.ts @@ -0,0 +1,46 @@ +import { permissions } from "@fixr/permissions"; +import { + getModelCategoriesQuerySchema, + getModelCategoryParamsSchema, +} from "@fixr/schemas/models"; +import { categoriesDocs } from "../../../core/docs/categories/categories.docs"; +import type { FastifyTypedInstance } from "../../../core/interfaces/fastify"; +import { authenticateEmployee } from "../../../core/middlewares/authenticate-employee"; +import { requirePermission } from "../../../core/middlewares/rbac"; +import { withErrorHandler } from "../../../core/middlewares/with-error-handler"; +import { CategoriesController } from "../controllers"; + +/** @description Categories routes plugin */ +export function categoriesRoutes(fastify: FastifyTypedInstance) { + fastify.get( + "/", + { + preHandler: [ + authenticateEmployee, + requirePermission(permissions.devices.read), + ], + schema: categoriesDocs.listCategoriesSchema, + }, + withErrorHandler(async (request, response) => { + const { query } = getModelCategoriesQuerySchema.parse(request.query); + + await CategoriesController.listCategories({ query, response }); + }) + ); + + fastify.get( + "/:slug", + { + preHandler: [ + authenticateEmployee, + requirePermission(permissions.devices.read), + ], + schema: categoriesDocs.getCategoryBySlugSchema, + }, + withErrorHandler(async (request, response) => { + const { slug } = getModelCategoryParamsSchema.parse(request.params); + + await CategoriesController.getCategoryBySlug({ slug, response }); + }) + ); +} diff --git a/apps/server/src/modules/categories/services/index.ts b/apps/server/src/modules/categories/services/index.ts new file mode 100644 index 0000000..a724fda --- /dev/null +++ b/apps/server/src/modules/categories/services/index.ts @@ -0,0 +1,64 @@ +import { modelCategorySelectSchema } from "@fixr/db/schema"; +import type { FastifyReply } from "fastify"; +import { AppError } from "../../../core/lib/app-error"; +import { apiResponse } from "../../../core/lib/response"; +import { CategoriesRepository } from "../repositories"; + +/** @description Business logic for device categories */ +export class CategoriesService { + /** + * List all categories, optionally filtered by query + * + * @param query - Optional name filter + * @param response - Fastify reply + */ + static async listCategories({ + query, + response, + }: { + query?: string; + response: FastifyReply; + }) { + const categories = await CategoriesRepository.queryAllCategories(query); + + return response.status(200).send( + apiResponse({ + status: 200, + error: null, + code: "list_categories_success", + message: "Categories retrieved successfully.", + data: categories.map((c) => modelCategorySelectSchema.parse(c)), + }) + ); + } + + /** + * Get a category by its slug + * + * @param slug - The category slug + * @param response - Fastify reply + */ + static async getCategoryBySlug({ + slug, + response, + }: { + slug: string; + response: FastifyReply; + }) { + const category = await CategoriesRepository.queryCategoryBySlug(slug); + + if (!category) { + throw new AppError("CATEGORY_NOT_FOUND"); + } + + return response.status(200).send( + apiResponse({ + status: 200, + error: null, + code: "get_category_success", + message: "Category retrieved successfully.", + data: modelCategorySelectSchema.parse(category), + }) + ); + } +} diff --git a/apps/server/src/modules/makers/controllers/index.ts b/apps/server/src/modules/makers/controllers/index.ts new file mode 100644 index 0000000..7843df9 --- /dev/null +++ b/apps/server/src/modules/makers/controllers/index.ts @@ -0,0 +1,41 @@ +import type { getModelMakersQuerySchema } from "@fixr/schemas/models"; +import type { FastifyReply } from "fastify"; +import type { z } from "zod"; +import { MakersService } from "../services"; + +/** @description Makers request handlers */ +export class MakersController { + /** @description List makers with pagination */ + static listMakers({ + page, + perPage, + query, + sort, + response, + }: { + page: number; + perPage?: number; + query?: string; + sort?: string; + response: FastifyReply; + } & z.infer) { + return MakersService.listMakers({ + page, + perPage, + query, + sort, + response, + }); + } + + /** @description Get a maker by slug */ + static getMakerBySlug({ + slug, + response, + }: { + slug: string; + response: FastifyReply; + }) { + return MakersService.getMakerBySlug({ slug, response }); + } +} diff --git a/apps/server/src/modules/makers/errors/index.ts b/apps/server/src/modules/makers/errors/index.ts new file mode 100644 index 0000000..345015a --- /dev/null +++ b/apps/server/src/modules/makers/errors/index.ts @@ -0,0 +1,15 @@ +import { defineErrors } from "../../../core/utils/errors"; + +/** @description Error definitions for the makers module */ +export const makersErrors = defineErrors({ + MAKER_NOT_FOUND: { + code: "maker_not_found", + message: "Maker not found.", + status: 404, + }, + MAKER_PAGE_OUT_OF_BOUNDS: { + code: "page_out_of_bounds", + message: "The requested page exceeds the total number of pages.", + status: 416, + }, +}); diff --git a/apps/server/src/modules/makers/repositories/index.ts b/apps/server/src/modules/makers/repositories/index.ts new file mode 100644 index 0000000..5b7d57d --- /dev/null +++ b/apps/server/src/modules/makers/repositories/index.ts @@ -0,0 +1,62 @@ +import { and, asc, db, desc, eq, like, type SQL } from "@fixr/db/connection"; +import { modelMakers } from "@fixr/db/schema"; + +/** @description Column selection for paginated makers list */ +export const makersListSelect = { + id: modelMakers.id, + name: modelMakers.name, + slug: modelMakers.slug, + url: modelMakers.url, + deviceCount: modelMakers.deviceCount, + pageCount: modelMakers.pageCount, + createdAt: modelMakers.createdAt, +}; + +/** @description Data access layer for device makers */ +export class MakersRepository { + /** + * Build a WHERE clause for filtering makers + * + * @param query - Optional name filter + */ + static buildListFilter(query?: string) { + const conditions: SQL[] = []; + if (query) { + conditions.push(like(modelMakers.name, `%${query}%`)); + } + return conditions.length > 0 ? and(...conditions) : undefined; + } + + /** + * Build an ORDER BY clause for makers + * + * @param sort - Sort key: newer, older, name, most_devices + */ + static buildOrder(sort?: string) { + switch (sort) { + case "newer": + return desc(modelMakers.createdAt); + case "older": + return asc(modelMakers.createdAt); + case "most_devices": + return desc(modelMakers.deviceCount); + default: + return asc(modelMakers.name); + } + } + + /** + * Find a maker by its slug + * + * @param slug - The maker slug + * @returns The maker record or null + */ + static async queryMakerBySlug(slug: string) { + const [maker] = await db + .select() + .from(modelMakers) + .where(eq(modelMakers.slug, slug)) + .limit(1); + return maker ?? null; + } +} diff --git a/apps/server/src/modules/makers/routes/index.ts b/apps/server/src/modules/makers/routes/index.ts new file mode 100644 index 0000000..28970a3 --- /dev/null +++ b/apps/server/src/modules/makers/routes/index.ts @@ -0,0 +1,54 @@ +import { permissions } from "@fixr/permissions"; +import { + getModelMakerParamsSchema, + getModelMakersQuerySchema, +} from "@fixr/schemas/models"; +import { makersDocs } from "../../../core/docs/makers/makers.docs"; +import type { FastifyTypedInstance } from "../../../core/interfaces/fastify"; +import { authenticateEmployee } from "../../../core/middlewares/authenticate-employee"; +import { requirePermission } from "../../../core/middlewares/rbac"; +import { withErrorHandler } from "../../../core/middlewares/with-error-handler"; +import { MakersController } from "../controllers"; + +/** @description Makers routes plugin */ +export function makersRoutes(fastify: FastifyTypedInstance) { + fastify.get( + "/", + { + preHandler: [ + authenticateEmployee, + requirePermission(permissions.devices.read), + ], + schema: makersDocs.listMakersSchema, + }, + withErrorHandler(async (request, response) => { + const { query, sort, page, perPage } = getModelMakersQuerySchema.parse( + request.query + ); + + await MakersController.listMakers({ + page, + perPage, + query, + sort, + response, + }); + }) + ); + + fastify.get( + "/:slug", + { + preHandler: [ + authenticateEmployee, + requirePermission(permissions.devices.read), + ], + schema: makersDocs.getMakerBySlugSchema, + }, + withErrorHandler(async (request, response) => { + const { slug } = getModelMakerParamsSchema.parse(request.params); + + await MakersController.getMakerBySlug({ slug, response }); + }) + ); +} diff --git a/apps/server/src/modules/makers/services/index.ts b/apps/server/src/modules/makers/services/index.ts new file mode 100644 index 0000000..881f54a --- /dev/null +++ b/apps/server/src/modules/makers/services/index.ts @@ -0,0 +1,134 @@ +import { modelMakerSelectSchema } from "@fixr/db/schema"; +import type { FastifyReply } from "fastify"; +import { AppError } from "../../../core/lib/app-error"; +import { + getPaginatedCount, + getPaginatedRecords, +} from "../../../core/lib/pagination"; +import { apiResponse, paginatedData } from "../../../core/lib/response"; +import { MakersRepository, makersListSelect } from "../repositories"; + +/** @description Business logic for device makers */ +export class MakersService { + /** + * List makers with pagination, filtering, and sorting + * + * @param page - Current page number + * @param perPage - Items per page + * @param query - Optional name filter + * @param sort - Sort direction + * @param response - Fastify reply + */ + static async listMakers({ + page, + perPage, + query, + sort, + response, + }: { + page: number; + perPage?: number; + query?: string; + sort?: string; + response: FastifyReply; + }) { + const PER_PAGE = perPage ?? 10; + + const filter = MakersRepository.buildListFilter(query); + const order = MakersRepository.buildOrder(sort); + + const [records, totalRecords] = await Promise.all([ + getPaginatedRecords({ + table: makersListSelect.id.table, + select: makersListSelect, + skip: (page - 1) * PER_PAGE, + take: PER_PAGE, + where: filter, + order, + }), + getPaginatedCount({ + table: makersListSelect.id.table, + where: filter, + }), + ]); + + if (totalRecords === 0) { + return response.status(200).send( + apiResponse({ + status: 200, + error: null, + message: "Makers successfully retrieved.", + code: "list_makers_success", + data: paginatedData({ + records: [], + pagination: { + total_records: 0, + total_pages: 0, + current_page: 1, + next_page: null, + prev_page: null, + }, + }), + }) + ); + } + + const total_pages = Math.ceil(totalRecords / PER_PAGE); + + if (page > total_pages) { + throw new AppError("MAKER_PAGE_OUT_OF_BOUNDS"); + } + + const next_page = + PER_PAGE * (page - 1) + records.length < totalRecords ? page + 1 : null; + + return response.status(200).send( + apiResponse({ + status: 200, + error: null, + message: "Makers successfully retrieved.", + code: "list_makers_success", + data: paginatedData({ + records, + pagination: { + total_records: totalRecords, + total_pages, + current_page: page, + next_page, + prev_page: page > 1 ? page - 1 : null, + }, + }), + }) + ); + } + + /** + * Get a maker by its slug + * + * @param slug - The maker slug + * @param response - Fastify reply + */ + static async getMakerBySlug({ + slug, + response, + }: { + slug: string; + response: FastifyReply; + }) { + const maker = await MakersRepository.queryMakerBySlug(slug); + + if (!maker) { + throw new AppError("MAKER_NOT_FOUND"); + } + + return response.status(200).send( + apiResponse({ + status: 200, + error: null, + code: "get_maker_success", + message: "Maker retrieved successfully.", + data: modelMakerSelectSchema.parse(maker), + }) + ); + } +} diff --git a/apps/server/src/modules/models/controllers/index.ts b/apps/server/src/modules/models/controllers/index.ts new file mode 100644 index 0000000..775f5c2 --- /dev/null +++ b/apps/server/src/modules/models/controllers/index.ts @@ -0,0 +1,62 @@ +import type { jwtPayload } from "@fixr/schemas/auth"; +import type { + getModelBySlugParamsSchema, + getModelsQuerySchema, +} from "@fixr/schemas/models"; +import type { FastifyReply } from "fastify"; +import type { z } from "zod"; +import { ModelsService } from "../services"; + +/** @description Models request handlers */ +export class ModelsController { + /** @description List models with pagination and filtering */ + static listModels({ + userJwt, + subdomain, + page, + perPage, + query, + makerId, + categoryId, + status, + sort, + response, + }: { + userJwt: z.infer; + subdomain: string; + response: FastifyReply; + } & z.infer) { + return ModelsService.listModels({ + userJwt, + subdomain, + page, + perPage, + query, + makerId, + categoryId, + status, + sort, + response, + }); + } + + /** @description Get a model by slug with full details */ + static getModelBySlug({ + userJwt, + subdomain, + slug, + response, + }: { + userJwt: z.infer; + subdomain: string; + slug: string; + response: FastifyReply; + } & z.infer) { + return ModelsService.getModelBySlug({ + userJwt, + subdomain, + slug, + response, + }); + } +} diff --git a/apps/server/src/modules/models/errors/index.ts b/apps/server/src/modules/models/errors/index.ts new file mode 100644 index 0000000..a908710 --- /dev/null +++ b/apps/server/src/modules/models/errors/index.ts @@ -0,0 +1,25 @@ +import { defineErrors } from "../../../core/utils/errors"; + +/** @description Error definitions for the models module */ +export const modelsErrors = defineErrors({ + MODEL_NOT_FOUND: { + code: "model_not_found", + message: "Model not found.", + status: 404, + }, + MODEL_PAGE_OUT_OF_BOUNDS: { + code: "page_out_of_bounds", + message: "The requested page exceeds the total number of pages.", + status: 416, + }, + MODEL_COMPANY_NOT_FOUND: { + code: "company_not_found", + message: "There's no companies bound to your account", + status: 404, + }, + MODEL_NOT_ALLOWED: { + code: "not_allowed", + message: "You are not authorized to access this company.", + status: 403, + }, +}); diff --git a/apps/server/src/modules/models/repositories/index.ts b/apps/server/src/modules/models/repositories/index.ts new file mode 100644 index 0000000..d2d50db --- /dev/null +++ b/apps/server/src/modules/models/repositories/index.ts @@ -0,0 +1,244 @@ +import { and, asc, db, desc, eq, or, type SQL, sql } from "@fixr/db/connection"; +import { + modelCategories, + modelImages, + modelMakers, + models, +} from "@fixr/db/schema"; +import { generatePresignedGetUrl } from "../../../config/r2"; + +const FTS_OPERATOR_REGEX = /[+\-*~()<>@]/; +const WHITESPACE_REGEX = /\s+/; + +/** @description Column selection for paginated models minimal list */ +export const modelMinimalListSelect = { + id: models.id, + name: models.name, + slug: models.slug, + imageUrl: models.imageUrl, + imageLocalPath: models.imageLocalPath, + status: models.status, + price: models.price, + released: models.released, + maker: { id: modelMakers.id, name: modelMakers.name, slug: modelMakers.slug }, + category: { + id: modelCategories.id, + name: modelCategories.name, + slug: modelCategories.slug, + }, +}; + +/** @description Join definitions for models list queries */ +export const modelListJoins = [ + { + type: "inner" as const, + table: modelMakers, + on: eq(modelMakers.id, models.makerId), + }, + { + type: "left" as const, + table: modelCategories, + on: eq(modelCategories.id, models.categoryId), + }, +]; + +/** @description Data access layer for device models */ +export class ModelsRepository { + /** + * Build a WHERE clause for filtering models with fulltext search support + * + * @param companyId - Company ID for scoping + * @param filters - Query, maker, category, and status filters + */ + static buildListFilter( + companyId: string, + filters: { + query?: string; + makerId?: string; + categoryId?: string; + status?: string; + } + ) { + const conditions: SQL[] = [ + or(eq(models.companyId, companyId), sql`${models.companyId} IS NULL`)!, + ]; + + if (filters.makerId) { + conditions.push(eq(models.makerId, filters.makerId)); + } + if (filters.categoryId) { + conditions.push(eq(models.categoryId, filters.categoryId)); + } + if (filters.status) { + conditions.push(eq(models.status, filters.status)); + } + if (filters.query) { + const hasOperators = FTS_OPERATOR_REGEX.test(filters.query); + const ftsQuery = hasOperators + ? filters.query + : filters.query + .trim() + .split(WHITESPACE_REGEX) + .map((w) => `${w}*`) + .join(" "); + conditions.push( + sql`MATCH(${models.name}, ${models.modelsText}, ${models.chipset}, ${models.cpu}, ${models.internalMemory}, ${models.os}) AGAINST(${ftsQuery} IN BOOLEAN MODE)` + ); + } + + return and(...conditions)!; + } + + /** + * Build an ORDER BY clause for models + * + * @param sort - Sort key: newer, older, name + */ + static buildOrder(sort?: string) { + switch (sort) { + case "newer": + return desc(models.createdAt); + case "older": + return asc(models.createdAt); + case "name": + return asc(models.name); + default: + return desc(models.createdAt); + } + } + + /** + * Find a model by its slug with full maker and category relations + * + * @param slug - The model slug + * @param companyId - Optional company ID for scoping + * @returns The model record with relations or null + */ + static async queryModelBySlug(slug: string, companyId?: string) { + const conditions: SQL[] = [eq(models.slug, slug)]; + if (companyId) { + conditions.push( + or(eq(models.companyId, companyId), sql`${models.companyId} IS NULL`)! + ); + } + + const result = await db + .select({ + id: models.id, + makerId: models.makerId, + name: models.name, + slug: models.slug, + url: models.url, + imageUrl: models.imageUrl, + imageLocalPath: models.imageLocalPath, + categoryId: models.categoryId, + announced: models.announced, + status: models.status, + dimensions: models.dimensions, + weight: models.weight, + build: models.build, + sim: models.sim, + displayType: models.displayType, + displaySize: models.displaySize, + displayResolution: models.displayResolution, + displayProtection: models.displayProtection, + os: models.os, + chipset: models.chipset, + cpu: models.cpu, + gpu: models.gpu, + cardSlot: models.cardSlot, + internalMemory: models.internalMemory, + mainCamera: models.mainCamera, + mainCameraFeatures: models.mainCameraFeatures, + mainCameraVideo: models.mainCameraVideo, + selfieCamera: models.selfieCamera, + selfieFeatures: models.selfieFeatures, + selfieVideo: models.selfieVideo, + battery: models.battery, + batteryCharging: models.batteryCharging, + networkTech: models.networkTech, + sensors: models.sensors, + colors: models.colors, + colorsHex: models.colorsHex, + modelsText: models.modelsText, + price: models.price, + dimensionsWidth: models.dimensionsWidth, + dimensionsHeight: models.dimensionsHeight, + dimensionsThickness: models.dimensionsThickness, + weightGrams: models.weightGrams, + displaySizeInches: models.displaySizeInches, + displaySizeRatio: models.displaySizeRatio, + displayResWidth: models.displayResWidth, + displayResHeight: models.displayResHeight, + displayResPpi: models.displayResPpi, + released: models.released, + meta: models.meta, + companyId: models.companyId, + createdAt: models.createdAt, + maker: { + id: modelMakers.id, + name: modelMakers.name, + slug: modelMakers.slug, + url: modelMakers.url, + }, + category: { + id: modelCategories.id, + name: modelCategories.name, + slug: modelCategories.slug, + }, + }) + .from(models) + .innerJoin(modelMakers, eq(modelMakers.id, models.makerId)) + .leftJoin(modelCategories, eq(modelCategories.id, models.categoryId)) + .where(and(...conditions)) + .limit(1); + + return result[0] ?? null; + } + + /** + * Query all images for a model, ordered by position + * + * @param modelId - The model ID + * @returns Array of model images + */ + static async queryModelImages(modelId: string) { + return await db + .select() + .from(modelImages) + .where(eq(modelImages.modelId, modelId)) + .orderBy(asc(modelImages.position)); + } + + /** + * Attach a presigned GET URL to a model record + * + * @param model - The model record + * @returns The model record with presignedImageUrl + */ + static async attachPresignedImageUrls( + model: Record + ): Promise> { + const localPath = model.imageLocalPath as string; + const presignedUrl = await generatePresignedGetUrl(localPath); + return { ...model, presignedImageUrl: presignedUrl ?? model.imageUrl }; + } + + /** + * Attach presigned GET URLs to an array of model images + * + * @param images - Array of model image records + * @returns Images with presignedUrl attached + */ + static async attachPresignedUrlsToImages( + images: Record[] + ): Promise[]> { + return await Promise.all( + images.map(async (img) => { + const r2Key = img.r2Key as string; + const presignedUrl = await generatePresignedGetUrl(r2Key); + return { ...img, presignedUrl: presignedUrl ?? img.originalUrl }; + }) + ); + } +} diff --git a/apps/server/src/modules/models/routes/index.ts b/apps/server/src/modules/models/routes/index.ts new file mode 100644 index 0000000..846e477 --- /dev/null +++ b/apps/server/src/modules/models/routes/index.ts @@ -0,0 +1,63 @@ +import { permissions } from "@fixr/permissions"; +import type { userJWT } from "@fixr/schemas/auth"; +import { getCompanyNestedDataSchema } from "@fixr/schemas/companies"; +import { + getModelBySlugParamsSchema, + getModelsQuerySchema, +} from "@fixr/schemas/models"; +import type { z } from "zod"; +import { modelsDocs } from "../../../core/docs/models/models.docs"; +import type { FastifyTypedInstance } from "../../../core/interfaces/fastify"; +import { authenticateEmployee } from "../../../core/middlewares/authenticate-employee"; +import { requirePermission } from "../../../core/middlewares/rbac"; +import { withErrorHandler } from "../../../core/middlewares/with-error-handler"; +import { ModelsController } from "../controllers"; + +/** @description Models routes plugin */ +export function modelsRoutes(fastify: FastifyTypedInstance) { + fastify.get( + "/", + { + preHandler: [ + authenticateEmployee, + requirePermission(permissions.devices.read), + ], + schema: modelsDocs.listModelsSchema, + }, + withErrorHandler(async (request, response) => { + const userJwt = request.user as z.infer; + const query = getModelsQuerySchema.parse(request.query); + const { subdomain } = getCompanyNestedDataSchema.parse(request.params); + + await ModelsController.listModels({ + userJwt, + subdomain, + response, + ...query, + }); + }) + ); + + fastify.get( + "/:slug", + { + preHandler: [ + authenticateEmployee, + requirePermission(permissions.devices.read), + ], + schema: modelsDocs.getModelBySlugSchema, + }, + withErrorHandler(async (request, response) => { + const userJwt = request.user as z.infer; + const { slug } = getModelBySlugParamsSchema.parse(request.params); + const { subdomain } = getCompanyNestedDataSchema.parse(request.params); + + await ModelsController.getModelBySlug({ + userJwt, + subdomain, + slug, + response, + }); + }) + ); +} diff --git a/apps/server/src/modules/models/services/index.ts b/apps/server/src/modules/models/services/index.ts new file mode 100644 index 0000000..71fdd7c --- /dev/null +++ b/apps/server/src/modules/models/services/index.ts @@ -0,0 +1,202 @@ +import { models } from "@fixr/db/schema"; +import type { FastifyReply } from "fastify"; +import { AppError } from "../../../core/lib/app-error"; +import { + getPaginatedCount, + getPaginatedRecords, +} from "../../../core/lib/pagination"; +import { apiResponse, paginatedData } from "../../../core/lib/response"; +import { + ModelsRepository, + modelListJoins, + modelMinimalListSelect, +} from "../repositories"; + +/** @description Business logic for device models */ +export class ModelsService { + /** + * List models with pagination, fulltext search, and filters + * + * @param userJwt - Authenticated user JWT payload + * @param subdomain - Company subdomain + * @param page - Current page number + * @param perPage - Items per page + * @param query - Fulltext search query + * @param makerId - Filter by maker + * @param categoryId - Filter by category + * @param status - Filter by release status + * @param sort - Sort direction + * @param response - Fastify reply + */ + static async listModels({ + userJwt, + subdomain, + page, + perPage, + query, + makerId, + categoryId, + status, + sort, + response, + }: { + userJwt: { id: string; company?: { id: string; subdomain: string } }; + subdomain: string; + page: number; + perPage?: number; + query?: string; + makerId?: string; + categoryId?: string; + status?: string; + sort?: string; + response: FastifyReply; + }) { + if (!userJwt.company) { + throw new AppError("MODEL_COMPANY_NOT_FOUND"); + } + + if (userJwt.company.subdomain !== subdomain) { + throw new AppError("MODEL_NOT_ALLOWED"); + } + + const companyId = userJwt.company.id; + const PER_PAGE = perPage ?? 10; + + const filter = ModelsRepository.buildListFilter(companyId, { + query, + makerId, + categoryId, + status, + }); + const order = ModelsRepository.buildOrder(sort); + + const [records, totalRecords] = await Promise.all([ + getPaginatedRecords({ + table: models, + select: modelMinimalListSelect, + skip: (page - 1) * PER_PAGE, + take: PER_PAGE, + where: filter, + order, + joins: modelListJoins, + }), + getPaginatedCount({ + table: models, + where: filter, + }), + ]); + + if (totalRecords === 0) { + return response.status(200).send( + apiResponse({ + status: 200, + error: null, + message: "Models successfully retrieved.", + code: "list_models_success", + data: paginatedData({ + records: [], + pagination: { + total_records: 0, + total_pages: 0, + current_page: 1, + next_page: null, + prev_page: null, + }, + }), + }) + ); + } + + const total_pages = Math.ceil(totalRecords / PER_PAGE); + + if (page > total_pages) { + throw new AppError("MODEL_PAGE_OUT_OF_BOUNDS"); + } + + const next_page = + PER_PAGE * (page - 1) + records.length < totalRecords ? page + 1 : null; + + const recordsWithImages = await Promise.all( + (records as Record[]).map((r) => + ModelsRepository.attachPresignedImageUrls(r) + ) + ); + + return response.status(200).send( + apiResponse({ + status: 200, + error: null, + message: "Models successfully retrieved.", + code: "list_models_success", + data: paginatedData({ + records: recordsWithImages, + pagination: { + total_records: totalRecords, + total_pages, + current_page: page, + next_page, + prev_page: page > 1 ? page - 1 : null, + }, + }), + }) + ); + } + + /** + * Get a single model by slug with full details and presigned image URLs + * + * @param userJwt - Authenticated user JWT payload + * @param subdomain - Company subdomain + * @param slug - The model slug + * @param response - Fastify reply + */ + static async getModelBySlug({ + userJwt, + subdomain, + slug, + response, + }: { + userJwt: { id: string; company?: { id: string; subdomain: string } }; + subdomain: string; + slug: string; + response: FastifyReply; + }) { + if (!userJwt.company) { + throw new AppError("MODEL_COMPANY_NOT_FOUND"); + } + + if (userJwt.company.subdomain !== subdomain) { + throw new AppError("MODEL_NOT_ALLOWED"); + } + + const model = await ModelsRepository.queryModelBySlug( + slug, + userJwt.company.id + ); + + if (!model) { + throw new AppError("MODEL_NOT_FOUND"); + } + + const images = await ModelsRepository.queryModelImages(model.id as string); + + const [modelWithPresignedUrl, imagesWithPresignedUrls] = await Promise.all([ + ModelsRepository.attachPresignedImageUrls( + model as Record + ), + ModelsRepository.attachPresignedUrlsToImages( + images as Record[] + ), + ]); + + return response.status(200).send( + apiResponse({ + status: 200, + error: null, + code: "get_model_success", + message: "Model retrieved successfully.", + data: { ...modelWithPresignedUrl, images: imagesWithPresignedUrls }, + }) + ); + } +} diff --git a/apps/server/src/server.ts b/apps/server/src/server.ts index 4546008..82b5670 100644 --- a/apps/server/src/server.ts +++ b/apps/server/src/server.ts @@ -30,9 +30,12 @@ import { AppError } from "./core/lib/app-error"; import { apiResponse } from "./core/lib/response"; import { accountRoutes } from "./modules/account/routes"; import { authRoutes } from "./modules/auth/routes"; +import { categoriesRoutes } from "./modules/categories/routes"; import { companiesRoutes } from "./modules/companies/routes"; import { credentialsRoutes } from "./modules/credentials/routes"; import { employeesRoutes } from "./modules/employees/routes"; +import { makersRoutes } from "./modules/makers/routes"; +import { modelsRoutes } from "./modules/models/routes"; import { serviceOrdersRoutes } from "./modules/service-orders/routes"; import { uploadsRoutes } from "./modules/uploads/routes"; @@ -155,6 +158,11 @@ async function registerPlugins() { name: "Uploads", description: "Pre-signed uploads to Cloudflare R2.", }, + { + name: "Devices", + description: + "Device catalog management: categories, makers, and models.", + }, ], security: [], components: { @@ -212,6 +220,18 @@ async function registerPlugins() { prefix: "/companies/:subdomain/service-orders", }); + await server.register(categoriesRoutes, { + prefix: "/companies/:subdomain/categories", + }); + + await server.register(makersRoutes, { + prefix: "/companies/:subdomain/makers", + }); + + await server.register(modelsRoutes, { + prefix: "/companies/:subdomain/models", + }); + await server.register(uploadsRoutes, { prefix: "/uploads", }); @@ -227,7 +247,7 @@ async function registerPlugins() { server.swagger() ); - // Scalar UI — register after all routes so the spec is complete. + // Scalar UI: register after all routes so the spec is complete. await server.register(scalarUi, { routePrefix: "/docs", configuration: { diff --git a/apps/web/app/(public)/downtime/page.tsx b/apps/web/app/(public)/downtime/page.tsx index 73c4f01..f4ae3d2 100644 --- a/apps/web/app/(public)/downtime/page.tsx +++ b/apps/web/app/(public)/downtime/page.tsx @@ -28,8 +28,8 @@ export default function DowntimePage() { projeto interdisciplinar desenvolvido na FAM (Faculdade das Américas) - . Sua infraestrutura envolve diversos serviços — como o servidor da - API, banco de dados e sistema de cache — todos hospedados em uma{" "} + . Sua infraestrutura envolve diversos serviços: como o servidor da + API, banco de dados e sistema de cache: todos hospedados em uma{" "} VPS privada.

diff --git a/packages/db/src/schema/index.ts b/packages/db/src/schema/index.ts index 4cbaa08..4d8e44a 100644 --- a/packages/db/src/schema/index.ts +++ b/packages/db/src/schema/index.ts @@ -2,7 +2,9 @@ export * from "./clients"; export * from "./companies"; export * from "./employees"; export * from "./model-categories"; +export * from "./model-images"; export * from "./model-makers"; +export * from "./models"; export * from "./one-time-tokens"; export * from "./refresh-tokens"; export * from "./service-order-photos"; diff --git a/packages/db/src/schema/model-categories.ts b/packages/db/src/schema/model-categories.ts index ba5e27f..70ec4c3 100644 --- a/packages/db/src/schema/model-categories.ts +++ b/packages/db/src/schema/model-categories.ts @@ -1,15 +1,19 @@ import { createId } from "@paralleldrive/cuid2"; -import { mysqlTable, varchar } from "drizzle-orm/mysql-core"; +import { mysqlTable, text, varchar } from "drizzle-orm/mysql-core"; import { createSelectSchema } from "drizzle-zod"; +/** @description Device categories table — groups models by type (e.g. smartphone, tablet) */ export const modelCategories = mysqlTable("model_categories", { id: varchar("id", { length: 25 }) .$defaultFn(() => createId()) .primaryKey(), name: varchar("name", { length: 100 }).notNull(), - slug: varchar("slug", { length: 100 }).unique().notNull(), + slug: varchar("slug", { length: 100 }).notNull(), + url: varchar("url", { length: 255 }).notNull(), + imageUrl: text("image_url"), }); +/** @description Zod schema for selecting a category record */ export const modelCategorySelectSchema = createSelectSchema(modelCategories); export type CategoryInsert = typeof modelCategories.$inferInsert; export type CategorySelect = typeof modelCategories.$inferSelect; diff --git a/packages/db/src/schema/model-makers.ts b/packages/db/src/schema/model-makers.ts index a92588b..3e62246 100644 --- a/packages/db/src/schema/model-makers.ts +++ b/packages/db/src/schema/model-makers.ts @@ -1,22 +1,24 @@ import { createId } from "@paralleldrive/cuid2"; import { int, mysqlTable, timestamp, varchar } from "drizzle-orm/mysql-core"; import { createSelectSchema } from "drizzle-zod"; -import { z } from "zod"; +/** @description Device makers (brands) table — stores manufacturer/brand info */ export const modelMakers = mysqlTable("model_makers", { id: varchar("id", { length: 25 }) .$defaultFn(() => createId()) .primaryKey(), name: varchar("name", { length: 100 }).notNull(), - slug: varchar("slug", { length: 100 }).unique().notNull(), + slug: varchar("slug", { length: 100 }).notNull(), url: varchar("url", { length: 255 }).notNull(), deviceCount: int("device_count").notNull().default(0), pageCount: int("page_count"), - createdAt: timestamp("created_at").defaultNow().notNull(), + createdAt: timestamp("created_at").notNull().defaultNow(), }); -export const modelMakerSelectSchema = createSelectSchema(modelMakers, { - createdAt: z.coerce.date(), -}); -export type MakerInsert = typeof modelMakers.$inferInsert; -export type MakerSelect = typeof modelMakers.$inferSelect; +/** @description Zod schema for selecting a maker record */ +export const modelMakerSelectSchema = createSelectSchema(modelMakers); + +/** @deprecated Renamed to {@link modelMakers} */ +export const deviceBrands = modelMakers; +/** @deprecated Renamed to {@link modelMakerSelectSchema} */ +export const deviceBrandSelectSchema = modelMakerSelectSchema; diff --git a/packages/permissions/src/abilities.ts b/packages/permissions/src/abilities.ts index ab0e4dc..6388c07 100644 --- a/packages/permissions/src/abilities.ts +++ b/packages/permissions/src/abilities.ts @@ -21,11 +21,13 @@ const roleAbilities: Record = { permissions.serviceOrders.read, permissions.serviceOrders.update, permissions.serviceOrders.changeStatus, + permissions.devices.read, ], warehouse: [ ...baseEmployee, permissions.inventory.read, permissions.inventory.update, + permissions.devices.read, ], financial: [ ...baseEmployee, @@ -34,6 +36,7 @@ const roleAbilities: Record = { permissions.estimates.update, permissions.estimates.delete, permissions.estimates.sendToCustomer, + permissions.devices.read, ], manager: [ ...baseEmployee, @@ -52,6 +55,10 @@ const roleAbilities: Record = { permissions.estimates.sendToCustomer, permissions.employees.read, permissions.employees.create, + permissions.devices.read, + permissions.devices.create, + permissions.devices.update, + permissions.devices.delete, ], admin: [ ...baseEmployee, diff --git a/packages/schemas/package.json b/packages/schemas/package.json index b96c951..907449d 100644 --- a/packages/schemas/package.json +++ b/packages/schemas/package.json @@ -57,6 +57,10 @@ "./uploads": { "types": "./src/uploads.ts", "default": "./src/uploads.ts" + }, + "./models": { + "types": "./src/models.ts", + "default": "./src/models.ts" } }, "devDependencies": { diff --git a/packages/schemas/src/models.ts b/packages/schemas/src/models.ts new file mode 100644 index 0000000..f2e92ad --- /dev/null +++ b/packages/schemas/src/models.ts @@ -0,0 +1,43 @@ +import { z } from "zod"; +import { getPaginatedDataSchema } from "./utils"; + +/** @description Query schema for listing categories — optional name filter */ +export const getModelCategoriesQuerySchema = z.object({ + query: z.string().optional(), +}); + +/** @description Params schema for getting a category by slug */ +export const getModelCategoryParamsSchema = z.object({ + slug: z.string().min(1), +}); + +/** @description Query schema for listing makers — pagination, sorting, and optional name filter */ +export const getModelMakersQuerySchema = getPaginatedDataSchema.extend({ + sort: z.enum(["newer", "older", "name", "most_devices"]).optional(), +}); + +/** @description Params schema for getting a maker by slug */ +export const getModelMakerParamsSchema = z.object({ + slug: z.string().min(1), +}); + +/** @description Enum of valid device model release statuses */ +export const modelStatuses = z.enum([ + "Available", + "Discontinued", + "Cancelled", + "Rumored", +]); + +/** @description Query schema for listing models — pagination, fulltext search, filters, and sorting */ +export const getModelsQuerySchema = getPaginatedDataSchema.extend({ + makerId: z.string().cuid2().optional(), + categoryId: z.string().cuid2().optional(), + status: modelStatuses.optional(), + sort: z.enum(["newer", "older", "name"]).optional(), +}); + +/** @description Params schema for getting a model by slug */ +export const getModelBySlugParamsSchema = z.object({ + slug: z.string().min(1), +}); From 2a1a27639696bd13b8457235c1cf04c8fc353b94 Mon Sep 17 00:00:00 2001 From: Ricardo Amorim <102877738+risixdzn@users.noreply.github.com> Date: Sun, 31 May 2026 17:36:49 -0300 Subject: [PATCH 6/9] feat(Devices): Create, update and delete models for your company --- apps/server/src/config/r2.ts | 9 +- .../src/core/docs/models/models.docs.ts | 196 +++++++++- apps/server/src/core/docs/uploads.docs.ts | 37 ++ .../src/modules/models/controllers/index.ts | 103 ++++++ .../server/src/modules/models/errors/index.ts | 15 + .../src/modules/models/repositories/index.ts | 148 +++++++- .../server/src/modules/models/routes/index.ts | 125 +++++++ .../src/modules/models/services/index.ts | 334 ++++++++++++++++++ .../src/modules/uploads/controllers/index.ts | 21 +- .../src/modules/uploads/repositories/index.ts | 51 +++ .../src/modules/uploads/routes/index.ts | 26 +- .../src/modules/uploads/services/index.ts | 42 +++ packages/constants/package.json | 4 + packages/constants/src/slug.ts | 13 + packages/schemas/src/models.ts | 72 ++++ packages/schemas/src/uploads.ts | 10 + 16 files changed, 1199 insertions(+), 7 deletions(-) create mode 100644 packages/constants/src/slug.ts diff --git a/apps/server/src/config/r2.ts b/apps/server/src/config/r2.ts index 6c3f995..23d27c4 100644 --- a/apps/server/src/config/r2.ts +++ b/apps/server/src/config/r2.ts @@ -54,10 +54,13 @@ export function isAllowedCompanyPhotoUrl(url: string, companyId: string) { /** * Generate a presigned GET URL for reading an object from R2 * - * @param key - The R2 object key - * @returns A presigned URL valid for 24 hours + * @param key - The R2 object key (nullable) + * @returns A presigned URL valid for 24 hours, or null if key is empty */ -export async function generatePresignedGetUrl(key: string): Promise { +export async function generatePresignedGetUrl( + key: string | null | undefined +): Promise { + if (!key) return null; const command = new GetObjectCommand({ Bucket: r2Bucket, Key: key, diff --git a/apps/server/src/core/docs/models/models.docs.ts b/apps/server/src/core/docs/models/models.docs.ts index 59f637c..3b81180 100644 --- a/apps/server/src/core/docs/models/models.docs.ts +++ b/apps/server/src/core/docs/models/models.docs.ts @@ -1,5 +1,10 @@ import { getCompanyNestedDataSchema } from "@fixr/schemas/companies"; -import { getModelsQuerySchema } from "@fixr/schemas/models"; +import { + createModelBodySchema, + createModelImageBodySchema, + getModelsQuerySchema, + patchModelBodySchema, +} from "@fixr/schemas/models"; import { paginatedDataSchema } from "@fixr/schemas/utils"; import type { FastifySchema } from "fastify"; import { z } from "zod"; @@ -195,8 +200,197 @@ Returns all spec fields, related maker and category, and model images with presi security: [{ JWT: [] }], }; +const createModelSchema: FastifySchema = { + tags: ["Devices"], + summary: "Create device model", + description: ` +**Creates a new device model record.** + +Only company-specific models can be created. +- \`name\` and \`makerId\` are required. +- \`slug\` is auto-generated from \`name\` if not provided. +- All spec fields are optional and can be filled later via PATCH. +`, + params: getCompanyNestedDataSchema, + body: createModelBodySchema, + response: { + 201: zodResponseSchema({ + status: 201, + error: null, + message: "Model created successfully.", + code: "create_model_success", + data: z.object({ id: z.string(), name: z.string(), slug: z.string() }), + }).describe("Model created successfully."), + 409: zodResponseSchema({ + status: 409, + error: "Conflict", + code: "model_slug_conflict", + message: "A model with this slug already exists.", + data: null, + }).describe("Slug already exists."), + 403: zodResponseSchema({ + status: 403, + error: "Forbidden", + code: "not_allowed", + message: "You are not authorized to access this company.", + data: null, + }).describe("Not allowed to access this company."), + }, + security: [{ JWT: [] }], +}; + +const patchModelSchema: FastifySchema = { + tags: ["Devices"], + summary: "Update device model (partial)", + description: ` +**Partially updates a device model record.** + +All fields are optional — only provided fields will be updated. +Returns the full model detail with presigned image URLs. +`, + params: z.object({ subdomain: z.string(), modelId: z.string() }), + body: patchModelBodySchema, + response: { + 200: zodResponseSchema({ + status: 200, + error: null, + message: "Model updated successfully.", + code: "patch_model_success", + data: modelDetailRecordSchema, + }).describe("Model updated successfully."), + 404: zodResponseSchema({ + status: 404, + error: "Not Found", + code: "model_not_found", + message: "Model not found.", + data: null, + }).describe("Model not found."), + 403: zodResponseSchema({ + status: 403, + error: "Forbidden", + code: "not_allowed", + message: "You are not authorized to access this company.", + data: null, + }).describe("Not allowed to access this company."), + }, + security: [{ JWT: [] }], +}; + +const deleteModelSchema: FastifySchema = { + tags: ["Devices"], + summary: "Delete device model", + description: ` +**Deletes a device model and its associated images.** + +Removes all related \`model_images\` records and deletes the uploaded files from storage. +`, + params: z.object({ subdomain: z.string(), modelId: z.string() }), + response: { + 200: zodResponseSchema({ + status: 200, + error: null, + message: "Model deleted successfully.", + code: "delete_model_success", + data: null, + }).describe("Model deleted successfully."), + 404: zodResponseSchema({ + status: 404, + error: "Not Found", + code: "model_not_found", + message: "Model not found.", + data: null, + }).describe("Model not found."), + 403: zodResponseSchema({ + status: 403, + error: "Forbidden", + code: "not_allowed", + message: "You are not authorized to access this company.", + data: null, + }).describe("Not allowed to access this company."), + }, + security: [{ JWT: [] }], +}; + +const createModelImageSchema: FastifySchema = { + tags: ["Devices"], + summary: "Assign an uploaded image to a model", + description: ` +**Creates a model image record, linking an uploaded file to a device model.** + +Provide the \`r2Key\` (and optional \`originalUrl\`) returned from the presign upload endpoint. Returns the created model image with a presigned URL. +`, + params: z.object({ subdomain: z.string(), modelId: z.string() }), + body: createModelImageBodySchema, + response: { + 201: zodResponseSchema({ + status: 201, + error: null, + message: "Model image created successfully.", + code: "create_model_image_success", + data: modelImageRecordSchema, + }).describe("Model image created."), + 404: zodResponseSchema({ + status: 404, + error: "Not Found", + code: "model_not_found", + message: "Model not found.", + data: null, + }).describe("Model not found."), + 403: zodResponseSchema({ + status: 403, + error: "Forbidden", + code: "not_allowed", + message: "You are not authorized to access this company.", + data: null, + }).describe("Not allowed."), + }, + security: [{ JWT: [] }], +}; + +const deleteModelImageSchema: FastifySchema = { + tags: ["Devices"], + summary: "Delete a model image", + description: ` +**Deletes a model image record and removes the uploaded file from storage.** +`, + params: z.object({ + subdomain: z.string(), + modelId: z.string(), + imageId: z.string(), + }), + response: { + 200: zodResponseSchema({ + status: 200, + error: null, + message: "Model image deleted successfully.", + code: "delete_model_image_success", + data: null, + }).describe("Model image deleted."), + 404: zodResponseSchema({ + status: 404, + error: "Not Found", + code: "model_image_not_found", + message: "Model image not found.", + data: null, + }).describe("Image not found."), + 403: zodResponseSchema({ + status: 403, + error: "Forbidden", + code: "not_allowed", + message: "You are not authorized to access this company.", + data: null, + }).describe("Not allowed."), + }, + security: [{ JWT: [] }], +}; + /** @description OpenAPI schemas for the models module */ export const modelsDocs = { listModelsSchema, getModelBySlugSchema, + createModelSchema, + patchModelSchema, + deleteModelSchema, + createModelImageSchema, + deleteModelImageSchema, }; diff --git a/apps/server/src/core/docs/uploads.docs.ts b/apps/server/src/core/docs/uploads.docs.ts index 63b1d9e..1f435ba 100644 --- a/apps/server/src/core/docs/uploads.docs.ts +++ b/apps/server/src/core/docs/uploads.docs.ts @@ -1,4 +1,5 @@ import { + createModelImageUploadPresignSchema, createUploadPresignSchema, uploadPresignResponseSchema, } from "@fixr/schemas/uploads"; @@ -42,6 +43,42 @@ The request accepts file metadata (\`fileName\`, \`contentType\`, \`size\`) and security: [{ JWT: [] }], }; +const createModelImagePresignSchemaDoc: FastifySchema = { + tags: ["Uploads"], + summary: "Generate pre-signed upload URL for a model image", + description: ` +**Generates a pre-signed URL for uploading a model image to Cloudflare R2** + +Returns a time-limited presigned PUT URL and an upload ID. Upload the file directly to R2 using the returned URL, then use \`POST /{modelId}/images\` in the devices module to assign it to a model. +`, + body: createModelImageUploadPresignSchema, + response: { + 200: zodResponseSchema({ + status: 200, + error: null, + message: "Upload URL generated successfully.", + code: "create_model_image_presign_success", + data: uploadPresignResponseSchema, + }).describe("Presigned URL generated."), + 403: zodResponseSchema({ + status: 403, + error: "Forbidden", + code: "not_allowed", + message: "You are not authorized to perform this action.", + data: null, + }), + 404: zodResponseSchema({ + status: 404, + error: "Not Found", + code: "company_not_found", + message: "There's no company associated with this account.", + data: null, + }), + }, + security: [{ JWT: [] }], +}; + export const uploadsDocs = { createUploadPresignSchema: createUploadPresignSchemaDoc, + createModelImagePresignSchema: createModelImagePresignSchemaDoc, }; diff --git a/apps/server/src/modules/models/controllers/index.ts b/apps/server/src/modules/models/controllers/index.ts index 775f5c2..16134ba 100644 --- a/apps/server/src/modules/models/controllers/index.ts +++ b/apps/server/src/modules/models/controllers/index.ts @@ -1,7 +1,11 @@ import type { jwtPayload } from "@fixr/schemas/auth"; import type { + createModelBodySchema, + createModelImageBodySchema, getModelBySlugParamsSchema, getModelsQuerySchema, + modelIdParamsSchema, + patchModelBodySchema, } from "@fixr/schemas/models"; import type { FastifyReply } from "fastify"; import type { z } from "zod"; @@ -59,4 +63,103 @@ export class ModelsController { response, }); } + + /** @description Create a new model */ + static createModel({ + userJwt, + subdomain, + data, + response, + }: { + userJwt: z.infer; + subdomain: string; + data: z.infer; + response: FastifyReply; + }) { + return ModelsService.createModel({ userJwt, subdomain, data, response }); + } + + /** @description Partially update a model */ + static patchModel({ + userJwt, + subdomain, + modelId, + data, + response, + }: { + userJwt: z.infer; + subdomain: string; + modelId: string; + data: Record; + response: FastifyReply; + } & z.infer) { + return ModelsService.patchModel({ + userJwt, + subdomain, + modelId, + data, + response, + }); + } + + /** @description Delete a model */ + static deleteModel({ + userJwt, + subdomain, + modelId, + response, + }: { + userJwt: z.infer; + subdomain: string; + modelId: string; + response: FastifyReply; + } & z.infer) { + return ModelsService.deleteModel({ userJwt, subdomain, modelId, response }); + } + + /** @description Assign an uploaded image to a model */ + static createModelImage({ + userJwt, + subdomain, + modelId, + data, + response, + }: { + userJwt: z.infer; + subdomain: string; + modelId: string; + data: z.infer; + response: FastifyReply; + }) { + return ModelsService.createModelImage({ + userJwt, + subdomain, + modelId, + data, + response, + }); + } + + /** @description Delete a model image */ + static deleteModelImage({ + userJwt, + subdomain, + modelId, + imageId, + response, + }: { + userJwt: z.infer; + subdomain: string; + modelId: string; + imageId: string; + response: FastifyReply; + }) { + return ModelsService.deleteModelImage({ + userJwt, + subdomain, + modelId, + imageId, + response, + }); + } } diff --git a/apps/server/src/modules/models/errors/index.ts b/apps/server/src/modules/models/errors/index.ts index a908710..a070579 100644 --- a/apps/server/src/modules/models/errors/index.ts +++ b/apps/server/src/modules/models/errors/index.ts @@ -22,4 +22,19 @@ export const modelsErrors = defineErrors({ message: "You are not authorized to access this company.", status: 403, }, + MODEL_SLUG_CONFLICT: { + code: "model_slug_conflict", + message: "A model with this slug already exists.", + status: 409, + }, + MODEL_MAKER_NOT_FOUND: { + code: "maker_not_found", + message: "The specified maker does not exist.", + status: 404, + }, + MODEL_IMAGE_NOT_FOUND: { + code: "model_image_not_found", + message: "Model image not found.", + status: 404, + }, }); diff --git a/apps/server/src/modules/models/repositories/index.ts b/apps/server/src/modules/models/repositories/index.ts index d2d50db..6a24a0c 100644 --- a/apps/server/src/modules/models/repositories/index.ts +++ b/apps/server/src/modules/models/repositories/index.ts @@ -1,3 +1,4 @@ +import { DeleteObjectCommand } from "@aws-sdk/client-s3"; import { and, asc, db, desc, eq, or, type SQL, sql } from "@fixr/db/connection"; import { modelCategories, @@ -5,7 +6,11 @@ import { modelMakers, models, } from "@fixr/db/schema"; -import { generatePresignedGetUrl } from "../../../config/r2"; +import { + generatePresignedGetUrl, + r2Bucket, + r2Client, +} from "../../../config/r2"; const FTS_OPERATOR_REGEX = /[+\-*~()<>@]/; const WHITESPACE_REGEX = /\s+/; @@ -241,4 +246,145 @@ export class ModelsRepository { }) ); } + + /** + * Check if a slug already exists for a given company + * + * @param slug - The slug to check + * @param companyId - Company ID for scoping + * @returns The matching model or undefined + */ + static async queryBySlugAndCompany(slug: string, companyId: string) { + const [model] = await db + .select({ id: models.id }) + .from(models) + .where( + and( + eq(models.slug, slug), + or(eq(models.companyId, companyId), sql`${models.companyId} IS NULL`) + ) + ) + .limit(1); + return model; + } + + /** + * Check if a maker exists by ID + * + * @param makerId - The maker ID + * @returns The maker or undefined + */ + static async queryMakerById(makerId: string) { + const [maker] = await db + .select({ id: modelMakers.id }) + .from(modelMakers) + .where(eq(modelMakers.id, makerId)) + .limit(1); + return maker; + } + + /** + * Insert a new model record + * + * @param data - The model data to insert + */ + static async insertModel(data: typeof models.$inferInsert) { + await db.insert(models).values(data); + } + + /** + * Insert a model image record + * + * @param data - The model image data + * @returns The created model image + */ + static async insertModelImage(data: typeof modelImages.$inferInsert) { + const id = data.id as string; + await db.insert(modelImages).values(data); + const [created] = await db + .select() + .from(modelImages) + .where(eq(modelImages.id, id)) + .limit(1); + return created; + } + + /** + * Delete a single model image record + * + * @param imageId - The image ID + */ + static async deleteModelImageRecord(imageId: string) { + await db.delete(modelImages).where(eq(modelImages.id, imageId)); + } + + /** + * Get all R2 keys associated with a model (model images + the model's own imageLocalPath) + * + * @param modelId - The model ID + * @returns Array of R2 keys + */ + static async queryR2KeysByModel(modelId: string) { + const [modelResult, imageKeys] = await Promise.all([ + db + .select({ key: models.imageLocalPath }) + .from(models) + .where(eq(models.id, modelId)) + .limit(1), + db + .select({ key: modelImages.r2Key }) + .from(modelImages) + .where(eq(modelImages.modelId, modelId)), + ]); + + const keys: string[] = []; + if (modelResult[0]?.key) { + keys.push(modelResult[0].key); + } + for (const img of imageKeys) { + if (img.key) { + keys.push(img.key); + } + } + return keys; + } + + /** + * Delete an R2 object by key + * + * @param key - The R2 object key + */ + static async deleteR2Object(key: string) { + await r2Client.send( + new DeleteObjectCommand({ + Bucket: r2Bucket, + Key: key, + }) + ); + } + + /** + * Update a model record (partial) + * + * @param id - The model ID + * @param data - The fields to update + */ + static async updateModel( + id: string, + data: Partial + ) { + await db.update(models).set(data).where(eq(models.id, id)); + } + + /** + * Delete a model record and its associated images + * + * @param id - The model ID + */ + static async deleteModel(id: string) { + const keys = await ModelsRepository.queryR2KeysByModel(id); + await Promise.all(keys.map((k) => ModelsRepository.deleteR2Object(k))); + await db.delete(modelImages).where(eq(modelImages.modelId, id)); + await db.delete(models).where(eq(models.id, id)); + } } diff --git a/apps/server/src/modules/models/routes/index.ts b/apps/server/src/modules/models/routes/index.ts index 846e477..18aecd7 100644 --- a/apps/server/src/modules/models/routes/index.ts +++ b/apps/server/src/modules/models/routes/index.ts @@ -2,8 +2,13 @@ import { permissions } from "@fixr/permissions"; import type { userJWT } from "@fixr/schemas/auth"; import { getCompanyNestedDataSchema } from "@fixr/schemas/companies"; import { + createModelBodySchema, + createModelImageBodySchema, getModelBySlugParamsSchema, getModelsQuerySchema, + modelIdParamsSchema, + modelImageParamsSchema, + patchModelBodySchema, } from "@fixr/schemas/models"; import type { z } from "zod"; import { modelsDocs } from "../../../core/docs/models/models.docs"; @@ -60,4 +65,124 @@ export function modelsRoutes(fastify: FastifyTypedInstance) { }); }) ); + + fastify.post( + "/", + { + preHandler: [ + authenticateEmployee, + requirePermission(permissions.devices.create), + ], + schema: modelsDocs.createModelSchema, + }, + withErrorHandler(async (request, response) => { + const userJwt = request.user as z.infer; + const data = createModelBodySchema.parse(request.body); + const { subdomain } = getCompanyNestedDataSchema.parse(request.params); + + await ModelsController.createModel({ + userJwt, + subdomain, + data, + response, + }); + }) + ); + + fastify.patch( + "/:modelId", + { + preHandler: [ + authenticateEmployee, + requirePermission(permissions.devices.update), + ], + schema: modelsDocs.patchModelSchema, + }, + withErrorHandler(async (request, response) => { + const userJwt = request.user as z.infer; + const { modelId } = modelIdParamsSchema.parse(request.params); + const data = patchModelBodySchema.parse(request.body); + const { subdomain } = getCompanyNestedDataSchema.parse(request.params); + + await ModelsController.patchModel({ + userJwt, + subdomain, + modelId, + data, + response, + }); + }) + ); + + fastify.delete( + "/:modelId", + { + preHandler: [ + authenticateEmployee, + requirePermission(permissions.devices.delete), + ], + schema: modelsDocs.deleteModelSchema, + }, + withErrorHandler(async (request, response) => { + const userJwt = request.user as z.infer; + const { modelId } = modelIdParamsSchema.parse(request.params); + const { subdomain } = getCompanyNestedDataSchema.parse(request.params); + + await ModelsController.deleteModel({ + userJwt, + subdomain, + modelId, + response, + }); + }) + ); + + fastify.post( + "/:modelId/images", + { + preHandler: [ + authenticateEmployee, + requirePermission(permissions.devices.update), + ], + schema: modelsDocs.createModelImageSchema, + }, + withErrorHandler(async (request, response) => { + const userJwt = request.user as z.infer; + const { modelId } = modelIdParamsSchema.parse(request.params); + const { subdomain } = getCompanyNestedDataSchema.parse(request.params); + const data = createModelImageBodySchema.parse(request.body); + + await ModelsController.createModelImage({ + userJwt, + subdomain, + modelId, + data, + response, + }); + }) + ); + + fastify.delete( + "/:modelId/images/:imageId", + { + preHandler: [ + authenticateEmployee, + requirePermission(permissions.devices.update), + ], + schema: modelsDocs.deleteModelImageSchema, + }, + withErrorHandler(async (request, response) => { + const userJwt = request.user as z.infer; + const { modelId, imageId } = modelImageParamsSchema.parse(request.params); + const { subdomain } = getCompanyNestedDataSchema.parse(request.params); + + await ModelsController.deleteModelImage({ + userJwt, + subdomain, + modelId, + imageId, + response, + }); + }) + ); } diff --git a/apps/server/src/modules/models/services/index.ts b/apps/server/src/modules/models/services/index.ts index 71fdd7c..88f60f6 100644 --- a/apps/server/src/modules/models/services/index.ts +++ b/apps/server/src/modules/models/services/index.ts @@ -1,5 +1,12 @@ +import { slugify } from "@fixr/constants/slug"; import { models } from "@fixr/db/schema"; +import type { + createModelBodySchema, + createModelImageBodySchema, +} from "@fixr/schemas/models"; +import { createId } from "@paralleldrive/cuid2"; import type { FastifyReply } from "fastify"; +import type { z } from "zod"; import { AppError } from "../../../core/lib/app-error"; import { getPaginatedCount, @@ -14,6 +21,22 @@ import { /** @description Business logic for device models */ export class ModelsService { + private static buildCreateModelValues( + data: z.infer, + modelId: string, + companyId: string, + slug: string + ): typeof models.$inferInsert { + return { + id: modelId, + slug, + url: `/models/${slug}`, + companyId, + ...Object.fromEntries( + Object.entries(data).filter(([_, v]) => v !== undefined) + ), + } as typeof models.$inferInsert; + } /** * List models with pagination, fulltext search, and filters * @@ -199,4 +222,315 @@ export class ModelsService { }) ); } + + /** + * Create a new model + * + * @param userJwt - Authenticated user JWT payload + * @param subdomain - Company subdomain + * @param data - The model data + * @param response - Fastify reply + */ + static async createModel({ + userJwt, + subdomain, + data, + response, + }: { + userJwt: { id: string; company?: { id: string; subdomain: string } }; + subdomain: string; + data: z.infer; + response: FastifyReply; + }) { + if (!userJwt.company) { + throw new AppError("MODEL_COMPANY_NOT_FOUND"); + } + + if (userJwt.company.subdomain !== subdomain) { + throw new AppError("MODEL_NOT_ALLOWED"); + } + + const maker = await ModelsRepository.queryMakerById(data.makerId); + + if (!maker) { + throw new AppError("MODEL_MAKER_NOT_FOUND"); + } + + const slug = slugify(data.name); + + const existing = await ModelsRepository.queryBySlugAndCompany( + slug, + userJwt.company.id + ); + + if (existing) { + throw new AppError("MODEL_SLUG_CONFLICT"); + } + + const modelId = createId(); + const companyId = userJwt.company.id; + + const values = ModelsService.buildCreateModelValues( + data, + modelId, + companyId, + slug + ); + await ModelsRepository.insertModel(values); + + return response.status(201).send( + apiResponse({ + status: 201, + error: null, + code: "create_model_success", + message: "Model created successfully.", + data: { id: modelId, name: data.name, slug }, + }) + ); + } + + /** + * Partially update a model + * + * @param userJwt - Authenticated user JWT payload + * @param subdomain - Company subdomain + * @param modelId - The model ID + * @param data - The fields to update + * @param response - Fastify reply + */ + static async patchModel({ + userJwt, + subdomain, + modelId, + data, + response, + }: { + userJwt: { id: string; company?: { id: string; subdomain: string } }; + subdomain: string; + modelId: string; + data: Record; + response: FastifyReply; + }) { + if (!userJwt.company) { + throw new AppError("MODEL_COMPANY_NOT_FOUND"); + } + if (userJwt.company.subdomain !== subdomain) { + throw new AppError("MODEL_NOT_ALLOWED"); + } + + const model = await ModelsRepository.queryModelBySlug( + modelId, + userJwt.company.id + ); + + if (!model) { + throw new AppError("MODEL_NOT_FOUND"); + } + + const updateData: Record = {}; + + for (const [key, value] of Object.entries(data)) { + updateData[key] = value ?? null; + } + + if (Object.keys(updateData).length > 0) { + await ModelsRepository.updateModel(modelId, updateData); + } + + const updated = await ModelsRepository.queryModelBySlug( + model.id as string, + userJwt.company.id + ); + + const images = await ModelsRepository.queryModelImages(model.id as string); + + const [modelWithPresignedUrl, imagesWithPresignedUrls] = await Promise.all([ + ModelsRepository.attachPresignedImageUrls( + (updated ?? model) as Record + ), + ModelsRepository.attachPresignedUrlsToImages( + images as Record[] + ), + ]); + + return response.status(200).send( + apiResponse({ + status: 200, + error: null, + code: "patch_model_success", + message: "Model updated successfully.", + data: { ...modelWithPresignedUrl, images: imagesWithPresignedUrls }, + }) + ); + } + + /** + * Delete a model + * + * @param userJwt - Authenticated user JWT payload + * @param subdomain - Company subdomain + * @param modelId - The model ID + * @param response - Fastify reply + */ + static async deleteModel({ + userJwt, + subdomain, + modelId, + response, + }: { + userJwt: { id: string; company?: { id: string; subdomain: string } }; + subdomain: string; + modelId: string; + response: FastifyReply; + }) { + if (!userJwt.company) { + throw new AppError("MODEL_COMPANY_NOT_FOUND"); + } + if (userJwt.company.subdomain !== subdomain) { + throw new AppError("MODEL_NOT_ALLOWED"); + } + + const model = await ModelsRepository.queryModelBySlug( + modelId, + userJwt.company.id + ); + if (!model) { + throw new AppError("MODEL_NOT_FOUND"); + } + + await ModelsRepository.deleteModel(model.id as string); + + return response.status(200).send( + apiResponse({ + status: 200, + error: null, + code: "delete_model_success", + message: "Model deleted successfully.", + data: null, + }) + ); + } + + /** + * Assign an uploaded image to a model + * + * @param userJwt - Authenticated user JWT payload + * @param subdomain - Company subdomain + * @param modelId - The model ID + * @param data - The image data + * @param response - Fastify reply + */ + static async createModelImage({ + userJwt, + subdomain, + modelId, + data, + response, + }: { + userJwt: { id: string; company?: { id: string; subdomain: string } }; + subdomain: string; + modelId: string; + data: z.infer; + response: FastifyReply; + }) { + if (!userJwt.company) { + throw new AppError("MODEL_COMPANY_NOT_FOUND"); + } + if (userJwt.company.subdomain !== subdomain) { + throw new AppError("MODEL_NOT_ALLOWED"); + } + + const model = await ModelsRepository.queryModelBySlug( + modelId, + userJwt.company.id + ); + if (!model) { + throw new AppError("MODEL_NOT_FOUND"); + } + + const imageId = createId(); + const image = await ModelsRepository.insertModelImage({ + id: imageId, + modelId: model.id as string, + r2Key: data.r2Key, + originalUrl: data.originalUrl ?? null, + isPrimary: data.isPrimary ?? false, + variant: data.variant ?? null, + position: data.position ?? 0, + }); + + const [imageWithPresignedUrl] = + await ModelsRepository.attachPresignedUrlsToImages([ + image as Record, + ]); + + return response.status(201).send( + apiResponse({ + status: 201, + error: null, + code: "create_model_image_success", + message: "Model image created successfully.", + data: imageWithPresignedUrl, + }) + ); + } + + /** + * Delete a model image + * + * @param userJwt - Authenticated user JWT payload + * @param subdomain - Company subdomain + * @param modelId - The model ID + * @param imageId - The image ID + * @param response - Fastify reply + */ + static async deleteModelImage({ + userJwt, + subdomain, + modelId, + imageId, + response, + }: { + userJwt: { id: string; company?: { id: string; subdomain: string } }; + subdomain: string; + modelId: string; + imageId: string; + response: FastifyReply; + }) { + if (!userJwt.company) { + throw new AppError("MODEL_COMPANY_NOT_FOUND"); + } + if (userJwt.company.subdomain !== subdomain) { + throw new AppError("MODEL_NOT_ALLOWED"); + } + + const model = await ModelsRepository.queryModelBySlug( + modelId, + userJwt.company.id + ); + if (!model) { + throw new AppError("MODEL_NOT_FOUND"); + } + + const images = await ModelsRepository.queryModelImages(model.id as string); + const image = images.find((img) => img.id === imageId); + if (!image) { + throw new AppError("MODEL_IMAGE_NOT_FOUND"); + } + + if (image.r2Key) { + await ModelsRepository.deleteR2Object(image.r2Key); + } + await ModelsRepository.deleteModelImageRecord(imageId); + + return response.status(200).send( + apiResponse({ + status: 200, + error: null, + code: "delete_model_image_success", + message: "Model image deleted successfully.", + data: null, + }) + ); + } } diff --git a/apps/server/src/modules/uploads/controllers/index.ts b/apps/server/src/modules/uploads/controllers/index.ts index 48e0b5d..87d66ea 100644 --- a/apps/server/src/modules/uploads/controllers/index.ts +++ b/apps/server/src/modules/uploads/controllers/index.ts @@ -1,5 +1,8 @@ import type { jwtPayload } from "@fixr/schemas/auth"; -import type { createUploadPresignSchema } from "@fixr/schemas/uploads"; +import type { + createModelImageUploadPresignSchema, + createUploadPresignSchema, +} from "@fixr/schemas/uploads"; import type { FastifyReply } from "fastify"; import type { z } from "zod"; import { UploadsService } from "../services"; @@ -21,4 +24,20 @@ export class UploadsController { response, }); } + + static createModelImagePresign({ + userJwt, + data, + response, + }: { + userJwt: z.infer; + data: z.infer; + response: FastifyReply; + }) { + return UploadsService.createModelImagePresign({ + userJwt, + data, + response, + }); + } } diff --git a/apps/server/src/modules/uploads/repositories/index.ts b/apps/server/src/modules/uploads/repositories/index.ts index 1596c7d..a11215c 100644 --- a/apps/server/src/modules/uploads/repositories/index.ts +++ b/apps/server/src/modules/uploads/repositories/index.ts @@ -5,6 +5,7 @@ import { uploads } from "@fixr/db/schema"; import type { createUploadPresignSchema } from "@fixr/schemas/uploads"; import type { z } from "zod"; import { + buildModelObjectKey, buildObjectPublicUrl, buildUploadObjectKey, r2Bucket, @@ -58,4 +59,54 @@ export class UploadsRepository { expiresIn: r2PresignExpiresIn, }; } + + static async createModelPresignedUpload({ + companyId, + employeeId, + fileName, + contentType, + size, + }: { + companyId: string; + employeeId: string; + fileName: string; + contentType: string; + size: number; + }) { + const key = buildModelObjectKey({ companyId, fileName }); + const url = buildObjectPublicUrl(key); + + const command = new PutObjectCommand({ + Bucket: r2Bucket, + Key: key, + ContentType: contentType, + ContentLength: size, + }); + + const uploadUrl = await getSignedUrl(r2Client, command, { + expiresIn: r2PresignExpiresIn, + }); + + const [record] = await db + .insert(uploads) + .values({ + companyId, + employeeId, + key, + url, + fileName, + contentType, + sizeInBytes: size, + status: "pending", + }) + .$returningId(); + + return { + id: record.id, + uploadUrl, + key, + url, + expiresIn: r2PresignExpiresIn, + }; + } } diff --git a/apps/server/src/modules/uploads/routes/index.ts b/apps/server/src/modules/uploads/routes/index.ts index 8bf4698..ad6fe85 100644 --- a/apps/server/src/modules/uploads/routes/index.ts +++ b/apps/server/src/modules/uploads/routes/index.ts @@ -1,6 +1,9 @@ import { permissions } from "@fixr/permissions"; import type { userJWT } from "@fixr/schemas/auth"; -import { createUploadPresignSchema } from "@fixr/schemas/uploads"; +import { + createModelImageUploadPresignSchema, + createUploadPresignSchema, +} from "@fixr/schemas/uploads"; import type { z } from "zod"; import { uploadsDocs } from "../../../core/docs/uploads.docs"; import type { FastifyTypedInstance } from "../../../core/interfaces/fastify"; @@ -30,4 +33,25 @@ export function uploadsRoutes(fastify: FastifyTypedInstance) { }); }) ); + + fastify.post( + "/models/presign", + { + preHandler: [ + authenticateEmployee, + requirePermission(permissions.devices.update), + ], + schema: uploadsDocs.createModelImagePresignSchema, + }, + withErrorHandler(async (request, response) => { + const userJwt = request.user as z.infer; + const body = createModelImageUploadPresignSchema.parse(request.body); + + await UploadsController.createModelImagePresign({ + userJwt, + data: body, + response, + }); + }) + ); } diff --git a/apps/server/src/modules/uploads/services/index.ts b/apps/server/src/modules/uploads/services/index.ts index b390bb3..ac0846f 100644 --- a/apps/server/src/modules/uploads/services/index.ts +++ b/apps/server/src/modules/uploads/services/index.ts @@ -48,4 +48,46 @@ export class UploadsService { }) ); } + + static async createModelImagePresign({ + userJwt, + data, + response, + }: { + userJwt: z.infer; + data: { fileName: string; contentType: string; size: number }; + response: FastifyReply; + }) { + if (!userJwt.company) { + throw new AppError("UPLOAD_COMPANY_NOT_FOUND"); + } + + const [employee] = await db + .select() + .from(employees) + .where(eq(employees.userId, userJwt.id)) + .limit(1); + + if (!employee || employee.companyId !== userJwt.company.id) { + throw new AppError("UPLOAD_COMPANY_NOT_FOUND"); + } + + const presign = await UploadsRepository.createModelPresignedUpload({ + companyId: userJwt.company.id, + employeeId: employee.id, + fileName: data.fileName, + contentType: data.contentType, + size: data.size, + }); + + return response.status(200).send( + apiResponse({ + status: 200, + error: null, + code: "create_model_image_presign_success", + message: "Upload URL generated successfully.", + data: presign, + }) + ); + } } diff --git a/packages/constants/package.json b/packages/constants/package.json index 3645f15..31731f9 100644 --- a/packages/constants/package.json +++ b/packages/constants/package.json @@ -33,6 +33,10 @@ "./enforcements": { "types": "./src/enforcements.ts", "default": "./src/enforcements.ts" + }, + "./slug": { + "types": "./src/slug.ts", + "default": "./src/slug.ts" } }, "devDependencies": { diff --git a/packages/constants/src/slug.ts b/packages/constants/src/slug.ts new file mode 100644 index 0000000..0240373 --- /dev/null +++ b/packages/constants/src/slug.ts @@ -0,0 +1,13 @@ +const SLUGIFY_SPACE_REGEX = /\s+/g; +const SLUGIFY_SPECIAL_REGEX = /[^\w-]/g; +const SLUGIFY_DUPLICATE_DASHES = /-+/g; +const SLUGIFY_TRIM_DASHES = /^-|-$/g; + +export function slugify(text: string): string { + return text + .toLowerCase() + .replace(SLUGIFY_SPACE_REGEX, "-") + .replace(SLUGIFY_SPECIAL_REGEX, "") + .replace(SLUGIFY_DUPLICATE_DASHES, "-") + .replace(SLUGIFY_TRIM_DASHES, ""); +} diff --git a/packages/schemas/src/models.ts b/packages/schemas/src/models.ts index f2e92ad..c1ef243 100644 --- a/packages/schemas/src/models.ts +++ b/packages/schemas/src/models.ts @@ -41,3 +41,75 @@ export const getModelsQuerySchema = getPaginatedDataSchema.extend({ export const getModelBySlugParamsSchema = z.object({ slug: z.string().min(1), }); + +/** @description Body schema for creating a model */ +export const createModelBodySchema = z.object({ + name: z.string().min(1).max(255), + makerId: z.string().min(1), + categoryId: z.string().optional(), + status: modelStatuses.optional(), + imageLocalPath: z.string().optional(), + announced: z.string().optional(), + dimensions: z.string().optional(), + weight: z.string().optional(), + build: z.string().optional(), + sim: z.string().optional(), + displayType: z.string().optional(), + displaySize: z.string().optional(), + displayResolution: z.string().optional(), + displayProtection: z.string().optional(), + os: z.string().optional(), + chipset: z.string().optional(), + cpu: z.string().optional(), + gpu: z.string().optional(), + cardSlot: z.string().optional(), + internalMemory: z.string().optional(), + mainCamera: z.string().optional(), + mainCameraFeatures: z.string().optional(), + mainCameraVideo: z.string().optional(), + selfieCamera: z.string().optional(), + selfieFeatures: z.string().optional(), + selfieVideo: z.string().optional(), + battery: z.string().optional(), + batteryCharging: z.string().optional(), + networkTech: z.string().optional(), + sensors: z.string().optional(), + colors: z.string().optional(), + colorsHex: z.string().optional(), + modelsText: z.string().optional(), + price: z.string().optional(), + dimensionsWidth: z.number().optional(), + dimensionsHeight: z.number().optional(), + dimensionsThickness: z.number().optional(), + weightGrams: z.number().optional(), + displaySizeInches: z.number().optional(), + displaySizeRatio: z.string().optional(), + displayResWidth: z.number().optional(), + displayResHeight: z.number().optional(), + displayResPpi: z.number().optional(), + released: z.string().optional(), + meta: z.string().optional(), +}); + +/** @description Body schema for partially updating a model (all fields optional) */ +export const patchModelBodySchema = createModelBodySchema.partial(); + +/** @description Params schema for operating on a model by its ID */ +export const modelIdParamsSchema = z.object({ + modelId: z.string().min(1), +}); + +/** @description Params schema for model image operations */ +export const modelImageParamsSchema = z.object({ + modelId: z.string().min(1), + imageId: z.string().min(1), +}); + +/** @description Body schema for assigning an uploaded image to a model */ +export const createModelImageBodySchema = z.object({ + r2Key: z.string().min(1), + originalUrl: z.string().url().optional(), + isPrimary: z.boolean().optional(), + variant: z.string().optional(), + position: z.number().int().optional(), +}); diff --git a/packages/schemas/src/uploads.ts b/packages/schemas/src/uploads.ts index a78343c..b73ddd2 100644 --- a/packages/schemas/src/uploads.ts +++ b/packages/schemas/src/uploads.ts @@ -30,3 +30,13 @@ export const uploadPresignResponseSchema = z.object({ url: z.string().url(), expiresIn: z.number().int().positive(), }); + +export const createModelImageUploadPresignSchema = z.object({ + fileName: z.string().min(1).max(255), + contentType: z + .string() + .min(1) + .max(255) + .regex(/^[^/]+\/[^/]+$/), + size: z.number().int().positive().max(MAX_UPLOAD_SIZE_BYTES), +}); From 271f09a0827af5e8683364efe87a7e63b8e5ace8 Mon Sep 17 00:00:00 2001 From: Ricardo Amorim <102877738+risixdzn@users.noreply.github.com> Date: Sun, 31 May 2026 19:06:25 -0300 Subject: [PATCH 7/9] fix(Models): Flatten select, source images from model_images, drop unused columns - Flatten modelMinimalListSelect to fix 500 error with nested selects + $dynamic() - Remove imageLocalPath and imageUrl references (columns dropped from DB) - Source primary image from model_images table; return presigned URL as imageUrl - Remove originalUrl from model_images response, schema, and insert - Add batch queryPrimaryImages + generateImagePresignedUrl helpers - Add "Available" status fallback for null status in all model endpoints - Add 416 code to httpStatusCodes to fix page_out_of_bounds serialization - Create migration 0010 for FULLTEXT index on models (name, models_text, ...) --- .../src/core/docs/models/models.docs.ts | 7 +- apps/server/src/core/lib/response.ts | 1 + .../src/modules/models/repositories/index.ts | 98 +- .../src/modules/models/services/index.ts | 63 +- .../db/drizzle/0007_romantic_union_jack.sql | 74 + .../db/drizzle/0008_slimy_abomination.sql | 1 + .../db/drizzle/0009_ambiguous_hammerhead.sql | 1 + packages/db/drizzle/0010_sturdy_fulltext.sql | 1 + packages/db/drizzle/0011_crazy_slapstick.sql | 1 + packages/db/drizzle/meta/0007_snapshot.json | 1442 +++++++++++++++++ packages/db/drizzle/meta/0008_snapshot.json | 1435 ++++++++++++++++ packages/db/drizzle/meta/0009_snapshot.json | 1428 ++++++++++++++++ packages/db/drizzle/meta/0011_snapshot.json | 1421 ++++++++++++++++ packages/db/drizzle/meta/_journal.json | 35 + packages/db/src/schema/model-categories.ts | 6 +- packages/db/src/schema/model-images.ts | 1 - packages/db/src/schema/model-makers.ts | 2 +- packages/db/src/schema/models.ts | 2 - packages/schemas/src/models.ts | 7 +- 19 files changed, 5952 insertions(+), 74 deletions(-) create mode 100644 packages/db/drizzle/0007_romantic_union_jack.sql create mode 100644 packages/db/drizzle/0008_slimy_abomination.sql create mode 100644 packages/db/drizzle/0009_ambiguous_hammerhead.sql create mode 100644 packages/db/drizzle/0010_sturdy_fulltext.sql create mode 100644 packages/db/drizzle/0011_crazy_slapstick.sql create mode 100644 packages/db/drizzle/meta/0007_snapshot.json create mode 100644 packages/db/drizzle/meta/0008_snapshot.json create mode 100644 packages/db/drizzle/meta/0009_snapshot.json create mode 100644 packages/db/drizzle/meta/0011_snapshot.json diff --git a/apps/server/src/core/docs/models/models.docs.ts b/apps/server/src/core/docs/models/models.docs.ts index 3b81180..19744fe 100644 --- a/apps/server/src/core/docs/models/models.docs.ts +++ b/apps/server/src/core/docs/models/models.docs.ts @@ -15,8 +15,6 @@ const modelListRecordSchema = z.object({ name: z.string(), slug: z.string(), imageUrl: z.string().nullable(), - imageLocalPath: z.string().nullable(), - presignedImageUrl: z.string().nullable(), status: z.string().nullable(), price: z.string().nullable(), released: z.string().nullable(), @@ -37,7 +35,6 @@ const modelListRecordSchema = z.object({ const modelImageRecordSchema = z.object({ id: z.string(), modelId: z.string(), - originalUrl: z.string().nullable(), r2Key: z.string().nullable(), presignedUrl: z.string().nullable(), isPrimary: z.boolean(), @@ -53,8 +50,6 @@ const modelDetailRecordSchema = z.object({ slug: z.string(), url: z.string(), imageUrl: z.string().nullable(), - imageLocalPath: z.string().nullable(), - presignedImageUrl: z.string().nullable(), categoryId: z.string().nullable(), announced: z.string().nullable(), status: z.string().nullable(), @@ -245,7 +240,7 @@ const patchModelSchema: FastifySchema = { description: ` **Partially updates a device model record.** -All fields are optional — only provided fields will be updated. +All fields are optional: only provided fields will be updated. Returns the full model detail with presigned image URLs. `, params: z.object({ subdomain: z.string(), modelId: z.string() }), diff --git a/apps/server/src/core/lib/response.ts b/apps/server/src/core/lib/response.ts index d7953dc..67bf1a5 100644 --- a/apps/server/src/core/lib/response.ts +++ b/apps/server/src/core/lib/response.ts @@ -28,6 +28,7 @@ export const httpStatusCodes: Record = { 405: "Method Not Allowed", 409: "Conflict", 410: "Gone", + 416: "Range Not Satisfiable", 418: "I'm a teapot", 429: "Too Many Requests", 500: "Internal Server Error", diff --git a/apps/server/src/modules/models/repositories/index.ts b/apps/server/src/modules/models/repositories/index.ts index 6a24a0c..b56da8a 100644 --- a/apps/server/src/modules/models/repositories/index.ts +++ b/apps/server/src/modules/models/repositories/index.ts @@ -1,5 +1,15 @@ import { DeleteObjectCommand } from "@aws-sdk/client-s3"; -import { and, asc, db, desc, eq, or, type SQL, sql } from "@fixr/db/connection"; +import { + and, + asc, + db, + desc, + eq, + inArray, + or, + type SQL, + sql, +} from "@fixr/db/connection"; import { modelCategories, modelImages, @@ -20,17 +30,15 @@ export const modelMinimalListSelect = { id: models.id, name: models.name, slug: models.slug, - imageUrl: models.imageUrl, - imageLocalPath: models.imageLocalPath, status: models.status, price: models.price, released: models.released, - maker: { id: modelMakers.id, name: modelMakers.name, slug: modelMakers.slug }, - category: { - id: modelCategories.id, - name: modelCategories.name, - slug: modelCategories.slug, - }, + makerId: modelMakers.id, + makerName: modelMakers.name, + makerSlug: modelMakers.slug, + categoryId: modelCategories.id, + categoryName: modelCategories.name, + categorySlug: modelCategories.slug, }; /** @description Join definitions for models list queries */ @@ -134,8 +142,6 @@ export class ModelsRepository { name: models.name, slug: models.slug, url: models.url, - imageUrl: models.imageUrl, - imageLocalPath: models.imageLocalPath, categoryId: models.categoryId, announced: models.announced, status: models.status, @@ -216,17 +222,41 @@ export class ModelsRepository { } /** - * Attach a presigned GET URL to a model record + * Batch fetch primary model images for a set of model IDs + * + * @param modelIds - Array of model IDs + * @returns Map of modelId -> r2Key + */ + static async queryPrimaryImages( + modelIds: string[] + ): Promise> { + if (modelIds.length === 0) return new Map(); + const rows = await db + .select({ + modelId: modelImages.modelId, + r2Key: modelImages.r2Key, + }) + .from(modelImages) + .where( + and( + inArray(modelImages.modelId, modelIds), + eq(modelImages.isPrimary, true) + ) + ); + return new Map( + rows.filter((r) => !!r.r2Key).map((r) => [r.modelId, r.r2Key!]) + ); + } + + /** + * Generate a presigned GET URL for an R2 key * - * @param model - The model record - * @returns The model record with presignedImageUrl + * @param r2Key - The R2 object key + * @returns Presigned URL or null */ - static async attachPresignedImageUrls( - model: Record - ): Promise> { - const localPath = model.imageLocalPath as string; - const presignedUrl = await generatePresignedGetUrl(localPath); - return { ...model, presignedImageUrl: presignedUrl ?? model.imageUrl }; + static async generateImagePresignedUrl(r2Key: string | null | undefined) { + if (!r2Key) return null; + return (await generatePresignedGetUrl(r2Key)) ?? null; } /** @@ -242,7 +272,7 @@ export class ModelsRepository { images.map(async (img) => { const r2Key = img.r2Key as string; const presignedUrl = await generatePresignedGetUrl(r2Key); - return { ...img, presignedUrl: presignedUrl ?? img.originalUrl }; + return { ...img, presignedUrl }; }) ); } @@ -325,28 +355,12 @@ export class ModelsRepository { * @returns Array of R2 keys */ static async queryR2KeysByModel(modelId: string) { - const [modelResult, imageKeys] = await Promise.all([ - db - .select({ key: models.imageLocalPath }) - .from(models) - .where(eq(models.id, modelId)) - .limit(1), - db - .select({ key: modelImages.r2Key }) - .from(modelImages) - .where(eq(modelImages.modelId, modelId)), - ]); + const imageKeys = await db + .select({ key: modelImages.r2Key }) + .from(modelImages) + .where(eq(modelImages.modelId, modelId)); - const keys: string[] = []; - if (modelResult[0]?.key) { - keys.push(modelResult[0].key); - } - for (const img of imageKeys) { - if (img.key) { - keys.push(img.key); - } - } - return keys; + return imageKeys.map((img) => img.key).filter((k): k is string => !!k); } /** diff --git a/apps/server/src/modules/models/services/index.ts b/apps/server/src/modules/models/services/index.ts index 88f60f6..8cbae99 100644 --- a/apps/server/src/modules/models/services/index.ts +++ b/apps/server/src/modules/models/services/index.ts @@ -139,10 +139,38 @@ export class ModelsService { const next_page = PER_PAGE * (page - 1) + records.length < totalRecords ? page + 1 : null; + const modelIds = (records as Record[]).map( + (r) => r.id as string + ); + const primaryImageMap = await ModelsRepository.queryPrimaryImages(modelIds); + const recordsWithImages = await Promise.all( - (records as Record[]).map((r) => - ModelsRepository.attachPresignedImageUrls(r) - ) + (records as Record[]).map(async (r) => { + const record = { ...r }; + record.maker = { + id: record.makerId, + name: record.makerName, + slug: record.makerSlug, + }; + record.category = record.categoryId + ? { + id: record.categoryId, + name: record.categoryName, + slug: record.categorySlug, + } + : null; + record.makerId = undefined; + record.makerName = undefined; + record.makerSlug = undefined; + record.categoryId = undefined; + record.categoryName = undefined; + record.categorySlug = undefined; + const r2Key = primaryImageMap.get(record.id as string); + record.imageUrl = + await ModelsRepository.generateImagePresignedUrl(r2Key); + record.status = record.status ?? "Available"; + return record as Record; + }) ); return response.status(200).send( @@ -203,10 +231,9 @@ export class ModelsService { const images = await ModelsRepository.queryModelImages(model.id as string); - const [modelWithPresignedUrl, imagesWithPresignedUrls] = await Promise.all([ - ModelsRepository.attachPresignedImageUrls( - model as Record - ), + const primaryImage = images.find((img) => img.isPrimary); + const [imageUrl, imagesWithPresignedUrls] = await Promise.all([ + ModelsRepository.generateImagePresignedUrl(primaryImage?.r2Key ?? null), ModelsRepository.attachPresignedUrlsToImages( images as Record[] ), @@ -218,7 +245,12 @@ export class ModelsService { error: null, code: "get_model_success", message: "Model retrieved successfully.", - data: { ...modelWithPresignedUrl, images: imagesWithPresignedUrls }, + data: { + ...(model as Record), + status: model.status ?? "Available", + imageUrl, + images: imagesWithPresignedUrls, + }, }) ); } @@ -344,10 +376,9 @@ export class ModelsService { const images = await ModelsRepository.queryModelImages(model.id as string); - const [modelWithPresignedUrl, imagesWithPresignedUrls] = await Promise.all([ - ModelsRepository.attachPresignedImageUrls( - (updated ?? model) as Record - ), + const primaryImage = images.find((img) => img.isPrimary); + const [imageUrl, imagesWithPresignedUrls] = await Promise.all([ + ModelsRepository.generateImagePresignedUrl(primaryImage?.r2Key ?? null), ModelsRepository.attachPresignedUrlsToImages( images as Record[] ), @@ -359,7 +390,12 @@ export class ModelsService { error: null, code: "patch_model_success", message: "Model updated successfully.", - data: { ...modelWithPresignedUrl, images: imagesWithPresignedUrls }, + data: { + ...(updated ?? model), + status: (updated ?? model).status ?? "Available", + imageUrl, + images: imagesWithPresignedUrls, + }, }) ); } @@ -453,7 +489,6 @@ export class ModelsService { id: imageId, modelId: model.id as string, r2Key: data.r2Key, - originalUrl: data.originalUrl ?? null, isPrimary: data.isPrimary ?? false, variant: data.variant ?? null, position: data.position ?? 0, diff --git a/packages/db/drizzle/0007_romantic_union_jack.sql b/packages/db/drizzle/0007_romantic_union_jack.sql new file mode 100644 index 0000000..0c62a17 --- /dev/null +++ b/packages/db/drizzle/0007_romantic_union_jack.sql @@ -0,0 +1,74 @@ +CREATE TABLE `model_images` ( + `id` varchar(25) NOT NULL, + `model_id` varchar(25) NOT NULL, + `original_url` varchar(255), + `r2_key` varchar(255), + `is_primary` boolean NOT NULL DEFAULT false, + `variant` varchar(50), + `position` int NOT NULL DEFAULT 0, + `created_at` timestamp NOT NULL DEFAULT (now()), + CONSTRAINT `model_images_id` PRIMARY KEY(`id`) +); +--> statement-breakpoint +CREATE TABLE `models` ( + `id` varchar(25) NOT NULL, + `maker_id` varchar(25) NOT NULL, + `name` varchar(255) NOT NULL, + `slug` varchar(100) NOT NULL, + `url` varchar(255) NOT NULL, + `image_url` varchar(255), + `image_local_path` varchar(255), + `category_id` varchar(25), + `announced` text, + `status` text, + `dimensions` text, + `weight` text, + `build` text, + `sim` text, + `display_type` text, + `display_size` text, + `display_resolution` text, + `display_protection` text, + `os` text, + `chipset` text, + `cpu` text, + `gpu` text, + `card_slot` text, + `internal_memory` text, + `main_camera` text, + `main_camera_features` text, + `main_camera_video` text, + `selfie_camera` text, + `selfie_features` text, + `selfie_video` text, + `battery` text, + `battery_charging` text, + `network_tech` text, + `sensors` text, + `colors` text, + `colors_hex` text, + `models_text` text, + `price` text, + `dimensions_width` float, + `dimensions_height` float, + `dimensions_thickness` float, + `weight_grams` float, + `display_size_inches` float, + `display_size_ratio` text, + `display_res_width` int, + `display_res_height` int, + `display_res_ppi` int, + `released` text, + `meta` text, + `company_id` varchar(25), + `created_at` timestamp NOT NULL DEFAULT (now()), + CONSTRAINT `models_id` PRIMARY KEY(`id`), + CONSTRAINT `slug_company_unique` UNIQUE(`slug`,`company_id`) +); +--> statement-breakpoint +ALTER TABLE `model_categories` DROP INDEX `model_categories_slug_unique`;--> statement-breakpoint +ALTER TABLE `model_makers` DROP INDEX `model_makers_slug_unique`;--> statement-breakpoint +ALTER TABLE `model_images` ADD CONSTRAINT `model_images_model_id_models_id_fk` FOREIGN KEY (`model_id`) REFERENCES `models`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE `models` ADD CONSTRAINT `models_maker_id_model_makers_id_fk` FOREIGN KEY (`maker_id`) REFERENCES `model_makers`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE `models` ADD CONSTRAINT `models_category_id_model_categories_id_fk` FOREIGN KEY (`category_id`) REFERENCES `model_categories`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE `models` ADD CONSTRAINT `models_company_id_companies_id_fk` FOREIGN KEY (`company_id`) REFERENCES `companies`(`id`) ON DELETE no action ON UPDATE no action; \ No newline at end of file diff --git a/packages/db/drizzle/0008_slimy_abomination.sql b/packages/db/drizzle/0008_slimy_abomination.sql new file mode 100644 index 0000000..5008d6b --- /dev/null +++ b/packages/db/drizzle/0008_slimy_abomination.sql @@ -0,0 +1 @@ +ALTER TABLE `models` DROP COLUMN `image_local_path`; \ No newline at end of file diff --git a/packages/db/drizzle/0009_ambiguous_hammerhead.sql b/packages/db/drizzle/0009_ambiguous_hammerhead.sql new file mode 100644 index 0000000..c1374d7 --- /dev/null +++ b/packages/db/drizzle/0009_ambiguous_hammerhead.sql @@ -0,0 +1 @@ +ALTER TABLE `models` DROP COLUMN `image_url`; \ No newline at end of file diff --git a/packages/db/drizzle/0010_sturdy_fulltext.sql b/packages/db/drizzle/0010_sturdy_fulltext.sql new file mode 100644 index 0000000..d2c3875 --- /dev/null +++ b/packages/db/drizzle/0010_sturdy_fulltext.sql @@ -0,0 +1 @@ +ALTER TABLE `models` ADD FULLTEXT INDEX `models_fulltext_idx` (`name`, `models_text`, `chipset`, `cpu`, `internal_memory`, `os`); diff --git a/packages/db/drizzle/0011_crazy_slapstick.sql b/packages/db/drizzle/0011_crazy_slapstick.sql new file mode 100644 index 0000000..0243498 --- /dev/null +++ b/packages/db/drizzle/0011_crazy_slapstick.sql @@ -0,0 +1 @@ +ALTER TABLE `model_images` DROP COLUMN `original_url`; \ No newline at end of file diff --git a/packages/db/drizzle/meta/0007_snapshot.json b/packages/db/drizzle/meta/0007_snapshot.json new file mode 100644 index 0000000..ba12de1 --- /dev/null +++ b/packages/db/drizzle/meta/0007_snapshot.json @@ -0,0 +1,1442 @@ +{ + "version": "5", + "dialect": "mysql", + "id": "f8e272be-5fd8-4902-aa53-8ee19994cce6", + "prevId": "ab909380-0bce-443b-b2a8-5ebb6488b252", + "tables": { + "clients": { + "name": "clients", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cpf": { + "name": "cpf", + "type": "varchar(11)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "phone": { + "name": "phone", + "type": "varchar(11)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "user_id": { + "name": "user_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "clients_user_id_users_id_fk": { + "name": "clients_user_id_users_id_fk", + "tableFrom": "clients", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "clients_id": { + "name": "clients_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "clients_cpf_unique": { + "name": "clients_cpf_unique", + "columns": ["cpf"] + } + }, + "checkConstraint": {} + }, + "companies": { + "name": "companies", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cnpj": { + "name": "cnpj", + "type": "varchar(14)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "address": { + "name": "address", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "subdomain": { + "name": "subdomain", + "type": "varchar(32)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "companies_id": { + "name": "companies_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "companies_cnpj_unique": { + "name": "companies_cnpj_unique", + "columns": ["cnpj"] + }, + "companies_subdomain_unique": { + "name": "companies_subdomain_unique", + "columns": ["subdomain"] + } + }, + "checkConstraint": {} + }, + "model_makers": { + "name": "model_makers", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "slug": { + "name": "slug", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "device_count": { + "name": "device_count", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "page_count": { + "name": "page_count", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "model_makers_id": { + "name": "model_makers_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "employees": { + "name": "employees", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cpf": { + "name": "cpf", + "type": "varchar(11)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "phone": { + "name": "phone", + "type": "varchar(11)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "roles": { + "name": "roles", + "type": "enum('guest','technician','warehouse','financial','manager','admin')", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "user_id": { + "name": "user_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "company_id": { + "name": "company_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "employees_user_id_users_id_fk": { + "name": "employees_user_id_users_id_fk", + "tableFrom": "employees", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "employees_company_id_companies_id_fk": { + "name": "employees_company_id_companies_id_fk", + "tableFrom": "employees", + "tableTo": "companies", + "columnsFrom": ["company_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "employees_id": { + "name": "employees_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "employees_cpf_unique": { + "name": "employees_cpf_unique", + "columns": ["cpf"] + } + }, + "checkConstraint": {} + }, + "model_categories": { + "name": "model_categories", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "slug": { + "name": "slug", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "model_categories_id": { + "name": "model_categories_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "model_images": { + "name": "model_images", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "model_id": { + "name": "model_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "original_url": { + "name": "original_url", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "r2_key": { + "name": "r2_key", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "is_primary": { + "name": "is_primary", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "variant": { + "name": "variant", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "position": { + "name": "position", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": { + "model_images_model_id_models_id_fk": { + "name": "model_images_model_id_models_id_fk", + "tableFrom": "model_images", + "tableTo": "models", + "columnsFrom": ["model_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "model_images_id": { + "name": "model_images_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "models": { + "name": "models", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "maker_id": { + "name": "maker_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "slug": { + "name": "slug", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "image_url": { + "name": "image_url", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "image_local_path": { + "name": "image_local_path", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "category_id": { + "name": "category_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "announced": { + "name": "announced", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "dimensions": { + "name": "dimensions", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "weight": { + "name": "weight", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "build": { + "name": "build", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "sim": { + "name": "sim", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_type": { + "name": "display_type", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_size": { + "name": "display_size", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_resolution": { + "name": "display_resolution", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_protection": { + "name": "display_protection", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "os": { + "name": "os", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "chipset": { + "name": "chipset", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "cpu": { + "name": "cpu", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "gpu": { + "name": "gpu", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "card_slot": { + "name": "card_slot", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "internal_memory": { + "name": "internal_memory", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "main_camera": { + "name": "main_camera", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "main_camera_features": { + "name": "main_camera_features", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "main_camera_video": { + "name": "main_camera_video", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "selfie_camera": { + "name": "selfie_camera", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "selfie_features": { + "name": "selfie_features", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "selfie_video": { + "name": "selfie_video", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "battery": { + "name": "battery", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "battery_charging": { + "name": "battery_charging", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "network_tech": { + "name": "network_tech", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "sensors": { + "name": "sensors", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "colors": { + "name": "colors", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "colors_hex": { + "name": "colors_hex", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "models_text": { + "name": "models_text", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "price": { + "name": "price", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "dimensions_width": { + "name": "dimensions_width", + "type": "float", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "dimensions_height": { + "name": "dimensions_height", + "type": "float", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "dimensions_thickness": { + "name": "dimensions_thickness", + "type": "float", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "weight_grams": { + "name": "weight_grams", + "type": "float", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_size_inches": { + "name": "display_size_inches", + "type": "float", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_size_ratio": { + "name": "display_size_ratio", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_res_width": { + "name": "display_res_width", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_res_height": { + "name": "display_res_height", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_res_ppi": { + "name": "display_res_ppi", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "released": { + "name": "released", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "meta": { + "name": "meta", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "company_id": { + "name": "company_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": { + "models_maker_id_model_makers_id_fk": { + "name": "models_maker_id_model_makers_id_fk", + "tableFrom": "models", + "tableTo": "model_makers", + "columnsFrom": ["maker_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "models_category_id_model_categories_id_fk": { + "name": "models_category_id_model_categories_id_fk", + "tableFrom": "models", + "tableTo": "model_categories", + "columnsFrom": ["category_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "models_company_id_companies_id_fk": { + "name": "models_company_id_companies_id_fk", + "tableFrom": "models", + "tableTo": "companies", + "columnsFrom": ["company_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "models_id": { + "name": "models_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "slug_company_unique": { + "name": "slug_company_unique", + "columns": ["slug", "company_id"] + } + }, + "checkConstraint": {} + }, + "one_time_tokens": { + "name": "one_time_tokens", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "ott_type": { + "name": "ott_type", + "type": "enum('confirmation','password_reset','account_deletion')", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "relates_to": { + "name": "relates_to", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "one_time_tokens_user_id_users_id_fk": { + "name": "one_time_tokens_user_id_users_id_fk", + "tableFrom": "one_time_tokens", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "one_time_tokens_id": { + "name": "one_time_tokens_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "one_time_tokens_token_unique": { + "name": "one_time_tokens_token_unique", + "columns": ["token"] + } + }, + "checkConstraint": {} + }, + "refresh_tokens": { + "name": "refresh_tokens", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "refresh_tokens_user_id_users_id_fk": { + "name": "refresh_tokens_user_id_users_id_fk", + "tableFrom": "refresh_tokens", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "refresh_tokens_id": { + "name": "refresh_tokens_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "refresh_tokens_token_unique": { + "name": "refresh_tokens_token_unique", + "columns": ["token"] + } + }, + "checkConstraint": {} + }, + "service_order_images": { + "name": "service_order_images", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "service_order_id": { + "name": "service_order_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "employee_id": { + "name": "employee_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "upload_id": { + "name": "upload_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "image_url": { + "name": "image_url", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "file_name": { + "name": "file_name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "size_in_bytes": { + "name": "size_in_bytes", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "content_type": { + "name": "content_type", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": { + "service_order_images_service_order_id_service_orders_id_fk": { + "name": "service_order_images_service_order_id_service_orders_id_fk", + "tableFrom": "service_order_images", + "tableTo": "service_orders", + "columnsFrom": ["service_order_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "service_order_images_employee_id_employees_id_fk": { + "name": "service_order_images_employee_id_employees_id_fk", + "tableFrom": "service_order_images", + "tableTo": "employees", + "columnsFrom": ["employee_id"], + "columnsTo": ["id"], + "onDelete": "restrict", + "onUpdate": "no action" + }, + "service_order_images_upload_id_uploads_id_fk": { + "name": "service_order_images_upload_id_uploads_id_fk", + "tableFrom": "service_order_images", + "tableTo": "uploads", + "columnsFrom": ["upload_id"], + "columnsTo": ["id"], + "onDelete": "restrict", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "service_order_images_id": { + "name": "service_order_images_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "service_orders": { + "name": "service_orders", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "company_id": { + "name": "company_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "client_id": { + "name": "client_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "employee_id": { + "name": "employee_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "device_brand_id": { + "name": "device_brand_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "device_category_id": { + "name": "device_category_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "device_model": { + "name": "device_model", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "imei": { + "name": "imei", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "reported_defect": { + "name": "reported_defect", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "observations": { + "name": "observations", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "enum('pending','diagnosing','waiting_approval','approved','fixing','ready','delivered')", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'pending'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": { + "service_orders_company_id_companies_id_fk": { + "name": "service_orders_company_id_companies_id_fk", + "tableFrom": "service_orders", + "tableTo": "companies", + "columnsFrom": ["company_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "service_orders_client_id_clients_id_fk": { + "name": "service_orders_client_id_clients_id_fk", + "tableFrom": "service_orders", + "tableTo": "clients", + "columnsFrom": ["client_id"], + "columnsTo": ["id"], + "onDelete": "restrict", + "onUpdate": "no action" + }, + "service_orders_employee_id_employees_id_fk": { + "name": "service_orders_employee_id_employees_id_fk", + "tableFrom": "service_orders", + "tableTo": "employees", + "columnsFrom": ["employee_id"], + "columnsTo": ["id"], + "onDelete": "restrict", + "onUpdate": "no action" + }, + "service_orders_device_brand_id_model_makers_id_fk": { + "name": "service_orders_device_brand_id_model_makers_id_fk", + "tableFrom": "service_orders", + "tableTo": "model_makers", + "columnsFrom": ["device_brand_id"], + "columnsTo": ["id"], + "onDelete": "restrict", + "onUpdate": "no action" + }, + "service_orders_device_category_id_model_categories_id_fk": { + "name": "service_orders_device_category_id_model_categories_id_fk", + "tableFrom": "service_orders", + "tableTo": "model_categories", + "columnsFrom": ["device_category_id"], + "columnsTo": ["id"], + "onDelete": "restrict", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "service_orders_id": { + "name": "service_orders_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "uploads": { + "name": "uploads", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "company_id": { + "name": "company_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "employee_id": { + "name": "employee_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "key": { + "name": "key", + "type": "varchar(512)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "varchar(512)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "file_name": { + "name": "file_name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "content_type": { + "name": "content_type", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "size_in_bytes": { + "name": "size_in_bytes", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "varchar(20)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'pending'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": { + "uploads_company_id_companies_id_fk": { + "name": "uploads_company_id_companies_id_fk", + "tableFrom": "uploads", + "tableTo": "companies", + "columnsFrom": ["company_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "uploads_employee_id_employees_id_fk": { + "name": "uploads_employee_id_employees_id_fk", + "tableFrom": "uploads", + "tableTo": "employees", + "columnsFrom": ["employee_id"], + "columnsTo": ["id"], + "onDelete": "restrict", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "uploads_id": { + "name": "uploads_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "users": { + "name": "users", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "password_hash": { + "name": "password_hash", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "google_id": { + "name": "google_id", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "avatar_url": { + "name": "avatar_url", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "verified": { + "name": "verified", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "users_id": { + "name": "users_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "users_email_unique": { + "name": "users_email_unique", + "columns": ["email"] + }, + "users_google_id_unique": { + "name": "users_google_id_unique", + "columns": ["google_id"] + } + }, + "checkConstraint": {} + } + }, + "views": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "tables": {}, + "indexes": {} + } +} diff --git a/packages/db/drizzle/meta/0008_snapshot.json b/packages/db/drizzle/meta/0008_snapshot.json new file mode 100644 index 0000000..3f21437 --- /dev/null +++ b/packages/db/drizzle/meta/0008_snapshot.json @@ -0,0 +1,1435 @@ +{ + "version": "5", + "dialect": "mysql", + "id": "7a33fdf9-9138-4db6-96e0-c729b47e5f0a", + "prevId": "f8e272be-5fd8-4902-aa53-8ee19994cce6", + "tables": { + "clients": { + "name": "clients", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cpf": { + "name": "cpf", + "type": "varchar(11)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "phone": { + "name": "phone", + "type": "varchar(11)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "user_id": { + "name": "user_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "clients_user_id_users_id_fk": { + "name": "clients_user_id_users_id_fk", + "tableFrom": "clients", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "clients_id": { + "name": "clients_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "clients_cpf_unique": { + "name": "clients_cpf_unique", + "columns": ["cpf"] + } + }, + "checkConstraint": {} + }, + "companies": { + "name": "companies", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cnpj": { + "name": "cnpj", + "type": "varchar(14)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "address": { + "name": "address", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "subdomain": { + "name": "subdomain", + "type": "varchar(32)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "companies_id": { + "name": "companies_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "companies_cnpj_unique": { + "name": "companies_cnpj_unique", + "columns": ["cnpj"] + }, + "companies_subdomain_unique": { + "name": "companies_subdomain_unique", + "columns": ["subdomain"] + } + }, + "checkConstraint": {} + }, + "model_makers": { + "name": "model_makers", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "slug": { + "name": "slug", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "device_count": { + "name": "device_count", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "page_count": { + "name": "page_count", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "model_makers_id": { + "name": "model_makers_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "employees": { + "name": "employees", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cpf": { + "name": "cpf", + "type": "varchar(11)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "phone": { + "name": "phone", + "type": "varchar(11)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "roles": { + "name": "roles", + "type": "enum('guest','technician','warehouse','financial','manager','admin')", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "user_id": { + "name": "user_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "company_id": { + "name": "company_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "employees_user_id_users_id_fk": { + "name": "employees_user_id_users_id_fk", + "tableFrom": "employees", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "employees_company_id_companies_id_fk": { + "name": "employees_company_id_companies_id_fk", + "tableFrom": "employees", + "tableTo": "companies", + "columnsFrom": ["company_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "employees_id": { + "name": "employees_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "employees_cpf_unique": { + "name": "employees_cpf_unique", + "columns": ["cpf"] + } + }, + "checkConstraint": {} + }, + "model_categories": { + "name": "model_categories", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "slug": { + "name": "slug", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "model_categories_id": { + "name": "model_categories_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "model_images": { + "name": "model_images", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "model_id": { + "name": "model_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "original_url": { + "name": "original_url", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "r2_key": { + "name": "r2_key", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "is_primary": { + "name": "is_primary", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "variant": { + "name": "variant", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "position": { + "name": "position", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": { + "model_images_model_id_models_id_fk": { + "name": "model_images_model_id_models_id_fk", + "tableFrom": "model_images", + "tableTo": "models", + "columnsFrom": ["model_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "model_images_id": { + "name": "model_images_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "models": { + "name": "models", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "maker_id": { + "name": "maker_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "slug": { + "name": "slug", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "image_url": { + "name": "image_url", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "category_id": { + "name": "category_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "announced": { + "name": "announced", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "dimensions": { + "name": "dimensions", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "weight": { + "name": "weight", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "build": { + "name": "build", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "sim": { + "name": "sim", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_type": { + "name": "display_type", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_size": { + "name": "display_size", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_resolution": { + "name": "display_resolution", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_protection": { + "name": "display_protection", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "os": { + "name": "os", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "chipset": { + "name": "chipset", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "cpu": { + "name": "cpu", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "gpu": { + "name": "gpu", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "card_slot": { + "name": "card_slot", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "internal_memory": { + "name": "internal_memory", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "main_camera": { + "name": "main_camera", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "main_camera_features": { + "name": "main_camera_features", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "main_camera_video": { + "name": "main_camera_video", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "selfie_camera": { + "name": "selfie_camera", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "selfie_features": { + "name": "selfie_features", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "selfie_video": { + "name": "selfie_video", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "battery": { + "name": "battery", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "battery_charging": { + "name": "battery_charging", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "network_tech": { + "name": "network_tech", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "sensors": { + "name": "sensors", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "colors": { + "name": "colors", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "colors_hex": { + "name": "colors_hex", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "models_text": { + "name": "models_text", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "price": { + "name": "price", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "dimensions_width": { + "name": "dimensions_width", + "type": "float", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "dimensions_height": { + "name": "dimensions_height", + "type": "float", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "dimensions_thickness": { + "name": "dimensions_thickness", + "type": "float", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "weight_grams": { + "name": "weight_grams", + "type": "float", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_size_inches": { + "name": "display_size_inches", + "type": "float", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_size_ratio": { + "name": "display_size_ratio", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_res_width": { + "name": "display_res_width", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_res_height": { + "name": "display_res_height", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_res_ppi": { + "name": "display_res_ppi", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "released": { + "name": "released", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "meta": { + "name": "meta", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "company_id": { + "name": "company_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": { + "models_maker_id_model_makers_id_fk": { + "name": "models_maker_id_model_makers_id_fk", + "tableFrom": "models", + "tableTo": "model_makers", + "columnsFrom": ["maker_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "models_category_id_model_categories_id_fk": { + "name": "models_category_id_model_categories_id_fk", + "tableFrom": "models", + "tableTo": "model_categories", + "columnsFrom": ["category_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "models_company_id_companies_id_fk": { + "name": "models_company_id_companies_id_fk", + "tableFrom": "models", + "tableTo": "companies", + "columnsFrom": ["company_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "models_id": { + "name": "models_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "slug_company_unique": { + "name": "slug_company_unique", + "columns": ["slug", "company_id"] + } + }, + "checkConstraint": {} + }, + "one_time_tokens": { + "name": "one_time_tokens", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "ott_type": { + "name": "ott_type", + "type": "enum('confirmation','password_reset','account_deletion')", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "relates_to": { + "name": "relates_to", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "one_time_tokens_user_id_users_id_fk": { + "name": "one_time_tokens_user_id_users_id_fk", + "tableFrom": "one_time_tokens", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "one_time_tokens_id": { + "name": "one_time_tokens_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "one_time_tokens_token_unique": { + "name": "one_time_tokens_token_unique", + "columns": ["token"] + } + }, + "checkConstraint": {} + }, + "refresh_tokens": { + "name": "refresh_tokens", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "refresh_tokens_user_id_users_id_fk": { + "name": "refresh_tokens_user_id_users_id_fk", + "tableFrom": "refresh_tokens", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "refresh_tokens_id": { + "name": "refresh_tokens_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "refresh_tokens_token_unique": { + "name": "refresh_tokens_token_unique", + "columns": ["token"] + } + }, + "checkConstraint": {} + }, + "service_order_images": { + "name": "service_order_images", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "service_order_id": { + "name": "service_order_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "employee_id": { + "name": "employee_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "upload_id": { + "name": "upload_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "image_url": { + "name": "image_url", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "file_name": { + "name": "file_name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "size_in_bytes": { + "name": "size_in_bytes", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "content_type": { + "name": "content_type", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": { + "service_order_images_service_order_id_service_orders_id_fk": { + "name": "service_order_images_service_order_id_service_orders_id_fk", + "tableFrom": "service_order_images", + "tableTo": "service_orders", + "columnsFrom": ["service_order_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "service_order_images_employee_id_employees_id_fk": { + "name": "service_order_images_employee_id_employees_id_fk", + "tableFrom": "service_order_images", + "tableTo": "employees", + "columnsFrom": ["employee_id"], + "columnsTo": ["id"], + "onDelete": "restrict", + "onUpdate": "no action" + }, + "service_order_images_upload_id_uploads_id_fk": { + "name": "service_order_images_upload_id_uploads_id_fk", + "tableFrom": "service_order_images", + "tableTo": "uploads", + "columnsFrom": ["upload_id"], + "columnsTo": ["id"], + "onDelete": "restrict", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "service_order_images_id": { + "name": "service_order_images_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "service_orders": { + "name": "service_orders", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "company_id": { + "name": "company_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "client_id": { + "name": "client_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "employee_id": { + "name": "employee_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "device_brand_id": { + "name": "device_brand_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "device_category_id": { + "name": "device_category_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "device_model": { + "name": "device_model", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "imei": { + "name": "imei", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "reported_defect": { + "name": "reported_defect", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "observations": { + "name": "observations", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "enum('pending','diagnosing','waiting_approval','approved','fixing','ready','delivered')", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'pending'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": { + "service_orders_company_id_companies_id_fk": { + "name": "service_orders_company_id_companies_id_fk", + "tableFrom": "service_orders", + "tableTo": "companies", + "columnsFrom": ["company_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "service_orders_client_id_clients_id_fk": { + "name": "service_orders_client_id_clients_id_fk", + "tableFrom": "service_orders", + "tableTo": "clients", + "columnsFrom": ["client_id"], + "columnsTo": ["id"], + "onDelete": "restrict", + "onUpdate": "no action" + }, + "service_orders_employee_id_employees_id_fk": { + "name": "service_orders_employee_id_employees_id_fk", + "tableFrom": "service_orders", + "tableTo": "employees", + "columnsFrom": ["employee_id"], + "columnsTo": ["id"], + "onDelete": "restrict", + "onUpdate": "no action" + }, + "service_orders_device_brand_id_model_makers_id_fk": { + "name": "service_orders_device_brand_id_model_makers_id_fk", + "tableFrom": "service_orders", + "tableTo": "model_makers", + "columnsFrom": ["device_brand_id"], + "columnsTo": ["id"], + "onDelete": "restrict", + "onUpdate": "no action" + }, + "service_orders_device_category_id_model_categories_id_fk": { + "name": "service_orders_device_category_id_model_categories_id_fk", + "tableFrom": "service_orders", + "tableTo": "model_categories", + "columnsFrom": ["device_category_id"], + "columnsTo": ["id"], + "onDelete": "restrict", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "service_orders_id": { + "name": "service_orders_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "uploads": { + "name": "uploads", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "company_id": { + "name": "company_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "employee_id": { + "name": "employee_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "key": { + "name": "key", + "type": "varchar(512)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "varchar(512)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "file_name": { + "name": "file_name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "content_type": { + "name": "content_type", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "size_in_bytes": { + "name": "size_in_bytes", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "varchar(20)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'pending'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": { + "uploads_company_id_companies_id_fk": { + "name": "uploads_company_id_companies_id_fk", + "tableFrom": "uploads", + "tableTo": "companies", + "columnsFrom": ["company_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "uploads_employee_id_employees_id_fk": { + "name": "uploads_employee_id_employees_id_fk", + "tableFrom": "uploads", + "tableTo": "employees", + "columnsFrom": ["employee_id"], + "columnsTo": ["id"], + "onDelete": "restrict", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "uploads_id": { + "name": "uploads_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "users": { + "name": "users", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "password_hash": { + "name": "password_hash", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "google_id": { + "name": "google_id", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "avatar_url": { + "name": "avatar_url", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "verified": { + "name": "verified", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "users_id": { + "name": "users_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "users_email_unique": { + "name": "users_email_unique", + "columns": ["email"] + }, + "users_google_id_unique": { + "name": "users_google_id_unique", + "columns": ["google_id"] + } + }, + "checkConstraint": {} + } + }, + "views": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "tables": {}, + "indexes": {} + } +} diff --git a/packages/db/drizzle/meta/0009_snapshot.json b/packages/db/drizzle/meta/0009_snapshot.json new file mode 100644 index 0000000..3ac8f5c --- /dev/null +++ b/packages/db/drizzle/meta/0009_snapshot.json @@ -0,0 +1,1428 @@ +{ + "version": "5", + "dialect": "mysql", + "id": "0f499b87-ef09-4b34-a384-2a6f28f37c2d", + "prevId": "7a33fdf9-9138-4db6-96e0-c729b47e5f0a", + "tables": { + "clients": { + "name": "clients", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cpf": { + "name": "cpf", + "type": "varchar(11)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "phone": { + "name": "phone", + "type": "varchar(11)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "user_id": { + "name": "user_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "clients_user_id_users_id_fk": { + "name": "clients_user_id_users_id_fk", + "tableFrom": "clients", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "clients_id": { + "name": "clients_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "clients_cpf_unique": { + "name": "clients_cpf_unique", + "columns": ["cpf"] + } + }, + "checkConstraint": {} + }, + "companies": { + "name": "companies", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cnpj": { + "name": "cnpj", + "type": "varchar(14)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "address": { + "name": "address", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "subdomain": { + "name": "subdomain", + "type": "varchar(32)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "companies_id": { + "name": "companies_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "companies_cnpj_unique": { + "name": "companies_cnpj_unique", + "columns": ["cnpj"] + }, + "companies_subdomain_unique": { + "name": "companies_subdomain_unique", + "columns": ["subdomain"] + } + }, + "checkConstraint": {} + }, + "model_makers": { + "name": "model_makers", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "slug": { + "name": "slug", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "device_count": { + "name": "device_count", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "page_count": { + "name": "page_count", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "model_makers_id": { + "name": "model_makers_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "employees": { + "name": "employees", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cpf": { + "name": "cpf", + "type": "varchar(11)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "phone": { + "name": "phone", + "type": "varchar(11)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "roles": { + "name": "roles", + "type": "enum('guest','technician','warehouse','financial','manager','admin')", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "user_id": { + "name": "user_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "company_id": { + "name": "company_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "employees_user_id_users_id_fk": { + "name": "employees_user_id_users_id_fk", + "tableFrom": "employees", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "employees_company_id_companies_id_fk": { + "name": "employees_company_id_companies_id_fk", + "tableFrom": "employees", + "tableTo": "companies", + "columnsFrom": ["company_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "employees_id": { + "name": "employees_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "employees_cpf_unique": { + "name": "employees_cpf_unique", + "columns": ["cpf"] + } + }, + "checkConstraint": {} + }, + "model_categories": { + "name": "model_categories", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "slug": { + "name": "slug", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "model_categories_id": { + "name": "model_categories_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "model_images": { + "name": "model_images", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "model_id": { + "name": "model_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "original_url": { + "name": "original_url", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "r2_key": { + "name": "r2_key", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "is_primary": { + "name": "is_primary", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "variant": { + "name": "variant", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "position": { + "name": "position", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": { + "model_images_model_id_models_id_fk": { + "name": "model_images_model_id_models_id_fk", + "tableFrom": "model_images", + "tableTo": "models", + "columnsFrom": ["model_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "model_images_id": { + "name": "model_images_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "models": { + "name": "models", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "maker_id": { + "name": "maker_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "slug": { + "name": "slug", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "category_id": { + "name": "category_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "announced": { + "name": "announced", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "dimensions": { + "name": "dimensions", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "weight": { + "name": "weight", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "build": { + "name": "build", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "sim": { + "name": "sim", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_type": { + "name": "display_type", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_size": { + "name": "display_size", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_resolution": { + "name": "display_resolution", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_protection": { + "name": "display_protection", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "os": { + "name": "os", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "chipset": { + "name": "chipset", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "cpu": { + "name": "cpu", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "gpu": { + "name": "gpu", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "card_slot": { + "name": "card_slot", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "internal_memory": { + "name": "internal_memory", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "main_camera": { + "name": "main_camera", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "main_camera_features": { + "name": "main_camera_features", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "main_camera_video": { + "name": "main_camera_video", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "selfie_camera": { + "name": "selfie_camera", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "selfie_features": { + "name": "selfie_features", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "selfie_video": { + "name": "selfie_video", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "battery": { + "name": "battery", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "battery_charging": { + "name": "battery_charging", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "network_tech": { + "name": "network_tech", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "sensors": { + "name": "sensors", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "colors": { + "name": "colors", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "colors_hex": { + "name": "colors_hex", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "models_text": { + "name": "models_text", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "price": { + "name": "price", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "dimensions_width": { + "name": "dimensions_width", + "type": "float", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "dimensions_height": { + "name": "dimensions_height", + "type": "float", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "dimensions_thickness": { + "name": "dimensions_thickness", + "type": "float", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "weight_grams": { + "name": "weight_grams", + "type": "float", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_size_inches": { + "name": "display_size_inches", + "type": "float", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_size_ratio": { + "name": "display_size_ratio", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_res_width": { + "name": "display_res_width", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_res_height": { + "name": "display_res_height", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_res_ppi": { + "name": "display_res_ppi", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "released": { + "name": "released", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "meta": { + "name": "meta", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "company_id": { + "name": "company_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": { + "models_maker_id_model_makers_id_fk": { + "name": "models_maker_id_model_makers_id_fk", + "tableFrom": "models", + "tableTo": "model_makers", + "columnsFrom": ["maker_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "models_category_id_model_categories_id_fk": { + "name": "models_category_id_model_categories_id_fk", + "tableFrom": "models", + "tableTo": "model_categories", + "columnsFrom": ["category_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "models_company_id_companies_id_fk": { + "name": "models_company_id_companies_id_fk", + "tableFrom": "models", + "tableTo": "companies", + "columnsFrom": ["company_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "models_id": { + "name": "models_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "slug_company_unique": { + "name": "slug_company_unique", + "columns": ["slug", "company_id"] + } + }, + "checkConstraint": {} + }, + "one_time_tokens": { + "name": "one_time_tokens", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "ott_type": { + "name": "ott_type", + "type": "enum('confirmation','password_reset','account_deletion')", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "relates_to": { + "name": "relates_to", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "one_time_tokens_user_id_users_id_fk": { + "name": "one_time_tokens_user_id_users_id_fk", + "tableFrom": "one_time_tokens", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "one_time_tokens_id": { + "name": "one_time_tokens_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "one_time_tokens_token_unique": { + "name": "one_time_tokens_token_unique", + "columns": ["token"] + } + }, + "checkConstraint": {} + }, + "refresh_tokens": { + "name": "refresh_tokens", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "refresh_tokens_user_id_users_id_fk": { + "name": "refresh_tokens_user_id_users_id_fk", + "tableFrom": "refresh_tokens", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "refresh_tokens_id": { + "name": "refresh_tokens_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "refresh_tokens_token_unique": { + "name": "refresh_tokens_token_unique", + "columns": ["token"] + } + }, + "checkConstraint": {} + }, + "service_order_images": { + "name": "service_order_images", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "service_order_id": { + "name": "service_order_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "employee_id": { + "name": "employee_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "upload_id": { + "name": "upload_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "image_url": { + "name": "image_url", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "file_name": { + "name": "file_name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "size_in_bytes": { + "name": "size_in_bytes", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "content_type": { + "name": "content_type", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": { + "service_order_images_service_order_id_service_orders_id_fk": { + "name": "service_order_images_service_order_id_service_orders_id_fk", + "tableFrom": "service_order_images", + "tableTo": "service_orders", + "columnsFrom": ["service_order_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "service_order_images_employee_id_employees_id_fk": { + "name": "service_order_images_employee_id_employees_id_fk", + "tableFrom": "service_order_images", + "tableTo": "employees", + "columnsFrom": ["employee_id"], + "columnsTo": ["id"], + "onDelete": "restrict", + "onUpdate": "no action" + }, + "service_order_images_upload_id_uploads_id_fk": { + "name": "service_order_images_upload_id_uploads_id_fk", + "tableFrom": "service_order_images", + "tableTo": "uploads", + "columnsFrom": ["upload_id"], + "columnsTo": ["id"], + "onDelete": "restrict", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "service_order_images_id": { + "name": "service_order_images_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "service_orders": { + "name": "service_orders", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "company_id": { + "name": "company_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "client_id": { + "name": "client_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "employee_id": { + "name": "employee_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "device_brand_id": { + "name": "device_brand_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "device_category_id": { + "name": "device_category_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "device_model": { + "name": "device_model", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "imei": { + "name": "imei", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "reported_defect": { + "name": "reported_defect", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "observations": { + "name": "observations", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "enum('pending','diagnosing','waiting_approval','approved','fixing','ready','delivered')", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'pending'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": { + "service_orders_company_id_companies_id_fk": { + "name": "service_orders_company_id_companies_id_fk", + "tableFrom": "service_orders", + "tableTo": "companies", + "columnsFrom": ["company_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "service_orders_client_id_clients_id_fk": { + "name": "service_orders_client_id_clients_id_fk", + "tableFrom": "service_orders", + "tableTo": "clients", + "columnsFrom": ["client_id"], + "columnsTo": ["id"], + "onDelete": "restrict", + "onUpdate": "no action" + }, + "service_orders_employee_id_employees_id_fk": { + "name": "service_orders_employee_id_employees_id_fk", + "tableFrom": "service_orders", + "tableTo": "employees", + "columnsFrom": ["employee_id"], + "columnsTo": ["id"], + "onDelete": "restrict", + "onUpdate": "no action" + }, + "service_orders_device_brand_id_model_makers_id_fk": { + "name": "service_orders_device_brand_id_model_makers_id_fk", + "tableFrom": "service_orders", + "tableTo": "model_makers", + "columnsFrom": ["device_brand_id"], + "columnsTo": ["id"], + "onDelete": "restrict", + "onUpdate": "no action" + }, + "service_orders_device_category_id_model_categories_id_fk": { + "name": "service_orders_device_category_id_model_categories_id_fk", + "tableFrom": "service_orders", + "tableTo": "model_categories", + "columnsFrom": ["device_category_id"], + "columnsTo": ["id"], + "onDelete": "restrict", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "service_orders_id": { + "name": "service_orders_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "uploads": { + "name": "uploads", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "company_id": { + "name": "company_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "employee_id": { + "name": "employee_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "key": { + "name": "key", + "type": "varchar(512)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "varchar(512)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "file_name": { + "name": "file_name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "content_type": { + "name": "content_type", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "size_in_bytes": { + "name": "size_in_bytes", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "varchar(20)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'pending'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": { + "uploads_company_id_companies_id_fk": { + "name": "uploads_company_id_companies_id_fk", + "tableFrom": "uploads", + "tableTo": "companies", + "columnsFrom": ["company_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "uploads_employee_id_employees_id_fk": { + "name": "uploads_employee_id_employees_id_fk", + "tableFrom": "uploads", + "tableTo": "employees", + "columnsFrom": ["employee_id"], + "columnsTo": ["id"], + "onDelete": "restrict", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "uploads_id": { + "name": "uploads_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "users": { + "name": "users", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "password_hash": { + "name": "password_hash", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "google_id": { + "name": "google_id", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "avatar_url": { + "name": "avatar_url", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "verified": { + "name": "verified", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "users_id": { + "name": "users_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "users_email_unique": { + "name": "users_email_unique", + "columns": ["email"] + }, + "users_google_id_unique": { + "name": "users_google_id_unique", + "columns": ["google_id"] + } + }, + "checkConstraint": {} + } + }, + "views": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "tables": {}, + "indexes": {} + } +} diff --git a/packages/db/drizzle/meta/0011_snapshot.json b/packages/db/drizzle/meta/0011_snapshot.json new file mode 100644 index 0000000..4ecf4c3 --- /dev/null +++ b/packages/db/drizzle/meta/0011_snapshot.json @@ -0,0 +1,1421 @@ +{ + "version": "5", + "dialect": "mysql", + "id": "0b530de8-4672-48e9-872d-56bc108a654e", + "prevId": "0f499b87-ef09-4b34-a384-2a6f28f37c2d", + "tables": { + "clients": { + "name": "clients", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cpf": { + "name": "cpf", + "type": "varchar(11)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "phone": { + "name": "phone", + "type": "varchar(11)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "user_id": { + "name": "user_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "clients_user_id_users_id_fk": { + "name": "clients_user_id_users_id_fk", + "tableFrom": "clients", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "clients_id": { + "name": "clients_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "clients_cpf_unique": { + "name": "clients_cpf_unique", + "columns": ["cpf"] + } + }, + "checkConstraint": {} + }, + "companies": { + "name": "companies", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cnpj": { + "name": "cnpj", + "type": "varchar(14)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "address": { + "name": "address", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "subdomain": { + "name": "subdomain", + "type": "varchar(32)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "companies_id": { + "name": "companies_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "companies_cnpj_unique": { + "name": "companies_cnpj_unique", + "columns": ["cnpj"] + }, + "companies_subdomain_unique": { + "name": "companies_subdomain_unique", + "columns": ["subdomain"] + } + }, + "checkConstraint": {} + }, + "model_makers": { + "name": "model_makers", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "slug": { + "name": "slug", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "device_count": { + "name": "device_count", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "page_count": { + "name": "page_count", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "model_makers_id": { + "name": "model_makers_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "employees": { + "name": "employees", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cpf": { + "name": "cpf", + "type": "varchar(11)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "phone": { + "name": "phone", + "type": "varchar(11)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "roles": { + "name": "roles", + "type": "enum('guest','technician','warehouse','financial','manager','admin')", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "user_id": { + "name": "user_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "company_id": { + "name": "company_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "employees_user_id_users_id_fk": { + "name": "employees_user_id_users_id_fk", + "tableFrom": "employees", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "employees_company_id_companies_id_fk": { + "name": "employees_company_id_companies_id_fk", + "tableFrom": "employees", + "tableTo": "companies", + "columnsFrom": ["company_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "employees_id": { + "name": "employees_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "employees_cpf_unique": { + "name": "employees_cpf_unique", + "columns": ["cpf"] + } + }, + "checkConstraint": {} + }, + "model_categories": { + "name": "model_categories", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "slug": { + "name": "slug", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "model_categories_id": { + "name": "model_categories_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "model_images": { + "name": "model_images", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "model_id": { + "name": "model_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "r2_key": { + "name": "r2_key", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "is_primary": { + "name": "is_primary", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "variant": { + "name": "variant", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "position": { + "name": "position", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": { + "model_images_model_id_models_id_fk": { + "name": "model_images_model_id_models_id_fk", + "tableFrom": "model_images", + "tableTo": "models", + "columnsFrom": ["model_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "model_images_id": { + "name": "model_images_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "models": { + "name": "models", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "maker_id": { + "name": "maker_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "slug": { + "name": "slug", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "category_id": { + "name": "category_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "announced": { + "name": "announced", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "dimensions": { + "name": "dimensions", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "weight": { + "name": "weight", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "build": { + "name": "build", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "sim": { + "name": "sim", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_type": { + "name": "display_type", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_size": { + "name": "display_size", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_resolution": { + "name": "display_resolution", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_protection": { + "name": "display_protection", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "os": { + "name": "os", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "chipset": { + "name": "chipset", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "cpu": { + "name": "cpu", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "gpu": { + "name": "gpu", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "card_slot": { + "name": "card_slot", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "internal_memory": { + "name": "internal_memory", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "main_camera": { + "name": "main_camera", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "main_camera_features": { + "name": "main_camera_features", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "main_camera_video": { + "name": "main_camera_video", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "selfie_camera": { + "name": "selfie_camera", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "selfie_features": { + "name": "selfie_features", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "selfie_video": { + "name": "selfie_video", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "battery": { + "name": "battery", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "battery_charging": { + "name": "battery_charging", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "network_tech": { + "name": "network_tech", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "sensors": { + "name": "sensors", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "colors": { + "name": "colors", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "colors_hex": { + "name": "colors_hex", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "models_text": { + "name": "models_text", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "price": { + "name": "price", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "dimensions_width": { + "name": "dimensions_width", + "type": "float", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "dimensions_height": { + "name": "dimensions_height", + "type": "float", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "dimensions_thickness": { + "name": "dimensions_thickness", + "type": "float", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "weight_grams": { + "name": "weight_grams", + "type": "float", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_size_inches": { + "name": "display_size_inches", + "type": "float", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_size_ratio": { + "name": "display_size_ratio", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_res_width": { + "name": "display_res_width", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_res_height": { + "name": "display_res_height", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_res_ppi": { + "name": "display_res_ppi", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "released": { + "name": "released", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "meta": { + "name": "meta", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "company_id": { + "name": "company_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": { + "models_maker_id_model_makers_id_fk": { + "name": "models_maker_id_model_makers_id_fk", + "tableFrom": "models", + "tableTo": "model_makers", + "columnsFrom": ["maker_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "models_category_id_model_categories_id_fk": { + "name": "models_category_id_model_categories_id_fk", + "tableFrom": "models", + "tableTo": "model_categories", + "columnsFrom": ["category_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "models_company_id_companies_id_fk": { + "name": "models_company_id_companies_id_fk", + "tableFrom": "models", + "tableTo": "companies", + "columnsFrom": ["company_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "models_id": { + "name": "models_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "slug_company_unique": { + "name": "slug_company_unique", + "columns": ["slug", "company_id"] + } + }, + "checkConstraint": {} + }, + "one_time_tokens": { + "name": "one_time_tokens", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "ott_type": { + "name": "ott_type", + "type": "enum('confirmation','password_reset','account_deletion')", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "relates_to": { + "name": "relates_to", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "one_time_tokens_user_id_users_id_fk": { + "name": "one_time_tokens_user_id_users_id_fk", + "tableFrom": "one_time_tokens", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "one_time_tokens_id": { + "name": "one_time_tokens_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "one_time_tokens_token_unique": { + "name": "one_time_tokens_token_unique", + "columns": ["token"] + } + }, + "checkConstraint": {} + }, + "refresh_tokens": { + "name": "refresh_tokens", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "refresh_tokens_user_id_users_id_fk": { + "name": "refresh_tokens_user_id_users_id_fk", + "tableFrom": "refresh_tokens", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "refresh_tokens_id": { + "name": "refresh_tokens_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "refresh_tokens_token_unique": { + "name": "refresh_tokens_token_unique", + "columns": ["token"] + } + }, + "checkConstraint": {} + }, + "service_order_images": { + "name": "service_order_images", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "service_order_id": { + "name": "service_order_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "employee_id": { + "name": "employee_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "upload_id": { + "name": "upload_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "image_url": { + "name": "image_url", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "file_name": { + "name": "file_name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "size_in_bytes": { + "name": "size_in_bytes", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "content_type": { + "name": "content_type", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": { + "service_order_images_service_order_id_service_orders_id_fk": { + "name": "service_order_images_service_order_id_service_orders_id_fk", + "tableFrom": "service_order_images", + "tableTo": "service_orders", + "columnsFrom": ["service_order_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "service_order_images_employee_id_employees_id_fk": { + "name": "service_order_images_employee_id_employees_id_fk", + "tableFrom": "service_order_images", + "tableTo": "employees", + "columnsFrom": ["employee_id"], + "columnsTo": ["id"], + "onDelete": "restrict", + "onUpdate": "no action" + }, + "service_order_images_upload_id_uploads_id_fk": { + "name": "service_order_images_upload_id_uploads_id_fk", + "tableFrom": "service_order_images", + "tableTo": "uploads", + "columnsFrom": ["upload_id"], + "columnsTo": ["id"], + "onDelete": "restrict", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "service_order_images_id": { + "name": "service_order_images_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "service_orders": { + "name": "service_orders", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "company_id": { + "name": "company_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "client_id": { + "name": "client_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "employee_id": { + "name": "employee_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "device_brand_id": { + "name": "device_brand_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "device_category_id": { + "name": "device_category_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "device_model": { + "name": "device_model", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "imei": { + "name": "imei", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "reported_defect": { + "name": "reported_defect", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "observations": { + "name": "observations", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "enum('pending','diagnosing','waiting_approval','approved','fixing','ready','delivered')", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'pending'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": { + "service_orders_company_id_companies_id_fk": { + "name": "service_orders_company_id_companies_id_fk", + "tableFrom": "service_orders", + "tableTo": "companies", + "columnsFrom": ["company_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "service_orders_client_id_clients_id_fk": { + "name": "service_orders_client_id_clients_id_fk", + "tableFrom": "service_orders", + "tableTo": "clients", + "columnsFrom": ["client_id"], + "columnsTo": ["id"], + "onDelete": "restrict", + "onUpdate": "no action" + }, + "service_orders_employee_id_employees_id_fk": { + "name": "service_orders_employee_id_employees_id_fk", + "tableFrom": "service_orders", + "tableTo": "employees", + "columnsFrom": ["employee_id"], + "columnsTo": ["id"], + "onDelete": "restrict", + "onUpdate": "no action" + }, + "service_orders_device_brand_id_model_makers_id_fk": { + "name": "service_orders_device_brand_id_model_makers_id_fk", + "tableFrom": "service_orders", + "tableTo": "model_makers", + "columnsFrom": ["device_brand_id"], + "columnsTo": ["id"], + "onDelete": "restrict", + "onUpdate": "no action" + }, + "service_orders_device_category_id_model_categories_id_fk": { + "name": "service_orders_device_category_id_model_categories_id_fk", + "tableFrom": "service_orders", + "tableTo": "model_categories", + "columnsFrom": ["device_category_id"], + "columnsTo": ["id"], + "onDelete": "restrict", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "service_orders_id": { + "name": "service_orders_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "uploads": { + "name": "uploads", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "company_id": { + "name": "company_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "employee_id": { + "name": "employee_id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "key": { + "name": "key", + "type": "varchar(512)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "varchar(512)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "file_name": { + "name": "file_name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "content_type": { + "name": "content_type", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "size_in_bytes": { + "name": "size_in_bytes", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "varchar(20)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'pending'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": { + "uploads_company_id_companies_id_fk": { + "name": "uploads_company_id_companies_id_fk", + "tableFrom": "uploads", + "tableTo": "companies", + "columnsFrom": ["company_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "uploads_employee_id_employees_id_fk": { + "name": "uploads_employee_id_employees_id_fk", + "tableFrom": "uploads", + "tableTo": "employees", + "columnsFrom": ["employee_id"], + "columnsTo": ["id"], + "onDelete": "restrict", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "uploads_id": { + "name": "uploads_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "users": { + "name": "users", + "columns": { + "id": { + "name": "id", + "type": "varchar(25)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "password_hash": { + "name": "password_hash", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "google_id": { + "name": "google_id", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "avatar_url": { + "name": "avatar_url", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "verified": { + "name": "verified", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "users_id": { + "name": "users_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "users_email_unique": { + "name": "users_email_unique", + "columns": ["email"] + }, + "users_google_id_unique": { + "name": "users_google_id_unique", + "columns": ["google_id"] + } + }, + "checkConstraint": {} + } + }, + "views": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "tables": {}, + "indexes": {} + } +} diff --git a/packages/db/drizzle/meta/_journal.json b/packages/db/drizzle/meta/_journal.json index a3a26fd..6f2e713 100644 --- a/packages/db/drizzle/meta/_journal.json +++ b/packages/db/drizzle/meta/_journal.json @@ -50,6 +50,41 @@ "when": 1779902286658, "tag": "0006_awesome_cloak", "breakpoints": true + }, + { + "idx": 7, + "version": "5", + "when": 1780260069002, + "tag": "0007_romantic_union_jack", + "breakpoints": true + }, + { + "idx": 8, + "version": "5", + "when": 1780260191632, + "tag": "0008_slimy_abomination", + "breakpoints": true + }, + { + "idx": 9, + "version": "5", + "when": 1780262325715, + "tag": "0009_ambiguous_hammerhead", + "breakpoints": true + }, + { + "idx": 10, + "version": "5", + "when": 1780263000000, + "tag": "0010_sturdy_fulltext", + "breakpoints": true + }, + { + "idx": 11, + "version": "5", + "when": 1780264072893, + "tag": "0011_crazy_slapstick", + "breakpoints": true } ] } diff --git a/packages/db/src/schema/model-categories.ts b/packages/db/src/schema/model-categories.ts index 70ec4c3..dfbdde9 100644 --- a/packages/db/src/schema/model-categories.ts +++ b/packages/db/src/schema/model-categories.ts @@ -1,16 +1,14 @@ import { createId } from "@paralleldrive/cuid2"; -import { mysqlTable, text, varchar } from "drizzle-orm/mysql-core"; +import { mysqlTable, varchar } from "drizzle-orm/mysql-core"; import { createSelectSchema } from "drizzle-zod"; -/** @description Device categories table — groups models by type (e.g. smartphone, tablet) */ +/** @description Device categories table: groups models by type (e.g. smartphone, tablet) */ export const modelCategories = mysqlTable("model_categories", { id: varchar("id", { length: 25 }) .$defaultFn(() => createId()) .primaryKey(), name: varchar("name", { length: 100 }).notNull(), slug: varchar("slug", { length: 100 }).notNull(), - url: varchar("url", { length: 255 }).notNull(), - imageUrl: text("image_url"), }); /** @description Zod schema for selecting a category record */ diff --git a/packages/db/src/schema/model-images.ts b/packages/db/src/schema/model-images.ts index 6636c66..081e067 100644 --- a/packages/db/src/schema/model-images.ts +++ b/packages/db/src/schema/model-images.ts @@ -17,7 +17,6 @@ export const modelImages = mysqlTable("model_images", { modelId: varchar("model_id", { length: 25 }) .notNull() .references(() => models.id), - originalUrl: varchar("original_url", { length: 255 }), r2Key: varchar("r2_key", { length: 255 }), isPrimary: boolean("is_primary").notNull().default(false), variant: varchar("variant", { length: 50 }), diff --git a/packages/db/src/schema/model-makers.ts b/packages/db/src/schema/model-makers.ts index 3e62246..3ac0249 100644 --- a/packages/db/src/schema/model-makers.ts +++ b/packages/db/src/schema/model-makers.ts @@ -2,7 +2,7 @@ import { createId } from "@paralleldrive/cuid2"; import { int, mysqlTable, timestamp, varchar } from "drizzle-orm/mysql-core"; import { createSelectSchema } from "drizzle-zod"; -/** @description Device makers (brands) table — stores manufacturer/brand info */ +/** @description Device makers (brands) table: stores manufacturer/brand info */ export const modelMakers = mysqlTable("model_makers", { id: varchar("id", { length: 25 }) .$defaultFn(() => createId()) diff --git a/packages/db/src/schema/models.ts b/packages/db/src/schema/models.ts index d0a8509..f49deaf 100644 --- a/packages/db/src/schema/models.ts +++ b/packages/db/src/schema/models.ts @@ -26,8 +26,6 @@ export const models = mysqlTable( name: varchar("name", { length: 255 }).notNull(), slug: varchar("slug", { length: 100 }).notNull(), url: varchar("url", { length: 255 }).notNull(), - imageUrl: varchar("image_url", { length: 255 }), - imageLocalPath: varchar("image_local_path", { length: 255 }), categoryId: varchar("category_id", { length: 25 }).references( () => modelCategories.id diff --git a/packages/schemas/src/models.ts b/packages/schemas/src/models.ts index c1ef243..bb63913 100644 --- a/packages/schemas/src/models.ts +++ b/packages/schemas/src/models.ts @@ -1,7 +1,7 @@ import { z } from "zod"; import { getPaginatedDataSchema } from "./utils"; -/** @description Query schema for listing categories — optional name filter */ +/** @description Query schema for listing categories: optional name filter */ export const getModelCategoriesQuerySchema = z.object({ query: z.string().optional(), }); @@ -11,7 +11,7 @@ export const getModelCategoryParamsSchema = z.object({ slug: z.string().min(1), }); -/** @description Query schema for listing makers — pagination, sorting, and optional name filter */ +/** @description Query schema for listing makers: pagination, sorting, and optional name filter */ export const getModelMakersQuerySchema = getPaginatedDataSchema.extend({ sort: z.enum(["newer", "older", "name", "most_devices"]).optional(), }); @@ -29,7 +29,7 @@ export const modelStatuses = z.enum([ "Rumored", ]); -/** @description Query schema for listing models — pagination, fulltext search, filters, and sorting */ +/** @description Query schema for listing models: pagination, fulltext search, filters, and sorting */ export const getModelsQuerySchema = getPaginatedDataSchema.extend({ makerId: z.string().cuid2().optional(), categoryId: z.string().cuid2().optional(), @@ -108,7 +108,6 @@ export const modelImageParamsSchema = z.object({ /** @description Body schema for assigning an uploaded image to a model */ export const createModelImageBodySchema = z.object({ r2Key: z.string().min(1), - originalUrl: z.string().url().optional(), isPrimary: z.boolean().optional(), variant: z.string().optional(), position: z.number().int().optional(), From b0b23baa1cba28f048accef2e7485dd2d273b5e9 Mon Sep 17 00:00:00 2001 From: Ricardo Amorim <102877738+risixdzn@users.noreply.github.com> Date: Sun, 31 May 2026 19:48:43 -0300 Subject: [PATCH 8/9] refactor(Devices): Remove unknown casts on known types --- apps/server/src/config/r2.ts | 5 +- .../src/modules/models/repositories/index.ts | 36 ++++++++-- .../src/modules/models/services/index.ts | 67 ++++++++----------- 3 files changed, 62 insertions(+), 46 deletions(-) diff --git a/apps/server/src/config/r2.ts b/apps/server/src/config/r2.ts index 23d27c4..10d6e96 100644 --- a/apps/server/src/config/r2.ts +++ b/apps/server/src/config/r2.ts @@ -57,10 +57,7 @@ export function isAllowedCompanyPhotoUrl(url: string, companyId: string) { * @param key - The R2 object key (nullable) * @returns A presigned URL valid for 24 hours, or null if key is empty */ -export async function generatePresignedGetUrl( - key: string | null | undefined -): Promise { - if (!key) return null; +export async function generatePresignedGetUrl(key: string): Promise { const command = new GetObjectCommand({ Bucket: r2Bucket, Key: key, diff --git a/apps/server/src/modules/models/repositories/index.ts b/apps/server/src/modules/models/repositories/index.ts index b56da8a..726965c 100644 --- a/apps/server/src/modules/models/repositories/index.ts +++ b/apps/server/src/modules/models/repositories/index.ts @@ -11,6 +11,7 @@ import { sql, } from "@fixr/db/connection"; import { + type ModelImageSelect, modelCategories, modelImages, modelMakers, @@ -55,6 +56,33 @@ export const modelListJoins = [ }, ]; +export interface ModelFlatRecord { + id: string; + name: string; + slug: string; + status: string | null; + price: string | null; + released: string | null; + makerId: string; + makerName: string; + makerSlug: string; + categoryId: string | null; + categoryName: string | null; + categorySlug: string | null; +} + +export interface ModelListRecord { + id: string; + name: string; + slug: string; + status: string; + price: string | null; + released: string | null; + maker: { id: string; name: string; slug: string }; + category: { id: string; name: string; slug: string } | null; + imageUrl: string | null; +} + /** @description Data access layer for device models */ export class ModelsRepository { /** @@ -254,9 +282,9 @@ export class ModelsRepository { * @param r2Key - The R2 object key * @returns Presigned URL or null */ - static async generateImagePresignedUrl(r2Key: string | null | undefined) { + static async generateImagePresignedUrl(r2Key: string | null) { if (!r2Key) return null; - return (await generatePresignedGetUrl(r2Key)) ?? null; + return await generatePresignedGetUrl(r2Key); } /** @@ -266,8 +294,8 @@ export class ModelsRepository { * @returns Images with presignedUrl attached */ static async attachPresignedUrlsToImages( - images: Record[] - ): Promise[]> { + images: ModelImageSelect[] + ): Promise<(ModelImageSelect & { presignedUrl: string })[]> { return await Promise.all( images.map(async (img) => { const r2Key = img.r2Key as string; diff --git a/apps/server/src/modules/models/services/index.ts b/apps/server/src/modules/models/services/index.ts index 8cbae99..c9f7efc 100644 --- a/apps/server/src/modules/models/services/index.ts +++ b/apps/server/src/modules/models/services/index.ts @@ -14,6 +14,8 @@ import { } from "../../../core/lib/pagination"; import { apiResponse, paginatedData } from "../../../core/lib/response"; import { + type ModelFlatRecord, + type ModelListRecord, ModelsRepository, modelListJoins, modelMinimalListSelect, @@ -139,38 +141,33 @@ export class ModelsService { const next_page = PER_PAGE * (page - 1) + records.length < totalRecords ? page + 1 : null; - const modelIds = (records as Record[]).map( - (r) => r.id as string - ); + const modelIds = (records as ModelFlatRecord[]).map((r) => r.id); const primaryImageMap = await ModelsRepository.queryPrimaryImages(modelIds); - const recordsWithImages = await Promise.all( - (records as Record[]).map(async (r) => { - const record = { ...r }; - record.maker = { - id: record.makerId, - name: record.makerName, - slug: record.makerSlug, - }; - record.category = record.categoryId + const recordsWithImages: ModelListRecord[] = await Promise.all( + (records as ModelFlatRecord[]).map(async (r) => ({ + id: r.id, + name: r.name, + slug: r.slug, + status: r.status ?? "Available", + price: r.price, + released: r.released, + maker: { + id: r.makerId, + name: r.makerName, + slug: r.makerSlug, + }, + category: r.categoryId ? { - id: record.categoryId, - name: record.categoryName, - slug: record.categorySlug, + id: r.categoryId, + name: r.categoryName!, + slug: r.categorySlug!, } - : null; - record.makerId = undefined; - record.makerName = undefined; - record.makerSlug = undefined; - record.categoryId = undefined; - record.categoryName = undefined; - record.categorySlug = undefined; - const r2Key = primaryImageMap.get(record.id as string); - record.imageUrl = - await ModelsRepository.generateImagePresignedUrl(r2Key); - record.status = record.status ?? "Available"; - return record as Record; - }) + : null, + imageUrl: await ModelsRepository.generateImagePresignedUrl( + primaryImageMap.get(r.id) ?? null + ), + })) ); return response.status(200).send( @@ -234,9 +231,7 @@ export class ModelsService { const primaryImage = images.find((img) => img.isPrimary); const [imageUrl, imagesWithPresignedUrls] = await Promise.all([ ModelsRepository.generateImagePresignedUrl(primaryImage?.r2Key ?? null), - ModelsRepository.attachPresignedUrlsToImages( - images as Record[] - ), + ModelsRepository.attachPresignedUrlsToImages(images), ]); return response.status(200).send( @@ -246,7 +241,7 @@ export class ModelsService { code: "get_model_success", message: "Model retrieved successfully.", data: { - ...(model as Record), + ...model, status: model.status ?? "Available", imageUrl, images: imagesWithPresignedUrls, @@ -379,9 +374,7 @@ export class ModelsService { const primaryImage = images.find((img) => img.isPrimary); const [imageUrl, imagesWithPresignedUrls] = await Promise.all([ ModelsRepository.generateImagePresignedUrl(primaryImage?.r2Key ?? null), - ModelsRepository.attachPresignedUrlsToImages( - images as Record[] - ), + ModelsRepository.attachPresignedUrlsToImages(images), ]); return response.status(200).send( @@ -495,9 +488,7 @@ export class ModelsService { }); const [imageWithPresignedUrl] = - await ModelsRepository.attachPresignedUrlsToImages([ - image as Record, - ]); + await ModelsRepository.attachPresignedUrlsToImages([image!]); return response.status(201).send( apiResponse({ From 30b44c4cf4aeb18a37d1413fc2260b0d89561777 Mon Sep 17 00:00:00 2001 From: Ricardo Amorim <102877738+risixdzn@users.noreply.github.com> Date: Fri, 12 Jun 2026 12:30:36 -0300 Subject: [PATCH 9/9] fix(Server): Copilot code quality review improvements --- .../src/core/docs/models/models.docs.ts | 2 +- .../server/src/modules/models/errors/index.ts | 5 ++ .../src/modules/models/repositories/index.ts | 85 ++++++++++++++++++- .../src/modules/models/services/index.ts | 40 ++++----- packages/db/package.json | 1 - packages/db/src/schema/models.ts | 11 +++ packages/schemas/src/models.ts | 1 - 7 files changed, 114 insertions(+), 31 deletions(-) diff --git a/apps/server/src/core/docs/models/models.docs.ts b/apps/server/src/core/docs/models/models.docs.ts index 19744fe..cfd4413 100644 --- a/apps/server/src/core/docs/models/models.docs.ts +++ b/apps/server/src/core/docs/models/models.docs.ts @@ -312,7 +312,7 @@ const createModelImageSchema: FastifySchema = { description: ` **Creates a model image record, linking an uploaded file to a device model.** -Provide the \`r2Key\` (and optional \`originalUrl\`) returned from the presign upload endpoint. Returns the created model image with a presigned URL. +Provide the \`r2Key\` returned from the presign upload endpoint. Returns the created model image with a presigned URL. `, params: z.object({ subdomain: z.string(), modelId: z.string() }), body: createModelImageBodySchema, diff --git a/apps/server/src/modules/models/errors/index.ts b/apps/server/src/modules/models/errors/index.ts index a070579..57f3feb 100644 --- a/apps/server/src/modules/models/errors/index.ts +++ b/apps/server/src/modules/models/errors/index.ts @@ -37,4 +37,9 @@ export const modelsErrors = defineErrors({ message: "Model image not found.", status: 404, }, + MODEL_IMAGE_KEY_MISMATCH: { + code: "model_image_key_mismatch", + message: "The provided image key does not belong to your company.", + status: 403, + }, }); diff --git a/apps/server/src/modules/models/repositories/index.ts b/apps/server/src/modules/models/repositories/index.ts index 726965c..a5ee04c 100644 --- a/apps/server/src/modules/models/repositories/index.ts +++ b/apps/server/src/modules/models/repositories/index.ts @@ -295,16 +295,95 @@ export class ModelsRepository { */ static async attachPresignedUrlsToImages( images: ModelImageSelect[] - ): Promise<(ModelImageSelect & { presignedUrl: string })[]> { + ): Promise<(ModelImageSelect & { presignedUrl: string | null })[]> { return await Promise.all( images.map(async (img) => { - const r2Key = img.r2Key as string; - const presignedUrl = await generatePresignedGetUrl(r2Key); + const presignedUrl = img.r2Key + ? await generatePresignedGetUrl(img.r2Key) + : null; return { ...img, presignedUrl }; }) ); } + /** + * Find a model by its ID with full maker and category relations + * + * @param id - The model ID + * @returns The model record with relations or null + */ + static async queryModelById(id: string) { + const [model] = await db + .select({ + id: models.id, + makerId: models.makerId, + name: models.name, + slug: models.slug, + url: models.url, + categoryId: models.categoryId, + announced: models.announced, + status: models.status, + dimensions: models.dimensions, + weight: models.weight, + build: models.build, + sim: models.sim, + displayType: models.displayType, + displaySize: models.displaySize, + displayResolution: models.displayResolution, + displayProtection: models.displayProtection, + os: models.os, + chipset: models.chipset, + cpu: models.cpu, + gpu: models.gpu, + cardSlot: models.cardSlot, + internalMemory: models.internalMemory, + mainCamera: models.mainCamera, + mainCameraFeatures: models.mainCameraFeatures, + mainCameraVideo: models.mainCameraVideo, + selfieCamera: models.selfieCamera, + selfieFeatures: models.selfieFeatures, + selfieVideo: models.selfieVideo, + battery: models.battery, + batteryCharging: models.batteryCharging, + networkTech: models.networkTech, + sensors: models.sensors, + colors: models.colors, + colorsHex: models.colorsHex, + modelsText: models.modelsText, + price: models.price, + dimensionsWidth: models.dimensionsWidth, + dimensionsHeight: models.dimensionsHeight, + dimensionsThickness: models.dimensionsThickness, + weightGrams: models.weightGrams, + displaySizeInches: models.displaySizeInches, + displaySizeRatio: models.displaySizeRatio, + displayResWidth: models.displayResWidth, + displayResHeight: models.displayResHeight, + displayResPpi: models.displayResPpi, + released: models.released, + meta: models.meta, + companyId: models.companyId, + createdAt: models.createdAt, + maker: { + id: modelMakers.id, + name: modelMakers.name, + slug: modelMakers.slug, + url: modelMakers.url, + }, + category: { + id: modelCategories.id, + name: modelCategories.name, + slug: modelCategories.slug, + }, + }) + .from(models) + .innerJoin(modelMakers, eq(modelMakers.id, models.makerId)) + .leftJoin(modelCategories, eq(modelCategories.id, models.categoryId)) + .where(eq(models.id, id)) + .limit(1); + return model ?? null; + } + /** * Check if a slug already exists for a given company * diff --git a/apps/server/src/modules/models/services/index.ts b/apps/server/src/modules/models/services/index.ts index c9f7efc..95bb192 100644 --- a/apps/server/src/modules/models/services/index.ts +++ b/apps/server/src/modules/models/services/index.ts @@ -226,7 +226,7 @@ export class ModelsService { throw new AppError("MODEL_NOT_FOUND"); } - const images = await ModelsRepository.queryModelImages(model.id as string); + const images = await ModelsRepository.queryModelImages(model.id); const primaryImage = images.find((img) => img.isPrimary); const [imageUrl, imagesWithPresignedUrls] = await Promise.all([ @@ -345,10 +345,7 @@ export class ModelsService { throw new AppError("MODEL_NOT_ALLOWED"); } - const model = await ModelsRepository.queryModelBySlug( - modelId, - userJwt.company.id - ); + const model = await ModelsRepository.queryModelById(modelId); if (!model) { throw new AppError("MODEL_NOT_FOUND"); @@ -364,12 +361,9 @@ export class ModelsService { await ModelsRepository.updateModel(modelId, updateData); } - const updated = await ModelsRepository.queryModelBySlug( - model.id as string, - userJwt.company.id - ); + const updated = await ModelsRepository.queryModelById(modelId); - const images = await ModelsRepository.queryModelImages(model.id as string); + const images = await ModelsRepository.queryModelImages(model.id); const primaryImage = images.find((img) => img.isPrimary); const [imageUrl, imagesWithPresignedUrls] = await Promise.all([ @@ -419,15 +413,12 @@ export class ModelsService { throw new AppError("MODEL_NOT_ALLOWED"); } - const model = await ModelsRepository.queryModelBySlug( - modelId, - userJwt.company.id - ); + const model = await ModelsRepository.queryModelById(modelId); if (!model) { throw new AppError("MODEL_NOT_FOUND"); } - await ModelsRepository.deleteModel(model.id as string); + await ModelsRepository.deleteModel(model.id); return response.status(200).send( apiResponse({ @@ -469,18 +460,20 @@ export class ModelsService { throw new AppError("MODEL_NOT_ALLOWED"); } - const model = await ModelsRepository.queryModelBySlug( - modelId, - userJwt.company.id - ); + const model = await ModelsRepository.queryModelById(modelId); if (!model) { throw new AppError("MODEL_NOT_FOUND"); } + const expectedPrefix = `companies/${userJwt.company.id}/models/`; + if (!data.r2Key.startsWith(expectedPrefix)) { + throw new AppError("MODEL_IMAGE_KEY_MISMATCH"); + } + const imageId = createId(); const image = await ModelsRepository.insertModelImage({ id: imageId, - modelId: model.id as string, + modelId: model.id, r2Key: data.r2Key, isPrimary: data.isPrimary ?? false, variant: data.variant ?? null, @@ -530,15 +523,12 @@ export class ModelsService { throw new AppError("MODEL_NOT_ALLOWED"); } - const model = await ModelsRepository.queryModelBySlug( - modelId, - userJwt.company.id - ); + const model = await ModelsRepository.queryModelById(modelId); if (!model) { throw new AppError("MODEL_NOT_FOUND"); } - const images = await ModelsRepository.queryModelImages(model.id as string); + const images = await ModelsRepository.queryModelImages(model.id); const image = images.find((img) => img.id === imageId); if (!image) { throw new AppError("MODEL_IMAGE_NOT_FOUND"); diff --git a/packages/db/package.json b/packages/db/package.json index 72ce746..3eb2c53 100644 --- a/packages/db/package.json +++ b/packages/db/package.json @@ -8,7 +8,6 @@ "db:generate": "bunx --bun drizzle-kit generate", "db:studio": "bunx --bun drizzle-kit studio", "db:migrate": "tsx src/migrate.ts", - "db:seed": "bun src/seed.ts", "db:start": "docker compose up -d", "db:watch": "docker compose up", "db:stop": "docker compose stop", diff --git a/packages/db/src/schema/models.ts b/packages/db/src/schema/models.ts index f49deaf..ca5860c 100644 --- a/packages/db/src/schema/models.ts +++ b/packages/db/src/schema/models.ts @@ -1,6 +1,7 @@ import { createId } from "@paralleldrive/cuid2"; import { float, + index, int, mysqlTable, text, @@ -84,6 +85,16 @@ export const models = mysqlTable( table.slug, table.companyId ), + modelsFulltextIdx: index("models_fulltext_idx") + .on( + table.name, + table.modelsText, + table.chipset, + table.cpu, + table.internalMemory, + table.os + ) + .using("fulltext" as "btree"), }) ); diff --git a/packages/schemas/src/models.ts b/packages/schemas/src/models.ts index bb63913..559f172 100644 --- a/packages/schemas/src/models.ts +++ b/packages/schemas/src/models.ts @@ -48,7 +48,6 @@ export const createModelBodySchema = z.object({ makerId: z.string().min(1), categoryId: z.string().optional(), status: modelStatuses.optional(), - imageLocalPath: z.string().optional(), announced: z.string().optional(), dimensions: z.string().optional(), weight: z.string().optional(),