2024-07-31 07:23:32 +02:00
|
|
|
-- migrate:up
|
|
|
|
|
CREATE SCHEMA api;
|
|
|
|
|
|
|
|
|
|
CREATE ROLE anon NOLOGIN NOINHERIT;
|
|
|
|
|
GRANT USAGE ON SCHEMA api TO anon;
|
|
|
|
|
|
|
|
|
|
CREATE ROLE authenticated_user NOLOGIN NOINHERIT;
|
|
|
|
|
GRANT USAGE ON SCHEMA api TO authenticated_user;
|
|
|
|
|
|
|
|
|
|
CREATE ROLE authenticator LOGIN NOINHERIT NOCREATEDB NOCREATEROLE NOSUPERUSER;
|
|
|
|
|
GRANT anon TO authenticator;
|
|
|
|
|
GRANT authenticated_user TO authenticator;
|
|
|
|
|
|
|
|
|
|
CREATE SCHEMA internal;
|
|
|
|
|
|
|
|
|
|
CREATE TABLE internal.user (
|
|
|
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
|
|
|
username VARCHAR(16) UNIQUE NOT NULL CHECK (length(username) >= 3),
|
|
|
|
|
password_hash CHAR(60) NOT NULL,
|
|
|
|
|
role NAME NOT NULL DEFAULT 'authenticated_user'
|
|
|
|
|
);
|
|
|
|
|
|
2024-07-31 10:29:46 +02:00
|
|
|
CREATE TABLE internal.website (
|
2024-07-31 07:23:32 +02:00
|
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
2024-08-08 16:30:01 +02:00
|
|
|
user_id UUID REFERENCES internal.user(id) ON DELETE CASCADE NOT NULL DEFAULT (current_setting('request.jwt.claims', true)::JSON->>'user_id')::UUID,
|
2024-07-31 07:23:32 +02:00
|
|
|
content_type VARCHAR(10) CHECK (content_type IN ('Blog', 'Docs')) NOT NULL,
|
2024-08-08 16:30:01 +02:00
|
|
|
title VARCHAR(50) NOT NULL CHECK (trim(title) != ''),
|
2024-07-31 07:23:32 +02:00
|
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT CLOCK_TIMESTAMP(),
|
2024-08-05 16:03:07 +02:00
|
|
|
last_modified_at TIMESTAMPTZ NOT NULL DEFAULT CLOCK_TIMESTAMP(),
|
2024-07-31 07:23:32 +02:00
|
|
|
last_modified_by UUID REFERENCES internal.user(id) ON DELETE SET NULL
|
|
|
|
|
);
|
|
|
|
|
|
2024-07-31 10:29:46 +02:00
|
|
|
CREATE TABLE internal.media (
|
2024-07-31 07:23:32 +02:00
|
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
2024-07-31 10:29:46 +02:00
|
|
|
website_id UUID REFERENCES internal.website(id) ON DELETE CASCADE NOT NULL,
|
2024-07-31 07:23:32 +02:00
|
|
|
user_id UUID REFERENCES internal.user(id) ON DELETE CASCADE NOT NULL DEFAULT (current_setting('request.jwt.claims', true)::JSON->>'user_id')::UUID,
|
|
|
|
|
original_name TEXT NOT NULL,
|
|
|
|
|
file_system_path TEXT NOT NULL,
|
|
|
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT CLOCK_TIMESTAMP()
|
|
|
|
|
);
|
|
|
|
|
|
2024-07-31 10:29:46 +02:00
|
|
|
CREATE TABLE internal.settings (
|
|
|
|
|
website_id UUID PRIMARY KEY REFERENCES internal.website(id) ON DELETE CASCADE,
|
2024-07-31 07:23:32 +02:00
|
|
|
accent_color_light_theme CHAR(7) CHECK (accent_color_light_theme ~ '^#[a-fA-F0-9]{6}$') NOT NULL DEFAULT '#a5d8ff',
|
|
|
|
|
accent_color_dark_theme CHAR(7) CHECK (accent_color_dark_theme ~ '^#[a-fA-F0-9]{6}$') NOT NULL DEFAULT '#114678',
|
2024-07-31 10:29:46 +02:00
|
|
|
favicon_image UUID REFERENCES internal.media(id) ON DELETE SET NULL,
|
2024-08-05 16:03:07 +02:00
|
|
|
last_modified_at TIMESTAMPTZ NOT NULL DEFAULT CLOCK_TIMESTAMP(),
|
2024-07-31 07:23:32 +02:00
|
|
|
last_modified_by UUID REFERENCES internal.user(id) ON DELETE SET NULL
|
|
|
|
|
);
|
|
|
|
|
|
2024-07-31 10:29:46 +02:00
|
|
|
CREATE TABLE internal.header (
|
|
|
|
|
website_id UUID PRIMARY KEY REFERENCES internal.website(id) ON DELETE CASCADE,
|
2024-07-31 07:23:32 +02:00
|
|
|
logo_type TEXT CHECK (logo_type IN ('text', 'image')) NOT NULL DEFAULT 'text',
|
2024-08-05 16:03:07 +02:00
|
|
|
logo_text VARCHAR(50),
|
2024-07-31 10:29:46 +02:00
|
|
|
logo_image UUID REFERENCES internal.media(id) ON DELETE SET NULL,
|
2024-08-05 16:03:07 +02:00
|
|
|
last_modified_at TIMESTAMPTZ NOT NULL DEFAULT CLOCK_TIMESTAMP(),
|
|
|
|
|
last_modified_by UUID REFERENCES internal.user(id) ON DELETE SET NULL,
|
|
|
|
|
CONSTRAINT logo_content_check CHECK (
|
2024-08-08 16:30:01 +02:00
|
|
|
(logo_type = 'text' AND logo_text IS NOT NULL AND trim(logo_text) != '') OR
|
2024-08-05 16:03:07 +02:00
|
|
|
(logo_type = 'image' AND logo_image IS NOT NULL)
|
|
|
|
|
)
|
2024-07-31 07:23:32 +02:00
|
|
|
);
|
|
|
|
|
|
2024-07-31 10:29:46 +02:00
|
|
|
CREATE TABLE internal.home (
|
|
|
|
|
website_id UUID PRIMARY KEY REFERENCES internal.website(id) ON DELETE CASCADE,
|
2024-08-08 16:30:01 +02:00
|
|
|
main_content TEXT NOT NULL CHECK (trim(main_content) != ''),
|
2024-08-05 16:03:07 +02:00
|
|
|
last_modified_at TIMESTAMPTZ NOT NULL DEFAULT CLOCK_TIMESTAMP(),
|
2024-07-31 07:23:32 +02:00
|
|
|
last_modified_by UUID REFERENCES internal.user(id) ON DELETE SET NULL
|
|
|
|
|
);
|
|
|
|
|
|
2024-07-31 10:29:46 +02:00
|
|
|
CREATE TABLE internal.article (
|
2024-07-31 07:23:32 +02:00
|
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
2024-07-31 10:29:46 +02:00
|
|
|
website_id UUID REFERENCES internal.website(id) ON DELETE CASCADE NOT NULL,
|
2024-08-07 16:25:05 +02:00
|
|
|
user_id UUID REFERENCES internal.user(id) ON DELETE SET NULL,
|
2024-08-08 16:30:01 +02:00
|
|
|
title VARCHAR(100) NOT NULL CHECK (trim(title) != ''),
|
|
|
|
|
meta_description VARCHAR(250) CHECK (trim(meta_description) != ''),
|
|
|
|
|
meta_author VARCHAR(100) CHECK (trim(meta_author) != ''),
|
2024-07-31 10:29:46 +02:00
|
|
|
cover_image UUID REFERENCES internal.media(id) ON DELETE SET NULL,
|
2024-07-31 07:23:32 +02:00
|
|
|
publication_date DATE NOT NULL DEFAULT CURRENT_DATE,
|
2024-08-08 16:30:01 +02:00
|
|
|
main_content TEXT CHECK (trim(main_content) != ''),
|
2024-07-31 07:23:32 +02:00
|
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT CLOCK_TIMESTAMP(),
|
2024-08-05 16:03:07 +02:00
|
|
|
last_modified_at TIMESTAMPTZ NOT NULL DEFAULT CLOCK_TIMESTAMP(),
|
2024-07-31 07:23:32 +02:00
|
|
|
last_modified_by UUID REFERENCES internal.user(id) ON DELETE SET NULL
|
|
|
|
|
);
|
|
|
|
|
|
2024-07-31 10:29:46 +02:00
|
|
|
CREATE TABLE internal.footer (
|
|
|
|
|
website_id UUID PRIMARY KEY REFERENCES internal.website(id) ON DELETE CASCADE,
|
2024-08-08 16:30:01 +02:00
|
|
|
additional_text VARCHAR(250) NOT NULL CHECK (trim(additional_text) != ''),
|
2024-08-05 16:03:07 +02:00
|
|
|
last_modified_at TIMESTAMPTZ NOT NULL DEFAULT CLOCK_TIMESTAMP(),
|
2024-07-31 07:23:32 +02:00
|
|
|
last_modified_by UUID REFERENCES internal.user(id) ON DELETE SET NULL
|
|
|
|
|
);
|
|
|
|
|
|
2024-07-31 10:29:46 +02:00
|
|
|
CREATE TABLE internal.collab (
|
|
|
|
|
website_id UUID REFERENCES internal.website(id) ON DELETE CASCADE,
|
2024-07-31 07:23:32 +02:00
|
|
|
user_id UUID REFERENCES internal.user(id) ON DELETE CASCADE,
|
|
|
|
|
permission_level INTEGER CHECK (permission_level IN (10, 20, 30)) NOT NULL DEFAULT 10,
|
|
|
|
|
added_at TIMESTAMPTZ NOT NULL DEFAULT CLOCK_TIMESTAMP(),
|
2024-08-05 16:03:07 +02:00
|
|
|
last_modified_at TIMESTAMPTZ NOT NULL DEFAULT CLOCK_TIMESTAMP(),
|
2024-07-31 07:23:32 +02:00
|
|
|
last_modified_by UUID REFERENCES internal.user(id) ON DELETE SET NULL,
|
2024-07-31 10:29:46 +02:00
|
|
|
PRIMARY KEY (website_id, user_id)
|
2024-07-31 07:23:32 +02:00
|
|
|
);
|
|
|
|
|
|
2024-07-31 10:29:46 +02:00
|
|
|
CREATE TABLE internal.change_log (
|
|
|
|
|
website_id UUID REFERENCES internal.website(id) ON DELETE CASCADE,
|
2024-07-31 07:23:32 +02:00
|
|
|
user_id UUID REFERENCES internal.user(id) ON DELETE CASCADE DEFAULT (current_setting('request.jwt.claims', true)::JSON->>'user_id')::UUID,
|
|
|
|
|
change_summary VARCHAR(255) NOT NULL,
|
|
|
|
|
previous_value JSONB,
|
|
|
|
|
new_value JSONB,
|
|
|
|
|
timestamp TIMESTAMPTZ NOT NULL DEFAULT CLOCK_TIMESTAMP(),
|
2024-07-31 10:29:46 +02:00
|
|
|
PRIMARY KEY (website_id, user_id, timestamp)
|
2024-07-31 07:23:32 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
-- migrate:down
|
2024-07-31 10:29:46 +02:00
|
|
|
DROP TABLE internal.change_log;
|
|
|
|
|
DROP TABLE internal.collab;
|
|
|
|
|
DROP TABLE internal.footer;
|
|
|
|
|
DROP TABLE internal.article;
|
|
|
|
|
DROP TABLE internal.home;
|
|
|
|
|
DROP TABLE internal.header;
|
|
|
|
|
DROP TABLE internal.settings;
|
|
|
|
|
DROP TABLE internal.media;
|
|
|
|
|
DROP TABLE internal.website;
|
2024-07-31 07:23:32 +02:00
|
|
|
DROP SCHEMA api;
|
|
|
|
|
|
|
|
|
|
DROP TABLE internal.user;
|
|
|
|
|
DROP SCHEMA internal;
|
|
|
|
|
|
|
|
|
|
DROP ROLE authenticator;
|
|
|
|
|
DROP ROLE anon;
|
|
|
|
|
DROP ROLE authenticated_user;
|