Files
warmbly/internal/infrastructure/db/migrations/000001_initial_schema.up.sql
T
2026-02-14 05:38:27 +01:00

130 lines
4.1 KiB
SQL

CREATE TABLE users (
id UUID NOT NULL DEFAULT gen_random_uuid (),
first_name VARCHAR(255) NOT NULL,
last_name VARCHAR(255) NOT NULL,
email TEXT UNIQUE NOT NULL,
password_hash TEXT,
max_organizations INT NOT NULL DEFAULT 5,
free_trial_used BOOLEAN NOT NULL DEFAULT FALSE,
-- Admin fields
admin_permissions INT NOT NULL DEFAULT 0,
admin_granted_at TIMESTAMPTZ,
admin_granted_by UUID,
banned_at TIMESTAMPTZ,
referral_source VARCHAR(50),
onboarding_completed_at TIMESTAMPTZ,
created_at TIMESTAMPTZ DEFAULT now (),
updated_at TIMESTAMPTZ DEFAULT now (),
PRIMARY KEY (id),
UNIQUE (email),
FOREIGN KEY (admin_granted_by) REFERENCES users(id)
);
CREATE INDEX idx_users_admin ON users(admin_permissions) WHERE admin_permissions > 0;
CREATE INDEX idx_users_banned ON users(banned_at) WHERE banned_at IS NOT NULL;
-- Organizations table
CREATE TABLE organizations (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name VARCHAR(255) NOT NULL,
slug VARCHAR(100) UNIQUE,
owner_user_id UUID NOT NULL REFERENCES users(id),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_organizations_owner ON organizations(owner_user_id);
CREATE INDEX idx_organizations_slug ON organizations(slug);
-- Organization membership
CREATE TABLE organization_members (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
organization_id UUID NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
role VARCHAR(50) NOT NULL DEFAULT 'viewer',
permissions SMALLINT NOT NULL DEFAULT 0,
invited_by UUID REFERENCES users(id),
invited_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
accepted_at TIMESTAMPTZ,
CONSTRAINT unique_org_member UNIQUE (organization_id, user_id)
);
CREATE INDEX idx_org_members_user ON organization_members(user_id);
CREATE INDEX idx_org_members_org ON organization_members(organization_id);
-- Organization invitations
CREATE TABLE organization_invitations (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
organization_id UUID NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
email VARCHAR(255) NOT NULL,
role VARCHAR(50) NOT NULL DEFAULT 'viewer',
permissions SMALLINT NOT NULL DEFAULT 0,
invited_by UUID NOT NULL REFERENCES users(id),
token VARCHAR(64) NOT NULL UNIQUE,
expires_at TIMESTAMPTZ NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
CONSTRAINT unique_pending_org_invite UNIQUE (organization_id, email)
);
CREATE INDEX idx_org_invitations_token ON organization_invitations(token);
CREATE INDEX idx_org_invitations_email ON organization_invitations(email);
-- Enterprise inquiries
CREATE TABLE enterprise_inquiries (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
company_name VARCHAR(255) NOT NULL,
contact_name VARCHAR(255) NOT NULL,
contact_email VARCHAR(255) NOT NULL,
estimated_volume INT,
team_size INT,
notes TEXT,
status VARCHAR(50) NOT NULL DEFAULT 'pending',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
processed_at TIMESTAMPTZ,
processed_by UUID REFERENCES users(id)
);
CREATE INDEX idx_enterprise_inquiries_status ON enterprise_inquiries(status);
CREATE INDEX idx_enterprise_inquiries_email ON enterprise_inquiries(contact_email);
CREATE TABLE sessions (
id UUID NOT NULL DEFAULT gen_random_uuid (),
user_id UUID NOT NULL,
current_organization_id UUID REFERENCES organizations(id),
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
expires_at TIMESTAMPTZ NOT NULL,
revoked_at TIMESTAMPTZ,
last_refreshed_at TIMESTAMPTZ,
refresh_nonce TEXT,
access_nonce TEXT,
location_city TEXT,
location_region TEXT,
location_country TEXT,
location_country_code TEXT,
location_postal_code TEXT,
os_name TEXT,
browser_name TEXT,
PRIMARY KEY (id),
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);
CREATE INDEX idx_sessions_current_org ON sessions(current_organization_id);
CREATE TABLE languages (
id UUID NOT NULL DEFAULT gen_random_uuid(),
name TEXT NOT NULL,
PRIMARY KEY (id)
)