From f5d64d391ff29d3c60cc34df0d9ddf66308b9e77 Mon Sep 17 00:00:00 2001 From: Michael Date: Wed, 30 Sep 2026 23:18:13 +0100 Subject: [PATCH] Add users and role/permission migrations - Replace the empty 00001_init.sql with 00001_users.sql: UUID ids, given_name/family_name, password_hash, case-insensitive unique email - 00002_roles_permissions.sql adds roles, permissions, role_permissions and user_roles with integer identity ids and cascading foreign keys Existing databases that applied 00001_init.sql need its goose record removed first: DELETE FROM goose_db_version WHERE version_id = 1 --- migrations/00001_init.sql | 3 -- migrations/00001_users.sql | 15 ++++++++++ migrations/00002_roles_permissions.sql | 39 ++++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 3 deletions(-) delete mode 100644 migrations/00001_init.sql create mode 100644 migrations/00001_users.sql create mode 100644 migrations/00002_roles_permissions.sql diff --git a/migrations/00001_init.sql b/migrations/00001_init.sql deleted file mode 100644 index 3b1e6a5..0000000 --- a/migrations/00001_init.sql +++ /dev/null @@ -1,3 +0,0 @@ --- +goose Up - --- +goose Down diff --git a/migrations/00001_users.sql b/migrations/00001_users.sql new file mode 100644 index 0000000..09917e0 --- /dev/null +++ b/migrations/00001_users.sql @@ -0,0 +1,15 @@ +-- +goose Up +CREATE TABLE users ( + id uuid PRIMARY KEY DEFAULT gen_random_uuid(), + email text NOT NULL, + given_name text NOT NULL, + family_name text NOT NULL, + password_hash text NOT NULL, + created_at timestamptz NOT NULL DEFAULT now(), + updated_at timestamptz NOT NULL DEFAULT now() +); + +CREATE UNIQUE INDEX users_email_key ON users (lower(email)); + +-- +goose Down +DROP TABLE users; diff --git a/migrations/00002_roles_permissions.sql b/migrations/00002_roles_permissions.sql new file mode 100644 index 0000000..3e256cc --- /dev/null +++ b/migrations/00002_roles_permissions.sql @@ -0,0 +1,39 @@ +-- +goose Up +CREATE TABLE roles ( + id integer PRIMARY KEY GENERATED ALWAYS AS IDENTITY, + name text NOT NULL UNIQUE, + created_at timestamptz NOT NULL DEFAULT now(), + updated_at timestamptz NOT NULL DEFAULT now() +); + +CREATE TABLE permissions ( + id integer PRIMARY KEY GENERATED ALWAYS AS IDENTITY, + name text NOT NULL UNIQUE, + description text NOT NULL DEFAULT '', + created_at timestamptz NOT NULL DEFAULT now(), + updated_at timestamptz NOT NULL DEFAULT now() +); + +CREATE TABLE role_permissions ( + role_id integer NOT NULL REFERENCES roles (id) ON DELETE CASCADE, + permission_id integer NOT NULL REFERENCES permissions (id) ON DELETE CASCADE, + created_at timestamptz NOT NULL DEFAULT now(), + PRIMARY KEY (role_id, permission_id) +); + +CREATE INDEX role_permissions_permission_id_idx ON role_permissions (permission_id); + +CREATE TABLE user_roles ( + user_id uuid NOT NULL REFERENCES users (id) ON DELETE CASCADE, + role_id integer NOT NULL REFERENCES roles (id) ON DELETE CASCADE, + created_at timestamptz NOT NULL DEFAULT now(), + PRIMARY KEY (user_id, role_id) +); + +CREATE INDEX user_roles_role_id_idx ON user_roles (role_id); + +-- +goose Down +DROP TABLE user_roles; +DROP TABLE role_permissions; +DROP TABLE permissions; +DROP TABLE roles;