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";
|
||||||
+71
-20
@@ -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,7 +33,6 @@ 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)
|
||||||
@@ -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,
|
||||||
@@ -74,7 +79,6 @@ 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,7 +102,6 @@ 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)
|
||||||
@@ -114,12 +118,13 @@ 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 UNIQUE INDEX tags_tenant_label_unique ON tags(tenant_id, label);
|
||||||
CREATE INDEX tags_tenant_id_idx ON tags(tenant_id);
|
CREATE INDEX tags_tenant_id_idx ON tags(tenant_id);
|
||||||
|
|
||||||
CREATE TABLE document_tags (
|
CREATE TABLE document_tags (
|
||||||
@@ -140,26 +145,24 @@ 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 UNIQUE INDEX correspondents_tenant_name_unique
|
||||||
|
ON correspondents (tenant_id, name);
|
||||||
CREATE INDEX correspondents_tenant_id_idx ON correspondents(tenant_id);
|
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 (
|
||||||
@@ -192,9 +195,7 @@ 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,
|
||||||
@@ -242,3 +243,53 @@ CREATE TABLE refresh_tokens (
|
|||||||
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