COMMIT 16MAR

This commit is contained in:
2026-03-17 07:34:09 -03:00
parent e88d145df7
commit c3563b9513
40 changed files with 903 additions and 2156 deletions

View File

@@ -0,0 +1,326 @@
-- Full Database Schema for GPI (PostgreSQL)
CREATE SCHEMA IF NOT EXISTS gpi;
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
-- 1. Organizations
CREATE TABLE IF NOT EXISTS gpi.organizations (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
clerk_id TEXT UNIQUE, -- Legacy
logto_id TEXT UNIQUE,
name TEXT NOT NULL,
is_banned BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- 2. Users
CREATE TABLE IF NOT EXISTS gpi.users (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
clerk_id TEXT UNIQUE, -- Legacy
logto_id TEXT UNIQUE,
email TEXT UNIQUE NOT NULL,
name TEXT NOT NULL,
role TEXT CHECK (role IN ('guest', 'user', 'admin')) DEFAULT 'guest',
is_banned BOOLEAN DEFAULT FALSE,
last_seen_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- 3. many-to-many user_organizations
CREATE TABLE IF NOT EXISTS gpi.user_organizations (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id UUID REFERENCES gpi.users(id) ON DELETE CASCADE,
organization_id UUID REFERENCES gpi.organizations(id) ON DELETE CASCADE,
role TEXT CHECK (role IN ('guest', 'user', 'admin')) DEFAULT 'guest',
is_banned BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
UNIQUE (user_id, organization_id)
);
-- 4. Technical Data Sheets (Fichas Técnicas)
CREATE TABLE IF NOT EXISTS gpi.technical_data_sheets (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
organization_id UUID REFERENCES gpi.organizations(id) ON DELETE CASCADE,
name TEXT NOT NULL,
manufacturer TEXT,
type TEXT,
file_url TEXT,
solids_volume DECIMAL,
density DECIMAL,
mixing_ratio TEXT,
yield_theoretical DECIMAL,
wft_min DECIMAL,
wft_max DECIMAL,
dft_min DECIMAL,
dft_max DECIMAL,
reducer TEXT,
yield_factor DECIMAL DEFAULT 1.0,
min_stock DECIMAL DEFAULT 0,
notes TEXT,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- 5. Projects
CREATE TABLE IF NOT EXISTS gpi.projects (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
organization_id UUID REFERENCES gpi.organizations(id) ON DELETE CASCADE,
name TEXT NOT NULL,
client TEXT NOT NULL,
start_date DATE,
end_date DATE,
technician TEXT,
environment TEXT,
weight_kg DECIMAL,
status TEXT DEFAULT 'active',
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- 6. Parts
CREATE TABLE IF NOT EXISTS gpi.parts (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
project_id UUID REFERENCES gpi.projects(id) ON DELETE CASCADE,
description TEXT NOT NULL,
dimensions TEXT,
weight DECIMAL,
type TEXT,
area DECIMAL,
complexity INTEGER,
quantity INTEGER DEFAULT 1,
notes TEXT,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- 7. Painting Schemes
CREATE TABLE IF NOT EXISTS gpi.painting_schemes (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
project_id UUID REFERENCES gpi.projects(id) ON DELETE CASCADE,
name TEXT NOT NULL,
type TEXT,
coat TEXT, -- Primer, Intermediate, Finish
solids_volume DECIMAL,
yield_theoretical DECIMAL,
eps_min DECIMAL,
eps_max DECIMAL,
dilution DECIMAL,
manufacturer TEXT,
color TEXT,
notes TEXT,
paint_id UUID REFERENCES gpi.technical_data_sheets(id),
thinner_id UUID REFERENCES gpi.technical_data_sheets(id),
color_hex TEXT,
thinner_symbol TEXT,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- 8. Application Records (Lotes de Pintura)
CREATE TABLE IF NOT EXISTS gpi.application_records (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
project_id UUID REFERENCES gpi.projects(id) ON DELETE CASCADE,
coat_stage TEXT,
piece_description TEXT,
date DATE,
operator TEXT,
real_weight DECIMAL,
volume_used DECIMAL,
area_painted DECIMAL,
wet_thickness_avg DECIMAL,
dry_thickness_calc DECIMAL,
real_yield DECIMAL,
method TEXT,
diluent_used DECIMAL,
notes TEXT,
items JSONB DEFAULT '[]', -- List of {partId, quantity}
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- 9. Instruments
CREATE TABLE IF NOT EXISTS gpi.instruments (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
organization_id UUID REFERENCES gpi.organizations(id) ON DELETE CASCADE,
name TEXT NOT NULL,
serial_number TEXT,
type TEXT,
last_calibration DATE,
calibration_due DATE,
status TEXT DEFAULT 'active',
notes TEXT,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- 10. Stock Items
CREATE TABLE IF NOT EXISTS gpi.stock_items (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
organization_id UUID REFERENCES gpi.organizations(id) ON DELETE CASCADE,
data_sheet_id UUID REFERENCES gpi.technical_data_sheets(id),
batch_number TEXT NOT NULL,
manufacturing_date DATE,
expiration_date DATE,
initial_quantity DECIMAL NOT NULL,
current_quantity DECIMAL NOT NULL,
unit TEXT DEFAULT 'L',
location TEXT,
status TEXT DEFAULT 'active',
notes TEXT,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- 11. Inspections
CREATE TABLE IF NOT EXISTS gpi.inspections (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
project_id UUID REFERENCES gpi.projects(id) ON DELETE CASCADE,
application_record_id UUID REFERENCES gpi.application_records(id),
stock_item_id UUID REFERENCES gpi.stock_items(id),
instrument_id UUID REFERENCES gpi.instruments(id),
type TEXT CHECK (type IN ('painting', 'surface_treatment')),
date DATE,
inspector TEXT,
part_temperature DECIMAL,
weight_kg DECIMAL,
appearance TEXT, -- approved, rejected, notes
defects TEXT,
photos TEXT[] DEFAULT '{}',
piece_description TEXT,
eps_points DECIMAL[] DEFAULT '{}',
adhesion_test TEXT,
batch TEXT,
treatment_executor TEXT,
treatment_type TEXT,
cleaning_degree TEXT,
roughness_readings DECIMAL[] DEFAULT '{}',
flash_rust TEXT,
temperature DECIMAL,
relative_humidity DECIMAL,
period TEXT,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- 12. Stock Movements
CREATE TABLE IF NOT EXISTS gpi.stock_movements (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
organization_id UUID REFERENCES gpi.organizations(id) ON DELETE CASCADE,
stock_item_id UUID REFERENCES gpi.stock_items(id) ON DELETE CASCADE,
type TEXT CHECK (type IN ('in', 'out', 'adjust')),
quantity DECIMAL NOT NULL,
reason TEXT,
project_id UUID REFERENCES gpi.projects(id),
user_id TEXT, -- external_id
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- 13. System Settings
CREATE TABLE IF NOT EXISTS gpi.system_settings (
settings_id TEXT PRIMARY KEY DEFAULT 'global',
app_name TEXT DEFAULT 'GPI',
app_subtitle TEXT DEFAULT 'Gestão de Pintura Industrial',
app_logo_url TEXT,
updated_by TEXT,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- 14. Notifications
CREATE TABLE IF NOT EXISTS gpi.notifications (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
organization_id UUID REFERENCES gpi.organizations(id) ON DELETE CASCADE,
recipient_id UUID REFERENCES gpi.users(id) ON DELETE CASCADE,
title TEXT NOT NULL,
message TEXT NOT NULL,
type TEXT CHECK (type IN ('info', 'warning', 'error', 'success')) DEFAULT 'info',
is_read BOOLEAN DEFAULT FALSE,
is_archived BOOLEAN DEFAULT FALSE,
archived_by UUID[] DEFAULT '{}',
deleted_by UUID[] DEFAULT '{}',
metadata JSONB DEFAULT '{}',
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- 15. Yield Studies
CREATE TABLE IF NOT EXISTS gpi.yield_studies (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
organization_id UUID REFERENCES gpi.organizations(id) ON DELETE CASCADE,
data_sheet_id UUID REFERENCES gpi.technical_data_sheets(id),
name TEXT NOT NULL,
target_dft DECIMAL NOT NULL,
dilution_percent DECIMAL DEFAULT 0,
categories JSONB DEFAULT '[]',
total_weight DECIMAL,
estimated_paint_volume DECIMAL,
estimated_reducer_volume DECIMAL,
estimated_paint_volume_by_area DECIMAL,
estimated_reducer_volume_by_area DECIMAL,
average_complexity DECIMAL,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- 16. Stock Audit Logs
CREATE TABLE IF NOT EXISTS gpi.stock_audit_logs (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
organization_id UUID REFERENCES gpi.organizations(id) ON DELETE CASCADE,
stock_item_id UUID REFERENCES gpi.stock_items(id) ON DELETE CASCADE,
movement_id UUID,
movement_number INTEGER,
user_id TEXT, -- external_id
user_name TEXT,
action TEXT NOT NULL,
details TEXT,
old_values JSONB,
new_values JSONB,
timestamp TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- 17. Messages
CREATE TABLE IF NOT EXISTS gpi.messages (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
organization_id UUID REFERENCES gpi.organizations(id) ON DELETE CASCADE,
from_user_id TEXT NOT NULL, -- external_id
to_user_id TEXT NOT NULL, -- external_id
message TEXT NOT NULL,
is_read BOOLEAN DEFAULT FALSE,
read_at TIMESTAMP WITH TIME ZONE,
is_archived BOOLEAN DEFAULT FALSE,
is_deleted_by_recipient BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- 18. Geometry Types
CREATE TABLE IF NOT EXISTS gpi.geometry_types (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
organization_id UUID REFERENCES gpi.organizations(id) ON DELETE CASCADE,
name TEXT NOT NULL,
efficiency_loss DECIMAL DEFAULT 0,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
UNIQUE (organization_id, name)
);
-- 19. Stored Files
CREATE TABLE IF NOT EXISTS gpi.stored_files (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
organization_id UUID REFERENCES gpi.organizations(id) ON DELETE CASCADE,
filename TEXT NOT NULL,
original_name TEXT,
mimetype TEXT,
size INTEGER,
path TEXT,
category TEXT,
reference_id TEXT,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Indexes
CREATE INDEX IF NOT EXISTS idx_projects_org ON gpi.projects(organization_id);
CREATE INDEX IF NOT EXISTS idx_parts_project ON gpi.parts(project_id);
CREATE INDEX IF NOT EXISTS idx_schemes_project ON gpi.painting_schemes(project_id);
CREATE INDEX IF NOT EXISTS idx_records_project ON gpi.application_records(project_id);
CREATE INDEX IF NOT EXISTS idx_inspections_project ON gpi.inspections(project_id);
CREATE INDEX IF NOT EXISTS idx_stock_org ON gpi.stock_items(organization_id);
CREATE INDEX IF NOT EXISTS idx_notifications_recipient ON gpi.notifications(recipient_id);
CREATE INDEX IF NOT EXISTS idx_messages_to ON gpi.messages(to_user_id, is_read);
CREATE INDEX IF NOT EXISTS idx_geometry_types_org ON gpi.geometry_types(organization_id);