From 627b91c380e5ad9706036d7bc6e34fdd78c79596 Mon Sep 17 00:00:00 2001 From: DualFroz Date: Tue, 25 Aug 2026 18:49:02 +0200 Subject: [PATCH] feat: add wave2 schema migration for multi-tenancy and availability --- .../resources/db/migration/h2/V2__wave2.sql | 78 +++++++++++++++++++ .../db/migration/postgresql/V2__wave2.sql | 78 +++++++++++++++++++ 2 files changed, 156 insertions(+) create mode 100644 src/main/resources/db/migration/h2/V2__wave2.sql create mode 100644 src/main/resources/db/migration/postgresql/V2__wave2.sql diff --git a/src/main/resources/db/migration/h2/V2__wave2.sql b/src/main/resources/db/migration/h2/V2__wave2.sql new file mode 100644 index 0000000..6ab5642 --- /dev/null +++ b/src/main/resources/db/migration/h2/V2__wave2.sql @@ -0,0 +1,78 @@ +CREATE TABLE organization ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + name VARCHAR(128) NOT NULL, + slug VARCHAR(64) NOT NULL, + created_at TIMESTAMP NOT NULL, + CONSTRAINT uq_organization_slug UNIQUE (slug) +); + +INSERT INTO organization (name, slug, created_at) VALUES ('Default Organization', 'default', CURRENT_TIMESTAMP); + +CREATE TABLE resource_group ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + organization_id BIGINT NOT NULL, + parent_group_id BIGINT, + name VARCHAR(128) NOT NULL, + created_at TIMESTAMP NOT NULL, + CONSTRAINT fk_group_org FOREIGN KEY (organization_id) REFERENCES organization (id), + CONSTRAINT fk_group_parent FOREIGN KEY (parent_group_id) REFERENCES resource_group (id) +); +CREATE INDEX idx_group_org ON resource_group (organization_id); + +ALTER TABLE app_user ADD COLUMN organization_id BIGINT; +UPDATE app_user SET organization_id = (SELECT id FROM organization WHERE slug = 'default'); +ALTER TABLE app_user ALTER COLUMN organization_id SET NOT NULL; +ALTER TABLE app_user ADD CONSTRAINT fk_user_org FOREIGN KEY (organization_id) REFERENCES organization (id); + +ALTER TABLE resource ADD COLUMN organization_id BIGINT; +UPDATE resource SET organization_id = (SELECT id FROM organization WHERE slug = 'default'); +ALTER TABLE resource ALTER COLUMN organization_id SET NOT NULL; +ALTER TABLE resource ADD COLUMN group_id BIGINT; +ALTER TABLE resource ADD COLUMN zone_id VARCHAR(64) NOT NULL DEFAULT 'UTC'; +ALTER TABLE resource ADD COLUMN buffer_minutes INT NOT NULL DEFAULT 0; +ALTER TABLE resource ADD CONSTRAINT fk_resource_org FOREIGN KEY (organization_id) REFERENCES organization (id); +ALTER TABLE resource ADD CONSTRAINT fk_resource_group FOREIGN KEY (group_id) REFERENCES resource_group (id); +CREATE INDEX idx_resource_org ON resource (organization_id); + +ALTER TABLE reservation ADD COLUMN organization_id BIGINT; +UPDATE reservation SET organization_id = (SELECT id FROM organization WHERE slug = 'default'); +ALTER TABLE reservation ALTER COLUMN organization_id SET NOT NULL; +ALTER TABLE reservation ADD COLUMN series_id VARCHAR(36); +ALTER TABLE reservation ADD CONSTRAINT fk_reservation_org FOREIGN KEY (organization_id) REFERENCES organization (id); +CREATE INDEX idx_reservation_series ON reservation (series_id); + +CREATE TABLE operating_hours ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + resource_id BIGINT NOT NULL, + day_of_week VARCHAR(9) NOT NULL, + open_time TIME NOT NULL, + close_time TIME NOT NULL, + CONSTRAINT fk_hours_resource FOREIGN KEY (resource_id) REFERENCES resource (id) +); +CREATE INDEX idx_hours_resource ON operating_hours (resource_id); + +CREATE TABLE blackout_date ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + resource_id BIGINT NOT NULL, + start_date DATE NOT NULL, + end_date DATE NOT NULL, + reason VARCHAR(256), + CONSTRAINT fk_blackout_resource FOREIGN KEY (resource_id) REFERENCES resource (id) +); +CREATE INDEX idx_blackout_resource ON blackout_date (resource_id); + +CREATE TABLE waitlist_entry ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + resource_id BIGINT NOT NULL, + organization_id BIGINT NOT NULL, + user_id BIGINT NOT NULL, + start_time TIMESTAMP NOT NULL, + end_time TIMESTAMP NOT NULL, + status VARCHAR(16) NOT NULL, + created_at TIMESTAMP NOT NULL, + promoted_reservation_id BIGINT, + CONSTRAINT fk_waitlist_resource FOREIGN KEY (resource_id) REFERENCES resource (id), + CONSTRAINT fk_waitlist_org FOREIGN KEY (organization_id) REFERENCES organization (id), + CONSTRAINT fk_waitlist_user FOREIGN KEY (user_id) REFERENCES app_user (id) +); +CREATE INDEX idx_waitlist_resource_status ON waitlist_entry (resource_id, status); diff --git a/src/main/resources/db/migration/postgresql/V2__wave2.sql b/src/main/resources/db/migration/postgresql/V2__wave2.sql new file mode 100644 index 0000000..1d67580 --- /dev/null +++ b/src/main/resources/db/migration/postgresql/V2__wave2.sql @@ -0,0 +1,78 @@ +CREATE TABLE organization ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + name VARCHAR(128) NOT NULL, + slug VARCHAR(64) NOT NULL, + created_at TIMESTAMPTZ NOT NULL, + CONSTRAINT uq_organization_slug UNIQUE (slug) +); + +INSERT INTO organization (name, slug, created_at) VALUES ('Default Organization', 'default', CURRENT_TIMESTAMP); + +CREATE TABLE resource_group ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + organization_id BIGINT NOT NULL, + parent_group_id BIGINT, + name VARCHAR(128) NOT NULL, + created_at TIMESTAMPTZ NOT NULL, + CONSTRAINT fk_group_org FOREIGN KEY (organization_id) REFERENCES organization (id), + CONSTRAINT fk_group_parent FOREIGN KEY (parent_group_id) REFERENCES resource_group (id) +); +CREATE INDEX idx_group_org ON resource_group (organization_id); + +ALTER TABLE app_user ADD COLUMN organization_id BIGINT; +UPDATE app_user SET organization_id = (SELECT id FROM organization WHERE slug = 'default'); +ALTER TABLE app_user ALTER COLUMN organization_id SET NOT NULL; +ALTER TABLE app_user ADD CONSTRAINT fk_user_org FOREIGN KEY (organization_id) REFERENCES organization (id); + +ALTER TABLE resource ADD COLUMN organization_id BIGINT; +UPDATE resource SET organization_id = (SELECT id FROM organization WHERE slug = 'default'); +ALTER TABLE resource ALTER COLUMN organization_id SET NOT NULL; +ALTER TABLE resource ADD COLUMN group_id BIGINT; +ALTER TABLE resource ADD COLUMN zone_id VARCHAR(64) NOT NULL DEFAULT 'UTC'; +ALTER TABLE resource ADD COLUMN buffer_minutes INT NOT NULL DEFAULT 0; +ALTER TABLE resource ADD CONSTRAINT fk_resource_org FOREIGN KEY (organization_id) REFERENCES organization (id); +ALTER TABLE resource ADD CONSTRAINT fk_resource_group FOREIGN KEY (group_id) REFERENCES resource_group (id); +CREATE INDEX idx_resource_org ON resource (organization_id); + +ALTER TABLE reservation ADD COLUMN organization_id BIGINT; +UPDATE reservation SET organization_id = (SELECT id FROM organization WHERE slug = 'default'); +ALTER TABLE reservation ALTER COLUMN organization_id SET NOT NULL; +ALTER TABLE reservation ADD COLUMN series_id VARCHAR(36); +ALTER TABLE reservation ADD CONSTRAINT fk_reservation_org FOREIGN KEY (organization_id) REFERENCES organization (id); +CREATE INDEX idx_reservation_series ON reservation (series_id); + +CREATE TABLE operating_hours ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + resource_id BIGINT NOT NULL, + day_of_week VARCHAR(9) NOT NULL, + open_time TIME NOT NULL, + close_time TIME NOT NULL, + CONSTRAINT fk_hours_resource FOREIGN KEY (resource_id) REFERENCES resource (id) +); +CREATE INDEX idx_hours_resource ON operating_hours (resource_id); + +CREATE TABLE blackout_date ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + resource_id BIGINT NOT NULL, + start_date DATE NOT NULL, + end_date DATE NOT NULL, + reason VARCHAR(256), + CONSTRAINT fk_blackout_resource FOREIGN KEY (resource_id) REFERENCES resource (id) +); +CREATE INDEX idx_blackout_resource ON blackout_date (resource_id); + +CREATE TABLE waitlist_entry ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + resource_id BIGINT NOT NULL, + organization_id BIGINT NOT NULL, + user_id BIGINT NOT NULL, + start_time TIMESTAMPTZ NOT NULL, + end_time TIMESTAMPTZ NOT NULL, + status VARCHAR(16) NOT NULL, + created_at TIMESTAMPTZ NOT NULL, + promoted_reservation_id BIGINT, + CONSTRAINT fk_waitlist_resource FOREIGN KEY (resource_id) REFERENCES resource (id), + CONSTRAINT fk_waitlist_org FOREIGN KEY (organization_id) REFERENCES organization (id), + CONSTRAINT fk_waitlist_user FOREIGN KEY (user_id) REFERENCES app_user (id) +); +CREATE INDEX idx_waitlist_resource_status ON waitlist_entry (resource_id, status);