05ed037fe8
- DNS: pilot.landvex.com -> 16.170.83.169 - TLS: Let's Encrypt certificate (expires 2026-09-30) - Nginx: reverse proxy with SSL termination - API: https://pilot.landvex.com/api/v1/missions - UI: https://pilot.landvex.com/ - Upload: POST /api/v1/missions/import (multipart/form-data) Verified: ✅ https://pilot.landvex.com/health ✅ https://pilot.landvex.com/version ✅ https://pilot.landvex.com/api/v1/missions (list) ✅ https://pilot.landvex.com/api/v1/missions/:id (get) ✅ POST /api/v1/missions/import (video upload) ✅ UI loads with title 'LandveX Intelligence Lab' Next: Pilot 001 — Break the system!
113 lines
4.7 KiB
PL/PgSQL
113 lines
4.7 KiB
PL/PgSQL
-- 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();
|