squash database migrations
This commit is contained in:
+5
-1
@@ -1,8 +1,10 @@
|
|||||||
DROP TRIGGER IF EXISTS trg_jobs_updated_at ON jobs;
|
DROP TRIGGER IF EXISTS trg_jobs_updated_at ON jobs;
|
||||||
DROP FUNCTION IF EXISTS touch_jobs_updated_at();
|
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;
|
ALTER TABLE documents DROP CONSTRAINT IF EXISTS documents_current_version_fk;
|
||||||
|
|
||||||
DROP TABLE IF EXISTS document_asset_objects;
|
DROP TABLE IF EXISTS document_asset_objects;
|
||||||
DROP TABLE IF EXISTS document_assets;
|
DROP TABLE IF EXISTS document_assets;
|
||||||
DROP TABLE IF EXISTS document_versions;
|
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 users;
|
||||||
DROP TABLE IF EXISTS tenants;
|
DROP TABLE IF EXISTS tenants;
|
||||||
|
|
||||||
|
DROP TYPE IF EXISTS tenant_status;
|
||||||
|
|
||||||
DROP EXTENSION IF EXISTS "pgcrypto";
|
DROP EXTENSION IF EXISTS "pgcrypto";
|
||||||
+96
-45
@@ -1,14 +1,17 @@
|
|||||||
CREATE EXTENSION IF NOT EXISTS "pgcrypto";
|
CREATE EXTENSION IF NOT EXISTS "pgcrypto";
|
||||||
|
|
||||||
|
CREATE TYPE tenant_status AS ENUM ('creating', 'active', 'suspended', 'deleting', 'error');
|
||||||
|
|
||||||
CREATE TABLE tenants (
|
CREATE TABLE tenants (
|
||||||
id UUID PRIMARY KEY,
|
id UUID PRIMARY KEY,
|
||||||
slug TEXT NOT NULL UNIQUE,
|
name TEXT NOT NULL,
|
||||||
storage_root TEXT,
|
storage_root TEXT,
|
||||||
quickwit_index TEXT,
|
quickwit_index TEXT,
|
||||||
status TEXT NOT NULL DEFAULT 'active',
|
|
||||||
config JSONB NOT NULL DEFAULT '{}'::jsonb,
|
config JSONB NOT NULL DEFAULT '{}'::jsonb,
|
||||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
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
|
CREATE UNIQUE INDEX tenants_storage_root_unique
|
||||||
@@ -22,7 +25,6 @@ CREATE UNIQUE INDEX tenants_quickwit_index_unique
|
|||||||
CREATE TABLE users (
|
CREATE TABLE users (
|
||||||
id UUID PRIMARY KEY,
|
id UUID PRIMARY KEY,
|
||||||
username VARCHAR(100) NOT NULL UNIQUE,
|
username VARCHAR(100) NOT NULL UNIQUE,
|
||||||
password_hash VARCHAR(255) NOT NULL,
|
|
||||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||||
updated_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,
|
id UUID PRIMARY KEY,
|
||||||
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||||
tenant_id UUID NOT NULL REFERENCES tenants(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(),
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||||
UNIQUE (user_id, tenant_id)
|
UNIQUE (user_id, tenant_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE INDEX user_memberships_tenant_id_idx ON user_memberships (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_user_id_idx ON user_memberships(user_id);
|
||||||
|
|
||||||
CREATE TABLE folders (
|
CREATE TABLE folders (
|
||||||
id UUID PRIMARY KEY,
|
id UUID PRIMARY KEY,
|
||||||
@@ -51,8 +52,12 @@ CREATE TABLE folders (
|
|||||||
|
|
||||||
CREATE INDEX idx_folders_parent ON folders(parent_id);
|
CREATE INDEX idx_folders_parent ON folders(parent_id);
|
||||||
CREATE INDEX folders_tenant_id_idx ON folders(tenant_id);
|
CREATE INDEX folders_tenant_id_idx ON folders(tenant_id);
|
||||||
CREATE UNIQUE INDEX folders_parent_name_unique_idx
|
CREATE UNIQUE INDEX folders_tenant_parent_name_unique_idx
|
||||||
ON folders (COALESCE(parent_id, '00000000-0000-0000-0000-000000000000'::uuid), name);
|
ON folders (
|
||||||
|
tenant_id,
|
||||||
|
COALESCE(parent_id, '00000000-0000-0000-0000-000000000000'::uuid),
|
||||||
|
name
|
||||||
|
);
|
||||||
|
|
||||||
CREATE TABLE documents (
|
CREATE TABLE documents (
|
||||||
id UUID PRIMARY KEY,
|
id UUID PRIMARY KEY,
|
||||||
@@ -70,11 +75,10 @@ CREATE TABLE documents (
|
|||||||
tenant_id UUID NOT NULL REFERENCES tenants(id)
|
tenant_id UUID NOT NULL REFERENCES tenants(id)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE INDEX idx_documents_folder ON documents (folder_id);
|
CREATE INDEX idx_documents_folder ON documents(folder_id);
|
||||||
CREATE INDEX idx_documents_deleted_at ON documents (deleted_at);
|
CREATE INDEX idx_documents_deleted_at ON documents(deleted_at);
|
||||||
CREATE INDEX documents_tenant_id_idx ON documents (tenant_id);
|
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_current_version_id ON documents(current_version_id);
|
||||||
|
|
||||||
CREATE INDEX idx_documents_folder_title
|
CREATE INDEX idx_documents_folder_title
|
||||||
ON documents (
|
ON documents (
|
||||||
COALESCE(folder_id, '00000000-0000-0000-0000-000000000000'::uuid),
|
COALESCE(folder_id, '00000000-0000-0000-0000-000000000000'::uuid),
|
||||||
@@ -82,8 +86,9 @@ CREATE INDEX idx_documents_folder_title
|
|||||||
)
|
)
|
||||||
WHERE deleted_at IS NULL;
|
WHERE deleted_at IS NULL;
|
||||||
|
|
||||||
CREATE UNIQUE INDEX documents_unique_folder_filename
|
CREATE UNIQUE INDEX documents_tenant_folder_filename_unique
|
||||||
ON documents (
|
ON documents (
|
||||||
|
tenant_id,
|
||||||
COALESCE(folder_id, '00000000-0000-0000-0000-000000000000'::uuid),
|
COALESCE(folder_id, '00000000-0000-0000-0000-000000000000'::uuid),
|
||||||
filename
|
filename
|
||||||
)
|
)
|
||||||
@@ -97,14 +102,13 @@ CREATE TABLE document_versions (
|
|||||||
size_bytes BIGINT NOT NULL,
|
size_bytes BIGINT NOT NULL,
|
||||||
checksum VARCHAR(64) NOT NULL,
|
checksum VARCHAR(64) NOT NULL,
|
||||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||||
operations_summary JSONB NOT NULL DEFAULT '{}'::jsonb,
|
|
||||||
metadata JSONB NOT NULL DEFAULT '{}'::jsonb,
|
metadata JSONB NOT NULL DEFAULT '{}'::jsonb,
|
||||||
tenant_id UUID NOT NULL REFERENCES tenants(id),
|
tenant_id UUID NOT NULL REFERENCES tenants(id),
|
||||||
CONSTRAINT document_versions_unique_version UNIQUE (document_id, version_number)
|
CONSTRAINT document_versions_unique_version UNIQUE (document_id, version_number)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE INDEX idx_document_versions_document ON document_versions (document_id);
|
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 document_versions_tenant_id_idx ON document_versions(tenant_id);
|
||||||
|
|
||||||
ALTER TABLE documents
|
ALTER TABLE documents
|
||||||
ADD CONSTRAINT documents_current_version_fk
|
ADD CONSTRAINT documents_current_version_fk
|
||||||
@@ -114,13 +118,14 @@ ALTER TABLE documents
|
|||||||
|
|
||||||
CREATE TABLE tags (
|
CREATE TABLE tags (
|
||||||
id UUID PRIMARY KEY,
|
id UUID PRIMARY KEY,
|
||||||
label VARCHAR(100) NOT NULL UNIQUE,
|
label VARCHAR(100) NOT NULL,
|
||||||
color VARCHAR(7),
|
color VARCHAR(7),
|
||||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||||
tenant_id UUID NOT NULL REFERENCES tenants(id)
|
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 (
|
CREATE TABLE document_tags (
|
||||||
document_id UUID NOT NULL REFERENCES documents(id) ON DELETE CASCADE,
|
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)
|
PRIMARY KEY (document_id, tag_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE INDEX idx_document_tags_tag ON document_tags (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 document_tags_tenant_id_idx ON document_tags(tenant_id);
|
||||||
|
|
||||||
CREATE TABLE correspondents (
|
CREATE TABLE correspondents (
|
||||||
id UUID PRIMARY KEY,
|
id UUID PRIMARY KEY,
|
||||||
@@ -140,27 +145,25 @@ CREATE TABLE correspondents (
|
|||||||
metadata JSONB NOT NULL DEFAULT '{}'::jsonb,
|
metadata JSONB NOT NULL DEFAULT '{}'::jsonb,
|
||||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||||
tenant_id UUID NOT NULL REFERENCES tenants(id),
|
tenant_id UUID NOT NULL REFERENCES tenants(id)
|
||||||
CONSTRAINT correspondents_name_unique UNIQUE (name)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
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 (
|
CREATE TABLE document_correspondents (
|
||||||
document_id UUID NOT NULL REFERENCES documents(id) ON DELETE CASCADE,
|
document_id UUID NOT NULL REFERENCES documents(id) ON DELETE CASCADE,
|
||||||
correspondent_id UUID NOT NULL REFERENCES correspondents(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_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||||
assigned_by UUID REFERENCES users(id),
|
assigned_by UUID REFERENCES users(id),
|
||||||
tenant_id UUID NOT NULL REFERENCES tenants(id),
|
tenant_id UUID NOT NULL REFERENCES tenants(id),
|
||||||
PRIMARY KEY (document_id, correspondent_id, role),
|
PRIMARY KEY (document_id, correspondent_id)
|
||||||
CONSTRAINT document_correspondents_role_check CHECK (role IN ('sender', 'receiver', 'other'))
|
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE INDEX idx_document_correspondents_document ON document_correspondents (document_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_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 document_correspondents_tenant_id_idx ON document_correspondents (tenant_id);
|
|
||||||
|
|
||||||
CREATE TABLE document_assets (
|
CREATE TABLE document_assets (
|
||||||
id UUID PRIMARY KEY,
|
id UUID PRIMARY KEY,
|
||||||
@@ -175,9 +178,9 @@ CREATE TABLE document_assets (
|
|||||||
CONSTRAINT document_assets_cardinality_positive CHECK (cardinality IS NULL OR cardinality >= 1)
|
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_version ON document_assets(document_version_id);
|
||||||
CREATE INDEX idx_document_assets_type ON document_assets (asset_type);
|
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 document_assets_tenant_id_idx ON document_assets(tenant_id);
|
||||||
|
|
||||||
CREATE TABLE document_asset_objects (
|
CREATE TABLE document_asset_objects (
|
||||||
id UUID PRIMARY KEY,
|
id UUID PRIMARY KEY,
|
||||||
@@ -191,10 +194,8 @@ CREATE TABLE document_asset_objects (
|
|||||||
);
|
);
|
||||||
|
|
||||||
CREATE INDEX idx_document_asset_objects_asset_ordinal
|
CREATE INDEX idx_document_asset_objects_asset_ordinal
|
||||||
ON document_asset_objects (asset_id, ordinal);
|
ON document_asset_objects(asset_id, ordinal);
|
||||||
|
CREATE INDEX document_asset_objects_tenant_id_idx ON document_asset_objects(tenant_id);
|
||||||
CREATE INDEX document_asset_objects_tenant_id_idx
|
|
||||||
ON document_asset_objects (tenant_id);
|
|
||||||
|
|
||||||
CREATE TABLE jobs (
|
CREATE TABLE jobs (
|
||||||
id UUID PRIMARY KEY,
|
id UUID PRIMARY KEY,
|
||||||
@@ -210,9 +211,9 @@ CREATE TABLE jobs (
|
|||||||
CONSTRAINT jobs_status_check CHECK (status IN ('queued', 'processing', 'succeeded', 'failed'))
|
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_status_run_after ON jobs(status, run_after);
|
||||||
CREATE INDEX idx_jobs_job_type ON jobs (job_type);
|
CREATE INDEX idx_jobs_job_type ON jobs(job_type);
|
||||||
CREATE INDEX jobs_tenant_id_idx ON jobs (tenant_id);
|
CREATE INDEX jobs_tenant_id_idx ON jobs(tenant_id);
|
||||||
|
|
||||||
CREATE OR REPLACE FUNCTION touch_jobs_updated_at()
|
CREATE OR REPLACE FUNCTION touch_jobs_updated_at()
|
||||||
RETURNS TRIGGER AS $$
|
RETURNS TRIGGER AS $$
|
||||||
@@ -239,6 +240,56 @@ CREATE TABLE refresh_tokens (
|
|||||||
tenant_id UUID NOT NULL REFERENCES tenants(id)
|
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_user_id ON refresh_tokens(user_id);
|
||||||
CREATE INDEX idx_refresh_tokens_token_hash ON refresh_tokens (token_hash);
|
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 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);
|
||||||
@@ -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
|
|
||||||
);
|
|
||||||
@@ -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
|
|
||||||
);
|
|
||||||
@@ -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;
|
|
||||||
@@ -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);
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
ALTER TABLE document_versions
|
|
||||||
ADD COLUMN operations_summary JSONB NOT NULL DEFAULT '{}'::jsonb;
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
ALTER TABLE document_versions
|
|
||||||
DROP COLUMN IF EXISTS operations_summary;
|
|
||||||
@@ -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);
|
|
||||||
@@ -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);
|
|
||||||
@@ -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;
|
|
||||||
@@ -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);
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
ALTER TABLE webdav_tokens
|
|
||||||
ADD COLUMN scopes JSONB NOT NULL DEFAULT '["webdav"]'::jsonb;
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
ALTER TABLE webdav_tokens
|
|
||||||
DROP COLUMN IF EXISTS scopes;
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
ALTER TABLE tenants
|
|
||||||
DROP COLUMN IF EXISTS status,
|
|
||||||
DROP COLUMN IF EXISTS created_by;
|
|
||||||
|
|
||||||
DROP TYPE IF EXISTS tenant_status;
|
|
||||||
@@ -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;
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
DROP TABLE IF EXISTS user_passkeys;
|
|
||||||
@@ -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);
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
DROP TABLE IF EXISTS webauthn_challenges;
|
|
||||||
@@ -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);
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
ALTER TABLE user_memberships
|
|
||||||
ADD COLUMN role TEXT NOT NULL DEFAULT 'user';
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
ALTER TABLE user_memberships
|
|
||||||
DROP COLUMN role;
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
ALTER TABLE tenants
|
|
||||||
RENAME COLUMN name TO slug;
|
|
||||||
|
|
||||||
ALTER TABLE tenants
|
|
||||||
RENAME CONSTRAINT tenants_name_key TO tenants_slug_key;
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
ALTER TABLE tenants
|
|
||||||
RENAME COLUMN slug TO name;
|
|
||||||
|
|
||||||
ALTER TABLE tenants
|
|
||||||
RENAME CONSTRAINT tenants_slug_key TO tenants_name_key;
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
ALTER TABLE tenants
|
|
||||||
ADD CONSTRAINT tenants_name_key UNIQUE (name);
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
ALTER TABLE tenants
|
|
||||||
DROP CONSTRAINT IF EXISTS tenants_name_key;
|
|
||||||
@@ -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;
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
ALTER TABLE users
|
|
||||||
DROP COLUMN password_hash;
|
|
||||||
@@ -37,6 +37,7 @@ use tower::util::ServiceExt;
|
|||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
const MIGRATIONS: EmbeddedMigrations = embed_migrations!("migrations");
|
const MIGRATIONS: EmbeddedMigrations = embed_migrations!("migrations");
|
||||||
|
const RESET_SCHEMA_SQL: &str = include_str!("../../migrations/202510300000_initial_schema/down.sql");
|
||||||
|
|
||||||
static DB_LOCK: Lazy<Mutex<()>> = Lazy::new(|| Mutex::new(()));
|
static DB_LOCK: Lazy<Mutex<()>> = Lazy::new(|| Mutex::new(()));
|
||||||
|
|
||||||
@@ -697,6 +698,8 @@ async fn prepare_database(pool: &PgPool) -> Result<()> {
|
|||||||
let mut conn = pool
|
let mut conn = pool
|
||||||
.get()
|
.get()
|
||||||
.map_err(|err| anyhow!("failed to acquire connection: {err}"))?;
|
.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)
|
conn.run_pending_migrations(MIGRATIONS)
|
||||||
.map_err(|err| anyhow!("failed to run migrations: {err}"))?;
|
.map_err(|err| anyhow!("failed to run migrations: {err}"))?;
|
||||||
truncate_all(&mut conn)?;
|
truncate_all(&mut conn)?;
|
||||||
@@ -721,6 +724,8 @@ fn truncate_all(conn: &mut PgConnection) -> Result<()> {
|
|||||||
refresh_tokens, \
|
refresh_tokens, \
|
||||||
tags, \
|
tags, \
|
||||||
webdav_tokens, \
|
webdav_tokens, \
|
||||||
|
webauthn_challenges, \
|
||||||
|
user_passkeys, \
|
||||||
user_memberships, \
|
user_memberships, \
|
||||||
users, \
|
users, \
|
||||||
tenants \
|
tenants \
|
||||||
|
|||||||
Reference in New Issue
Block a user