From bb34a47fa8c8fe57569dff2008bb441f099ac16d Mon Sep 17 00:00:00 2001 From: Nils Schneider Date: Thu, 30 Oct 2025 17:53:00 +0100 Subject: [PATCH] squash database migrations --- .../down.sql | 6 +- .../up.sql | 141 ++++++++++++------ .../down.sql | 6 - .../up.sql | 7 - .../down.sql | 16 -- .../up.sql | 20 --- .../down.sql | 2 - .../up.sql | 2 - .../down.sql | 7 - .../up.sql | 24 --- .../202512010100_add_webdav_tokens/down.sql | 3 - .../202512010100_add_webdav_tokens/up.sql | 16 -- .../down.sql | 2 - .../up.sql | 2 - .../down.sql | 5 - .../up.sql | 19 --- .../202512010130_add_user_passkeys/down.sql | 1 - .../202512010130_add_user_passkeys/up.sql | 19 --- .../down.sql | 1 - .../up.sql | 13 -- .../down.sql | 2 - .../up.sql | 2 - .../202512010160_replace_tenant_slug/down.sql | 5 - .../202512010160_replace_tenant_slug/up.sql | 5 - .../down.sql | 2 - .../up.sql | 2 - .../down.sql | 6 - .../up.sql | 2 - backend/tests/common/mod.rs | 5 + 29 files changed, 106 insertions(+), 237 deletions(-) rename backend/migrations/{202503260001_initial_schema => 202510300000_initial_schema}/down.sql (82%) rename backend/migrations/{202503260001_initial_schema => 202510300000_initial_schema}/up.sql (62%) delete mode 100644 backend/migrations/202512010000_update_folder_unique_index/down.sql delete mode 100644 backend/migrations/202512010000_update_folder_unique_index/up.sql delete mode 100644 backend/migrations/202512010010_update_tenant_unique_indexes/down.sql delete mode 100644 backend/migrations/202512010010_update_tenant_unique_indexes/up.sql delete mode 100644 backend/migrations/202512010020_drop_document_version_operations_summary/down.sql delete mode 100644 backend/migrations/202512010020_drop_document_version_operations_summary/up.sql delete mode 100644 backend/migrations/202512010050_drop_correspondent_roles/down.sql delete mode 100644 backend/migrations/202512010050_drop_correspondent_roles/up.sql delete mode 100644 backend/migrations/202512010100_add_webdav_tokens/down.sql delete mode 100644 backend/migrations/202512010100_add_webdav_tokens/up.sql delete mode 100644 backend/migrations/202512010110_drop_webdav_token_scopes/down.sql delete mode 100644 backend/migrations/202512010110_drop_webdav_token_scopes/up.sql delete mode 100644 backend/migrations/202512010120_add_tenant_status_column/down.sql delete mode 100644 backend/migrations/202512010120_add_tenant_status_column/up.sql delete mode 100644 backend/migrations/202512010130_add_user_passkeys/down.sql delete mode 100644 backend/migrations/202512010130_add_user_passkeys/up.sql delete mode 100644 backend/migrations/202512010140_add_webauthn_challenges/down.sql delete mode 100644 backend/migrations/202512010140_add_webauthn_challenges/up.sql delete mode 100644 backend/migrations/202512010150_drop_user_membership_role/down.sql delete mode 100644 backend/migrations/202512010150_drop_user_membership_role/up.sql delete mode 100644 backend/migrations/202512010160_replace_tenant_slug/down.sql delete mode 100644 backend/migrations/202512010160_replace_tenant_slug/up.sql delete mode 100644 backend/migrations/202512010165_drop_tenant_name_unique/down.sql delete mode 100644 backend/migrations/202512010165_drop_tenant_name_unique/up.sql delete mode 100644 backend/migrations/202512010175_drop_password_column_on_users/down.sql delete mode 100644 backend/migrations/202512010175_drop_password_column_on_users/up.sql diff --git a/backend/migrations/202503260001_initial_schema/down.sql b/backend/migrations/202510300000_initial_schema/down.sql similarity index 82% rename from backend/migrations/202503260001_initial_schema/down.sql rename to backend/migrations/202510300000_initial_schema/down.sql index acd7e40..bf79af8 100644 --- a/backend/migrations/202503260001_initial_schema/down.sql +++ b/backend/migrations/202510300000_initial_schema/down.sql @@ -1,8 +1,10 @@ DROP TRIGGER IF EXISTS trg_jobs_updated_at ON jobs; DROP FUNCTION IF EXISTS touch_jobs_updated_at(); +DROP TABLE IF EXISTS webauthn_challenges; +DROP TABLE IF EXISTS user_passkeys; +DROP TABLE IF EXISTS webdav_tokens; ALTER TABLE documents DROP CONSTRAINT IF EXISTS documents_current_version_fk; - DROP TABLE IF EXISTS document_asset_objects; DROP TABLE IF EXISTS document_assets; DROP TABLE IF EXISTS document_versions; @@ -18,4 +20,6 @@ DROP TABLE IF EXISTS user_memberships; DROP TABLE IF EXISTS users; DROP TABLE IF EXISTS tenants; +DROP TYPE IF EXISTS tenant_status; + DROP EXTENSION IF EXISTS "pgcrypto"; diff --git a/backend/migrations/202503260001_initial_schema/up.sql b/backend/migrations/202510300000_initial_schema/up.sql similarity index 62% rename from backend/migrations/202503260001_initial_schema/up.sql rename to backend/migrations/202510300000_initial_schema/up.sql index bb328f3..c6d4296 100644 --- a/backend/migrations/202503260001_initial_schema/up.sql +++ b/backend/migrations/202510300000_initial_schema/up.sql @@ -1,14 +1,17 @@ CREATE EXTENSION IF NOT EXISTS "pgcrypto"; +CREATE TYPE tenant_status AS ENUM ('creating', 'active', 'suspended', 'deleting', 'error'); + CREATE TABLE tenants ( id UUID PRIMARY KEY, - slug TEXT NOT NULL UNIQUE, + name TEXT NOT NULL, storage_root TEXT, quickwit_index TEXT, - status TEXT NOT NULL DEFAULT 'active', config JSONB NOT NULL DEFAULT '{}'::jsonb, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), - updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() + updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + status tenant_status NOT NULL, + created_by UUID ); CREATE UNIQUE INDEX tenants_storage_root_unique @@ -22,7 +25,6 @@ CREATE UNIQUE INDEX tenants_quickwit_index_unique CREATE TABLE users ( id UUID PRIMARY KEY, username VARCHAR(100) NOT NULL UNIQUE, - password_hash VARCHAR(255) NOT NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); @@ -31,14 +33,13 @@ CREATE TABLE user_memberships ( id UUID PRIMARY KEY, user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, tenant_id UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE, - role TEXT NOT NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), UNIQUE (user_id, tenant_id) ); -CREATE INDEX user_memberships_tenant_id_idx ON user_memberships (tenant_id); -CREATE INDEX user_memberships_user_id_idx ON user_memberships (user_id); +CREATE INDEX user_memberships_tenant_id_idx ON user_memberships(tenant_id); +CREATE INDEX user_memberships_user_id_idx ON user_memberships(user_id); CREATE TABLE folders ( id UUID PRIMARY KEY, @@ -51,8 +52,12 @@ CREATE TABLE folders ( CREATE INDEX idx_folders_parent ON folders(parent_id); CREATE INDEX folders_tenant_id_idx ON folders(tenant_id); -CREATE UNIQUE INDEX folders_parent_name_unique_idx - ON folders (COALESCE(parent_id, '00000000-0000-0000-0000-000000000000'::uuid), name); +CREATE UNIQUE INDEX folders_tenant_parent_name_unique_idx + ON folders ( + tenant_id, + COALESCE(parent_id, '00000000-0000-0000-0000-000000000000'::uuid), + name + ); CREATE TABLE documents ( id UUID PRIMARY KEY, @@ -70,11 +75,10 @@ CREATE TABLE documents ( tenant_id UUID NOT NULL REFERENCES tenants(id) ); -CREATE INDEX idx_documents_folder ON documents (folder_id); -CREATE INDEX idx_documents_deleted_at ON documents (deleted_at); -CREATE INDEX documents_tenant_id_idx ON documents (tenant_id); -CREATE INDEX idx_documents_current_version_id ON documents (current_version_id); - +CREATE INDEX idx_documents_folder ON documents(folder_id); +CREATE INDEX idx_documents_deleted_at ON documents(deleted_at); +CREATE INDEX documents_tenant_id_idx ON documents(tenant_id); +CREATE INDEX idx_documents_current_version_id ON documents(current_version_id); CREATE INDEX idx_documents_folder_title ON documents ( COALESCE(folder_id, '00000000-0000-0000-0000-000000000000'::uuid), @@ -82,8 +86,9 @@ CREATE INDEX idx_documents_folder_title ) WHERE deleted_at IS NULL; -CREATE UNIQUE INDEX documents_unique_folder_filename +CREATE UNIQUE INDEX documents_tenant_folder_filename_unique ON documents ( + tenant_id, COALESCE(folder_id, '00000000-0000-0000-0000-000000000000'::uuid), filename ) @@ -97,14 +102,13 @@ CREATE TABLE document_versions ( size_bytes BIGINT NOT NULL, checksum VARCHAR(64) NOT NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), - operations_summary JSONB NOT NULL DEFAULT '{}'::jsonb, metadata JSONB NOT NULL DEFAULT '{}'::jsonb, tenant_id UUID NOT NULL REFERENCES tenants(id), CONSTRAINT document_versions_unique_version UNIQUE (document_id, version_number) ); -CREATE INDEX idx_document_versions_document ON document_versions (document_id); -CREATE INDEX document_versions_tenant_id_idx ON document_versions (tenant_id); +CREATE INDEX idx_document_versions_document ON document_versions(document_id); +CREATE INDEX document_versions_tenant_id_idx ON document_versions(tenant_id); ALTER TABLE documents ADD CONSTRAINT documents_current_version_fk @@ -114,13 +118,14 @@ ALTER TABLE documents CREATE TABLE tags ( id UUID PRIMARY KEY, - label VARCHAR(100) NOT NULL UNIQUE, + label VARCHAR(100) NOT NULL, color VARCHAR(7), created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), tenant_id UUID NOT NULL REFERENCES tenants(id) ); -CREATE INDEX tags_tenant_id_idx ON tags (tenant_id); +CREATE UNIQUE INDEX tags_tenant_label_unique ON tags(tenant_id, label); +CREATE INDEX tags_tenant_id_idx ON tags(tenant_id); CREATE TABLE document_tags ( document_id UUID NOT NULL REFERENCES documents(id) ON DELETE CASCADE, @@ -131,8 +136,8 @@ CREATE TABLE document_tags ( PRIMARY KEY (document_id, tag_id) ); -CREATE INDEX idx_document_tags_tag ON document_tags (tag_id); -CREATE INDEX document_tags_tenant_id_idx ON document_tags (tenant_id); +CREATE INDEX idx_document_tags_tag ON document_tags(tag_id); +CREATE INDEX document_tags_tenant_id_idx ON document_tags(tenant_id); CREATE TABLE correspondents ( id UUID PRIMARY KEY, @@ -140,27 +145,25 @@ CREATE TABLE correspondents ( metadata JSONB NOT NULL DEFAULT '{}'::jsonb, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), - tenant_id UUID NOT NULL REFERENCES tenants(id), - CONSTRAINT correspondents_name_unique UNIQUE (name) + tenant_id UUID NOT NULL REFERENCES tenants(id) ); -CREATE INDEX correspondents_tenant_id_idx ON correspondents (tenant_id); +CREATE UNIQUE INDEX correspondents_tenant_name_unique + ON correspondents (tenant_id, name); +CREATE INDEX correspondents_tenant_id_idx ON correspondents(tenant_id); CREATE TABLE document_correspondents ( document_id UUID NOT NULL REFERENCES documents(id) ON DELETE CASCADE, correspondent_id UUID NOT NULL REFERENCES correspondents(id) ON DELETE CASCADE, - role VARCHAR(32) NOT NULL, assigned_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), assigned_by UUID REFERENCES users(id), tenant_id UUID NOT NULL REFERENCES tenants(id), - PRIMARY KEY (document_id, correspondent_id, role), - CONSTRAINT document_correspondents_role_check CHECK (role IN ('sender', 'receiver', 'other')) + PRIMARY KEY (document_id, correspondent_id) ); -CREATE INDEX idx_document_correspondents_document ON document_correspondents (document_id); -CREATE INDEX idx_document_correspondents_correspondent ON document_correspondents (correspondent_id); -CREATE INDEX idx_document_correspondents_role ON document_correspondents (role); -CREATE INDEX document_correspondents_tenant_id_idx ON document_correspondents (tenant_id); +CREATE INDEX idx_document_correspondents_document ON document_correspondents(document_id); +CREATE INDEX idx_document_correspondents_correspondent ON document_correspondents(correspondent_id); +CREATE INDEX document_correspondents_tenant_id_idx ON document_correspondents(tenant_id); CREATE TABLE document_assets ( id UUID PRIMARY KEY, @@ -175,9 +178,9 @@ CREATE TABLE document_assets ( CONSTRAINT document_assets_cardinality_positive CHECK (cardinality IS NULL OR cardinality >= 1) ); -CREATE INDEX idx_document_assets_version ON document_assets (document_version_id); -CREATE INDEX idx_document_assets_type ON document_assets (asset_type); -CREATE INDEX document_assets_tenant_id_idx ON document_assets (tenant_id); +CREATE INDEX idx_document_assets_version ON document_assets(document_version_id); +CREATE INDEX idx_document_assets_type ON document_assets(asset_type); +CREATE INDEX document_assets_tenant_id_idx ON document_assets(tenant_id); CREATE TABLE document_asset_objects ( id UUID PRIMARY KEY, @@ -191,10 +194,8 @@ CREATE TABLE document_asset_objects ( ); CREATE INDEX idx_document_asset_objects_asset_ordinal - ON document_asset_objects (asset_id, ordinal); - -CREATE INDEX document_asset_objects_tenant_id_idx - ON document_asset_objects (tenant_id); + ON document_asset_objects(asset_id, ordinal); +CREATE INDEX document_asset_objects_tenant_id_idx ON document_asset_objects(tenant_id); CREATE TABLE jobs ( id UUID PRIMARY KEY, @@ -210,9 +211,9 @@ CREATE TABLE jobs ( CONSTRAINT jobs_status_check CHECK (status IN ('queued', 'processing', 'succeeded', 'failed')) ); -CREATE INDEX idx_jobs_status_run_after ON jobs (status, run_after); -CREATE INDEX idx_jobs_job_type ON jobs (job_type); -CREATE INDEX jobs_tenant_id_idx ON jobs (tenant_id); +CREATE INDEX idx_jobs_status_run_after ON jobs(status, run_after); +CREATE INDEX idx_jobs_job_type ON jobs(job_type); +CREATE INDEX jobs_tenant_id_idx ON jobs(tenant_id); CREATE OR REPLACE FUNCTION touch_jobs_updated_at() RETURNS TRIGGER AS $$ @@ -239,6 +240,56 @@ CREATE TABLE refresh_tokens ( tenant_id UUID NOT NULL REFERENCES tenants(id) ); -CREATE INDEX idx_refresh_tokens_user_id ON refresh_tokens (user_id); -CREATE INDEX idx_refresh_tokens_token_hash ON refresh_tokens (token_hash); -CREATE INDEX refresh_tokens_tenant_id_idx ON refresh_tokens (tenant_id); +CREATE INDEX idx_refresh_tokens_user_id ON refresh_tokens(user_id); +CREATE INDEX idx_refresh_tokens_token_hash ON refresh_tokens(token_hash); +CREATE INDEX refresh_tokens_tenant_id_idx ON refresh_tokens(tenant_id); + +CREATE TABLE webdav_tokens ( + id UUID PRIMARY KEY, + user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, + tenant_id UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE, + token_prefix TEXT NOT NULL, + token_hash TEXT NOT NULL, + label TEXT, + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + last_used_at TIMESTAMPTZ, + expires_at TIMESTAMPTZ, + revoked_at TIMESTAMPTZ +); + +CREATE UNIQUE INDEX webdav_tokens_token_prefix_key ON webdav_tokens(token_prefix); +CREATE INDEX webdav_tokens_user_tenant_idx ON webdav_tokens(user_id, tenant_id); + +CREATE TABLE user_passkeys ( + id UUID PRIMARY KEY, + user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, + credential_id BYTEA NOT NULL UNIQUE, + public_key BYTEA NOT NULL, + credential JSONB NOT NULL, + sign_count BIGINT NOT NULL, + transports TEXT[] NOT NULL DEFAULT '{}'::text[], + aaguid UUID, + nickname TEXT, + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + last_used_at TIMESTAMPTZ, + revoked_at TIMESTAMPTZ, + revoked_by UUID, + revoked_reason TEXT +); + +CREATE INDEX user_passkeys_user_id_idx ON user_passkeys(user_id); + +CREATE TABLE webauthn_challenges ( + id UUID PRIMARY KEY, + user_id UUID REFERENCES users(id) ON DELETE CASCADE, + purpose TEXT NOT NULL, + challenge BYTEA NOT NULL, + state BYTEA NOT NULL, + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + expires_at TIMESTAMPTZ NOT NULL, + CONSTRAINT webauthn_challenges_purpose_check CHECK (purpose IN ('registration', 'authentication')) +); + +CREATE INDEX webauthn_challenges_user_id_idx ON webauthn_challenges(user_id); +CREATE INDEX webauthn_challenges_expires_at_idx ON webauthn_challenges(expires_at); diff --git a/backend/migrations/202512010000_update_folder_unique_index/down.sql b/backend/migrations/202512010000_update_folder_unique_index/down.sql deleted file mode 100644 index cac48e9..0000000 --- a/backend/migrations/202512010000_update_folder_unique_index/down.sql +++ /dev/null @@ -1,6 +0,0 @@ -DROP INDEX IF EXISTS folders_tenant_parent_name_unique_idx; -CREATE UNIQUE INDEX folders_parent_name_unique_idx - ON folders ( - COALESCE(parent_id, '00000000-0000-0000-0000-000000000000'::uuid), - name - ); diff --git a/backend/migrations/202512010000_update_folder_unique_index/up.sql b/backend/migrations/202512010000_update_folder_unique_index/up.sql deleted file mode 100644 index b8ad7dd..0000000 --- a/backend/migrations/202512010000_update_folder_unique_index/up.sql +++ /dev/null @@ -1,7 +0,0 @@ -DROP INDEX IF EXISTS folders_parent_name_unique_idx; -CREATE UNIQUE INDEX folders_tenant_parent_name_unique_idx - ON folders ( - tenant_id, - COALESCE(parent_id, '00000000-0000-0000-0000-000000000000'::uuid), - name - ); diff --git a/backend/migrations/202512010010_update_tenant_unique_indexes/down.sql b/backend/migrations/202512010010_update_tenant_unique_indexes/down.sql deleted file mode 100644 index b7fd9c5..0000000 --- a/backend/migrations/202512010010_update_tenant_unique_indexes/down.sql +++ /dev/null @@ -1,16 +0,0 @@ --- Revert correspondent uniqueness to global name -DROP INDEX IF EXISTS correspondents_tenant_name_unique; -ALTER TABLE correspondents ADD CONSTRAINT correspondents_name_unique UNIQUE (name); - --- Revert tag uniqueness to global label -DROP INDEX IF EXISTS tags_tenant_label_unique; -ALTER TABLE tags ADD CONSTRAINT tags_label_key UNIQUE (label); - --- Revert document filename uniqueness to global folder scope -DROP INDEX IF EXISTS documents_tenant_folder_filename_unique; -CREATE UNIQUE INDEX documents_unique_folder_filename - ON documents ( - COALESCE(folder_id, '00000000-0000-0000-0000-000000000000'::uuid), - filename - ) - WHERE deleted_at IS NULL; diff --git a/backend/migrations/202512010010_update_tenant_unique_indexes/up.sql b/backend/migrations/202512010010_update_tenant_unique_indexes/up.sql deleted file mode 100644 index a25879c..0000000 --- a/backend/migrations/202512010010_update_tenant_unique_indexes/up.sql +++ /dev/null @@ -1,20 +0,0 @@ --- Ensure document filenames are unique per tenant + folder -DROP INDEX IF EXISTS documents_tenant_folder_filename_unique; -DROP INDEX IF EXISTS documents_unique_folder_filename; -CREATE UNIQUE INDEX documents_tenant_folder_filename_unique - ON documents ( - tenant_id, - COALESCE(folder_id, '00000000-0000-0000-0000-000000000000'::uuid), - filename - ) - WHERE deleted_at IS NULL; - --- Ensure tag labels are unique per tenant -ALTER TABLE tags DROP CONSTRAINT IF EXISTS tags_label_key; -DROP INDEX IF EXISTS tags_tenant_label_unique; -CREATE UNIQUE INDEX tags_tenant_label_unique ON tags (tenant_id, label); - --- Ensure correspondent names are unique per tenant -ALTER TABLE correspondents DROP CONSTRAINT IF EXISTS correspondents_name_unique; -DROP INDEX IF EXISTS correspondents_tenant_name_unique; -CREATE UNIQUE INDEX correspondents_tenant_name_unique ON correspondents (tenant_id, name); diff --git a/backend/migrations/202512010020_drop_document_version_operations_summary/down.sql b/backend/migrations/202512010020_drop_document_version_operations_summary/down.sql deleted file mode 100644 index 128b066..0000000 --- a/backend/migrations/202512010020_drop_document_version_operations_summary/down.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE document_versions - ADD COLUMN operations_summary JSONB NOT NULL DEFAULT '{}'::jsonb; diff --git a/backend/migrations/202512010020_drop_document_version_operations_summary/up.sql b/backend/migrations/202512010020_drop_document_version_operations_summary/up.sql deleted file mode 100644 index 5528dd9..0000000 --- a/backend/migrations/202512010020_drop_document_version_operations_summary/up.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE document_versions - DROP COLUMN IF EXISTS operations_summary; diff --git a/backend/migrations/202512010050_drop_correspondent_roles/down.sql b/backend/migrations/202512010050_drop_correspondent_roles/down.sql deleted file mode 100644 index e8b059d..0000000 --- a/backend/migrations/202512010050_drop_correspondent_roles/down.sql +++ /dev/null @@ -1,7 +0,0 @@ -ALTER TABLE document_correspondents DROP CONSTRAINT document_correspondents_pkey; -ALTER TABLE document_correspondents ADD COLUMN role VARCHAR(32) NOT NULL DEFAULT 'other'; -UPDATE document_correspondents SET role = 'other'; -ALTER TABLE document_correspondents ALTER COLUMN role DROP DEFAULT; -ALTER TABLE document_correspondents - ADD CONSTRAINT document_correspondents_pkey - PRIMARY KEY (document_id, correspondent_id, role); diff --git a/backend/migrations/202512010050_drop_correspondent_roles/up.sql b/backend/migrations/202512010050_drop_correspondent_roles/up.sql deleted file mode 100644 index 43fb1d6..0000000 --- a/backend/migrations/202512010050_drop_correspondent_roles/up.sql +++ /dev/null @@ -1,24 +0,0 @@ -WITH ranked AS ( - SELECT - document_id, - correspondent_id, - role, - assigned_at, - assigned_by, - tenant_id, - ROW_NUMBER() OVER (PARTITION BY document_id, correspondent_id ORDER BY assigned_at DESC) AS rn - FROM document_correspondents -) -DELETE FROM document_correspondents dc -USING ranked r -WHERE dc.document_id = r.document_id - AND dc.correspondent_id = r.correspondent_id - AND dc.role = r.role - AND dc.tenant_id = r.tenant_id - AND r.rn > 1; - -ALTER TABLE document_correspondents DROP CONSTRAINT document_correspondents_pkey; -ALTER TABLE document_correspondents DROP COLUMN role; -ALTER TABLE document_correspondents - ADD CONSTRAINT document_correspondents_pkey - PRIMARY KEY (document_id, correspondent_id); diff --git a/backend/migrations/202512010100_add_webdav_tokens/down.sql b/backend/migrations/202512010100_add_webdav_tokens/down.sql deleted file mode 100644 index dc42dd5..0000000 --- a/backend/migrations/202512010100_add_webdav_tokens/down.sql +++ /dev/null @@ -1,3 +0,0 @@ -DROP INDEX IF EXISTS webdav_tokens_user_tenant_idx; -DROP INDEX IF EXISTS webdav_tokens_token_prefix_key; -DROP TABLE IF EXISTS webdav_tokens; diff --git a/backend/migrations/202512010100_add_webdav_tokens/up.sql b/backend/migrations/202512010100_add_webdav_tokens/up.sql deleted file mode 100644 index 83ec511..0000000 --- a/backend/migrations/202512010100_add_webdav_tokens/up.sql +++ /dev/null @@ -1,16 +0,0 @@ -CREATE TABLE webdav_tokens ( - id UUID PRIMARY KEY, - user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, - tenant_id UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE, - token_prefix TEXT NOT NULL, - token_hash TEXT NOT NULL, - label TEXT, - scopes JSONB NOT NULL DEFAULT '["webdav"]'::jsonb, - created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), - last_used_at TIMESTAMPTZ, - expires_at TIMESTAMPTZ, - revoked_at TIMESTAMPTZ -); - -CREATE UNIQUE INDEX webdav_tokens_token_prefix_key ON webdav_tokens(token_prefix); -CREATE INDEX webdav_tokens_user_tenant_idx ON webdav_tokens(user_id, tenant_id); diff --git a/backend/migrations/202512010110_drop_webdav_token_scopes/down.sql b/backend/migrations/202512010110_drop_webdav_token_scopes/down.sql deleted file mode 100644 index c375e1e..0000000 --- a/backend/migrations/202512010110_drop_webdav_token_scopes/down.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE webdav_tokens - ADD COLUMN scopes JSONB NOT NULL DEFAULT '["webdav"]'::jsonb; diff --git a/backend/migrations/202512010110_drop_webdav_token_scopes/up.sql b/backend/migrations/202512010110_drop_webdav_token_scopes/up.sql deleted file mode 100644 index 04fe456..0000000 --- a/backend/migrations/202512010110_drop_webdav_token_scopes/up.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE webdav_tokens - DROP COLUMN IF EXISTS scopes; diff --git a/backend/migrations/202512010120_add_tenant_status_column/down.sql b/backend/migrations/202512010120_add_tenant_status_column/down.sql deleted file mode 100644 index 3e2ff3d..0000000 --- a/backend/migrations/202512010120_add_tenant_status_column/down.sql +++ /dev/null @@ -1,5 +0,0 @@ -ALTER TABLE tenants - DROP COLUMN IF EXISTS status, - DROP COLUMN IF EXISTS created_by; - -DROP TYPE IF EXISTS tenant_status; diff --git a/backend/migrations/202512010120_add_tenant_status_column/up.sql b/backend/migrations/202512010120_add_tenant_status_column/up.sql deleted file mode 100644 index f102138..0000000 --- a/backend/migrations/202512010120_add_tenant_status_column/up.sql +++ /dev/null @@ -1,19 +0,0 @@ -ALTER TABLE tenants - DROP COLUMN IF EXISTS status; - -ALTER TABLE tenants - DROP COLUMN IF EXISTS created_by; - -DROP TYPE IF EXISTS tenant_status; - -CREATE TYPE tenant_status AS ENUM ('creating', 'active', 'suspended', 'deleting', 'error'); - -ALTER TABLE tenants - ADD COLUMN status tenant_status, - ADD COLUMN created_by UUID; - -UPDATE tenants -SET status = 'active'; - -ALTER TABLE tenants - ALTER COLUMN status SET NOT NULL; diff --git a/backend/migrations/202512010130_add_user_passkeys/down.sql b/backend/migrations/202512010130_add_user_passkeys/down.sql deleted file mode 100644 index 44fd842..0000000 --- a/backend/migrations/202512010130_add_user_passkeys/down.sql +++ /dev/null @@ -1 +0,0 @@ -DROP TABLE IF EXISTS user_passkeys; diff --git a/backend/migrations/202512010130_add_user_passkeys/up.sql b/backend/migrations/202512010130_add_user_passkeys/up.sql deleted file mode 100644 index 565a741..0000000 --- a/backend/migrations/202512010130_add_user_passkeys/up.sql +++ /dev/null @@ -1,19 +0,0 @@ -CREATE TABLE user_passkeys ( - id UUID PRIMARY KEY, - user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, - credential_id BYTEA NOT NULL UNIQUE, - public_key BYTEA NOT NULL, - credential JSONB NOT NULL, - sign_count BIGINT NOT NULL, - transports TEXT[] NOT NULL DEFAULT '{}', - aaguid UUID, - nickname TEXT, - created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), - updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), - last_used_at TIMESTAMPTZ, - revoked_at TIMESTAMPTZ, - revoked_by UUID, - revoked_reason TEXT -); - -CREATE INDEX user_passkeys_user_id_idx ON user_passkeys (user_id); diff --git a/backend/migrations/202512010140_add_webauthn_challenges/down.sql b/backend/migrations/202512010140_add_webauthn_challenges/down.sql deleted file mode 100644 index be00eb1..0000000 --- a/backend/migrations/202512010140_add_webauthn_challenges/down.sql +++ /dev/null @@ -1 +0,0 @@ -DROP TABLE IF EXISTS webauthn_challenges; diff --git a/backend/migrations/202512010140_add_webauthn_challenges/up.sql b/backend/migrations/202512010140_add_webauthn_challenges/up.sql deleted file mode 100644 index 97ae634..0000000 --- a/backend/migrations/202512010140_add_webauthn_challenges/up.sql +++ /dev/null @@ -1,13 +0,0 @@ -CREATE TABLE webauthn_challenges ( - id UUID PRIMARY KEY, - user_id UUID REFERENCES users(id) ON DELETE CASCADE, - purpose TEXT NOT NULL, - challenge BYTEA NOT NULL, - state BYTEA NOT NULL, - created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), - expires_at TIMESTAMPTZ NOT NULL, - CONSTRAINT webauthn_challenges_purpose_check CHECK (purpose IN ('registration', 'authentication')) -); - -CREATE INDEX webauthn_challenges_user_id_idx ON webauthn_challenges (user_id); -CREATE INDEX webauthn_challenges_expires_at_idx ON webauthn_challenges (expires_at); diff --git a/backend/migrations/202512010150_drop_user_membership_role/down.sql b/backend/migrations/202512010150_drop_user_membership_role/down.sql deleted file mode 100644 index 404df88..0000000 --- a/backend/migrations/202512010150_drop_user_membership_role/down.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE user_memberships - ADD COLUMN role TEXT NOT NULL DEFAULT 'user'; diff --git a/backend/migrations/202512010150_drop_user_membership_role/up.sql b/backend/migrations/202512010150_drop_user_membership_role/up.sql deleted file mode 100644 index 63117ff..0000000 --- a/backend/migrations/202512010150_drop_user_membership_role/up.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE user_memberships - DROP COLUMN role; diff --git a/backend/migrations/202512010160_replace_tenant_slug/down.sql b/backend/migrations/202512010160_replace_tenant_slug/down.sql deleted file mode 100644 index 18dde60..0000000 --- a/backend/migrations/202512010160_replace_tenant_slug/down.sql +++ /dev/null @@ -1,5 +0,0 @@ -ALTER TABLE tenants - RENAME COLUMN name TO slug; - -ALTER TABLE tenants - RENAME CONSTRAINT tenants_name_key TO tenants_slug_key; diff --git a/backend/migrations/202512010160_replace_tenant_slug/up.sql b/backend/migrations/202512010160_replace_tenant_slug/up.sql deleted file mode 100644 index fba2d6b..0000000 --- a/backend/migrations/202512010160_replace_tenant_slug/up.sql +++ /dev/null @@ -1,5 +0,0 @@ -ALTER TABLE tenants - RENAME COLUMN slug TO name; - -ALTER TABLE tenants - RENAME CONSTRAINT tenants_slug_key TO tenants_name_key; diff --git a/backend/migrations/202512010165_drop_tenant_name_unique/down.sql b/backend/migrations/202512010165_drop_tenant_name_unique/down.sql deleted file mode 100644 index 4c306fa..0000000 --- a/backend/migrations/202512010165_drop_tenant_name_unique/down.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE tenants - ADD CONSTRAINT tenants_name_key UNIQUE (name); diff --git a/backend/migrations/202512010165_drop_tenant_name_unique/up.sql b/backend/migrations/202512010165_drop_tenant_name_unique/up.sql deleted file mode 100644 index 4dffef4..0000000 --- a/backend/migrations/202512010165_drop_tenant_name_unique/up.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE tenants - DROP CONSTRAINT IF EXISTS tenants_name_key; diff --git a/backend/migrations/202512010175_drop_password_column_on_users/down.sql b/backend/migrations/202512010175_drop_password_column_on_users/down.sql deleted file mode 100644 index b702e7e..0000000 --- a/backend/migrations/202512010175_drop_password_column_on_users/down.sql +++ /dev/null @@ -1,6 +0,0 @@ -ALTER TABLE users - ADD COLUMN password_hash VARCHAR(255) NOT NULL DEFAULT ''; - --- Optional: remove the default if you need to reintroduce passwords later -ALTER TABLE users - ALTER COLUMN password_hash DROP DEFAULT; diff --git a/backend/migrations/202512010175_drop_password_column_on_users/up.sql b/backend/migrations/202512010175_drop_password_column_on_users/up.sql deleted file mode 100644 index 889b80f..0000000 --- a/backend/migrations/202512010175_drop_password_column_on_users/up.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE users - DROP COLUMN password_hash; diff --git a/backend/tests/common/mod.rs b/backend/tests/common/mod.rs index a1b4808..ab6c082 100644 --- a/backend/tests/common/mod.rs +++ b/backend/tests/common/mod.rs @@ -37,6 +37,7 @@ use tower::util::ServiceExt; use uuid::Uuid; const MIGRATIONS: EmbeddedMigrations = embed_migrations!("migrations"); +const RESET_SCHEMA_SQL: &str = include_str!("../../migrations/202510300000_initial_schema/down.sql"); static DB_LOCK: Lazy> = Lazy::new(|| Mutex::new(())); @@ -697,6 +698,8 @@ async fn prepare_database(pool: &PgPool) -> Result<()> { let mut conn = pool .get() .map_err(|err| anyhow!("failed to acquire connection: {err}"))?; + let _ = conn.batch_execute(RESET_SCHEMA_SQL); + let _ = conn.batch_execute("DROP TABLE IF EXISTS __diesel_schema_migrations;"); conn.run_pending_migrations(MIGRATIONS) .map_err(|err| anyhow!("failed to run migrations: {err}"))?; truncate_all(&mut conn)?; @@ -721,6 +724,8 @@ fn truncate_all(conn: &mut PgConnection) -> Result<()> { refresh_tokens, \ tags, \ webdav_tokens, \ + webauthn_challenges, \ + user_passkeys, \ user_memberships, \ users, \ tenants \