-- Push subscriptions and delivery tracking for mobile employee notifications. -- Protected by PostgreSQL Row Level Security (RLS) and tenant isolation. CREATE TABLE staff_push_subscriptions ( id VARCHAR(26) PRIMARY KEY CHECK (id ~ '^[0-9A-HJKMNP-TV-Z]{26}$'), tenant_id VARCHAR(26) NOT NULL CHECK (tenant_id ~ '^[0-9A-HJKMNP-TV-Z]{26}$'), employee_id VARCHAR(26) NOT NULL, endpoint TEXT NOT NULL, p256dh TEXT NOT NULL, auth TEXT NOT NULL, user_agent TEXT NOT NULL DEFAULT '', created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), UNIQUE (tenant_id, id), UNIQUE (tenant_id, endpoint), FOREIGN KEY (tenant_id, employee_id) REFERENCES staff_employees (tenant_id, id) ON DELETE CASCADE ); CREATE INDEX staff_push_subscriptions_employee_idx ON staff_push_subscriptions (tenant_id, employee_id); ALTER TABLE staff_push_subscriptions ENABLE ROW LEVEL SECURITY; ALTER TABLE staff_push_subscriptions FORCE ROW LEVEL SECURITY; CREATE POLICY staff_push_subscriptions_tenant_isolation ON staff_push_subscriptions USING (tenant_id = current_setting('app.tenant_id', true)) WITH CHECK (tenant_id = current_setting('app.tenant_id', true)); CREATE TABLE staff_notification_deliveries ( id VARCHAR(26) PRIMARY KEY CHECK (id ~ '^[0-9A-HJKMNP-TV-Z]{26}$'), tenant_id VARCHAR(26) NOT NULL CHECK (tenant_id ~ '^[0-9A-HJKMNP-TV-Z]{26}$'), employee_id VARCHAR(26) NOT NULL, outbox_id VARCHAR(26) NOT NULL CHECK (outbox_id ~ '^[0-9A-HJKMNP-TV-Z]{26}$'), endpoint TEXT NOT NULL, status VARCHAR(20) NOT NULL DEFAULT 'pending' CHECK (status IN ('pending', 'delivered', 'failed')), attempts INTEGER NOT NULL DEFAULT 0, last_error TEXT, delivered_at TIMESTAMPTZ, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), UNIQUE (tenant_id, id), UNIQUE (tenant_id, outbox_id, endpoint), FOREIGN KEY (tenant_id, employee_id) REFERENCES staff_employees (tenant_id, id) ON DELETE CASCADE, FOREIGN KEY (outbox_id) REFERENCES staff_outbox (id) ON DELETE CASCADE ); CREATE INDEX staff_notification_deliveries_pending_idx ON staff_notification_deliveries (tenant_id, status) WHERE status = 'pending'; ALTER TABLE staff_notification_deliveries ENABLE ROW LEVEL SECURITY; ALTER TABLE staff_notification_deliveries FORCE ROW LEVEL SECURITY; CREATE POLICY staff_notification_deliveries_tenant_isolation ON staff_notification_deliveries USING (tenant_id = current_setting('app.tenant_id', true)) WITH CHECK (tenant_id = current_setting('app.tenant_id', true)); GRANT SELECT, INSERT, UPDATE, DELETE ON staff_push_subscriptions TO krona_staff_app; GRANT SELECT, INSERT, UPDATE, DELETE ON staff_notification_deliveries TO krona_staff_app;