-- LandveX Reporting Module — PostgreSQL Schema -- Tenant-isolerad, audit-loggad, schemalagd rapportering -- Rapporter (self-service, per tenant) CREATE TABLE reports ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL, name VARCHAR(255) NOT NULL, description TEXT, type VARCHAR(50) NOT NULL CHECK (type IN ('table','chart','pivot','map','dashboard')), config JSONB NOT NULL DEFAULT '{}', data_source_id UUID, created_by UUID NOT NULL, created_at TIMESTAMPTZ DEFAULT now(), updated_at TIMESTAMPTZ DEFAULT now() ); CREATE INDEX idx_reports_tenant ON reports(tenant_id); CREATE INDEX idx_reports_type ON reports(type); -- Körningshistorik (audit + resultat) CREATE TABLE report_runs ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), report_id UUID NOT NULL REFERENCES reports(id) ON DELETE CASCADE, status VARCHAR(20) NOT NULL DEFAULT 'pending' CHECK (status IN ('pending','running','completed','failed','cancelled')), started_at TIMESTAMPTZ, completed_at TIMESTAMPTZ, result_url TEXT, result_format VARCHAR(10) DEFAULT 'json' CHECK (result_format IN ('json','csv','xlsx','pdf')), row_count INTEGER, error_message TEXT, triggered_by UUID, parameters JSONB DEFAULT '{}', created_at TIMESTAMPTZ DEFAULT now() ); CREATE INDEX idx_report_runs_report ON report_runs(report_id, created_at DESC); CREATE INDEX idx_report_runs_status ON report_runs(status) WHERE status IN ('pending','running'); -- Scheman (cron-baserade) CREATE TABLE report_schedules ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), report_id UUID NOT NULL REFERENCES reports(id) ON DELETE CASCADE, cron_expression VARCHAR(100) NOT NULL, timezone VARCHAR(50) DEFAULT 'Europe/Stockholm', next_run_at TIMESTAMPTZ, last_run_at TIMESTAMPTZ, status VARCHAR(20) DEFAULT 'active' CHECK (status IN ('active','paused','disabled')), created_by UUID NOT NULL, created_at TIMESTAMPTZ DEFAULT now() ); CREATE INDEX idx_schedules_next_run ON report_schedules(next_run_at) WHERE status = 'active'; CREATE INDEX idx_schedules_report ON report_schedules(report_id); -- Delning (användare + externa e-post) CREATE TABLE report_shares ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), report_id UUID NOT NULL REFERENCES reports(id) ON DELETE CASCADE, shared_with_user_id UUID, shared_with_email VARCHAR(255), permission VARCHAR(20) NOT NULL DEFAULT 'read' CHECK (permission IN ('read','write','admin')), share_token VARCHAR(64) UNIQUE, expires_at TIMESTAMPTZ, created_by UUID NOT NULL, created_at TIMESTAMPTZ DEFAULT now(), CONSTRAINT share_target CHECK (shared_with_user_id IS NOT NULL OR shared_with_email IS NOT NULL) ); CREATE INDEX idx_shares_user ON report_shares(shared_with_user_id); CREATE INDEX idx_shares_token ON report_shares(share_token) WHERE share_token IS NOT NULL; -- Datakällor (befintlig tabell, utökas) CREATE TABLE data_sources ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL, name VARCHAR(255) NOT NULL, type VARCHAR(50) NOT NULL CHECK (type IN ('postgresql','mysql','api','s3','bigquery','snowflake','mssql')), connection JSONB NOT NULL, config JSONB DEFAULT '{}', status VARCHAR(20) DEFAULT 'active', created_at TIMESTAMPTZ DEFAULT now() ); CREATE INDEX idx_data_sources_tenant ON data_sources(tenant_id); -- Audit-logg för alla rapport-händelser CREATE TABLE report_audit_log ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), report_id UUID REFERENCES reports(id) ON DELETE SET NULL, run_id UUID REFERENCES report_runs(id) ON DELETE SET NULL, user_id UUID, action VARCHAR(50) NOT NULL CHECK (action IN ('created','updated','deleted','run','exported','shared','schedule_created','schedule_updated','schedule_deleted')), details JSONB DEFAULT '{}', ip_address INET, created_at TIMESTAMPTZ DEFAULT now() ); CREATE INDEX idx_audit_report ON report_audit_log(report_id, created_at DESC); CREATE INDEX idx_audit_user ON report_audit_log(user_id, created_at DESC); -- Uppdatera updated_at automatiskt CREATE OR REPLACE FUNCTION update_updated_at_column() RETURNS TRIGGER AS $$ BEGIN NEW.updated_at = now(); RETURN NEW; END; $$ language 'plpgsql'; CREATE TRIGGER update_reports_updated_at BEFORE UPDATE ON reports FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();