```sql -- Organizations (multi-tenancy foundation) CREATE TABLE organizations ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name TEXT NOT NULL, slug TEXT UNIQUE NOT NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), is_active BOOLEAN DEFAULT TRUE, subscription_tier TEXT DEFAULT 'basic', modules_enabled JSONB DEFAULT '{ "crm": true, "hr": true, "finance": false, "inventory": false }' ); -- Users (Supabase Auth handles auth.users, we extend) CREATE TABLE user_profiles ( id UUID PRIMARY KEY REFERENCES auth.users(id) ON DELETE CASCADE, email TEXT NOT NULL UNIQUE, full_name TEXT, phone TEXT, avatar_url TEXT, role TEXT NOT NULL CHECK (role IN ( 'superadmin', 'org_admin', 'hr_manager', 'finance_manager', 'inventory_manager', 'crm_lead_manager', 'support_staff', 'normal_employee', 'viewer' )), organization_id UUID REFERENCES organizations(id) ON DELETE CASCADE, department_id UUID, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), is_active BOOLEAN DEFAULT TRUE ); -- Departments CREATE TABLE departments ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name TEXT NOT NULL, organization_id UUID NOT NULL REFERENCES organizations(id) ON DELETE CASCADE, parent_id UUID REFERENCES departments(id), created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); -- Now add the foreign key constraint to user_profiles ALTER TABLE user_profiles ADD CONSTRAINT fk_department FOREIGN KEY (department_id) REFERENCES departments(id); -- CRM Module Tables CREATE TABLE crm_leads ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), organization_id UUID NOT NULL REFERENCES organizations(id) ON DELETE CASCADE, first_name TEXT NOT NULL, last_name TEXT, email TEXT, phone TEXT, company TEXT, title TEXT, lead_source TEXT, lead_score INTEGER DEFAULT 0, stage TEXT NOT NULL DEFAULT 'new', value DECIMAL(12,2), owner_id UUID REFERENCES user_profiles(id), notes TEXT, loss_reason TEXT, next_followup_at TIMESTAMPTZ, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); -- HR Module Tables CREATE TABLE hr_employees ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), user_id UUID REFERENCES user_profiles(id) ON DELETE CASCADE, organization_id UUID NOT NULL REFERENCES organizations(id) ON DELETE CASCADE, employee_id TEXT NOT NULL, joining_date DATE NOT NULL, designation TEXT NOT NULL, salary DECIMAL(12,2) NOT NULL, bank_details JSONB, documents JSONB, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), UNIQUE(organization_id, employee_id) ); CREATE TABLE hr_attendance ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), employee_id UUID NOT NULL REFERENCES hr_employees(id) ON DELETE CASCADE, organization_id UUID NOT NULL REFERENCES organizations(id) ON DELETE CASCADE, date DATE NOT NULL, clock_in TIMESTAMPTZ, clock_out TIMESTAMPTZ, status TEXT DEFAULT 'present', notes TEXT, UNIQUE(employee_id, date) ); CREATE TABLE hr_leaves ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), employee_id UUID NOT NULL REFERENCES hr_employees(id) ON DELETE CASCADE, organization_id UUID NOT NULL REFERENCES organizations(id) ON DELETE CASCADE, start_date DATE NOT NULL, end_date DATE NOT NULL, type TEXT NOT NULL, reason TEXT, status TEXT DEFAULT 'pending', approved_by UUID REFERENCES user_profiles(id), created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); -- Finance Module Tables CREATE TABLE finance_invoices ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), organization_id UUID NOT NULL REFERENCES organizations(id) ON DELETE CASCADE, invoice_number TEXT NOT NULL, customer_id UUID, customer_name TEXT NOT NULL, date DATE NOT NULL, due_date DATE NOT NULL, status TEXT DEFAULT 'draft', subtotal DECIMAL(12,2) NOT NULL, tax_amount DECIMAL(12,2) NOT NULL, discount_amount DECIMAL(12,2) DEFAULT 0, total DECIMAL(12,2) NOT NULL, items JSONB NOT NULL, notes TEXT, created_by UUID REFERENCES user_profiles(id), created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), UNIQUE(organization_id, invoice_number) ); -- Inventory Module Tables CREATE TABLE inventory_products ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), organization_id UUID NOT NULL REFERENCES organizations(id) ON DELETE CASCADE, sku TEXT NOT NULL, name TEXT NOT NULL, description TEXT, category TEXT, hsn_code TEXT, gst_slab DECIMAL(5,2), cost_price DECIMAL(12,2) NOT NULL, selling_price DECIMAL(12,2) NOT NULL, current_stock INTEGER DEFAULT 0, min_stock_level INTEGER DEFAULT 10, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), UNIQUE(organization_id, sku) ); CREATE TABLE inventory_stock_movements ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), organization_id UUID NOT NULL REFERENCES organizations(id) ON DELETE CASCADE, product_id UUID NOT NULL REFERENCES inventory_products(id) ON DELETE CASCADE, type TEXT NOT NULL CHECK (type IN ('in', 'out')), quantity INTEGER NOT NULL, reference_id TEXT, reference_type TEXT, notes TEXT, created_by UUID REFERENCES user_profiles(id), created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); -- Workflows CREATE TABLE workflows ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), organization_id UUID NOT NULL REFERENCES organizations(id) ON DELETE CASCADE, name TEXT NOT NULL, description TEXT, trigger_type TEXT NOT NULL, trigger_condition JSONB NOT NULL, actions JSONB NOT NULL, is_active BOOLEAN DEFAULT TRUE, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); -- Audit Logs CREATE TABLE audit_logs ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), organization_id UUID REFERENCES organizations(id) ON DELETE CASCADE, user_id UUID REFERENCES user_profiles(id) ON DELETE SET NULL, action TEXT NOT NULL, entity_type TEXT, entity_id UUID, old_value JSONB, new_value JSONB, ip_address TEXT, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); -- Add indexes for performance CREATE INDEX idx_user_profiles_org ON user_profiles(organization_id); CREATE INDEX idx_crm_leads_org ON crm_leads(organization_id); CREATE INDEX idx_crm_leads_stage ON crm_leads(stage); CREATE INDEX idx_hr_employees_org ON hr_employees(organization_id); CREATE INDEX idx_finance_invoices_org ON finance_invoices(organization_id); CREATE INDEX idx_inventory_products_org ON inventory_products(organization_id); ```