bmc_hub/migrations/1030_project_ct_vtiger_archive.sql
Christian 1cfe5aee76 feat(migrations): add AI benchmark and vTiger archive tables
- Created tables for AI benchmark runs and results to facilitate model evaluation.
- Added expected answers column to benchmark results.
- Introduced tables for internet connection change cases and vTiger archive management, including records, relations, and checkpoints.
- Implemented triggers to enforce append-only behavior for vTiger archive records and files.
- Enhanced solution management with soft delete capabilities for sag_solutions and knowledge_articles.

feat(scripts): add CRM benchmarking script for Ollama models

- Developed a Python script to benchmark CRM models exposed through Ollama, including various test cases and scoring mechanisms.

test(tests): add comprehensive tests for new features

- Implemented tests for internet change case service, vTiger archive functionality, and sag solution knowledge management.
- Ensured coverage for edge cases and error handling in the new features.
2026-08-31 13:01:35 +02:00

86 lines
3.6 KiB
PL/PgSQL

-- Project CT: permanent, versioned and application-read-only vTiger archive.
CREATE TABLE IF NOT EXISTS vtiger_archive_versions (
id BIGSERIAL PRIMARY KEY,
sync_kind VARCHAR(20) NOT NULL CHECK (sync_kind IN ('full','incremental','final')),
status VARCHAR(20) NOT NULL DEFAULT 'running' CHECK (status IN ('running','completed','failed')),
started_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
completed_at TIMESTAMPTZ,
source_cutoff TIMESTAMPTZ NOT NULL DEFAULT NOW(),
initiated_by INTEGER REFERENCES users(user_id) ON DELETE SET NULL,
module_counts JSONB NOT NULL DEFAULT '{}'::jsonb,
warnings JSONB NOT NULL DEFAULT '[]'::jsonb,
critical_errors JSONB NOT NULL DEFAULT '[]'::jsonb,
control_report JSONB NOT NULL DEFAULT '{}'::jsonb,
control_approved_at TIMESTAMPTZ,
control_approved_by INTEGER REFERENCES users(user_id) ON DELETE SET NULL,
raw_export_sha256 VARCHAR(64),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS vtiger_archive_records (
id BIGSERIAL PRIMARY KEY,
version_id BIGINT NOT NULL REFERENCES vtiger_archive_versions(id) ON DELETE RESTRICT,
module VARCHAR(80) NOT NULL,
vtiger_id VARCHAR(120) NOT NULL,
revision_no INTEGER NOT NULL,
source_created_at TIMESTAMPTZ,
source_modified_at TIMESTAMPTZ,
is_deleted BOOLEAN NOT NULL DEFAULT FALSE,
payload JSONB NOT NULL,
payload_sha256 VARCHAR(64) NOT NULL,
archived_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE(module, vtiger_id, revision_no),
UNIQUE(version_id, module, vtiger_id, payload_sha256)
);
CREATE INDEX IF NOT EXISTS idx_vtiger_archive_records_lookup
ON vtiger_archive_records(module, vtiger_id, revision_no DESC);
CREATE INDEX IF NOT EXISTS idx_vtiger_archive_records_version
ON vtiger_archive_records(version_id, module);
CREATE TABLE IF NOT EXISTS vtiger_archive_relations (
id BIGSERIAL PRIMARY KEY,
version_id BIGINT NOT NULL REFERENCES vtiger_archive_versions(id) ON DELETE RESTRICT,
source_module VARCHAR(80) NOT NULL,
source_vtiger_id VARCHAR(120) NOT NULL,
field_name VARCHAR(120) NOT NULL,
target_vtiger_id VARCHAR(120) NOT NULL,
target_module VARCHAR(80),
UNIQUE(version_id, source_module, source_vtiger_id, field_name, target_vtiger_id)
);
CREATE INDEX IF NOT EXISTS idx_vtiger_archive_relations_target
ON vtiger_archive_relations(target_vtiger_id);
CREATE TABLE IF NOT EXISTS vtiger_archive_checkpoints (
module VARCHAR(80) PRIMARY KEY,
last_modified_at TIMESTAMPTZ,
last_vtiger_id VARCHAR(120),
last_successful_version_id BIGINT REFERENCES vtiger_archive_versions(id) ON DELETE SET NULL,
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS hub_impact_reports (
id BIGSERIAL PRIMARY KEY,
archive_version_id BIGINT NOT NULL REFERENCES vtiger_archive_versions(id) ON DELETE RESTRICT,
vtiger_from DATE NOT NULL,
vtiger_to DATE NOT NULL,
hub_from DATE NOT NULL,
hub_to DATE NOT NULL,
filters JSONB NOT NULL DEFAULT '{}'::jsonb,
result JSONB NOT NULL,
result_sha256 VARCHAR(64) NOT NULL,
generated_by INTEGER REFERENCES users(user_id) ON DELETE SET NULL,
generated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE OR REPLACE FUNCTION deny_vtiger_archive_mutation() RETURNS trigger AS $$
BEGIN
RAISE EXCEPTION 'vTiger archive revisions are append-only';
END;
$$ LANGUAGE plpgsql;
DROP TRIGGER IF EXISTS trg_vtiger_archive_records_immutable ON vtiger_archive_records;
CREATE TRIGGER trg_vtiger_archive_records_immutable
BEFORE UPDATE OR DELETE ON vtiger_archive_records
FOR EACH ROW EXECUTE FUNCTION deny_vtiger_archive_mutation();