Files
company-tool/backend/migrations/20260521170000_public_core.sql
Torsten Schulz (local) 0e539710c0 feat: Add password reset functionality with request and reset forms
feat: Implement price list import feature with preview and apply options

feat: Create price rules management page with CRUD operations

feat: Develop quotes management page with itemized quotes and status tracking

feat: Introduce organization registration page for new users

feat: Build suppliers management page with detailed supplier information

feat: Create users management page for inviting and managing roles

chore: Add TypeScript configuration for improved type checking

chore: Set up Vite configuration for development server and API proxy

chore: Add Vite environment type definitions for better TypeScript support
2026-06-02 15:28:38 +02:00

95 lines
3.5 KiB
SQL

create table if not exists users (
id uuid primary key,
email text not null unique,
display_name_ciphertext bytea,
display_name_nonce bytea,
display_name_key_id text,
password_hash text,
is_active boolean not null default true,
must_change_password boolean not null default false,
initial_password_expires_at timestamptz,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now(),
last_login_at timestamptz,
constraint users_email_lowercase check (email = lower(email)),
constraint users_display_name_encryption_complete check (
(
display_name_ciphertext is null
and display_name_nonce is null
and display_name_key_id is null
)
or (
display_name_ciphertext is not null
and display_name_nonce is not null
and display_name_key_id is not null
)
)
);
create table if not exists organizations (
id uuid primary key,
display_name_ciphertext bytea,
display_name_nonce bytea,
display_name_key_id text,
schema_name text unique,
status text not null default 'pending_approval',
registration_email text not null,
setup_completed_at timestamptz,
approved_by_user_id uuid references users(id),
approved_at timestamptz,
rejected_by_user_id uuid references users(id),
rejected_at timestamptz,
rejection_reason text,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now(),
constraint organizations_status_valid check (
status in ('pending_approval', 'approved', 'active', 'rejected', 'suspended')
),
constraint organizations_registration_email_lowercase check (registration_email = lower(registration_email)),
constraint organizations_schema_name_valid check (
schema_name is null or schema_name ~ '^company_[a-z0-9_]+$'
),
constraint organizations_display_name_encryption_complete check (
(
display_name_ciphertext is null
and display_name_nonce is null
and display_name_key_id is null
)
or (
display_name_ciphertext is not null
and display_name_nonce is not null
and display_name_key_id is not null
)
)
);
create table if not exists user_organizations (
user_id uuid not null references users(id) on delete cascade,
organization_id uuid not null references organizations(id) on delete cascade,
status text not null default 'pending_invitation',
invited_by_user_id uuid references users(id),
invited_at timestamptz,
accepted_at timestamptz,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now(),
primary key (user_id, organization_id),
constraint user_organizations_status_valid check (
status in ('pending_invitation', 'active', 'disabled')
)
);
create table if not exists organization_domains (
id uuid primary key,
organization_id uuid not null references organizations(id) on delete cascade,
domain text not null unique,
is_primary boolean not null default false,
created_at timestamptz not null default now(),
constraint organization_domains_domain_lowercase check (domain = lower(domain))
);
create index if not exists idx_user_organizations_organization_id
on user_organizations (organization_id);
create index if not exists idx_organizations_status
on organizations (status);