diff --git a/full_schema.sql b/full_schema.sql new file mode 100644 index 0000000..7933a63 --- /dev/null +++ b/full_schema.sql @@ -0,0 +1,285 @@ +DROP SCHEMA IF EXISTS gpi CASCADE; +-- Criar schema gpi +CREATE SCHEMA IF NOT EXISTS gpi; + +-- Tabela organizations +CREATE TABLE IF NOT EXISTS gpi.organizations ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + name TEXT NOT NULL, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +-- Inserir organização padrão +INSERT INTO gpi.organizations (id, name) +VALUES ('e47e6210-4879-4e5b-bf21-9285d2713123', 'Organização Migrada') +ON CONFLICT (id) DO NOTHING; +CREATE TABLE IF NOT EXISTS gpi.users ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + logto_id TEXT UNIQUE, + email TEXT NOT NULL, + name TEXT, + role TEXT DEFAULT 'user', + is_banned BOOLEAN DEFAULT false, + last_seen_at TIMESTAMPTZ, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE TABLE IF NOT EXISTS gpi.projects ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + organization_id UUID NOT NULL, + name TEXT NOT NULL, + client TEXT, + start_date DATE, + end_date DATE, + environment TEXT, + technician TEXT, + weight_kg DECIMAL(10,2), + status TEXT DEFAULT 'active' CHECK (status IN ('active', 'archived')), + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +-- Tabela parts +CREATE TABLE IF NOT EXISTS gpi.parts ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + organization_id UUID NOT NULL, + project_id UUID REFERENCES gpi.projects(id) ON DELETE CASCADE, + description TEXT, + dimensions TEXT, + weight DECIMAL(10,3), + type TEXT, + area DECIMAL(10,3), + complexity INTEGER DEFAULT 1, + quantity INTEGER NOT NULL DEFAULT 1, + notes TEXT, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +-- Tabela painting_schemes +CREATE TABLE IF NOT EXISTS gpi.painting_schemes ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + organization_id UUID NOT NULL, + project_id UUID REFERENCES gpi.projects(id) ON DELETE CASCADE, + name TEXT NOT NULL, + type TEXT, + coat TEXT, + solids_volume DECIMAL(5,2), + yield_theoretical DECIMAL(10,2), + eps_min DECIMAL(5,2), + eps_max DECIMAL(5,2), + dilution DECIMAL(5,2), + manufacturer TEXT, + color TEXT, + paint_consumption DECIMAL(10,3), + thinner_consumption DECIMAL(10,3), + paint_id TEXT, + thinner_id TEXT, + color_hex TEXT, + thinner_symbol TEXT, + notes TEXT, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +-- Tabela application_records +CREATE TABLE IF NOT EXISTS gpi.application_records ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + organization_id UUID NOT NULL, + project_id UUID REFERENCES gpi.projects(id) ON DELETE CASCADE, + coat_stage TEXT NOT NULL, + piece_description TEXT, + date DATE, + operator TEXT, + real_weight DECIMAL(10,3), + volume_used DECIMAL(10,3), + area_painted DECIMAL(10,3), + wet_thickness_avg DECIMAL(6,2), + dry_thickness_calc DECIMAL(6,2), + real_yield DECIMAL(10,3), + method TEXT, + diluent_used DECIMAL(10,3), + items JSONB, + notes TEXT, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +-- Tabela inspections +CREATE TABLE IF NOT EXISTS gpi.inspections ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + organization_id UUID NOT NULL, + project_id UUID REFERENCES gpi.projects(id) ON DELETE CASCADE, + application_record_id UUID REFERENCES gpi.application_records(id), + stock_item_id TEXT, + instrument_id TEXT, + type TEXT CHECK (type IN ('painting', 'surface_treatment')), + date DATE, + inspector TEXT, + part_temperature DECIMAL(6,2), + weight_kg DECIMAL(10,3), + appearance TEXT, + defects TEXT, + photos TEXT[], + piece_description TEXT, + eps_points DECIMAL(6,2)[], + adhesion_test TEXT, + batch TEXT, + treatment_executor TEXT, + treatment_type TEXT, + cleaning_degree TEXT, + roughness_readings DECIMAL(6,2)[], + flash_rust TEXT, + temperature DECIMAL(6,2), + relative_humidity DECIMAL(5,2), + period TEXT CHECK (period IN ('morning', 'afternoon', 'night')), + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +-- Tabela technical_data_sheets +CREATE TABLE IF NOT EXISTS gpi.technical_data_sheets ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + organization_id UUID NOT NULL, + name TEXT NOT NULL, + manufacturer TEXT, + type TEXT, + file_url TEXT, + upload_date DATE, + solids_volume DECIMAL(5,2), + density DECIMAL(6,3), + mixing_ratio TEXT, + yield_theoretical DECIMAL(10,2), + wft_min DECIMAL(6,2), + wft_max DECIMAL(6,2), + dft_min DECIMAL(6,2), + dft_max DECIMAL(6,2), + reducer TEXT, + mixing_ratio_weight TEXT, + mixing_ratio_volume TEXT, + dft_reference DECIMAL(6,2), + yield_factor DECIMAL(5,3), + dilution DECIMAL(5,2), + notes TEXT, + manufacturer_code TEXT, + min_stock DECIMAL(10,3), + typical_application TEXT, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +-- Tabela yield_studies +CREATE TABLE IF NOT EXISTS gpi.yield_studies ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + organization_id UUID NOT NULL, + name TEXT NOT NULL, + data_sheet_id TEXT NOT NULL, + target_dft DECIMAL(6,2) NOT NULL, + dilution_percent DECIMAL(5,2) NOT NULL, + categories JSONB NOT NULL, + total_weight DECIMAL(10,3), + estimated_paint_volume DECIMAL(10,3), + estimated_reducer_volume DECIMAL(10,3), + estimated_paint_volume_by_area DECIMAL(10,3), + estimated_reducer_volume_by_area DECIMAL(10,3), + average_complexity DECIMAL(3,1), + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +-- Tabela instruments +CREATE TABLE IF NOT EXISTS gpi.instruments ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + organization_id UUID NOT NULL, + name TEXT NOT NULL, + type TEXT NOT NULL, + serial_number TEXT, + manufacturer TEXT, + model TEXT, + last_calibration DATE, + next_calibration DATE, + status TEXT DEFAULT 'active', + notes TEXT, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +-- Tabela stock_items +CREATE TABLE IF NOT EXISTS gpi.stock_items ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + organization_id UUID NOT NULL, + name TEXT NOT NULL, + type TEXT NOT NULL, + batch_number TEXT, + quantity DECIMAL(10,3) DEFAULT 0, + unit TEXT DEFAULT 'L', + data_sheet_id TEXT, + location TEXT, + expiration_date DATE, + status TEXT DEFAULT 'available', + notes TEXT, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +-- Tabela stock_movements +CREATE TABLE IF NOT EXISTS gpi.stock_movements ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + organization_id UUID NOT NULL, + stock_item_id UUID REFERENCES gpi.stock_items(id) ON DELETE CASCADE, + type TEXT NOT NULL CHECK (type IN ('in', 'out', 'adjustment')), + quantity DECIMAL(10,3) NOT NULL, + reason TEXT, + performed_by TEXT, + notes TEXT, + created_at TIMESTAMPTZ DEFAULT NOW() +); + +-- Tabela notifications +CREATE TABLE IF NOT EXISTS gpi.notifications ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + organization_id UUID NOT NULL, + title TEXT NOT NULL, + message TEXT NOT NULL, + type TEXT DEFAULT 'info' CHECK (type IN ('info', 'warning', 'error', 'success')), + is_read BOOLEAN DEFAULT false, + is_archived BOOLEAN DEFAULT false, + archived_by TEXT[], + deleted_by TEXT[], + metadata JSONB, + created_at TIMESTAMPTZ DEFAULT NOW() +); + +-- Tabela geometry_types +CREATE TABLE IF NOT EXISTS gpi.geometry_types ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + organization_id UUID NOT NULL, + name TEXT NOT NULL, + efficiency_loss DECIMAL(5,2), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +-- Habilitar PostgREST para o schema gpi +GRANT USAGE ON SCHEMA gpi TO postgres, anon, authenticated, service_role; + +-- Grant permissions em todas as tabelas +GRANT ALL ON TABLE gpi.users TO postgres, anon, authenticated, service_role; +GRANT ALL ON TABLE gpi.projects TO postgres, anon, authenticated, service_role; +GRANT ALL ON TABLE gpi.parts TO postgres, anon, authenticated, service_role; +GRANT ALL ON TABLE gpi.painting_schemes TO postgres, anon, authenticated, service_role; +GRANT ALL ON TABLE gpi.application_records TO postgres, anon, authenticated, service_role; +GRANT ALL ON TABLE gpi.inspections TO postgres, anon, authenticated, service_role; +GRANT ALL ON TABLE gpi.technical_data_sheets TO postgres, anon, authenticated, service_role; +GRANT ALL ON TABLE gpi.yield_studies TO postgres, anon, authenticated, service_role; +GRANT ALL ON TABLE gpi.instruments TO postgres, anon, authenticated, service_role; +GRANT ALL ON TABLE gpi.stock_items TO postgres, anon, authenticated, service_role; +GRANT ALL ON TABLE gpi.stock_movements TO postgres, anon, authenticated, service_role; +GRANT ALL ON TABLE gpi.notifications TO postgres, anon, authenticated, service_role; +GRANT ALL ON TABLE gpi.geometry_types TO postgres, anon, authenticated, service_role; + +-- Grant sequences +GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA gpi TO postgres, anon, authenticated, service_role; + +SELECT 'Schema gpi criado com sucesso!' AS result; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 6ea7c7d..7938b95 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,6 +24,7 @@ "express": "^5.2.1", "jose": "^5.2.0", "lucide-react": "^0.562.0", + "mongodb": "^7.1.1", "multer": "^2.0.2", "pdf-parse": "^1.1.1", "prop-types": "^15.8.1", @@ -2389,6 +2390,15 @@ "node": ">=10" } }, + "node_modules/@mongodb-js/saslprep": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.4.6.tgz", + "integrity": "sha512-y+x3H1xBZd38n10NZF/rEBlvDOOMQ6LKUTHqr8R9VkJ+mmQOYtJFxIlkkK8fZrtOiL6VixbOBWMbZGBdal3Z1g==", + "license": "MIT", + "dependencies": { + "sparse-bitfield": "^3.0.3" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "dev": true, @@ -3595,6 +3605,21 @@ "version": "10.0.0", "license": "MIT" }, + "node_modules/@types/webidl-conversions": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", + "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==", + "license": "MIT" + }, + "node_modules/@types/whatwg-url": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-13.0.0.tgz", + "integrity": "sha512-N8WXpbE6Wgri7KUSvrmQcqrMllKZ9uxkYWMt+mCSGwNc0Hsw9VQTW7ApqI4XNrx6/SaM2QQJCzMPDEXE058s+Q==", + "license": "MIT", + "dependencies": { + "@types/webidl-conversions": "*" + } + }, "node_modules/@types/ws": { "version": "8.18.1", "license": "MIT", @@ -5022,6 +5047,15 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/bson": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/bson/-/bson-7.2.0.tgz", + "integrity": "sha512-YCEo7KjMlbNlyHhz7zAZNDpIpQbd+wOEHJYezv0nMYTn4x31eIUM2yomNNubclAt63dObUzKHWsBLJ9QcZNSnQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=20.19.0" + } + }, "node_modules/buffer-from": { "version": "1.1.2", "license": "MIT" @@ -8010,6 +8044,12 @@ "node": ">= 0.8" } }, + "node_modules/memory-pager": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", + "license": "MIT" + }, "node_modules/merge-descriptors": { "version": "2.0.0", "license": "MIT", @@ -8133,6 +8173,65 @@ "mkdirp": "bin/cmd.js" } }, + "node_modules/mongodb": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-7.1.1.tgz", + "integrity": "sha512-067DXiMjcpYQl6bGjWQoTUEE9UoRViTtKFcoqX7z08I+iDZv/emH1g8XEFiO3qiDfXAheT5ozl1VffDTKhIW/w==", + "license": "Apache-2.0", + "dependencies": { + "@mongodb-js/saslprep": "^1.3.0", + "bson": "^7.1.1", + "mongodb-connection-string-url": "^7.0.0" + }, + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@aws-sdk/credential-providers": "^3.806.0", + "@mongodb-js/zstd": "^7.0.0", + "gcp-metadata": "^7.0.1", + "kerberos": "^7.0.0", + "mongodb-client-encryption": ">=7.0.0 <7.1.0", + "snappy": "^7.3.2", + "socks": "^2.8.6" + }, + "peerDependenciesMeta": { + "@aws-sdk/credential-providers": { + "optional": true + }, + "@mongodb-js/zstd": { + "optional": true + }, + "gcp-metadata": { + "optional": true + }, + "kerberos": { + "optional": true + }, + "mongodb-client-encryption": { + "optional": true + }, + "snappy": { + "optional": true + }, + "socks": { + "optional": true + } + } + }, + "node_modules/mongodb-connection-string-url": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-7.0.1.tgz", + "integrity": "sha512-h0AZ9A7IDVwwHyMxmdMXKy+9oNlF0zFoahHiX3vQ8e3KFcSP3VmsmfvtRSuLPxmyv2vjIDxqty8smTgie/SNRQ==", + "license": "Apache-2.0", + "dependencies": { + "@types/whatwg-url": "^13.0.0", + "whatwg-url": "^14.1.0" + }, + "engines": { + "node": ">=20.19.0" + } + }, "node_modules/mri": { "version": "1.2.0", "dev": true, @@ -8769,7 +8868,6 @@ }, "node_modules/punycode": { "version": "2.3.1", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -9695,6 +9793,15 @@ "dev": true, "license": "MIT" }, + "node_modules/sparse-bitfield": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", + "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", + "license": "MIT", + "dependencies": { + "memory-pager": "^1.0.2" + } + }, "node_modules/statuses": { "version": "2.0.2", "license": "MIT", @@ -10084,6 +10191,18 @@ "nodetouch": "bin/nodetouch.js" } }, + "node_modules/tr46": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz", + "integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==", + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/tree-kill": { "version": "1.2.2", "dev": true, @@ -11126,6 +11245,28 @@ "version": "1.8.0", "license": "Apache-2.0" }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-url": { + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz", + "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==", + "license": "MIT", + "dependencies": { + "tr46": "^5.1.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/which": { "version": "2.0.2", "license": "ISC", diff --git a/package.json b/package.json index b43e3f5..5aab0a0 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "express": "^5.2.1", "jose": "^5.2.0", "lucide-react": "^0.562.0", + "mongodb": "^7.1.1", "multer": "^2.0.2", "pdf-parse": "^1.1.1", "prop-types": "^15.8.1", diff --git a/reset_gpi.sql b/reset_gpi.sql new file mode 100644 index 0000000..153eb55 --- /dev/null +++ b/reset_gpi.sql @@ -0,0 +1 @@ +DROP SCHEMA IF EXISTS gpi CASCADE; diff --git a/supabase_gpi_schema.sql b/supabase_gpi_schema.sql index 400e9f1..ec168a1 100644 --- a/supabase_gpi_schema.sql +++ b/supabase_gpi_schema.sql @@ -1,7 +1,18 @@ -- Criar schema gpi CREATE SCHEMA IF NOT EXISTS gpi; --- Tabela users (já existe em public, mas replicamos em gpi) +-- Tabela organizations +CREATE TABLE IF NOT EXISTS gpi.organizations ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + name TEXT NOT NULL, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +-- Inserir organização padrão +INSERT INTO gpi.organizations (id, name) +VALUES ('e47e6210-4879-4e5b-bf21-9285d2713123', 'Organização Migrada') +ON CONFLICT (id) DO NOTHING; CREATE TABLE IF NOT EXISTS gpi.users ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), logto_id TEXT UNIQUE, @@ -14,9 +25,9 @@ CREATE TABLE IF NOT EXISTS gpi.users ( updated_at TIMESTAMPTZ DEFAULT NOW() ); --- Tabela projects CREATE TABLE IF NOT EXISTS gpi.projects ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + organization_id UUID NOT NULL, name TEXT NOT NULL, client TEXT, start_date DATE, @@ -24,8 +35,7 @@ CREATE TABLE IF NOT EXISTS gpi.projects ( environment TEXT, technician TEXT, weight_kg DECIMAL(10,2), - painted_weight DECIMAL(10,2), - created_by TEXT, + status TEXT DEFAULT 'active' CHECK (status IN ('active', 'archived')), created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); @@ -33,7 +43,8 @@ CREATE TABLE IF NOT EXISTS gpi.projects ( -- Tabela parts CREATE TABLE IF NOT EXISTS gpi.parts ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - project_id UUID REFERENCES gpi/projects(id) ON DELETE CASCADE, + organization_id UUID NOT NULL, + project_id UUID REFERENCES gpi.projects(id) ON DELETE CASCADE, description TEXT, dimensions TEXT, weight DECIMAL(10,3), @@ -49,7 +60,8 @@ CREATE TABLE IF NOT EXISTS gpi.parts ( -- Tabela painting_schemes CREATE TABLE IF NOT EXISTS gpi.painting_schemes ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - project_id UUID REFERENCES gpi/projects(id) ON DELETE CASCADE, + organization_id UUID NOT NULL, + project_id UUID REFERENCES gpi.projects(id) ON DELETE CASCADE, name TEXT NOT NULL, type TEXT, coat TEXT, @@ -67,7 +79,6 @@ CREATE TABLE IF NOT EXISTS gpi.painting_schemes ( color_hex TEXT, thinner_symbol TEXT, notes TEXT, - created_by TEXT, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); @@ -75,7 +86,8 @@ CREATE TABLE IF NOT EXISTS gpi.painting_schemes ( -- Tabela application_records CREATE TABLE IF NOT EXISTS gpi.application_records ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - project_id UUID REFERENCES gpi/projects(id) ON DELETE CASCADE, + organization_id UUID NOT NULL, + project_id UUID REFERENCES gpi.projects(id) ON DELETE CASCADE, coat_stage TEXT NOT NULL, piece_description TEXT, date DATE, @@ -90,7 +102,6 @@ CREATE TABLE IF NOT EXISTS gpi.application_records ( diluent_used DECIMAL(10,3), items JSONB, notes TEXT, - created_by TEXT, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); @@ -98,8 +109,9 @@ CREATE TABLE IF NOT EXISTS gpi.application_records ( -- Tabela inspections CREATE TABLE IF NOT EXISTS gpi.inspections ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - project_id UUID REFERENCES gpi/projects(id) ON DELETE CASCADE, - application_record_id UUID REFERENCES gpi/application_records(id), + organization_id UUID NOT NULL, + project_id UUID REFERENCES gpi.projects(id) ON DELETE CASCADE, + application_record_id UUID REFERENCES gpi.application_records(id), stock_item_id TEXT, instrument_id TEXT, type TEXT CHECK (type IN ('painting', 'surface_treatment')), @@ -122,7 +134,6 @@ CREATE TABLE IF NOT EXISTS gpi.inspections ( temperature DECIMAL(6,2), relative_humidity DECIMAL(5,2), period TEXT CHECK (period IN ('morning', 'afternoon', 'night')), - created_by TEXT, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); @@ -130,11 +141,12 @@ CREATE TABLE IF NOT EXISTS gpi.inspections ( -- Tabela technical_data_sheets CREATE TABLE IF NOT EXISTS gpi.technical_data_sheets ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + organization_id UUID NOT NULL, name TEXT NOT NULL, manufacturer TEXT, type TEXT, - file_url TEXT NOT NULL, - upload_date DATE NOT NULL, + file_url TEXT, + upload_date DATE, solids_volume DECIMAL(5,2), density DECIMAL(6,3), mixing_ratio TEXT, @@ -160,6 +172,7 @@ CREATE TABLE IF NOT EXISTS gpi.technical_data_sheets ( -- Tabela yield_studies CREATE TABLE IF NOT EXISTS gpi.yield_studies ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + organization_id UUID NOT NULL, name TEXT NOT NULL, data_sheet_id TEXT NOT NULL, target_dft DECIMAL(6,2) NOT NULL, @@ -178,16 +191,16 @@ CREATE TABLE IF NOT EXISTS gpi.yield_studies ( -- Tabela instruments CREATE TABLE IF NOT EXISTS gpi.instruments ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + organization_id UUID NOT NULL, name TEXT NOT NULL, type TEXT NOT NULL, - serial_number TEXT UNIQUE, + serial_number TEXT, manufacturer TEXT, model TEXT, last_calibration DATE, next_calibration DATE, status TEXT DEFAULT 'active', notes TEXT, - organization_id TEXT, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); @@ -195,6 +208,7 @@ CREATE TABLE IF NOT EXISTS gpi.instruments ( -- Tabela stock_items CREATE TABLE IF NOT EXISTS gpi.stock_items ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + organization_id UUID NOT NULL, name TEXT NOT NULL, type TEXT NOT NULL, batch_number TEXT, @@ -205,7 +219,6 @@ CREATE TABLE IF NOT EXISTS gpi.stock_items ( expiration_date DATE, status TEXT DEFAULT 'available', notes TEXT, - organization_id TEXT, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); @@ -213,7 +226,8 @@ CREATE TABLE IF NOT EXISTS gpi.stock_items ( -- Tabela stock_movements CREATE TABLE IF NOT EXISTS gpi.stock_movements ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - stock_item_id UUID REFERENCES gpi/stock_items(id) ON DELETE CASCADE, + organization_id UUID NOT NULL, + stock_item_id UUID REFERENCES gpi.stock_items(id) ON DELETE CASCADE, type TEXT NOT NULL CHECK (type IN ('in', 'out', 'adjustment')), quantity DECIMAL(10,3) NOT NULL, reason TEXT, @@ -225,6 +239,7 @@ CREATE TABLE IF NOT EXISTS gpi.stock_movements ( -- Tabela notifications CREATE TABLE IF NOT EXISTS gpi.notifications ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + organization_id UUID NOT NULL, title TEXT NOT NULL, message TEXT NOT NULL, type TEXT DEFAULT 'info' CHECK (type IN ('info', 'warning', 'error', 'success')), @@ -239,13 +254,13 @@ CREATE TABLE IF NOT EXISTS gpi.notifications ( -- Tabela geometry_types CREATE TABLE IF NOT EXISTS gpi.geometry_types ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + organization_id UUID NOT NULL, name TEXT NOT NULL, efficiency_loss DECIMAL(5,2), updated_at TIMESTAMPTZ DEFAULT NOW() ); -- Habilitar PostgREST para o schema gpi -ALTER SCHEMA gpi ENABLE VALUE; GRANT USAGE ON SCHEMA gpi TO postgres, anon, authenticated, service_role; -- Grant permissions em todas as tabelas