feat(settings): add organization settings and loyalty setting history

Migration 000091 creates organization_settings, a key-value store per
organization shaped like outlet_settings, for the loyalty settings that must
be the same in every outlet (point value, exchange rate, transfer limits,
expiry). Until now there was nowhere to keep organization-level settings.

Also creates loyalty_setting_changes, the append-only log of who changed
which loyalty setting from what to what (PRD F2), for both organization and
outlet settings (PC-102).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
efrilm
2026-09-30 01:01:02 +07:00
co-authored by Claude Opus 5.5
parent 84401cc708
commit b107f4ef04
2 changed files with 37 additions and 0 deletions
@@ -0,0 +1,2 @@
DROP TABLE IF EXISTS loyalty_setting_changes;
DROP TABLE IF EXISTS organization_settings;
@@ -0,0 +1,35 @@
-- Settings that must be the same in every outlet of an organization, starting with the
-- loyalty ones (docs/prd-point-coin.md F2, F12): point value, exchange rate, transfer
-- limits and expiry. Same key-value shape as outlet_settings.
CREATE TABLE organization_settings (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
organization_id UUID NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
key VARCHAR(255) NOT NULL,
value TEXT,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
UNIQUE(organization_id, key)
);
-- The unique constraint leads with organization_id, so it also serves the plain
-- per-organization lookups and there is no separate index on that column.
-- Who changed which loyalty setting, from what, to what (F2). Covers both the
-- organization settings above and the per-outlet loyalty keys in outlet_settings.
-- Append-only. Values are stored as text, the same as in the settings tables.
CREATE TABLE loyalty_setting_changes (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
organization_id UUID NOT NULL,
-- NULL for an organization setting.
outlet_id UUID,
key VARCHAR(100) NOT NULL,
-- NULL when the key had no stored value yet (it was on its default).
old_value TEXT,
new_value TEXT,
changed_by UUID NOT NULL,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
CREATE INDEX idx_loyalty_setting_changes_organization_id_created_at ON loyalty_setting_changes(organization_id, created_at DESC);
CREATE INDEX idx_loyalty_setting_changes_outlet_id_created_at ON loyalty_setting_changes(outlet_id, created_at DESC)
WHERE outlet_id IS NOT NULL;